Compare commits

...

48 Commits

Author SHA1 Message Date
778939d018 sys,dll,inc: implement user mode locking 2017-11-28 14:18:48 -08:00
5c962c8fc5 doc: includes notes on backwards compat testing 2017-11-15 15:08:26 -08:00
a9080208d9 tools,tst: backwards compat testing for FUSE layer 2017-11-15 13:41:17 -08:00
3cc9697248 update changelog for v1.2B3 2017-11-15 11:57:53 -08:00
9f45d513ca build: update version to 2017.2 B3 2017-11-15 11:29:08 -08:00
77349c1330 tst: winfsp-tests: setfileinfo_test, stream_setfileinfo_test:
- perform time tests around UNIX epoch to accommodate 32-bit file systems
2017-11-15 10:48:15 -08:00
7c11a45e6e tst: passthrough-fuse: setcrtime 2017-11-14 21:55:41 -08:00
48ad297df1 dll: fuse: setcrtime, setchgtime 2017-11-14 21:55:09 -08:00
3d2de57e9d tst: passthrough-fuse: streamline time calculations 2017-11-14 21:38:20 -08:00
658d873efb dll: fuse: streamline time calculations 2017-11-14 21:37:50 -08:00
efc93cacd3 tst: passthrough-fuse: BSD flags support 2017-11-14 14:25:17 -08:00
41b54ef57a tools: run-tests: enable setfileinfo_test for passthrough-fuse 2017-11-14 12:02:19 -08:00
fd662ee848 tst: passthrough-fuse: BSD flags support 2017-11-14 12:01:00 -08:00
895bf67691 dll: fuse: implement BSD flags support 2017-11-14 09:11:51 -08:00
e06fe4153d dll: fuse: implement BSD flags support 2017-11-13 20:44:49 -08:00
9f2fe92db7 tst: memfs: slowio: improvements 2017-11-03 10:01:27 -07:00
d3f829b2df tools: run-tests: fsx-memfs-*-slowio 2017-11-02 21:45:08 -07:00
fa4651b3ce tst: winfsp-tests: enable slowio 2017-11-02 17:36:52 -07:00
5a44e5c04a tst: memfs: fix pending Write 2017-11-02 16:19:19 -07:00
68122b5c68 tst: winfsp-tests: enable slowiio 2017-11-02 15:59:32 -07:00
b672312c79 tst: memfs: code cleanup and testing 2017-11-02 15:43:14 -07:00
0ab35fde1a tst: memfs: slowio: minor code cleanup 2017-11-01 18:30:36 -07:00
9be2b7a2b9 tst: memfs: slowio 2017-11-01 17:12:29 -07:00
39dd7662bd Update Contributors.asciidoc 2017-11-01 09:58:11 -07:00
244afc8a3c Update memfs-main.c 2017-10-31 15:50:50 -07:00
111955db84 Update memfs.cpp 2017-10-31 15:44:24 -07:00
76ff8232bc Update memfs-main.c 2017-10-31 15:42:26 -07:00
9a3ac3c7a1 Update memfs.h 2017-10-31 15:39:19 -07:00
4adc0d4700 Update memfs-test.c 2017-10-31 15:36:09 -07:00
91c714dd53 Update fscrash-main.c 2017-10-31 15:32:12 -07:00
11cb57a0bf dll: np: pass username as argument to launcher 2017-10-27 15:12:18 -07:00
3a8ad9c8d7 sys: QueryDirectory stability:
- FspMetaCacheAddItem now handles exceptions during copy from fs buffer
- FspFsvolQueryDirectoryLengthMax is correct max length for QueryDirectory
2017-10-25 10:44:33 -07:00
fa388e57ad appveyor: add avast testing 2017-10-20 13:54:26 -07:00
1952d0d941 update changelog 2017-10-19 19:18:21 -07:00
1a02438488 sys: dirctl: fix 32-bit builds (after Avast changes) 2017-10-19 17:19:31 -07:00
07f15c236b sys: dirctl: eliminate use of SystemBuffer to work around problems with Avast 2017-10-19 16:49:10 -07:00
93af1be861 update changelog 2017-10-12 10:11:01 -07:00
b52c90f980 update changelog 2017-10-12 10:02:28 -07:00
b154c307b7 version.properties: update build to 2017.2 B2 2017-10-12 09:52:41 -07:00
697063af51 inc: winfsp.h: minor restructuring 2017-10-11 17:17:18 -07:00
436e31da34 dotnet: GetOperationProcessId 2017-10-11 17:07:38 -07:00
92e7dbad21 sys: Create and Rename requests should include the originating process PID 2017-10-11 16:28:50 -07:00
4812f5bbd0 sys: Create and Rename requests should include the originating process PID 2017-10-11 16:25:22 -07:00
045a1fa19c Update memfs-test.c 2017-10-09 14:51:18 -07:00
c9b2c0460b Update fscrash-main.c 2017-10-09 14:49:50 -07:00
1468df78a2 Update memfs.h 2017-10-09 14:48:33 -07:00
0fb6299f17 Update memfs-main.c 2017-10-09 14:47:28 -07:00
0da43fe2d4 Update memfs.cpp 2017-10-09 14:46:24 -07:00
45 changed files with 1381 additions and 634 deletions

View File

@ -1,6 +1,29 @@
= Changelog = Changelog
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:
- New command line tool `fsptool` allows command line access to some WinFsp features.
- New `GetDirInfoByName` file system operation adds fast queries of directory info by file name rather than pattern [e.g. `FindFirstFileW(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`.
- Important GitHub issues fixed: #96, #97, #103, #107
v1.2B1 (2017.2 B1):: v1.2B1 (2017.2 B1)::
- New command line tool `fsptool` allows command line access to some WinFsp features. - New command line tool `fsptool` allows command line access to some WinFsp features.

View File

@ -55,6 +55,7 @@ CONTRIBUTOR LIST
---------------- ----------------
|=== |===
|Bill Zissimopoulos |billziss at navimatics.com |Bill Zissimopoulos |billziss at navimatics.com
|John Oberschelp |john at oberschelp.net
|Sam Kelly (DuroSoft Technologies LLC, https://durosoft.com) |sam at durosoft.com |Sam Kelly (DuroSoft Technologies LLC, https://durosoft.com) |sam at durosoft.com
|Tobias Urlaub |saibotu at outlook.de |Tobias Urlaub |saibotu at outlook.de
|=== |===

View File

@ -6,8 +6,10 @@ environment:
TESTING: Func TESTING: Func
- CONFIGURATION: Release - CONFIGURATION: Release
TESTING: Func TESTING: Func
- CONFIGURATION: Release #- CONFIGURATION: Release
TESTING: Perf # TESTING: Avast
#- CONFIGURATION: Release
# TESTING: Perf
install: install:
- git submodule update --init --recursive - git submodule update --init --recursive
@ -30,6 +32,9 @@ test_script:
- if %TESTING%==Func tools\run-tests.bat %CONFIGURATION% - if %TESTING%==Func tools\run-tests.bat %CONFIGURATION%
- if %TESTING%==Func tools\run-tests.bat %CONFIGURATION% ifstest - if %TESTING%==Func tools\run-tests.bat %CONFIGURATION% ifstest
- if %TESTING%==Func tools\run-tests.bat %CONFIGURATION% sample - 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 - if %TESTING%==Perf tools\run-perf-tests.bat %CONFIGURATION% baseline > perf-tests.csv && type perf-tests.csv & appveyor PushArtifact perf-tests.csv
- choco uninstall winfsp -y - choco uninstall winfsp -y
- if exist %SystemRoot%\memory.dmp exit 1 - if exist %SystemRoot%\memory.dmp exit 1

View File

@ -18,7 +18,7 @@
<MyCanonicalVersion>1.2</MyCanonicalVersion> <MyCanonicalVersion>1.2</MyCanonicalVersion>
<MyProductVersion>2017.2 B1</MyProductVersion> <MyProductVersion>2017.2 B3</MyProductVersion>
<MyProductStage>Beta</MyProductStage> <MyProductStage>Beta</MyProductStage>
<MyVersion>$(MyCanonicalVersion).$(MyBuildNumber)</MyVersion> <MyVersion>$(MyCanonicalVersion).$(MyBuildNumber)</MyVersion>

View File

@ -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. 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. 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. 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 == Code Analysis
WinFsp is regularly run under the Visual Studio's Code Analyzer. Any issues found are examined and if necessary acted upon. WinFsp is regularly run under the Visual Studio's Code Analyzer. Any issues found are examined and if necessary acted upon.

View File

@ -39,54 +39,82 @@ typedef int (*fuse_dirfil_t)(fuse_dirh_t h, const char *name,
struct fuse_operations struct fuse_operations
{ {
int (*getattr)(const char *path, struct fuse_stat *stbuf); /* S - supported by WinFsp */
int (*getdir)(const char *path, fuse_dirh_t h, fuse_dirfil_t filler); /* S */ int (*getattr)(const char *path, struct fuse_stat *stbuf);
int (*readlink)(const char *path, char *buf, size_t size); /* S */ int (*getdir)(const char *path, fuse_dirh_t h, fuse_dirfil_t filler);
int (*mknod)(const char *path, fuse_mode_t mode, fuse_dev_t dev); /* S */ int (*readlink)(const char *path, char *buf, size_t size);
int (*mkdir)(const char *path, fuse_mode_t mode); /* S */ int (*mknod)(const char *path, fuse_mode_t mode, fuse_dev_t dev);
int (*unlink)(const char *path); /* S */ int (*mkdir)(const char *path, fuse_mode_t mode);
int (*rmdir)(const char *path); /* S */ int (*unlink)(const char *path);
int (*symlink)(const char *dstpath, const char *srcpath); /* S */ int (*rmdir)(const char *path);
int (*rename)(const char *oldpath, const char *newpath); /* S */ int (*symlink)(const char *dstpath, const char *srcpath);
int (*link)(const char *srcpath, const char *dstpath); /* S */ int (*rename)(const char *oldpath, const char *newpath);
int (*chmod)(const char *path, fuse_mode_t mode); /* _ */ int (*link)(const char *srcpath, const char *dstpath);
int (*chown)(const char *path, fuse_uid_t uid, fuse_gid_t gid); /* S */ int (*chmod)(const char *path, fuse_mode_t mode);
int (*truncate)(const char *path, fuse_off_t size); /* S */ int (*chown)(const char *path, fuse_uid_t uid, fuse_gid_t gid);
int (*utime)(const char *path, struct fuse_utimbuf *timbuf); /* S */ int (*truncate)(const char *path, fuse_off_t size);
int (*open)(const char *path, struct fuse_file_info *fi); /* S */ int (*utime)(const char *path, struct fuse_utimbuf *timbuf);
int (*read)(const char *path, char *buf, size_t size, fuse_off_t off, /* 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); 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); struct fuse_file_info *fi);
int (*statfs)(const char *path, struct fuse_statvfs *stbuf); /* S */ int (*statfs)(const char *path, struct fuse_statvfs *stbuf);
int (*flush)(const char *path, struct fuse_file_info *fi); /* S */ int (*flush)(const char *path, struct fuse_file_info *fi);
int (*release)(const char *path, struct fuse_file_info *fi); /* S */ int (*release)(const char *path, struct fuse_file_info *fi);
int (*fsync)(const char *path, int datasync, 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 (*setxattr)(const char *path, const char *name, const char *value, size_t size,
int flags); int flags);
int (*getxattr)(const char *path, const char *name, char *value, size_t size); /* _ */ int (*getxattr)(const char *path, const char *name, char *value, size_t size);
int (*listxattr)(const char *path, char *namebuf, size_t size); /* _ */ int (*listxattr)(const char *path, char *namebuf, size_t size);
int (*removexattr)(const char *path, const char *name); /* _ */ int (*removexattr)(const char *path, const char *name);
int (*opendir)(const char *path, struct fuse_file_info *fi); /* S */ 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, /* S */ int (*readdir)(const char *path, void *buf, fuse_fill_dir_t filler, fuse_off_t off,
struct fuse_file_info *fi); struct fuse_file_info *fi);
int (*releasedir)(const char *path, struct fuse_file_info *fi); /* S */ int (*releasedir)(const char *path, struct fuse_file_info *fi);
int (*fsyncdir)(const char *path, int datasync, struct fuse_file_info *fi); /* S */ int (*fsyncdir)(const char *path, int datasync, struct fuse_file_info *fi);
void *(*init)(struct fuse_conn_info *conn); /* S */ void *(*init)(struct fuse_conn_info *conn);
void (*destroy)(void *data); /* S */ void (*destroy)(void *data);
int (*access)(const char *path, int mask); /* _ */ int (*access)(const char *path, int mask);
int (*create)(const char *path, fuse_mode_t mode, struct fuse_file_info *fi); /* S */ 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); /* S */ 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); /* 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); /* _ */ int (*lock)(const char *path,
int (*utimens)(const char *path, const struct fuse_timespec tv[2]); struct fuse_file_info *fi, int cmd, struct fuse_flock *lock);
int (*bmap)(const char *path, size_t blocksize, uint64_t *idx); /* S */ int (*utimens)(const char *path, const struct fuse_timespec tv[2]);
unsigned int flag_nullpath_ok:1; /* _ */ int (*bmap)(const char *path, size_t blocksize, uint64_t *idx);
unsigned int flag_reserved:31; /* _ */ unsigned int flag_nullpath_ok:1;
int (*ioctl)(const char *path, int cmd, void *arg, struct fuse_file_info *fi, /* _ */ 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); 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); 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 struct fuse_context

View File

@ -49,6 +49,7 @@ extern "C" {
#define FSP_FUSE_CAP_READDIR_PLUS (1 << 21) /* file system supports enhanced readdir */ #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_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 FSP_FUSE_CAP_CASE_INSENSITIVE FUSE_CAP_CASE_INSENSITIVE
#define FUSE_IOCTL_COMPAT (1 << 0) #define FUSE_IOCTL_COMPAT (1 << 0)
@ -56,6 +57,24 @@ extern "C" {
#define FUSE_IOCTL_RETRY (1 << 2) #define FUSE_IOCTL_RETRY (1 << 2)
#define FUSE_IOCTL_MAX_IOV 256 #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 struct fuse_file_info
{ {
int flags; int flags;
@ -85,6 +104,9 @@ struct fuse_conn_info
struct fuse_session; struct fuse_session;
struct fuse_chan; struct fuse_chan;
struct fuse_pollhandle; 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 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, FSP_FUSE_API struct fuse_chan *FSP_FUSE_API_NAME(fsp_fuse_mount)(struct fsp_fuse_env *env,

View File

@ -65,6 +65,27 @@ extern "C" {
* to be usable from Cygwin. * 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) #if defined(_WIN64) || defined(_WIN32)
typedef uint32_t fuse_uid_t; typedef uint32_t fuse_uid_t;
@ -111,23 +132,17 @@ struct fuse_timespec
}; };
#endif #endif
#if !defined(FSP_FUSE_USE_STAT_EX)
struct fuse_stat struct fuse_stat
{ {
fuse_dev_t st_dev; FSP_FUSE_STAT_FIELD_DEFN
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;
}; };
#else
struct fuse_stat
{
FSP_FUSE_STAT_EX_FIELD_DEFN
};
#endif
#if defined(_WIN64) #if defined(_WIN64)
struct fuse_statvfs struct fuse_statvfs
@ -222,7 +237,14 @@ struct fuse_flock
#define fuse_utimbuf utimbuf #define fuse_utimbuf utimbuf
#define fuse_timespec timespec #define fuse_timespec timespec
#if !defined(FSP_FUSE_USE_STAT_EX)
#define fuse_stat stat #define fuse_stat stat
#else
struct fuse_stat
{
FSP_FUSE_STAT_EX_FIELD_DEFN
};
#endif
#define fuse_statvfs statvfs #define fuse_statvfs statvfs
#define fuse_flock flock #define fuse_flock flock
@ -246,6 +268,11 @@ struct fuse_flock
#error unsupported environment #error unsupported environment
#endif #endif
struct fuse_stat_ex
{
FSP_FUSE_STAT_EX_FIELD_DEFN
};
struct fsp_fuse_env struct fsp_fuse_env
{ {
unsigned environment; unsigned environment;

View File

@ -153,7 +153,8 @@ typedef struct
UINT32 PassQueryDirectoryPattern:1; /* pass Pattern during QueryDirectory operations */ UINT32 PassQueryDirectoryPattern:1; /* pass Pattern during QueryDirectory operations */
UINT32 AlwaysUseDoubleBuffering:1; UINT32 AlwaysUseDoubleBuffering:1;
UINT32 PassQueryDirectoryFileName:1; /* pass FileName during QueryDirectory (GetDirInfoByName) */ UINT32 PassQueryDirectoryFileName:1; /* pass FileName during QueryDirectory (GetDirInfoByName) */
UINT32 KmReservedFlags:2; UINT32 UserModeFileLocking:1; /* pass file locking requests to user mode */
UINT32 KmReservedFlags:1;
/* user-mode flags */ /* user-mode flags */
UINT32 UmFileContextIsUserContext2:1; /* user mode: FileContext parameter is UserContext2 */ UINT32 UmFileContextIsUserContext2:1; /* user mode: FileContext parameter is UserContext2 */
UINT32 UmFileContextIsFullContext:1; /* user mode: FileContext parameter is FullContext */ UINT32 UmFileContextIsFullContext:1; /* user mode: FileContext parameter is FullContext */
@ -259,6 +260,7 @@ typedef struct
UINT32 SetLastAccessTime:1; UINT32 SetLastAccessTime:1;
UINT32 SetLastWriteTime:1; UINT32 SetLastWriteTime:1;
UINT32 SetChangeTime:1; UINT32 SetChangeTime:1;
UINT32 UnlockAll:1;
} Cleanup; } Cleanup;
struct struct
{ {
@ -273,6 +275,7 @@ typedef struct
UINT64 Offset; UINT64 Offset;
UINT32 Length; UINT32 Length;
UINT32 Key; UINT32 Key;
UINT32 ProcessId;
} Read; } Read;
struct struct
{ {
@ -283,6 +286,8 @@ typedef struct
UINT32 Length; UINT32 Length;
UINT32 Key; UINT32 Key;
UINT32 ConstrainedIo:1; UINT32 ConstrainedIo:1;
UINT32 ReservedFlags:31;
UINT32 ProcessId;
} Write; } Write;
struct struct
{ {
@ -359,6 +364,18 @@ typedef struct
UINT16 TargetOnFileSystem; /* the target of the symbolic link is on this file system */ UINT16 TargetOnFileSystem; /* the target of the symbolic link is on this file system */
} FileSystemControl; } FileSystemControl;
struct struct
{
UINT64 UserContext;
UINT64 UserContext2;
UINT32 LockFunction;
UINT64 Offset;
UINT64 Length;
UINT32 Key;
UINT32 ProcessId;
UINT32 Exclusive:1;
UINT32 FailImmediately:1;
} LockControl;
struct
{ {
UINT64 UserContext; UINT64 UserContext;
UINT64 UserContext2; UINT64 UserContext2;

View File

@ -133,6 +133,7 @@ enum
FspCleanupSetLastAccessTime = 0x20, FspCleanupSetLastAccessTime = 0x20,
FspCleanupSetLastWriteTime = 0x40, FspCleanupSetLastWriteTime = 0x40,
FspCleanupSetChangeTime = 0x80, FspCleanupSetChangeTime = 0x80,
FspCleanupUnlockAll = 0x0100,
}; };
/** /**
* @class FSP_FILE_SYSTEM * @class FSP_FILE_SYSTEM
@ -822,12 +823,80 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
NTSTATUS (*GetDirInfoByName)(FSP_FILE_SYSTEM *FileSystem, NTSTATUS (*GetDirInfoByName)(FSP_FILE_SYSTEM *FileSystem,
PVOID FileContext, PWSTR FileName, PVOID FileContext, PWSTR FileName,
FSP_FSCTL_DIR_INFO *DirInfo); FSP_FSCTL_DIR_INFO *DirInfo);
/**
* Lock a file range.
*
* At the time of this call the FSD has already done its own locking processing.
* Thus the kernel may fail a lock control request or a Read or Write without
* informing the user mode file system.
*
* @param FileSystem
* The file system on which this request is posted.
* @param FileContext
* The file context of the file to be locked.
* @param Offset
* Offset within the file to lock.
* @param Length
* Length of data to lock.
* @param Owner
* Lock owner. This 64-bit value consists of a PID in the high 32-bits and a "Key"
* in the low 32-bits. The PID is that of the process requesting the lock. The Key
* is an arbitrary value.
*
* The triplet (FileDesc,PID,Key) uniquely identifies the lock owner.
* @param Exclusive
* When TRUE an exclusive lock is requested. Otherwise a shared lock is requested.
* @param FailImmediately
* When TRUE the function should return immediately if it is unable to acquire the
* requested lock. Otherwise the function should wait until the lock can be granted.
* In this case the function may also return STATUS_PENDING.
* @return
* STATUS_SUCCESS or error code. STATUS_PENDING is supported allowing for asynchronous
* operation.
*/
NTSTATUS (*Lock)(FSP_FILE_SYSTEM *FileSystem,
PVOID FileContext, UINT64 Offset, UINT64 Length, UINT64 Owner,
BOOLEAN Exclusive, BOOLEAN FailImmediately);
/**
* Unlock file ranges.
*
* At the time of this call the FSD has already done its own locking processing.
* Thus the kernel may fail a lock control request or a Read or Write without
* informing the user mode file system.
*
* An Unlock operation with Offset == Length == -1 is a request to remove multiple locks.
* The set of possible locks to remove includes all locks made by the process described
* by the Owner parameter through the file descriptor described by the FileContext parameter.
* If the Key portion of the Owner parameter is 0, all the locks in the set are removed.
* If the Key portion of the Owner paramter is non-0, only locks that match the Key are
* removed.
*
* @param FileSystem
* The file system on which this request is posted.
* @param FileContext
* The file context of the file to be unlocked.
* @param Offset
* Offset within the file to unlock.
* @param Length
* Length of data to unlock.
* @param Owner
* Lock owner. This 64-bit value consists of a PID in the high 32-bits and a "Key"
* in the low 32-bits. The PID is that of the process requesting the lock. The Key
* is an arbitrary value.
*
* The triplet (FileDesc,PID,Key) uniquely identifies the lock owner.
* @return
* STATUS_SUCCESS or error code. STATUS_PENDING is supported allowing for asynchronous
* operation.
*/
NTSTATUS (*Unlock)(FSP_FILE_SYSTEM *FileSystem,
PVOID FileContext, UINT64 Offset, UINT64 Length, UINT64 Owner);
/* /*
* This ensures that this interface will always contain 64 function pointers. * This ensures that this interface will always contain 64 function pointers.
* Please update when changing the interface as it is important for future compatibility. * Please update when changing the interface as it is important for future compatibility.
*/ */
NTSTATUS (*Reserved[39])(); NTSTATUS (*Reserved[37])();
} FSP_FILE_SYSTEM_INTERFACE; } FSP_FILE_SYSTEM_INTERFACE;
FSP_FSCTL_STATIC_ASSERT(sizeof(FSP_FILE_SYSTEM_INTERFACE) == 64 * sizeof(NTSTATUS (*)()), FSP_FSCTL_STATIC_ASSERT(sizeof(FSP_FILE_SYSTEM_INTERFACE) == 64 * sizeof(NTSTATUS (*)()),
"FSP_FILE_SYSTEM_INTERFACE must have 64 entries."); "FSP_FILE_SYSTEM_INTERFACE must have 64 entries.");
@ -981,14 +1050,12 @@ FSP_API VOID FspFileSystemSendResponse(FSP_FILE_SYSTEM *FileSystem,
* The current operation context. * The current operation context.
*/ */
FSP_API FSP_FILE_SYSTEM_OPERATION_CONTEXT *FspFileSystemGetOperationContext(VOID); FSP_API FSP_FILE_SYSTEM_OPERATION_CONTEXT *FspFileSystemGetOperationContext(VOID);
FSP_API PWSTR FspFileSystemMountPointF(FSP_FILE_SYSTEM *FileSystem);
static inline static inline
PWSTR FspFileSystemMountPoint(FSP_FILE_SYSTEM *FileSystem) PWSTR FspFileSystemMountPoint(FSP_FILE_SYSTEM *FileSystem)
{ {
return FileSystem->MountPoint; return FileSystem->MountPoint;
} }
FSP_API NTSTATUS FspFileSystemEnterOperationF(FSP_FILE_SYSTEM *FileSystem, FSP_API PWSTR FspFileSystemMountPointF(FSP_FILE_SYSTEM *FileSystem);
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response);
static inline static inline
NTSTATUS FspFileSystemEnterOperation(FSP_FILE_SYSTEM *FileSystem, NTSTATUS FspFileSystemEnterOperation(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response) FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response)
@ -998,7 +1065,7 @@ NTSTATUS FspFileSystemEnterOperation(FSP_FILE_SYSTEM *FileSystem,
return FileSystem->EnterOperation(FileSystem, Request, Response); return FileSystem->EnterOperation(FileSystem, Request, Response);
} }
FSP_API NTSTATUS FspFileSystemLeaveOperationF(FSP_FILE_SYSTEM *FileSystem, FSP_API NTSTATUS FspFileSystemEnterOperationF(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response); FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response);
static inline static inline
NTSTATUS FspFileSystemLeaveOperation(FSP_FILE_SYSTEM *FileSystem, NTSTATUS FspFileSystemLeaveOperation(FSP_FILE_SYSTEM *FileSystem,
@ -1009,9 +1076,8 @@ NTSTATUS FspFileSystemLeaveOperation(FSP_FILE_SYSTEM *FileSystem,
return FileSystem->LeaveOperation(FileSystem, Request, Response); return FileSystem->LeaveOperation(FileSystem, Request, Response);
} }
FSP_API VOID FspFileSystemSetOperationGuardF(FSP_FILE_SYSTEM *FileSystem, FSP_API NTSTATUS FspFileSystemLeaveOperationF(FSP_FILE_SYSTEM *FileSystem,
FSP_FILE_SYSTEM_OPERATION_GUARD *EnterOperation, FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response);
FSP_FILE_SYSTEM_OPERATION_GUARD *LeaveOperation);
static inline static inline
VOID FspFileSystemSetOperationGuard(FSP_FILE_SYSTEM *FileSystem, VOID FspFileSystemSetOperationGuard(FSP_FILE_SYSTEM *FileSystem,
FSP_FILE_SYSTEM_OPERATION_GUARD *EnterOperation, FSP_FILE_SYSTEM_OPERATION_GUARD *EnterOperation,
@ -1020,6 +1086,9 @@ VOID FspFileSystemSetOperationGuard(FSP_FILE_SYSTEM *FileSystem,
FileSystem->EnterOperation = EnterOperation; FileSystem->EnterOperation = EnterOperation;
FileSystem->LeaveOperation = LeaveOperation; FileSystem->LeaveOperation = LeaveOperation;
} }
FSP_API VOID FspFileSystemSetOperationGuardF(FSP_FILE_SYSTEM *FileSystem,
FSP_FILE_SYSTEM_OPERATION_GUARD *EnterOperation,
FSP_FILE_SYSTEM_OPERATION_GUARD *LeaveOperation);
/** /**
* Set file system locking strategy. * Set file system locking strategy.
* *
@ -1030,17 +1099,14 @@ VOID FspFileSystemSetOperationGuard(FSP_FILE_SYSTEM *FileSystem,
* @see * @see
* FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY * FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY
*/ */
FSP_API VOID FspFileSystemSetOperationGuardStrategyF(FSP_FILE_SYSTEM *FileSystem,
FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY GuardStrategy);
static inline static inline
VOID FspFileSystemSetOperationGuardStrategy(FSP_FILE_SYSTEM *FileSystem, VOID FspFileSystemSetOperationGuardStrategy(FSP_FILE_SYSTEM *FileSystem,
FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY GuardStrategy) FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY GuardStrategy)
{ {
FileSystem->OpGuardStrategy = GuardStrategy; FileSystem->OpGuardStrategy = GuardStrategy;
} }
FSP_API VOID FspFileSystemSetOperationF(FSP_FILE_SYSTEM *FileSystem, FSP_API VOID FspFileSystemSetOperationGuardStrategyF(FSP_FILE_SYSTEM *FileSystem,
ULONG Index, FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY GuardStrategy);
FSP_FILE_SYSTEM_OPERATION *Operation);
static inline static inline
VOID FspFileSystemSetOperation(FSP_FILE_SYSTEM *FileSystem, VOID FspFileSystemSetOperation(FSP_FILE_SYSTEM *FileSystem,
ULONG Index, ULONG Index,
@ -1048,8 +1114,9 @@ VOID FspFileSystemSetOperation(FSP_FILE_SYSTEM *FileSystem,
{ {
FileSystem->Operations[Index] = Operation; FileSystem->Operations[Index] = Operation;
} }
FSP_API VOID FspFileSystemGetDispatcherResultF(FSP_FILE_SYSTEM *FileSystem, FSP_API VOID FspFileSystemSetOperationF(FSP_FILE_SYSTEM *FileSystem,
NTSTATUS *PDispatcherResult); ULONG Index,
FSP_FILE_SYSTEM_OPERATION *Operation);
static inline static inline
VOID FspFileSystemGetDispatcherResult(FSP_FILE_SYSTEM *FileSystem, VOID FspFileSystemGetDispatcherResult(FSP_FILE_SYSTEM *FileSystem,
NTSTATUS *PDispatcherResult) NTSTATUS *PDispatcherResult)
@ -1058,8 +1125,8 @@ VOID FspFileSystemGetDispatcherResult(FSP_FILE_SYSTEM *FileSystem,
*PDispatcherResult = FileSystem->DispatcherResult; *PDispatcherResult = FileSystem->DispatcherResult;
MemoryBarrier(); MemoryBarrier();
} }
FSP_API VOID FspFileSystemSetDispatcherResultF(FSP_FILE_SYSTEM *FileSystem, FSP_API VOID FspFileSystemGetDispatcherResultF(FSP_FILE_SYSTEM *FileSystem,
NTSTATUS DispatcherResult); NTSTATUS *PDispatcherResult);
static inline static inline
VOID FspFileSystemSetDispatcherResult(FSP_FILE_SYSTEM *FileSystem, VOID FspFileSystemSetDispatcherResult(FSP_FILE_SYSTEM *FileSystem,
NTSTATUS DispatcherResult) NTSTATUS DispatcherResult)
@ -1068,15 +1135,16 @@ VOID FspFileSystemSetDispatcherResult(FSP_FILE_SYSTEM *FileSystem,
return; return;
InterlockedCompareExchange(&FileSystem->DispatcherResult, DispatcherResult, 0); InterlockedCompareExchange(&FileSystem->DispatcherResult, DispatcherResult, 0);
} }
FSP_API VOID FspFileSystemSetDebugLogF(FSP_FILE_SYSTEM *FileSystem, FSP_API VOID FspFileSystemSetDispatcherResultF(FSP_FILE_SYSTEM *FileSystem,
UINT32 DebugLog); NTSTATUS DispatcherResult);
static inline static inline
VOID FspFileSystemSetDebugLog(FSP_FILE_SYSTEM *FileSystem, VOID FspFileSystemSetDebugLog(FSP_FILE_SYSTEM *FileSystem,
UINT32 DebugLog) UINT32 DebugLog)
{ {
FileSystem->DebugLog = DebugLog; FileSystem->DebugLog = DebugLog;
} }
FSP_API BOOLEAN FspFileSystemIsOperationCaseSensitiveF(VOID); FSP_API VOID FspFileSystemSetDebugLogF(FSP_FILE_SYSTEM *FileSystem,
UINT32 DebugLog);
static inline static inline
BOOLEAN FspFileSystemIsOperationCaseSensitive(VOID) BOOLEAN FspFileSystemIsOperationCaseSensitive(VOID)
{ {
@ -1085,7 +1153,12 @@ BOOLEAN FspFileSystemIsOperationCaseSensitive(VOID)
FspFsctlTransactCreateKind == Request->Kind && Request->Req.Create.CaseSensitive || FspFsctlTransactCreateKind == Request->Kind && Request->Req.Create.CaseSensitive ||
FspFsctlTransactQueryDirectoryKind == Request->Kind && Request->Req.QueryDirectory.CaseSensitive; FspFsctlTransactQueryDirectoryKind == Request->Kind && Request->Req.QueryDirectory.CaseSensitive;
} }
FSP_API UINT32 FspFileSystemOperationProcessIdF(VOID); FSP_API BOOLEAN FspFileSystemIsOperationCaseSensitiveF(VOID);
/**
* Get the originating process ID.
*
* Valid only during Create, Open and Rename requests when the target exists.
*/
static inline static inline
UINT32 FspFileSystemOperationProcessId(VOID) UINT32 FspFileSystemOperationProcessId(VOID)
{ {
@ -1102,6 +1175,29 @@ UINT32 FspFileSystemOperationProcessId(VOID)
return 0; return 0;
} }
} }
FSP_API UINT32 FspFileSystemOperationProcessIdF(VOID);
/**
* Get the lock owner.
*
* Valid only during Read, Write, Lock and Unlock requests.
*/
static inline
UINT64 FspFileSystemOperationLockOwner(VOID)
{
FSP_FSCTL_TRANSACT_REQ *Request = FspFileSystemGetOperationContext()->Request;
switch (Request->Kind)
{
case FspFsctlTransactReadKind:
return ((UINT64)Request->Req.Read.ProcessId << 32) | (UINT64)Request->Req.Read.Key;
case FspFsctlTransactWriteKind:
return ((UINT64)Request->Req.Write.ProcessId << 32) | (UINT64)Request->Req.Write.Key;
case FspFsctlTransactLockControlKind:
return ((UINT64)Request->Req.LockControl.ProcessId << 32) | (UINT64)Request->Req.LockControl.Key;
default:
return 0;
}
}
FSP_API UINT64 FspFileSystemOperationLockOwnerF(VOID);
/* /*
* Operations * Operations
@ -1136,6 +1232,8 @@ FSP_API NTSTATUS FspFileSystemOpQueryDirectory(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response); FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response);
FSP_API NTSTATUS FspFileSystemOpFileSystemControl(FSP_FILE_SYSTEM *FileSystem, FSP_API NTSTATUS FspFileSystemOpFileSystemControl(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response); FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response);
FSP_API NTSTATUS FspFileSystemOpLockControl(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response);
FSP_API NTSTATUS FspFileSystemOpQuerySecurity(FSP_FILE_SYSTEM *FileSystem, FSP_API NTSTATUS FspFileSystemOpQuerySecurity(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response); FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response);
FSP_API NTSTATUS FspFileSystemOpSetSecurity(FSP_FILE_SYSTEM *FileSystem, FSP_API NTSTATUS FspFileSystemOpSetSecurity(FSP_FILE_SYSTEM *FileSystem,
@ -1467,6 +1565,21 @@ NTSTATUS FspPosixMapPosixToWindowsPath(const char *PosixPath, PWSTR *PWindowsPat
FSP_API VOID FspPosixDeletePath(void *Path); FSP_API VOID FspPosixDeletePath(void *Path);
FSP_API VOID FspPosixEncodeWindowsPath(PWSTR WindowsPath, ULONG Size); FSP_API VOID FspPosixEncodeWindowsPath(PWSTR WindowsPath, ULONG Size);
FSP_API VOID FspPosixDecodeWindowsPath(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 * Path Handling

View File

@ -162,6 +162,7 @@ FSP_API NTSTATUS FspFileSystemCreate(PWSTR DevicePath,
FileSystem->Operations[FspFsctlTransactSetVolumeInformationKind] = FspFileSystemOpSetVolumeInformation; FileSystem->Operations[FspFsctlTransactSetVolumeInformationKind] = FspFileSystemOpSetVolumeInformation;
FileSystem->Operations[FspFsctlTransactQueryDirectoryKind] = FspFileSystemOpQueryDirectory; FileSystem->Operations[FspFsctlTransactQueryDirectoryKind] = FspFileSystemOpQueryDirectory;
FileSystem->Operations[FspFsctlTransactFileSystemControlKind] = FspFileSystemOpFileSystemControl; FileSystem->Operations[FspFsctlTransactFileSystemControlKind] = FspFileSystemOpFileSystemControl;
FileSystem->Operations[FspFsctlTransactLockControlKind] = FspFileSystemOpLockControl;
FileSystem->Operations[FspFsctlTransactQuerySecurityKind] = FspFileSystemOpQuerySecurity; FileSystem->Operations[FspFsctlTransactQuerySecurityKind] = FspFileSystemOpQuerySecurity;
FileSystem->Operations[FspFsctlTransactSetSecurityKind] = FspFileSystemOpSetSecurity; FileSystem->Operations[FspFsctlTransactSetSecurityKind] = FspFileSystemOpSetSecurity;
FileSystem->Operations[FspFsctlTransactQueryStreamInformationKind] = FspFileSystemOpQueryStreamInformation; FileSystem->Operations[FspFsctlTransactQueryStreamInformationKind] = FspFileSystemOpQueryStreamInformation;
@ -688,3 +689,8 @@ FSP_API UINT32 FspFileSystemOperationProcessIdF(VOID)
{ {
return FspFileSystemOperationProcessId(); return FspFileSystemOperationProcessId();
} }
FSP_API UINT64 FspFileSystemOperationLockOwnerF(VOID)
{
return FspFileSystemOperationLockOwner();
}

View File

@ -886,6 +886,7 @@ FSP_API NTSTATUS FspFileSystemOpCleanup(FSP_FILE_SYSTEM *FileSystem,
(0 != Request->Req.Cleanup.SetArchiveBit ? FspCleanupSetArchiveBit : 0) | (0 != Request->Req.Cleanup.SetArchiveBit ? FspCleanupSetArchiveBit : 0) |
(0 != Request->Req.Cleanup.SetLastAccessTime ? FspCleanupSetLastAccessTime : 0) | (0 != Request->Req.Cleanup.SetLastAccessTime ? FspCleanupSetLastAccessTime : 0) |
(0 != Request->Req.Cleanup.SetLastWriteTime ? FspCleanupSetLastWriteTime : 0) | (0 != Request->Req.Cleanup.SetLastWriteTime ? FspCleanupSetLastWriteTime : 0) |
(0 != Request->Req.Cleanup.UnlockAll ? FspCleanupUnlockAll : 0) |
(0 != Request->Req.Cleanup.SetChangeTime ? FspCleanupSetChangeTime : 0)); (0 != Request->Req.Cleanup.SetChangeTime ? FspCleanupSetChangeTime : 0));
return STATUS_SUCCESS; return STATUS_SUCCESS;
@ -1247,6 +1248,43 @@ FSP_API NTSTATUS FspFileSystemOpFileSystemControl(FSP_FILE_SYSTEM *FileSystem,
return Result; return Result;
} }
FSP_API NTSTATUS FspFileSystemOpLockControl(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response)
{
NTSTATUS Result;
Result = STATUS_INVALID_DEVICE_REQUEST;
switch (Request->Req.LockControl.LockFunction)
{
case 0x01/*IRP_MN_LOCK*/:
if (0 != FileSystem->Interface->Lock)
Result = FileSystem->Interface->Lock(FileSystem,
(PVOID)ValOfFileContext(Request->Req.LockControl),
Request->Req.LockControl.Offset, Request->Req.LockControl.Length,
((UINT64)Request->Req.LockControl.ProcessId << 32) | (UINT64)Request->Req.LockControl.Key,
0 != Request->Req.LockControl.Exclusive,
0 != Request->Req.LockControl.FailImmediately);
break;
case 0x02/*IRP_MN_UNLOCK_SINGLE*/:
if (0 != FileSystem->Interface->Unlock)
Result = FileSystem->Interface->Unlock(FileSystem,
(PVOID)ValOfFileContext(Request->Req.LockControl),
Request->Req.LockControl.Offset, Request->Req.LockControl.Length,
((UINT64)Request->Req.LockControl.ProcessId << 32) | (UINT64)Request->Req.LockControl.Key);
break;
case 0x03/*IRP_MN_UNLOCK_ALL*/:
case 0x04/*IRP_MN_UNLOCK_ALL_BY_KEY*/:
if (0 != FileSystem->Interface->Unlock)
Result = FileSystem->Interface->Unlock(FileSystem,
(PVOID)ValOfFileContext(Request->Req.LockControl),
(UINT64)-1LL, (UINT64)-1LL,
((UINT64)Request->Req.LockControl.ProcessId << 32) | (UINT64)Request->Req.LockControl.Key);
break;
}
return Result;
}
FSP_API NTSTATUS FspFileSystemOpQuerySecurity(FSP_FILE_SYSTEM *FileSystem, FSP_API NTSTATUS FspFileSystemOpQuerySecurity(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response) FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response)
{ {

View File

@ -299,6 +299,7 @@ static NTSTATUS fsp_fuse_svcstart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
FUSE_CAP_DONT_MASK | FUSE_CAP_DONT_MASK |
FSP_FUSE_CAP_READDIR_PLUS | FSP_FUSE_CAP_READDIR_PLUS |
FSP_FUSE_CAP_READ_ONLY | FSP_FUSE_CAP_READ_ONLY |
FSP_FUSE_CAP_STAT_EX |
FSP_FUSE_CAP_CASE_INSENSITIVE; FSP_FUSE_CAP_CASE_INSENSITIVE;
if (0 != f->ops.init) 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) if (0 != f->ops.getattr)
{ {
struct fuse_stat stbuf; struct fuse_stat_ex stbuf;
int err; int err;
memset(&stbuf, 0, sizeof stbuf); 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 == f->VolumeParams.VolumeCreationTime)
{ {
if (0 != stbuf.st_birthtim.tv_sec) if (0 != stbuf.st_birthtim.tv_sec)
f->VolumeParams.VolumeCreationTime = FspPosixUnixTimeToFileTime((void *)&stbuf.st_birthtim,
Int32x32To64(stbuf.st_birthtim.tv_sec, 10000000) + 116444736000000000 + &f->VolumeParams.VolumeCreationTime);
stbuf.st_birthtim.tv_nsec / 100;
else else
if (0 != stbuf.st_ctim.tv_sec) if (0 != stbuf.st_ctim.tv_sec)
f->VolumeParams.VolumeCreationTime = FspPosixUnixTimeToFileTime((void *)&stbuf.st_ctim,
Int32x32To64(stbuf.st_ctim.tv_sec, 10000000) + 116444736000000000 + &f->VolumeParams.VolumeCreationTime);
stbuf.st_ctim.tv_nsec / 100;
} }
} }

View File

@ -219,7 +219,7 @@ static NTSTATUS fsp_fuse_intf_NewHiddenName(FSP_FILE_SYSTEM *FileSystem,
struct { UINT32 V[4]; } Values; struct { UINT32 V[4]; } Values;
UUID Uuid; UUID Uuid;
} UuidBuf; } UuidBuf;
struct fuse_stat stbuf; struct fuse_stat_ex stbuf;
int err, maxtries = 3; int err, maxtries = 3;
*PPosixHiddenPath = 0; *PPosixHiddenPath = 0;
@ -291,7 +291,7 @@ static BOOLEAN fsp_fuse_intf_CheckSymlinkDirectory(FSP_FILE_SYSTEM *FileSystem,
struct fuse *f = FileSystem->UserContext; struct fuse *f = FileSystem->UserContext;
char *PosixDotPath = 0; char *PosixDotPath = 0;
size_t Length; size_t Length;
struct fuse_stat stbuf; struct fuse_stat_ex stbuf;
int err; int err;
BOOLEAN Result = FALSE; BOOLEAN Result = FALSE;
@ -304,6 +304,7 @@ static BOOLEAN fsp_fuse_intf_CheckSymlinkDirectory(FSP_FILE_SYSTEM *FileSystem,
PosixDotPath[Length + 1] = '.'; PosixDotPath[Length + 1] = '.';
PosixDotPath[Length + 2] = '\0'; PosixDotPath[Length + 2] = '\0';
memset(&stbuf, 0, sizeof stbuf);
if (0 != f->ops.getattr) if (0 != f->ops.getattr)
err = f->ops.getattr(PosixDotPath, (void *)&stbuf); err = f->ops.getattr(PosixDotPath, (void *)&stbuf);
else else
@ -317,25 +318,57 @@ static BOOLEAN fsp_fuse_intf_CheckSymlinkDirectory(FSP_FILE_SYSTEM *FileSystem,
return Result; 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)\ #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) fsp_fuse_intf_GetFileInfoFunnel(FileSystem, PosixPath, fi, 0, PUid, PGid, PMode, 0, FileInfo)
static NTSTATUS fsp_fuse_intf_GetFileInfoFunnel(FSP_FILE_SYSTEM *FileSystem, 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, PUINT32 PUid, PUINT32 PGid, PUINT32 PMode, PUINT32 PDev,
FSP_FSCTL_FILE_INFO *FileInfo) FSP_FSCTL_FILE_INFO *FileInfo)
{ {
struct fuse *f = FileSystem->UserContext; struct fuse *f = FileSystem->UserContext;
UINT64 AllocationUnit; 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) if (0 != stbufp)
memcpy(&stbuf, stbufp, sizeof stbuf); memcpy(&stbuf, stbufp, StatEx ? sizeof(struct fuse_stat_ex) : sizeof(struct fuse_stat));
else else
{ {
int err; int err;
memset(&stbuf, 0, sizeof stbuf);
if (0 != f->ops.fgetattr && 0 != fi && -1 != fi->fh) if (0 != f->ops.fgetattr && 0 != fi && -1 != fi->fh)
err = f->ops.fgetattr(PosixPath, (void *)&stbuf, fi); err = f->ops.fgetattr(PosixPath, (void *)&stbuf, fi);
else if (0 != f->ops.getattr) else if (0 != f->ops.getattr)
@ -390,21 +423,15 @@ static NTSTATUS fsp_fuse_intf_GetFileInfoFunnel(FSP_FILE_SYSTEM *FileSystem,
FileInfo->ReparseTag = 0; FileInfo->ReparseTag = 0;
break; break;
} }
if (StatEx)
FileInfo->FileAttributes |= fsp_fuse_intf_MapFlagsToFileAttributes(stbuf.st_flags);
FileInfo->FileSize = stbuf.st_size; FileInfo->FileSize = stbuf.st_size;
FileInfo->AllocationSize = FileInfo->AllocationSize =
(FileInfo->FileSize + AllocationUnit - 1) / AllocationUnit * AllocationUnit; (FileInfo->FileSize + AllocationUnit - 1) / AllocationUnit * AllocationUnit;
FileInfo->CreationTime = FspPosixUnixTimeToFileTime((void *)&stbuf.st_birthtim, &FileInfo->CreationTime);
Int32x32To64(stbuf.st_birthtim.tv_sec, 10000000) + 116444736000000000 + FspPosixUnixTimeToFileTime((void *)&stbuf.st_atim, &FileInfo->LastAccessTime);
stbuf.st_birthtim.tv_nsec / 100; FspPosixUnixTimeToFileTime((void *)&stbuf.st_mtim, &FileInfo->LastWriteTime);
FileInfo->LastAccessTime = FspPosixUnixTimeToFileTime((void *)&stbuf.st_ctim, &FileInfo->ChangeTime);
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;
FileInfo->IndexNumber = stbuf.st_ino; FileInfo->IndexNumber = stbuf.st_ino;
return STATUS_SUCCESS; return STATUS_SUCCESS;
@ -1241,67 +1268,74 @@ static NTSTATUS fsp_fuse_intf_SetBasicInfo(FSP_FILE_SYSTEM *FileSystem,
int err; int err;
NTSTATUS Result; 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); memset(&fi, 0, sizeof fi);
fi.flags = filedesc->OpenFlags; fi.flags = filedesc->OpenFlags;
fi.fh = filedesc->FileHandle; fi.fh = filedesc->FileHandle;
if (INVALID_FILE_ATTRIBUTES != FileAttributes &&
0 != (f->conn_want & FSP_FUSE_CAP_STAT_EX) && 0 != f->ops.chflags)
{
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;
}
if ((0 != LastAccessTime || 0 != LastWriteTime) &&
(0 != f->ops.utimens || 0 != f->ops.utime))
{
if (0 == LastAccessTime || 0 == LastWriteTime)
{
Result = fsp_fuse_intf_GetFileInfoEx(FileSystem, filedesc->PosixPath, &fi, Result = fsp_fuse_intf_GetFileInfoEx(FileSystem, filedesc->PosixPath, &fi,
&Uid, &Gid, &Mode, &FileInfoBuf); &Uid, &Gid, &Mode, &FileInfoBuf);
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
return Result; return Result;
if (0 != LastAccessTime) if (0 == LastAccessTime)
FileInfoBuf.LastAccessTime = LastAccessTime; LastAccessTime = FileInfoBuf.LastAccessTime;
if (0 != LastWriteTime) if (0 == LastWriteTime)
FileInfoBuf.LastWriteTime = LastWriteTime; LastWriteTime = FileInfoBuf.LastWriteTime;
}
/* UNIX epoch in 100-ns intervals */
LastAccessTime = FileInfoBuf.LastAccessTime - 116444736000000000;
LastWriteTime = FileInfoBuf.LastWriteTime - 116444736000000000;
FspPosixFileTimeToUnixTime(LastAccessTime, (void *)&tv[0]);
FspPosixFileTimeToUnixTime(LastWriteTime, (void *)&tv[1]);
if (0 != f->ops.utimens) if (0 != f->ops.utimens)
{ {
#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.utimens(filedesc->PosixPath, tv);
Result = fsp_fuse_ntstatus_from_errno(f->env, err); Result = fsp_fuse_ntstatus_from_errno(f->env, err);
} }
else else
{ {
#if defined(_WIN64) timbuf.actime = tv[0].tv_sec;
timbuf.actime = (int64_t)(LastAccessTime / 10000000); timbuf.modtime = tv[1].tv_sec;
timbuf.modtime = (int64_t)(LastWriteTime / 10000000);
#else
timbuf.actime = (int32_t)(LastAccessTime / 10000000);
timbuf.modtime = (int32_t)(LastWriteTime / 10000000);
#endif
err = f->ops.utime(filedesc->PosixPath, &timbuf); err = f->ops.utime(filedesc->PosixPath, &timbuf);
Result = fsp_fuse_ntstatus_from_errno(f->env, err); Result = fsp_fuse_ntstatus_from_errno(f->env, err);
} }
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
return 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, static NTSTATUS fsp_fuse_intf_SetFileSize(FSP_FILE_SYSTEM *FileSystem,

View File

@ -17,6 +17,7 @@
#include <dll/library.h> #include <dll/library.h>
#include <launcher/launcher.h> #include <launcher/launcher.h>
#include <lmcons.h>
#include <npapi.h> #include <npapi.h>
#include <wincred.h> #include <wincred.h>
@ -147,7 +148,7 @@ static inline BOOLEAN FspNpParseRemoteName(PWSTR RemoteName,
return TRUE; return TRUE;
} }
static inline BOOLEAN FspNpParseUserName(PWSTR RemoteName, static inline BOOLEAN FspNpParseRemoteUserName(PWSTR RemoteName,
PWSTR UserName, ULONG UserNameSize/* in chars */) PWSTR UserName, ULONG UserNameSize/* in chars */)
{ {
PWSTR ClassName, InstanceName, P; PWSTR ClassName, InstanceName, P;
@ -168,6 +169,12 @@ static inline BOOLEAN FspNpParseUserName(PWSTR RemoteName,
return FALSE; return FALSE;
} }
static inline BOOLEAN FspNpGetLocalUserName(
PWSTR UserName, ULONG UserNameSize/* in chars */)
{
return GetUserName(UserName, &UserNameSize);
}
static inline DWORD FspNpCallLauncherPipe(PWSTR PipeBuf, ULONG SendSize, ULONG RecvSize) static inline DWORD FspNpCallLauncherPipe(PWSTR PipeBuf, ULONG SendSize, ULONG RecvSize)
{ {
DWORD NpResult; DWORD NpResult;
@ -489,6 +496,7 @@ DWORD APIENTRY NPAddConnection(LPNETRESOURCEW lpNetResource, LPWSTR lpPassword,
WCHAR LocalNameBuf[3]; WCHAR LocalNameBuf[3];
PWSTR ClassName, InstanceName, RemoteName, P; PWSTR ClassName, InstanceName, RemoteName, P;
ULONG ClassNameLen, InstanceNameLen; ULONG ClassNameLen, InstanceNameLen;
WCHAR LocalUserName[UNLEN + 1];
DWORD CredentialsKind; DWORD CredentialsKind;
PWSTR PipeBuf = 0; PWSTR PipeBuf = 0;
#if defined(FSP_NP_CREDENTIAL_MANAGER) #if defined(FSP_NP_CREDENTIAL_MANAGER)
@ -517,6 +525,9 @@ DWORD APIENTRY NPAddConnection(LPNETRESOURCEW lpNetResource, LPWSTR lpPassword,
return WN_ALREADY_CONNECTED; return WN_ALREADY_CONNECTED;
} }
if (!FspNpGetLocalUserName(LocalUserName, sizeof LocalUserName / sizeof LocalUserName[0]))
LocalUserName[0] = L'\0';
FspNpGetCredentialsKind(lpRemoteName, &CredentialsKind); FspNpGetCredentialsKind(lpRemoteName, &CredentialsKind);
#if defined(FSP_NP_CREDENTIAL_MANAGER) #if defined(FSP_NP_CREDENTIAL_MANAGER)
@ -571,6 +582,7 @@ DWORD APIENTRY NPAddConnection(LPNETRESOURCEW lpNetResource, LPWSTR lpPassword,
memcpy(P, InstanceName, InstanceNameLen * sizeof(WCHAR)); P += InstanceNameLen; *P++ = L'\0'; memcpy(P, InstanceName, InstanceNameLen * sizeof(WCHAR)); P += InstanceNameLen; *P++ = L'\0';
lstrcpyW(P, RemoteName); P += lstrlenW(RemoteName) + 1; lstrcpyW(P, RemoteName); P += lstrlenW(RemoteName) + 1;
lstrcpyW(P, LocalNameBuf); P += lstrlenW(LocalNameBuf) + 1; lstrcpyW(P, LocalNameBuf); P += lstrlenW(LocalNameBuf) + 1;
lstrcpyW(P, LocalUserName); P += lstrlenW(LocalUserName) + 1;
if (FSP_NP_CREDENTIALS_USERPASS == CredentialsKind) if (FSP_NP_CREDENTIALS_USERPASS == CredentialsKind)
{ {
lstrcpyW(P, lpUserName); P += lstrlenW(lpUserName) + 1; lstrcpyW(P, lpUserName); P += lstrlenW(lpUserName) + 1;
@ -721,7 +733,7 @@ DWORD APIENTRY NPAddConnection3(HWND hwndOwner,
lstrcpyW(UserName, L"UNSPECIFIED"); lstrcpyW(UserName, L"UNSPECIFIED");
Password[0] = L'\0'; Password[0] = L'\0';
if (FSP_NP_CREDENTIALS_PASSWORD == CredentialsKind) if (FSP_NP_CREDENTIALS_PASSWORD == CredentialsKind)
FspNpParseUserName(RemoteName, UserName, sizeof UserName / sizeof UserName[0]); FspNpParseRemoteUserName(RemoteName, UserName, sizeof UserName / sizeof UserName[0]);
do do
{ {
NpResult = FspNpGetCredentials( NpResult = FspNpGetCredentials(

View File

@ -983,6 +983,16 @@ namespace Fsp
return Api.FspWin32FromNtStatus(Status); return Api.FspWin32FromNtStatus(Status);
} }
/// <summary> /// <summary>
/// Gets the originating process ID.
/// </summary>
/// <remarks>
/// Valid only during Create, Open and Rename requests when the target exists.
/// </remarks>
public static int GetOperationProcessId()
{
return (int)Api.FspFileSystemOperationProcessId();
}
/// <summary>
/// Modifies a security descriptor. /// Modifies a security descriptor.
/// </summary> /// </summary>
/// <remarks> /// <remarks>

View File

@ -539,6 +539,8 @@ namespace Fsp.Interop
IntPtr FileSystem, IntPtr FileSystem,
UInt32 DebugLog); UInt32 DebugLog);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate UInt32 FspFileSystemOperationProcessIdF();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.U1)] [return: MarshalAs(UnmanagedType.U1)]
internal delegate Boolean FspFileSystemAddDirInfo( internal delegate Boolean FspFileSystemAddDirInfo(
IntPtr DirInfo, IntPtr DirInfo,
@ -706,6 +708,7 @@ namespace Fsp.Interop
internal static Proto.FspFileSystemMountPointF FspFileSystemMountPoint; internal static Proto.FspFileSystemMountPointF FspFileSystemMountPoint;
internal static Proto.FspFileSystemSetOperationGuardStrategyF FspFileSystemSetOperationGuardStrategy; internal static Proto.FspFileSystemSetOperationGuardStrategyF FspFileSystemSetOperationGuardStrategy;
internal static Proto.FspFileSystemSetDebugLogF FspFileSystemSetDebugLog; internal static Proto.FspFileSystemSetDebugLogF FspFileSystemSetDebugLog;
internal static Proto.FspFileSystemOperationProcessIdF FspFileSystemOperationProcessId;
internal static Proto.FspFileSystemAddDirInfo _FspFileSystemAddDirInfo; internal static Proto.FspFileSystemAddDirInfo _FspFileSystemAddDirInfo;
internal static Proto.FspFileSystemFindReparsePoint FspFileSystemFindReparsePoint; internal static Proto.FspFileSystemFindReparsePoint FspFileSystemFindReparsePoint;
internal static Proto.FspFileSystemResolveReparsePoints FspFileSystemResolveReparsePoints; internal static Proto.FspFileSystemResolveReparsePoints FspFileSystemResolveReparsePoints;
@ -1015,6 +1018,7 @@ namespace Fsp.Interop
FspFileSystemMountPoint = GetEntryPoint<Proto.FspFileSystemMountPointF>(Module); FspFileSystemMountPoint = GetEntryPoint<Proto.FspFileSystemMountPointF>(Module);
FspFileSystemSetOperationGuardStrategy = GetEntryPoint<Proto.FspFileSystemSetOperationGuardStrategyF>(Module); FspFileSystemSetOperationGuardStrategy = GetEntryPoint<Proto.FspFileSystemSetOperationGuardStrategyF>(Module);
FspFileSystemSetDebugLog = GetEntryPoint<Proto.FspFileSystemSetDebugLogF>(Module); FspFileSystemSetDebugLog = GetEntryPoint<Proto.FspFileSystemSetDebugLogF>(Module);
FspFileSystemOperationProcessId = GetEntryPoint<Proto.FspFileSystemOperationProcessIdF>(Module);
_FspFileSystemAddDirInfo = GetEntryPoint<Proto.FspFileSystemAddDirInfo>(Module); _FspFileSystemAddDirInfo = GetEntryPoint<Proto.FspFileSystemAddDirInfo>(Module);
FspFileSystemFindReparsePoint = GetEntryPoint<Proto.FspFileSystemFindReparsePoint>(Module); FspFileSystemFindReparsePoint = GetEntryPoint<Proto.FspFileSystemFindReparsePoint>(Module);
FspFileSystemResolveReparsePoints = GetEntryPoint<Proto.FspFileSystemResolveReparsePoints>(Module); FspFileSystemResolveReparsePoints = GetEntryPoint<Proto.FspFileSystemResolveReparsePoints>(Module);

View File

@ -117,6 +117,8 @@ static NTSTATUS FspFsvolCleanup(
Request->Req.Cleanup.SetLastWriteTime = FileModified && !FileDesc->DidSetLastWriteTime; Request->Req.Cleanup.SetLastWriteTime = FileModified && !FileDesc->DidSetLastWriteTime;
Request->Req.Cleanup.SetChangeTime = (FileModified || FileDesc->DidSetMetadata) && Request->Req.Cleanup.SetChangeTime = (FileModified || FileDesc->DidSetMetadata) &&
!FileDesc->DidSetChangeTime; !FileDesc->DidSetChangeTime;
Request->Req.Cleanup.UnlockAll = FsvolDeviceExtension->VolumeParams.UserModeFileLocking &&
FsRtlAreThereCurrentOrInProgressFileLocks(&FileNode->FileLock);
FspFileNodeAcquireExclusive(FileNode, Pgio); FspFileNodeAcquireExclusive(FileNode, Pgio);
@ -128,6 +130,7 @@ static NTSTATUS FspFsvolCleanup(
Request->Req.Cleanup.SetArchiveBit || Request->Req.Cleanup.SetArchiveBit ||
Request->Req.Cleanup.SetLastWriteTime || Request->Req.Cleanup.SetLastWriteTime ||
Request->Req.Cleanup.SetChangeTime || Request->Req.Cleanup.SetChangeTime ||
Request->Req.Cleanup.UnlockAll ||
!FsvolDeviceExtension->VolumeParams.PostCleanupWhenModifiedOnly) !FsvolDeviceExtension->VolumeParams.PostCleanupWhenModifiedOnly)
/* /*
* Note that it is still possible for this request to not be delivered, * Note that it is still possible for this request to not be delivered,

View File

@ -545,7 +545,7 @@ NTSTATUS FspFsvolCreatePrepare(
SECURITY_CLIENT_CONTEXT SecurityClientContext; SECURITY_CLIENT_CONTEXT SecurityClientContext;
HANDLE UserModeAccessToken; HANDLE UserModeAccessToken;
PEPROCESS Process; PEPROCESS Process;
HANDLE ProcessId; ULONG OriginatingProcessId;
FSP_FILE_NODE *FileNode; FSP_FILE_NODE *FileNode;
FSP_FILE_DESC *FileDesc; FSP_FILE_DESC *FileDesc;
PFILE_OBJECT FileObject; PFILE_OBJECT FileObject;
@ -579,15 +579,17 @@ NTSTATUS FspFsvolCreatePrepare(
/* get a pointer to the current process so that we can close the impersonation token later */ /* get a pointer to the current process so that we can close the impersonation token later */
Process = PsGetCurrentProcess(); Process = PsGetCurrentProcess();
ObReferenceObject(Process); ObReferenceObject(Process);
ProcessId = PsGetProcessId(Process);
/* get the originating process ID stored in the IRP */
OriginatingProcessId = IoGetRequestorProcessId(Irp);
/* send the user-mode handle to the user-mode file system */ /* send the user-mode handle to the user-mode file system */
FspIopRequestContext(Request, RequestAccessToken) = UserModeAccessToken; FspIopRequestContext(Request, RequestAccessToken) = UserModeAccessToken;
FspIopRequestContext(Request, RequestProcess) = Process; FspIopRequestContext(Request, RequestProcess) = Process;
ASSERT((UINT64)(UINT_PTR)UserModeAccessToken <= 0xffffffffULL); ASSERT((UINT64)(UINT_PTR)UserModeAccessToken <= 0xffffffffULL);
ASSERT((UINT64)(UINT_PTR)ProcessId <= 0xffffffffULL); ASSERT((UINT64)(UINT_PTR)OriginatingProcessId <= 0xffffffffULL);
Request->Req.Create.AccessToken = Request->Req.Create.AccessToken =
((UINT64)(UINT_PTR)ProcessId << 32) | (UINT64)(UINT_PTR)UserModeAccessToken; ((UINT64)(UINT_PTR)OriginatingProcessId << 32) | (UINT64)(UINT_PTR)UserModeAccessToken;
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }

View File

@ -17,15 +17,6 @@
#include <sys/driver.h> #include <sys/driver.h>
/*
* NOTE:
*
* FspIopCompleteIrpEx does some special processing for IRP_MJ_DIRECTORY_CONTROL /
* IRP_MN_QUERY_DIRECTORY IRP's that come from SRV2. If the processing of this IRP
* changes substantially (in particular if we eliminate our use of
* Irp->AssociatedIrp.SystemBuffer) we should also revisit FspIopCompleteIrpEx.
*/
static NTSTATUS FspFsvolQueryDirectoryCopy( static NTSTATUS FspFsvolQueryDirectoryCopy(
PUNICODE_STRING DirectoryPattern, BOOLEAN CaseInsensitive, PUNICODE_STRING DirectoryPattern, BOOLEAN CaseInsensitive,
PUNICODE_STRING DirectoryMarker, PUNICODE_STRING DirectoryMarkerOut, PUNICODE_STRING DirectoryMarker, PUNICODE_STRING DirectoryMarkerOut,
@ -77,19 +68,17 @@ FSP_DRIVER_DISPATCH FspDirectoryControl;
enum enum
{ {
/* QueryDirectory */ /* QueryDirectory */
RequestIrp = 0, RequestFileNode = 0,
RequestCookie = 1, RequestCookie = 1,
RequestMdl = 1,
RequestAddress = 2, RequestAddress = 2,
RequestProcess = 3, RequestProcess = 3,
/* QueryDirectoryRetry */
RequestSystemBufferLength = 0,
/* DirectoryControlComplete retry */
RequestDirInfoChangeNumber = 0,
}; };
FSP_FSCTL_STATIC_ASSERT(RequestCookie == RequestMdl, "");
enum
{
FspFsvolQueryDirectoryLengthMax =
FspFsvolDeviceDirInfoCacheItemSizeMax - FspMetaCacheItemHeaderSize,
};
static NTSTATUS FspFsvolQueryDirectoryCopy( static NTSTATUS FspFsvolQueryDirectoryCopy(
PUNICODE_STRING DirectoryPattern, BOOLEAN CaseInsensitive, PUNICODE_STRING DirectoryPattern, BOOLEAN CaseInsensitive,
@ -362,7 +351,6 @@ static NTSTATUS FspFsvolQueryDirectoryCopyInPlace(
PUNICODE_STRING DirectoryPattern = &FileDesc->DirectoryPattern; PUNICODE_STRING DirectoryPattern = &FileDesc->DirectoryPattern;
UNICODE_STRING DirectoryMarker = FileDesc->DirectoryMarker; UNICODE_STRING DirectoryMarker = FileDesc->DirectoryMarker;
ASSERT(DirInfo == DestBuf);
FSP_FSCTL_STATIC_ASSERT( FSP_FSCTL_STATIC_ASSERT(
FIELD_OFFSET(FSP_FSCTL_DIR_INFO, FileNameBuf) >= FIELD_OFFSET(FSP_FSCTL_DIR_INFO, FileNameBuf) >=
FIELD_OFFSET(FILE_ID_BOTH_DIR_INFORMATION, FileName), FIELD_OFFSET(FILE_ID_BOTH_DIR_INFORMATION, FileName),
@ -389,77 +377,10 @@ static NTSTATUS FspFsvolQueryDirectoryCopyInPlace(
return Result; return Result;
} }
static inline NTSTATUS FspFsvolQueryDirectoryBufferUserBuffer(
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension, PIRP Irp, PULONG PLength)
{
if (0 != Irp->AssociatedIrp.SystemBuffer)
return STATUS_SUCCESS;
NTSTATUS Result;
ULONG Length = *PLength;
if (Length > FspFsvolDeviceDirInfoCacheItemSizeMax)
Length = FspFsvolDeviceDirInfoCacheItemSizeMax;
else if (Length < sizeof(FSP_FSCTL_DIR_INFO) +
FsvolDeviceExtension->VolumeParams.MaxComponentLength * sizeof(WCHAR))
Length = sizeof(FSP_FSCTL_DIR_INFO) +
FsvolDeviceExtension->VolumeParams.MaxComponentLength * sizeof(WCHAR);
Result = FspBufferUserBuffer(Irp, FSP_FSCTL_ALIGN_UP(Length, PAGE_SIZE), IoWriteAccess);
if (!NT_SUCCESS(Result))
return Result;
*PLength = Length;
return STATUS_SUCCESS;
}
static NTSTATUS FspFsvolQueryDirectoryRetry( static NTSTATUS FspFsvolQueryDirectoryRetry(
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp, PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp,
BOOLEAN CanWait) BOOLEAN CanWait)
{ {
/*
* The SystemBufferLength contains the length of the SystemBuffer that we
* are going to allocate (in FspFsvolQueryDirectoryBufferUserBuffer). This
* buffer is going to be used as the IRP SystemBuffer and it will also be
* mapped into the user mode file system process (in
* FspFsvolDirectoryControlPrepare) so that the file system can fill in the
* buffer.
*
* The SystemBufferLength is not the actual length that we are going to use
* when completing the IRP. This will be computed at IRP completion time
* (using FspFsvolQueryDirectoryCopy). Instead the SystemBufferLength is
* the size that we want the user mode file system to see and it may be
* different from the requested length for the following reasons:
*
* - If the FileInfoTimeout is non-zero, then the directory maintains a
* DirInfo meta cache that can be used to fulfill IRP requests without
* reaching out to user mode. In this case we want the SystemBufferLength
* to be FspFsvolDeviceDirInfoCacheItemSizeMax so that we read up to the
* cache size maximum.
*
* - If the requested DirectoryPattern (stored in FileDesc) is not the "*"
* (MatchAll) pattern, then we want to read as many entries as possible
* from the user mode file system to avoid multiple roundtrips to user
* mode when doing file name matching. In this case we set again the
* SystemBufferLength to be FspFsvolDeviceDirInfoCacheItemSizeMax. This
* is an important optimization and without it QueryDirectory is *very*
* slow without the DirInfo meta cache (i.e. when FileInfoTimeout is 0).
*
* - If the requsted DirectoryPattern is the MatchAll pattern then we set
* the SystemBufferLength to the requested (IRP) length as it is actually
* counter-productive to try to read more than we need.
*/
#define GetSystemBufferLengthMaybeCached()\
(0 != FsvolDeviceExtension->VolumeParams.FileInfoTimeout && 0 == FileDesc->DirectoryMarker.Buffer) ||\
FspFileDescDirectoryPatternMatchAll != FileDesc->DirectoryPattern.Buffer ?\
FspFsvolDeviceDirInfoCacheItemSizeMax : Length
#define GetSystemBufferLengthNonCached()\
FspFileDescDirectoryPatternMatchAll != FileDesc->DirectoryPattern.Buffer ?\
FspFsvolDeviceDirInfoCacheItemSizeMax : Length
#define GetSystemBufferLengthBestGuess()\
FspFsvolDeviceDirInfoCacheItemSizeMax
PAGED_CODE(); PAGED_CODE();
NTSTATUS Result; NTSTATUS Result;
@ -471,12 +392,13 @@ static NTSTATUS FspFsvolQueryDirectoryRetry(
BOOLEAN IndexSpecified = BooleanFlagOn(IrpSp->Flags, SL_INDEX_SPECIFIED); BOOLEAN IndexSpecified = BooleanFlagOn(IrpSp->Flags, SL_INDEX_SPECIFIED);
BOOLEAN ReturnSingleEntry = BooleanFlagOn(IrpSp->Flags, SL_RETURN_SINGLE_ENTRY); BOOLEAN ReturnSingleEntry = BooleanFlagOn(IrpSp->Flags, SL_RETURN_SINGLE_ENTRY);
FILE_INFORMATION_CLASS FileInformationClass = IrpSp->Parameters.QueryDirectory.FileInformationClass; FILE_INFORMATION_CLASS FileInformationClass = IrpSp->Parameters.QueryDirectory.FileInformationClass;
ULONG BaseInfoLen;
PUNICODE_STRING FileName = IrpSp->Parameters.QueryDirectory.FileName; PUNICODE_STRING FileName = IrpSp->Parameters.QueryDirectory.FileName;
//ULONG FileIndex = IrpSp->Parameters.QueryDirectory.FileIndex; //ULONG FileIndex = IrpSp->Parameters.QueryDirectory.FileIndex;
PVOID Buffer = 0 != Irp->AssociatedIrp.SystemBuffer ? PVOID Buffer = 0 == Irp->MdlAddress ?
Irp->AssociatedIrp.SystemBuffer : Irp->UserBuffer; Irp->UserBuffer : MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
ULONG Length = IrpSp->Parameters.QueryDirectory.Length; ULONG Length = IrpSp->Parameters.QueryDirectory.Length;
ULONG SystemBufferLength; ULONG QueryDirectoryLength, QueryDirectoryLengthMin;
PVOID DirInfoBuffer; PVOID DirInfoBuffer;
ULONG DirInfoSize; ULONG DirInfoSize;
FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp); FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp);
@ -485,34 +407,42 @@ static NTSTATUS FspFsvolQueryDirectoryRetry(
ASSERT(FileNode == FileDesc->FileNode); ASSERT(FileNode == FileDesc->FileNode);
SystemBufferLength = 0 != Request ? if (0 == Buffer)
(ULONG)(UINT_PTR)FspIopRequestContext(Request, RequestSystemBufferLength) : 0; return 0 == Irp->MdlAddress ? STATUS_INVALID_PARAMETER : STATUS_INSUFFICIENT_RESOURCES;
/* is this an allowed file information class? */
switch (FileInformationClass)
{
case FileDirectoryInformation:
BaseInfoLen = FIELD_OFFSET(FILE_DIRECTORY_INFORMATION, FileName);
break;
case FileFullDirectoryInformation:
BaseInfoLen = FIELD_OFFSET(FILE_FULL_DIR_INFORMATION, FileName);
break;
case FileIdFullDirectoryInformation:
BaseInfoLen = FIELD_OFFSET(FILE_ID_FULL_DIR_INFORMATION, FileName);
break;
case FileNamesInformation:
BaseInfoLen = FIELD_OFFSET(FILE_NAMES_INFORMATION, FileName);
break;
case FileBothDirectoryInformation:
BaseInfoLen = FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION, FileName);
break;
case FileIdBothDirectoryInformation:
BaseInfoLen = FIELD_OFFSET(FILE_ID_BOTH_DIR_INFORMATION, FileName);
break;
default:
return STATUS_INVALID_INFO_CLASS;
}
if (BaseInfoLen >= Length)
return STATUS_BUFFER_TOO_SMALL;
/* try to acquire the FileNode exclusive; Full because we may need to send a Request */ /* try to acquire the FileNode exclusive; Full because we may need to send a Request */
Success = DEBUGTEST(90) && Success = DEBUGTEST(90) &&
FspFileNodeTryAcquireExclusiveF(FileNode, FspFileNodeAcquireFull, CanWait); FspFileNodeTryAcquireExclusiveF(FileNode, FspFileNodeAcquireFull, CanWait);
if (!Success) if (!Success)
{ return FspWqRepostIrpWorkItem(Irp, FspFsvolQueryDirectoryRetry, 0);
if (0 == SystemBufferLength)
SystemBufferLength = GetSystemBufferLengthBestGuess();
Result = FspFsvolQueryDirectoryBufferUserBuffer(
FsvolDeviceExtension, Irp, &SystemBufferLength);
if (!NT_SUCCESS(Result))
return Result;
Result = FspWqCreateIrpWorkItem(Irp, FspFsvolQueryDirectoryRetry, 0);
if (!NT_SUCCESS(Result))
return Result;
Request = FspIrpRequest(Irp);
FspIopRequestContext(Request, RequestSystemBufferLength) =
(PVOID)(UINT_PTR)SystemBufferLength;
FspWqPostIrpWorkItem(Irp);
return STATUS_PENDING;
}
/* if we have been retried reset our work item now! */ /* if we have been retried reset our work item now! */
if (0 != Request) if (0 != Request)
@ -532,9 +462,6 @@ static NTSTATUS FspFsvolQueryDirectoryRetry(
/* see if the required information is still in the cache and valid! */ /* see if the required information is still in the cache and valid! */
if (FspFileNodeReferenceDirInfo(FileNode, &DirInfoBuffer, &DirInfoSize)) if (FspFileNodeReferenceDirInfo(FileNode, &DirInfoBuffer, &DirInfoSize))
{ {
if (0 == SystemBufferLength)
SystemBufferLength = GetSystemBufferLengthNonCached();
Result = FspFsvolQueryDirectoryCopyCache(FileDesc, Result = FspFsvolQueryDirectoryCopyCache(FileDesc,
IndexSpecified || RestartScan, IndexSpecified || RestartScan,
FileInformationClass, ReturnSingleEntry, FileInformationClass, ReturnSingleEntry,
@ -548,11 +475,9 @@ static NTSTATUS FspFsvolQueryDirectoryRetry(
Irp->IoStatus.Information = Length; Irp->IoStatus.Information = Length;
return Result; return Result;
} }
}
else /* reset Length! */
{ Length = IrpSp->Parameters.QueryDirectory.Length;
if (0 == SystemBufferLength)
SystemBufferLength = GetSystemBufferLengthMaybeCached();
} }
FspFileNodeConvertExclusiveToShared(FileNode, Full); FspFileNodeConvertExclusiveToShared(FileNode, Full);
@ -573,9 +498,8 @@ static NTSTATUS FspFsvolQueryDirectoryRetry(
STATUS_NO_SUCH_FILE : STATUS_NO_MORE_FILES; STATUS_NO_SUCH_FILE : STATUS_NO_MORE_FILES;
} }
/* buffer the user buffer! */ /* probe and lock the user buffer */
Result = FspFsvolQueryDirectoryBufferUserBuffer( Result = FspLockUserBuffer(Irp, Length, IoWriteAccess);
FsvolDeviceExtension, Irp, &SystemBufferLength);
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
{ {
FspFileNodeRelease(FileNode, Full); FspFileNodeRelease(FileNode, Full);
@ -593,10 +517,81 @@ static NTSTATUS FspFsvolQueryDirectoryRetry(
return Result; return Result;
} }
/*
* Compute QueryDirectoryLength
*
* How much data to request from the file system varies according to the following matrix:
*
* Pattern | NoCache | Cache+1st | Cache+2nd
* -------------------------+---------+-----------+----------
* Full Wild | Ratio | Maximum | Ratio
* Partial Wild w/o PassQDP | Maximum | Maximum | Maximum
* Partial Wild w/ PassQDP | Ratio | Ratio | Ratio
* File Name w/o PassQDF | Maximum | Maximum | Maximum
* File Name w/ PassQDF | Minimum | Minimum | Minimum
*
* NoCache means DirInfo caching disabled. Cache+1st means DirInfo caching enabled, but
* cache not primed. Cache+2nd means DirInfo caching enabled, cache is primed, but missed.
* [If there is no cache miss, there is no need to send the request to the file system.]
*
* Maximum means to request the maximum size allowed by the FSD. Minimum means the size that
* is guaranteed to contain at least one entry. Ratio means to compute how many directory
* entries to request from the file system based on an estimate of how many entries the FSD
* is supposed to deliver.
*
* The Ratio computation is as follows: Assume that N is the size of the average file name,
* taken to be 24 * sizeof(WCHAR). Let M be the number of entries that can fit in the passed
* buffer:
*
* M := Length / (BaseInfoLen + N) = QueryDirectoryLength / (sizeof(FSP_FSCTL_DIR_INFO) + N)
* => QueryDirectoryLength = Length * (sizeof(FSP_FSCTL_DIR_INFO) + N) / (BaseInfoLen + N)
*/
QueryDirectoryLengthMin = sizeof(FSP_FSCTL_DIR_INFO) +
FsvolDeviceExtension->VolumeParams.MaxComponentLength * sizeof(WCHAR);
QueryDirectoryLengthMin = FSP_FSCTL_ALIGN_UP(QueryDirectoryLengthMin, 8);
ASSERT(QueryDirectoryLengthMin < FspFsvolQueryDirectoryLengthMax);
if (0 != FsvolDeviceExtension->VolumeParams.FileInfoTimeout &&
0 == FileDesc->DirectoryMarker.Buffer)
{
if (PatternIsFileName)
QueryDirectoryLength = QueryDirectoryLengthMin;
else if (PassQueryDirectoryPattern)
{
QueryDirectoryLength = Length *
(sizeof(FSP_FSCTL_DIR_INFO) + 24 * sizeof(WCHAR)) / (BaseInfoLen + 24 * sizeof(WCHAR));
QueryDirectoryLength = FSP_FSCTL_ALIGN_UP(QueryDirectoryLength, 8);
if (QueryDirectoryLength < QueryDirectoryLengthMin)
QueryDirectoryLength = QueryDirectoryLengthMin;
else if (QueryDirectoryLength > FspFsvolQueryDirectoryLengthMax)
QueryDirectoryLength = FspFsvolQueryDirectoryLengthMax;
}
else
QueryDirectoryLength = FspFsvolQueryDirectoryLengthMax;
}
else
{
if (PatternIsFileName)
QueryDirectoryLength = QueryDirectoryLengthMin;
else if (PassQueryDirectoryPattern ||
FspFileDescDirectoryPatternMatchAll == FileDesc->DirectoryPattern.Buffer)
{
QueryDirectoryLength = Length *
(sizeof(FSP_FSCTL_DIR_INFO) + 24 * sizeof(WCHAR)) / (BaseInfoLen + 24 * sizeof(WCHAR));
QueryDirectoryLength = FSP_FSCTL_ALIGN_UP(QueryDirectoryLength, 8);
if (QueryDirectoryLength < QueryDirectoryLengthMin)
QueryDirectoryLength = QueryDirectoryLengthMin;
else if (QueryDirectoryLength > FspFsvolQueryDirectoryLengthMax)
QueryDirectoryLength = FspFsvolQueryDirectoryLengthMax;
}
else
QueryDirectoryLength = FspFsvolQueryDirectoryLengthMax;
}
Request->Kind = FspFsctlTransactQueryDirectoryKind; Request->Kind = FspFsctlTransactQueryDirectoryKind;
Request->Req.QueryDirectory.UserContext = FileNode->UserContext; Request->Req.QueryDirectory.UserContext = FileNode->UserContext;
Request->Req.QueryDirectory.UserContext2 = FileDesc->UserContext2; Request->Req.QueryDirectory.UserContext2 = FileDesc->UserContext2;
Request->Req.QueryDirectory.Length = SystemBufferLength; Request->Req.QueryDirectory.Length = QueryDirectoryLength;
Request->Req.QueryDirectory.CaseSensitive = FileDesc->CaseSensitive; Request->Req.QueryDirectory.CaseSensitive = FileDesc->CaseSensitive;
if (PassQueryDirectoryPattern) if (PassQueryDirectoryPattern)
@ -631,13 +626,9 @@ static NTSTATUS FspFsvolQueryDirectoryRetry(
} }
FspFileNodeSetOwner(FileNode, Full, Request); FspFileNodeSetOwner(FileNode, Full, Request);
FspIopRequestContext(Request, RequestIrp) = Irp; FspIopRequestContext(Request, RequestFileNode) = FileNode;
return FSP_STATUS_IOQ_POST; return FSP_STATUS_IOQ_POST;
#undef GetSystemBufferLengthBestGuess
#undef GetSystemBufferLengthNonCached
#undef GetSystemBufferLengthMaybeCached
} }
static NTSTATUS FspFsvolQueryDirectory( static NTSTATUS FspFsvolQueryDirectory(
@ -649,21 +640,10 @@ static NTSTATUS FspFsvolQueryDirectory(
if (!FspFileNodeIsValid(IrpSp->FileObject->FsContext)) if (!FspFileNodeIsValid(IrpSp->FileObject->FsContext))
return STATUS_INVALID_DEVICE_REQUEST; return STATUS_INVALID_DEVICE_REQUEST;
NTSTATUS Result;
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject); FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
PFILE_OBJECT FileObject = IrpSp->FileObject; PFILE_OBJECT FileObject = IrpSp->FileObject;
FSP_FILE_NODE *FileNode = FileObject->FsContext; FSP_FILE_NODE *FileNode = FileObject->FsContext;
FILE_INFORMATION_CLASS FileInformationClass = IrpSp->Parameters.QueryDirectory.FileInformationClass;
PUNICODE_STRING FileName = IrpSp->Parameters.QueryDirectory.FileName; PUNICODE_STRING FileName = IrpSp->Parameters.QueryDirectory.FileName;
ULONG Length = IrpSp->Parameters.QueryDirectory.Length;
ULONG BaseInfoLen;
/* SystemBuffer must be NULL as we are going to be using it! */
if (0 != Irp->AssociatedIrp.SystemBuffer)
{
ASSERT(0);
return STATUS_INVALID_PARAMETER;
}
/* only directory files can be queried */ /* only directory files can be queried */
if (!FileNode->IsDirectory) if (!FileNode->IsDirectory)
@ -674,36 +654,7 @@ static NTSTATUS FspFsvolQueryDirectory(
!FspFileNameIsValidPattern(FileName, FsvolDeviceExtension->VolumeParams.MaxComponentLength)) !FspFileNameIsValidPattern(FileName, FsvolDeviceExtension->VolumeParams.MaxComponentLength))
return STATUS_INVALID_PARAMETER; return STATUS_INVALID_PARAMETER;
/* is this an allowed file information class? */ return FspFsvolQueryDirectoryRetry(FsvolDeviceObject, Irp, IrpSp, IoIsOperationSynchronous(Irp));
switch (FileInformationClass)
{
case FileDirectoryInformation:
BaseInfoLen = FIELD_OFFSET(FILE_DIRECTORY_INFORMATION, FileName);
break;
case FileFullDirectoryInformation:
BaseInfoLen = FIELD_OFFSET(FILE_FULL_DIR_INFORMATION, FileName);
break;
case FileIdFullDirectoryInformation:
BaseInfoLen = FIELD_OFFSET(FILE_ID_FULL_DIR_INFORMATION, FileName);
break;
case FileNamesInformation:
BaseInfoLen = FIELD_OFFSET(FILE_NAMES_INFORMATION, FileName);
break;
case FileBothDirectoryInformation:
BaseInfoLen = FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION, FileName);
break;
case FileIdBothDirectoryInformation:
BaseInfoLen = FIELD_OFFSET(FILE_ID_BOTH_DIR_INFORMATION, FileName);
break;
default:
return STATUS_INVALID_INFO_CLASS;
}
if (BaseInfoLen >= Length)
return STATUS_BUFFER_TOO_SMALL;
Result = FspFsvolQueryDirectoryRetry(FsvolDeviceObject, Irp, IrpSp, IoIsOperationSynchronous(Irp));
return Result;
} }
typedef struct typedef struct
@ -850,8 +801,6 @@ NTSTATUS FspFsvolDirectoryControlPrepare(
{ {
PAGED_CODE(); PAGED_CODE();
if (FspQueryDirectoryIrpShouldUseProcessBuffer(Irp, Request->Req.QueryDirectory.Length))
{
NTSTATUS Result; NTSTATUS Result;
PVOID Cookie; PVOID Cookie;
PVOID Address; PVOID Address;
@ -873,45 +822,6 @@ NTSTATUS FspFsvolDirectoryControlPrepare(
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
else
{
NTSTATUS Result;
PMDL Mdl = 0;
PVOID Address;
PEPROCESS Process;
Mdl = IoAllocateMdl(
Irp->AssociatedIrp.SystemBuffer,
Request->Req.QueryDirectory.Length,
FALSE, FALSE, 0);
if (0 == Mdl)
return STATUS_INSUFFICIENT_RESOURCES;
MmBuildMdlForNonPagedPool(Mdl);
/* map the MDL into user-mode */
Result = FspMapLockedPagesInUserMode(Mdl, &Address, 0);
if (!NT_SUCCESS(Result))
{
if (0 != Mdl)
IoFreeMdl(Mdl);
return Result;
}
/* get a pointer to the current process so that we can unmap the address later */
Process = PsGetCurrentProcess();
ObReferenceObject(Process);
Request->Req.QueryDirectory.Address = (UINT64)(UINT_PTR)Address;
FspIopRequestContext(Request, RequestMdl) = Mdl;
FspIopRequestContext(Request, RequestAddress) = Address;
FspIopRequestContext(Request, RequestProcess) = Process;
return STATUS_SUCCESS;
}
}
NTSTATUS FspFsvolDirectoryControlComplete( NTSTATUS FspFsvolDirectoryControlComplete(
PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response) PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response)
@ -935,9 +845,8 @@ NTSTATUS FspFsvolDirectoryControlComplete(
FSP_FILE_DESC *FileDesc = FileObject->FsContext2; FSP_FILE_DESC *FileDesc = FileObject->FsContext2;
BOOLEAN ReturnSingleEntry = BooleanFlagOn(IrpSp->Flags, SL_RETURN_SINGLE_ENTRY); BOOLEAN ReturnSingleEntry = BooleanFlagOn(IrpSp->Flags, SL_RETURN_SINGLE_ENTRY);
FILE_INFORMATION_CLASS FileInformationClass = IrpSp->Parameters.QueryDirectory.FileInformationClass; FILE_INFORMATION_CLASS FileInformationClass = IrpSp->Parameters.QueryDirectory.FileInformationClass;
PVOID Buffer = Irp->AssociatedIrp.SystemBuffer; PVOID Buffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
ULONG Length = IrpSp->Parameters.QueryDirectory.Length; ULONG Length = IrpSp->Parameters.QueryDirectory.Length;
ULONG DirInfoChangeNumber;
PVOID DirInfoBuffer; PVOID DirInfoBuffer;
ULONG DirInfoSize; ULONG DirInfoSize;
BOOLEAN Success; BOOLEAN Success;
@ -951,33 +860,14 @@ NTSTATUS FspFsvolDirectoryControlComplete(
FSP_RETURN(); FSP_RETURN();
} }
if (FspFsctlTransactQueryDirectoryKind == Request->Kind) if (0 != FspIopRequestContext(Request, RequestFileNode))
{ {
if ((UINT_PTR)FspIopRequestContext(Request, RequestCookie) & 1) FspIopRequestContext(Request, FspIopRequestExtraContext) = (PVOID)
{ FspFileNodeDirInfoChangeNumber(FileNode);
PVOID Address = FspIopRequestContext(Request, RequestAddress); FspIopRequestContext(Request, RequestFileNode) = 0;
ASSERT(0 != Address); FspFileNodeReleaseOwner(FileNode, Full, Request);
try
{
RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, Address, Response->IoStatus.Information);
} }
except (EXCEPTION_EXECUTE_HANDLER)
{
Result = GetExceptionCode();
Result = FsRtlIsNtstatusExpected(Result) ? STATUS_INVALID_USER_BUFFER : Result;
FSP_RETURN();
}
}
DirInfoChangeNumber = FspFileNodeDirInfoChangeNumber(FileNode);
Request->Kind = FspFsctlTransactReservedKind;
FspIopResetRequest(Request, 0);
FspIopRequestContext(Request, RequestDirInfoChangeNumber) = (PVOID)DirInfoChangeNumber;
}
else
DirInfoChangeNumber =
(ULONG)(UINT_PTR)FspIopRequestContext(Request, RequestDirInfoChangeNumber);
/* acquire FileNode exclusive Full (because we may need to go back to user-mode) */ /* acquire FileNode exclusive Full (because we may need to go back to user-mode) */
Success = DEBUGTEST(90) && FspFileNodeTryAcquireExclusive(FileNode, Full); Success = DEBUGTEST(90) && FspFileNodeTryAcquireExclusive(FileNode, Full);
@ -990,9 +880,9 @@ NTSTATUS FspFsvolDirectoryControlComplete(
if (0 == Request->Req.QueryDirectory.Pattern.Size && if (0 == Request->Req.QueryDirectory.Pattern.Size &&
0 == Request->Req.QueryDirectory.Marker.Size && 0 == Request->Req.QueryDirectory.Marker.Size &&
FspFileNodeTrySetDirInfo(FileNode, FspFileNodeTrySetDirInfo(FileNode,
Irp->AssociatedIrp.SystemBuffer, (PVOID)(UINT_PTR)Request->Req.QueryDirectory.Address,
(ULONG)Response->IoStatus.Information, (ULONG)Response->IoStatus.Information,
DirInfoChangeNumber) && (ULONG)(UINT_PTR)FspIopRequestContext(Request, FspIopRequestExtraContext)) &&
FspFileNodeReferenceDirInfo(FileNode, &DirInfoBuffer, &DirInfoSize)) FspFileNodeReferenceDirInfo(FileNode, &DirInfoBuffer, &DirInfoSize))
{ {
Result = FspFsvolQueryDirectoryCopyCache(FileDesc, Result = FspFsvolQueryDirectoryCopyCache(FileDesc,
@ -1004,7 +894,7 @@ NTSTATUS FspFsvolDirectoryControlComplete(
} }
else else
{ {
DirInfoBuffer = Irp->AssociatedIrp.SystemBuffer; DirInfoBuffer = (PVOID)(UINT_PTR)Request->Req.QueryDirectory.Address;
DirInfoSize = (ULONG)Response->IoStatus.Information; DirInfoSize = (ULONG)Response->IoStatus.Information;
Result = FspFsvolQueryDirectoryCopyInPlace(FileDesc, Result = FspFsvolQueryDirectoryCopyInPlace(FileDesc,
FileInformationClass, ReturnSingleEntry, FileInformationClass, ReturnSingleEntry,
@ -1023,7 +913,6 @@ NTSTATUS FspFsvolDirectoryControlComplete(
FspFileNodeConvertExclusiveToShared(FileNode, Full); FspFileNodeConvertExclusiveToShared(FileNode, Full);
Request->Kind = FspFsctlTransactQueryDirectoryKind;
FspIopResetRequest(Request, FspFsvolQueryDirectoryRequestFini); FspIopResetRequest(Request, FspFsvolQueryDirectoryRequestFini);
Request->Req.QueryDirectory.Address = 0; Request->Req.QueryDirectory.Address = 0;
@ -1047,7 +936,7 @@ NTSTATUS FspFsvolDirectoryControlComplete(
} }
FspFileNodeSetOwner(FileNode, Full, Request); FspFileNodeSetOwner(FileNode, Full, Request);
FspIopRequestContext(Request, RequestIrp) = Irp; FspIopRequestContext(Request, RequestFileNode) = FileNode;
FspIoqPostIrp(FsvolDeviceExtension->Ioq, Irp, &Result); FspIoqPostIrp(FsvolDeviceExtension->Ioq, Irp, &Result);
} }
@ -1069,10 +958,7 @@ static VOID FspFsvolQueryDirectoryRequestFini(FSP_FSCTL_TRANSACT_REQ *Request, P
{ {
PAGED_CODE(); PAGED_CODE();
PIRP Irp = Context[RequestIrp]; FSP_FILE_NODE *FileNode = Context[RequestFileNode];
if ((UINT_PTR)Context[RequestCookie] & 1)
{
PVOID Cookie = (PVOID)((UINT_PTR)Context[RequestCookie] & ~1); PVOID Cookie = (PVOID)((UINT_PTR)Context[RequestCookie] & ~1);
PVOID Address = Context[RequestAddress]; PVOID Address = Context[RequestAddress];
PEPROCESS Process = Context[RequestProcess]; PEPROCESS Process = Context[RequestProcess];
@ -1093,42 +979,10 @@ static VOID FspFsvolQueryDirectoryRequestFini(FSP_FSCTL_TRANSACT_REQ *Request, P
ObDereferenceObject(Process); ObDereferenceObject(Process);
} }
}
else
{
PMDL Mdl = Context[RequestMdl];
PVOID Address = Context[RequestAddress];
PEPROCESS Process = Context[RequestProcess];
if (0 != Address)
{
KAPC_STATE ApcState;
BOOLEAN Attach;
ASSERT(0 != Process);
Attach = Process != PsGetCurrentProcess();
if (Attach)
KeStackAttachProcess(Process, &ApcState);
MmUnmapLockedPages(Address, Mdl);
if (Attach)
KeUnstackDetachProcess(&ApcState);
ObDereferenceObject(Process);
}
if (0 != Mdl)
IoFreeMdl(Mdl);
}
if (0 != Irp)
{
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
FSP_FILE_NODE *FileNode = IrpSp->FileObject->FsContext;
if (0 != FileNode)
FspFileNodeReleaseOwner(FileNode, Full, Request); FspFileNodeReleaseOwner(FileNode, Full, Request);
} }
}
NTSTATUS FspDirectoryControl( NTSTATUS FspDirectoryControl(
PDEVICE_OBJECT DeviceObject, PIRP Irp) PDEVICE_OBJECT DeviceObject, PIRP Irp)

View File

@ -128,6 +128,7 @@ NTSTATUS DriverEntry(
FspIopCompleteFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = FspFsvolFileSystemControlComplete; FspIopCompleteFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = FspFsvolFileSystemControlComplete;
FspIopCompleteFunction[IRP_MJ_DEVICE_CONTROL] = FspFsvolDeviceControlComplete; FspIopCompleteFunction[IRP_MJ_DEVICE_CONTROL] = FspFsvolDeviceControlComplete;
FspIopCompleteFunction[IRP_MJ_SHUTDOWN] = FspFsvolShutdownComplete; FspIopCompleteFunction[IRP_MJ_SHUTDOWN] = FspFsvolShutdownComplete;
FspFileNodeCompleteLockIrp = FspFsvolLockControlForward;
FspIopCompleteFunction[IRP_MJ_LOCK_CONTROL] = FspFsvolLockControlComplete; FspIopCompleteFunction[IRP_MJ_LOCK_CONTROL] = FspFsvolLockControlComplete;
FspIopCompleteFunction[IRP_MJ_CLEANUP] = FspFsvolCleanupComplete; FspIopCompleteFunction[IRP_MJ_CLEANUP] = FspFsvolCleanupComplete;
FspIopCompleteFunction[IRP_MJ_QUERY_SECURITY] = FspFsvolQuerySecurityComplete; FspIopCompleteFunction[IRP_MJ_QUERY_SECURITY] = FspFsvolQuerySecurityComplete;

View File

@ -316,6 +316,7 @@ FSP_IOPREP_DISPATCH FspFsvolDirectoryControlPrepare;
FSP_IOCMPL_DISPATCH FspFsvolDirectoryControlComplete; FSP_IOCMPL_DISPATCH FspFsvolDirectoryControlComplete;
FSP_IOCMPL_DISPATCH FspFsvolFileSystemControlComplete; FSP_IOCMPL_DISPATCH FspFsvolFileSystemControlComplete;
FSP_IOCMPL_DISPATCH FspFsvolFlushBuffersComplete; FSP_IOCMPL_DISPATCH FspFsvolFlushBuffersComplete;
NTSTATUS FspFsvolLockControlForward(PVOID Context, PIRP Irp);
FSP_IOCMPL_DISPATCH FspFsvolLockControlComplete; FSP_IOCMPL_DISPATCH FspFsvolLockControlComplete;
FSP_IOCMPL_DISPATCH FspFsvolQueryEaComplete; FSP_IOCMPL_DISPATCH FspFsvolQueryEaComplete;
FSP_IOCMPL_DISPATCH FspFsvolQueryInformationComplete; FSP_IOCMPL_DISPATCH FspFsvolQueryInformationComplete;
@ -837,6 +838,10 @@ PIRP FspIoqNextCompleteIrp(FSP_IOQ *Ioq, PIRP BoundaryIrp);
ULONG FspIoqRetriedIrpCount(FSP_IOQ *Ioq); ULONG FspIoqRetriedIrpCount(FSP_IOQ *Ioq);
/* meta cache */ /* meta cache */
enum
{
FspMetaCacheItemHeaderSize = MEMORY_ALLOCATION_ALIGNMENT,
};
typedef struct typedef struct
{ {
KSPIN_LOCK SpinLock; KSPIN_LOCK SpinLock;
@ -1144,11 +1149,13 @@ BOOLEAN FspWriteIrpShouldUseProcessBuffer(PIRP Irp, SIZE_T BufferSize)
return FspProcessBufferSizeMax >= BufferSize; return FspProcessBufferSizeMax >= BufferSize;
#endif #endif
} }
#if 0
static inline static inline
BOOLEAN FspQueryDirectoryIrpShouldUseProcessBuffer(PIRP Irp, SIZE_T BufferSize) BOOLEAN FspQueryDirectoryIrpShouldUseProcessBuffer(PIRP Irp, SIZE_T BufferSize)
{ {
return FspReadIrpShouldUseProcessBuffer(Irp, BufferSize); return FspReadIrpShouldUseProcessBuffer(Irp, BufferSize);
} }
#endif
/* volume management */ /* volume management */
#define FspVolumeTransactEarlyTimeout (1 * 10000ULL) #define FspVolumeTransactEarlyTimeout (1 * 10000ULL)
@ -1558,6 +1565,7 @@ extern CACHE_MANAGER_CALLBACKS FspCacheManagerCallbacks;
extern FSP_IOPREP_DISPATCH *FspIopPrepareFunction[]; extern FSP_IOPREP_DISPATCH *FspIopPrepareFunction[];
extern FSP_IOCMPL_DISPATCH *FspIopCompleteFunction[]; extern FSP_IOCMPL_DISPATCH *FspIopCompleteFunction[];
extern ERESOURCE FspDeviceGlobalResource; extern ERESOURCE FspDeviceGlobalResource;
extern PCOMPLETE_LOCK_IRP_ROUTINE FspFileNodeCompleteLockIrp;
extern WCHAR FspFileDescDirectoryPatternMatchAll[]; extern WCHAR FspFileDescDirectoryPatternMatchAll[];
extern const GUID FspMainFileOpenEcpGuid; extern const GUID FspMainFileOpenEcpGuid;
extern ULONG FspProcessorCount; extern ULONG FspProcessorCount;

View File

@ -83,7 +83,6 @@ VOID FspFileNodeInvalidateStreamInfo(FSP_FILE_NODE *FileNode);
VOID FspFileNodeNotifyChange(FSP_FILE_NODE *FileNode, ULONG Filter, ULONG Action, VOID FspFileNodeNotifyChange(FSP_FILE_NODE *FileNode, ULONG Filter, ULONG Action,
BOOLEAN InvalidateCaches); BOOLEAN InvalidateCaches);
NTSTATUS FspFileNodeProcessLockIrp(FSP_FILE_NODE *FileNode, PIRP Irp); NTSTATUS FspFileNodeProcessLockIrp(FSP_FILE_NODE *FileNode, PIRP Irp);
static NTSTATUS FspFileNodeCompleteLockIrp(PVOID Context, PIRP Irp);
NTSTATUS FspFileDescCreate(FSP_FILE_DESC **PFileDesc); NTSTATUS FspFileDescCreate(FSP_FILE_DESC **PFileDesc);
VOID FspFileDescDelete(FSP_FILE_DESC *FileDesc); VOID FspFileDescDelete(FSP_FILE_DESC *FileDesc);
NTSTATUS FspFileDescResetDirectory(FSP_FILE_DESC *FileDesc, NTSTATUS FspFileDescResetDirectory(FSP_FILE_DESC *FileDesc,
@ -149,7 +148,6 @@ VOID FspFileNodeOplockComplete(PVOID Context, PIRP Irp);
// !#pragma alloc_text(PAGE, FspFileNodeInvalidateStreamInfo) // !#pragma alloc_text(PAGE, FspFileNodeInvalidateStreamInfo)
#pragma alloc_text(PAGE, FspFileNodeNotifyChange) #pragma alloc_text(PAGE, FspFileNodeNotifyChange)
#pragma alloc_text(PAGE, FspFileNodeProcessLockIrp) #pragma alloc_text(PAGE, FspFileNodeProcessLockIrp)
#pragma alloc_text(PAGE, FspFileNodeCompleteLockIrp)
#pragma alloc_text(PAGE, FspFileDescCreate) #pragma alloc_text(PAGE, FspFileDescCreate)
#pragma alloc_text(PAGE, FspFileDescDelete) #pragma alloc_text(PAGE, FspFileDescDelete)
#pragma alloc_text(PAGE, FspFileDescResetDirectory) #pragma alloc_text(PAGE, FspFileDescResetDirectory)
@ -2030,19 +2028,6 @@ NTSTATUS FspFileNodeProcessLockIrp(FSP_FILE_NODE *FileNode, PIRP Irp)
return Result; return Result;
} }
static NTSTATUS FspFileNodeCompleteLockIrp(PVOID Context, PIRP Irp)
{
PAGED_CODE();
NTSTATUS Result = Irp->IoStatus.Status;
DEBUGLOGIRP(Irp, Result);
FspIopCompleteIrp(Irp, Result);
return Result;
}
NTSTATUS FspFileDescCreate(FSP_FILE_DESC **PFileDesc) NTSTATUS FspFileDescCreate(FSP_FILE_DESC **PFileDesc)
{ {
PAGED_CODE(); PAGED_CODE();
@ -2379,6 +2364,7 @@ VOID FspFileNodeOplockComplete(PVOID Context, PIRP Irp)
FspIopCompleteIrp(Irp, Irp->IoStatus.Status); FspIopCompleteIrp(Irp, Irp->IoStatus.Status);
} }
PCOMPLETE_LOCK_IRP_ROUTINE FspFileNodeCompleteLockIrp;
WCHAR FspFileDescDirectoryPatternMatchAll[] = L"*"; WCHAR FspFileDescDirectoryPatternMatchAll[] = L"*";
// {904862B4-EB3F-461E-ACB2-4DF2B3FC898B} // {904862B4-EB3F-461E-ACB2-4DF2B3FC898B}

View File

@ -1573,7 +1573,7 @@ NTSTATUS FspFsvolSetInformationPrepare(
SECURITY_CLIENT_CONTEXT SecurityClientContext; SECURITY_CLIENT_CONTEXT SecurityClientContext;
HANDLE UserModeAccessToken; HANDLE UserModeAccessToken;
PEPROCESS Process; PEPROCESS Process;
HANDLE ProcessId; ULONG OriginatingProcessId;
SecuritySubjectContext = FspIopRequestContext(Request, RequestSubjectContextOrAccessToken); SecuritySubjectContext = FspIopRequestContext(Request, RequestSubjectContextOrAccessToken);
@ -1605,15 +1605,17 @@ NTSTATUS FspFsvolSetInformationPrepare(
/* get a pointer to the current process so that we can close the impersonation token later */ /* get a pointer to the current process so that we can close the impersonation token later */
Process = PsGetCurrentProcess(); Process = PsGetCurrentProcess();
ObReferenceObject(Process); ObReferenceObject(Process);
ProcessId = PsGetProcessId(Process);
/* get the originating process ID stored in the IRP */
OriginatingProcessId = IoGetRequestorProcessId(Irp);
/* send the user-mode handle to the user-mode file system */ /* send the user-mode handle to the user-mode file system */
FspIopRequestContext(Request, RequestSubjectContextOrAccessToken) = UserModeAccessToken; FspIopRequestContext(Request, RequestSubjectContextOrAccessToken) = UserModeAccessToken;
FspIopRequestContext(Request, RequestProcess) = Process; FspIopRequestContext(Request, RequestProcess) = Process;
ASSERT((UINT64)(UINT_PTR)UserModeAccessToken <= 0xffffffffULL); ASSERT((UINT64)(UINT_PTR)UserModeAccessToken <= 0xffffffffULL);
ASSERT((UINT64)(UINT_PTR)ProcessId <= 0xffffffffULL); ASSERT((UINT64)(UINT_PTR)OriginatingProcessId <= 0xffffffffULL);
Request->Req.SetInformation.Info.Rename.AccessToken = Request->Req.SetInformation.Info.Rename.AccessToken =
((UINT64)(UINT_PTR)ProcessId << 32) | (UINT64)(UINT_PTR)UserModeAccessToken; ((UINT64)(UINT_PTR)OriginatingProcessId << 32) | (UINT64)(UINT_PTR)UserModeAccessToken;
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }

View File

@ -306,47 +306,6 @@ VOID FspIopCompleteIrpEx(PIRP Irp, NTSTATUS Result, BOOLEAN DeviceDereference)
} }
} }
} }
else
/*
* HACK:
*
* Turns out that SRV2 sends an undocumented flavor of IRP_MJ_DIRECTORY_CONTROL /
* IRP_MN_QUERY_DIRECTORY. These IRP's have a non-NULL Irp->MdlAddress. They expect
* the FSD to fill the buffer pointed by Irp->MdlAddress and they cannot handle
* completed IRP's with a non-NULL Irp->AssociatedIrp.SystemBuffer. So we have to
* provide special support for these IRPs.
*
* While this processing is IRP_MJ_DIRECTORY_CONTROL specific, we do this here for
* these reasons:
*
* 1. There may be other IRP's that have similar completion requirements under SRV2.
* If/when such IRP's are discovered the completion processing can be centralized
* here.
* 2. IRP_MJ_DIRECTORY_CONTROL has a few different ways that it can complete IRP's.
* It is far simpler to do this processing here, even if not academically correct.
*
* This will have to be revisited if IRP_MJ_DIRECTORY_CONTROL processing changes
* substantially (e.g. to no longer use Irp->AssociatedIrp.SystemBuffer).
*/
if (IRP_MJ_DIRECTORY_CONTROL == IrpSp->MajorFunction &&
IRP_MN_QUERY_DIRECTORY == IrpSp->MinorFunction &&
0 != Irp->MdlAddress && /* SRV2 queries have this set */
0 != Irp->AssociatedIrp.SystemBuffer &&
FlagOn(Irp->Flags, IRP_BUFFERED_IO))
{
if (STATUS_SUCCESS == Result)
{
PVOID Address = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
if (0 != Address)
RtlCopyMemory(Address, Irp->AssociatedIrp.SystemBuffer, Irp->IoStatus.Information);
else
Result = STATUS_INSUFFICIENT_RESOURCES;
}
FspFreeExternal(Irp->AssociatedIrp.SystemBuffer);
Irp->AssociatedIrp.SystemBuffer = 0;
ClearFlag(Irp->Flags, IRP_INPUT_OPERATION | IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER);
}
if (STATUS_SUCCESS != Result && if (STATUS_SUCCESS != Result &&
STATUS_REPARSE != Result && STATUS_REPARSE != Result &&

View File

@ -22,12 +22,14 @@ static NTSTATUS FspFsvolLockControlRetry(
BOOLEAN CanWait); BOOLEAN CanWait);
static NTSTATUS FspFsvolLockControl( static NTSTATUS FspFsvolLockControl(
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
NTSTATUS FspFsvolLockControlForward(PVOID Context, PIRP Irp);
FSP_IOCMPL_DISPATCH FspFsvolLockControlComplete; FSP_IOCMPL_DISPATCH FspFsvolLockControlComplete;
FSP_DRIVER_DISPATCH FspLockControl; FSP_DRIVER_DISPATCH FspLockControl;
#ifdef ALLOC_PRAGMA #ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, FspFsvolLockControlRetry) #pragma alloc_text(PAGE, FspFsvolLockControlRetry)
#pragma alloc_text(PAGE, FspFsvolLockControl) #pragma alloc_text(PAGE, FspFsvolLockControl)
#pragma alloc_text(PAGE, FspFsvolLockControlForward)
#pragma alloc_text(PAGE, FspFsvolLockControlComplete) #pragma alloc_text(PAGE, FspFsvolLockControlComplete)
#pragma alloc_text(PAGE, FspLockControl) #pragma alloc_text(PAGE, FspLockControl)
#endif #endif
@ -94,6 +96,57 @@ static NTSTATUS FspFsvolLockControl(
return Result; return Result;
} }
NTSTATUS FspFsvolLockControlForward(PVOID Context, PIRP Irp)
{
/*
* At this point the FSRTL package has processed the lock IRP.
* Either complete the IRP or if we are supposed to forward to
* user mode do so now.
*/
PAGED_CODE();
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
PDEVICE_OBJECT FsvolDeviceObject = IrpSp->DeviceObject;
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
NTSTATUS Result = Irp->IoStatus.Status;
if (!NT_SUCCESS(Result) || !FsvolDeviceExtension->VolumeParams.UserModeFileLocking)
goto complete;
PFILE_OBJECT FileObject = IrpSp->FileObject;
FSP_FILE_NODE *FileNode = FileObject->FsContext;
FSP_FILE_DESC *FileDesc = FileObject->FsContext2;
FSP_FSCTL_TRANSACT_REQ *Request;
ASSERT(FileNode == FileDesc->FileNode);
Result = FspIopCreateRequest(Irp, 0, 0, &Request);
if (!NT_SUCCESS(Result))
goto complete;
Request->Kind = FspFsctlTransactLockControlKind;
Request->Req.LockControl.UserContext = FileNode->UserContext;
Request->Req.LockControl.UserContext2 = FileDesc->UserContext2;
Request->Req.LockControl.LockFunction = IrpSp->MinorFunction;
Request->Req.LockControl.Offset = IrpSp->Parameters.LockControl.ByteOffset.QuadPart;
Request->Req.LockControl.Length = IrpSp->Parameters.LockControl.Length->QuadPart;
Request->Req.LockControl.Key = IrpSp->Parameters.LockControl.Key;
Request->Req.LockControl.ProcessId = IoGetRequestorProcessId(Irp);
Request->Req.LockControl.Exclusive = 0 != (IrpSp->Flags & SL_EXCLUSIVE_LOCK);
Request->Req.LockControl.FailImmediately = 0 != (IrpSp->Flags & SL_FAIL_IMMEDIATELY);
if (!FspIoqPostIrp(FsvolDeviceExtension->Ioq, Irp, &Result))
goto complete;
return Result;
complete:
DEBUGLOGIRP(Irp, Result);
FspIopCompleteIrp(Irp, Result);
return Result;
}
NTSTATUS FspFsvolLockControlComplete( NTSTATUS FspFsvolLockControlComplete(
PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response) PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response)
{ {

View File

@ -33,6 +33,8 @@ typedef struct
ULONG Size; ULONG Size;
__declspec(align(MEMORY_ALLOCATION_ALIGNMENT)) UINT8 Buffer[]; __declspec(align(MEMORY_ALLOCATION_ALIGNMENT)) UINT8 Buffer[];
} FSP_META_CACHE_ITEM_BUFFER; } FSP_META_CACHE_ITEM_BUFFER;
FSP_FSCTL_STATIC_ASSERT(FIELD_OFFSET(FSP_META_CACHE_ITEM_BUFFER, Buffer) == FspMetaCacheItemHeaderSize,
"FspMetaCacheItemHeaderSize must match offset of FSP_META_CACHE_ITEM_BUFFER::Buffer");
static inline VOID FspMetaCacheDereferenceItem(FSP_META_CACHE_ITEM *Item) static inline VOID FspMetaCacheDereferenceItem(FSP_META_CACHE_ITEM *Item)
{ {
@ -218,7 +220,16 @@ UINT64 FspMetaCacheAddItem(FSP_META_CACHE *MetaCache, PCVOID Buffer, ULONG Size)
Item->RefCount = 1; Item->RefCount = 1;
ItemBuffer->Item = Item; ItemBuffer->Item = Item;
ItemBuffer->Size = Size; ItemBuffer->Size = Size;
try
{
RtlCopyMemory(ItemBuffer->Buffer, Buffer, Size); RtlCopyMemory(ItemBuffer->Buffer, Buffer, Size);
}
except (EXCEPTION_EXECUTE_HANDLER)
{
FspFree(ItemBuffer);
FspFree(Item);
return 0;
}
KeAcquireSpinLock(&MetaCache->SpinLock, &Irql); KeAcquireSpinLock(&MetaCache->SpinLock, &Irql);
if (MetaCache->ItemCount >= MetaCache->MetaCapacity) if (MetaCache->ItemCount >= MetaCache->MetaCapacity)
FspMetaCacheRemoveExpiredItemAtDpcLevel(MetaCache, (UINT64)-1LL); FspMetaCacheRemoveExpiredItemAtDpcLevel(MetaCache, (UINT64)-1LL);

View File

@ -228,7 +228,6 @@ static NTSTATUS FspFsvolReadNonCached(
FSP_FILE_DESC *FileDesc = FileObject->FsContext2; FSP_FILE_DESC *FileDesc = FileObject->FsContext2;
LARGE_INTEGER ReadOffset = IrpSp->Parameters.Read.ByteOffset; LARGE_INTEGER ReadOffset = IrpSp->Parameters.Read.ByteOffset;
ULONG ReadLength = IrpSp->Parameters.Read.Length; ULONG ReadLength = IrpSp->Parameters.Read.Length;
ULONG ReadKey = IrpSp->Parameters.Read.Key;
BOOLEAN PagingIo = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO); BOOLEAN PagingIo = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO);
FSP_FSCTL_TRANSACT_REQ *Request; FSP_FSCTL_TRANSACT_REQ *Request;
BOOLEAN Success; BOOLEAN Success;
@ -321,7 +320,11 @@ static NTSTATUS FspFsvolReadNonCached(
Request->Req.Read.UserContext2 = FileDesc->UserContext2; Request->Req.Read.UserContext2 = FileDesc->UserContext2;
Request->Req.Read.Offset = ReadOffset.QuadPart; Request->Req.Read.Offset = ReadOffset.QuadPart;
Request->Req.Read.Length = ReadLength; Request->Req.Read.Length = ReadLength;
Request->Req.Read.Key = ReadKey; if (!PagingIo)
{
Request->Req.Read.Key = IrpSp->Parameters.Read.Key;
Request->Req.Read.ProcessId = IoGetRequestorProcessId(Irp);
}
FspFileNodeSetOwner(FileNode, Full, Request); FspFileNodeSetOwner(FileNode, Full, Request);
FspIopRequestContext(Request, RequestIrp) = Irp; FspIopRequestContext(Request, RequestIrp) = Irp;

View File

@ -32,7 +32,7 @@ static VOID FspWqWorkRoutine(PVOID Context);
static inline static inline
NTSTATUS FspWqPrepareIrpWorkItem(PIRP Irp) NTSTATUS FspWqPrepareIrpWorkItem(PIRP Irp)
{ {
NTSTATUS Result; NTSTATUS Result = STATUS_SUCCESS;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
/* lock/buffer the user buffer */ /* lock/buffer the user buffer */
@ -43,11 +43,12 @@ NTSTATUS FspWqPrepareIrpWorkItem(PIRP Irp)
Result = FspLockUserBuffer(Irp, IrpSp->Parameters.Read.Length, IoWriteAccess); Result = FspLockUserBuffer(Irp, IrpSp->Parameters.Read.Length, IoWriteAccess);
else else
Result = FspLockUserBuffer(Irp, IrpSp->Parameters.Write.Length, IoReadAccess); Result = FspLockUserBuffer(Irp, IrpSp->Parameters.Write.Length, IoReadAccess);
if (!NT_SUCCESS(Result))
return Result;
} }
else
if (IRP_MJ_DIRECTORY_CONTROL == IrpSp->MajorFunction)
Result = FspLockUserBuffer(Irp, IrpSp->Parameters.QueryDirectory.Length, IoWriteAccess);
return STATUS_SUCCESS; return Result;
} }
NTSTATUS FspWqCreateAndPostIrpWorkItem(PIRP Irp, NTSTATUS FspWqCreateAndPostIrpWorkItem(PIRP Irp,

View File

@ -289,7 +289,6 @@ static NTSTATUS FspFsvolWriteNonCached(
FSP_FILE_DESC *FileDesc = FileObject->FsContext2; FSP_FILE_DESC *FileDesc = FileObject->FsContext2;
LARGE_INTEGER WriteOffset = IrpSp->Parameters.Write.ByteOffset; LARGE_INTEGER WriteOffset = IrpSp->Parameters.Write.ByteOffset;
ULONG WriteLength = IrpSp->Parameters.Write.Length; ULONG WriteLength = IrpSp->Parameters.Write.Length;
ULONG WriteKey = IrpSp->Parameters.Write.Key;
BOOLEAN WriteToEndOfFile = BOOLEAN WriteToEndOfFile =
FILE_WRITE_TO_END_OF_FILE == WriteOffset.LowPart && -1L == WriteOffset.HighPart; FILE_WRITE_TO_END_OF_FILE == WriteOffset.LowPart && -1L == WriteOffset.HighPart;
BOOLEAN PagingIo = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO); BOOLEAN PagingIo = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO);
@ -390,8 +389,13 @@ static NTSTATUS FspFsvolWriteNonCached(
Request->Req.Write.UserContext2 = FileDesc->UserContext2; Request->Req.Write.UserContext2 = FileDesc->UserContext2;
Request->Req.Write.Offset = WriteOffset.QuadPart; Request->Req.Write.Offset = WriteOffset.QuadPart;
Request->Req.Write.Length = WriteLength; Request->Req.Write.Length = WriteLength;
Request->Req.Write.Key = WriteKey; if (!PagingIo)
Request->Req.Write.ConstrainedIo = !!PagingIo; {
Request->Req.Write.Key = IrpSp->Parameters.Write.Key;
Request->Req.Write.ProcessId = IoGetRequestorProcessId(Irp);
}
else
Request->Req.Write.ConstrainedIo = TRUE;
FspFileNodeSetOwner(FileNode, Full, Request); FspFileNodeSetOwner(FileNode, Full, Request);
FspIopRequestContext(Request, RequestIrp) = Irp; FspIopRequestContext(Request, RequestIrp) = Irp;

View File

@ -39,6 +39,7 @@ set dfl_tests=^
winfsp-tests-x64-external-share ^ winfsp-tests-x64-external-share ^
fsx-memfs-x64-disk ^ fsx-memfs-x64-disk ^
fsx-memfs-x64-net ^ fsx-memfs-x64-net ^
fsx-memfs-x64-slowio ^
standby-memfs-x64-disk ^ standby-memfs-x64-disk ^
standby-memfs-x64-net ^ standby-memfs-x64-net ^
net-use-memfs-x64 ^ net-use-memfs-x64 ^
@ -55,6 +56,7 @@ set dfl_tests=^
winfsp-tests-x86-external-share ^ winfsp-tests-x86-external-share ^
fsx-memfs-x86-disk ^ fsx-memfs-x86-disk ^
fsx-memfs-x86-net ^ fsx-memfs-x86-net ^
fsx-memfs-x86-slowio ^
standby-memfs-x86-disk ^ standby-memfs-x86-disk ^
standby-memfs-x86-net ^ standby-memfs-x86-net ^
net-use-memfs-x86 ^ net-use-memfs-x86 ^
@ -77,7 +79,12 @@ set opt_tests=^
sample-fsx-passthrough-fuse-x64 ^ sample-fsx-passthrough-fuse-x64 ^
sample-passthrough-fuse-x86 ^ sample-passthrough-fuse-x86 ^
sample-fsx-passthrough-fuse-x86 ^ sample-fsx-passthrough-fuse-x86 ^
sample-passthrough-dotnet sample-passthrough-dotnet ^
compat-v1.1-passthrough-fuse-x64 ^
compat-v1.1-passthrough-fuse-x86 ^
avast-tests-x64 ^
avast-tests-x86 ^
avast-tests-dotnet
set tests= set tests=
for %%f in (%dfl_tests%) do ( for %%f in (%dfl_tests%) do (
@ -212,14 +219,28 @@ exit /b 0
:winfsp-tests-x64-external :winfsp-tests-x64-external
M: M:
fltmc instances -v M: | findstr aswSnx >nul
if !ERRORLEVEL! neq 0 (
"%ProjRoot%\build\VStudio\build\%Configuration%\winfsp-tests-x64.exe" --external --resilient "%ProjRoot%\build\VStudio\build\%Configuration%\winfsp-tests-x64.exe" --external --resilient
) else (
REM Avast present
"%ProjRoot%\build\VStudio\build\%Configuration%\winfsp-tests-x64.exe" --external --resilient ^
-querydir_buffer_overflow_test
)
if !ERRORLEVEL! neq 0 goto fail if !ERRORLEVEL! neq 0 goto fail
exit /b 0 exit /b 0
:winfsp-tests-x64-external-share :winfsp-tests-x64-external-share
M: M:
fltmc instances -v M: | findstr aswSnx >nul
if !ERRORLEVEL! neq 0 (
"%ProjRoot%\build\VStudio\build\%Configuration%\winfsp-tests-x64.exe" --external --share=winfsp-tests-share=M:\ --resilient ^ "%ProjRoot%\build\VStudio\build\%Configuration%\winfsp-tests-x64.exe" --external --share=winfsp-tests-share=M:\ --resilient ^
-reparse_symlink* -reparse_symlink*
) else (
REM Avast present
"%ProjRoot%\build\VStudio\build\%Configuration%\winfsp-tests-x64.exe" --external --share=winfsp-tests-share=M:\ --resilient ^
-reparse_symlink* -querydir_buffer_overflow_test
)
if !ERRORLEVEL! neq 0 goto fail if !ERRORLEVEL! neq 0 goto fail
exit /b 0 exit /b 0
@ -265,14 +286,28 @@ exit /b 0
:winfsp-tests-x86-external :winfsp-tests-x86-external
O: O:
fltmc instances -v O: | findstr aswSnx >nul
if !ERRORLEVEL! neq 0 (
"%ProjRoot%\build\VStudio\build\%Configuration%\winfsp-tests-x86.exe" --external --resilient "%ProjRoot%\build\VStudio\build\%Configuration%\winfsp-tests-x86.exe" --external --resilient
) else (
REM Avast present
"%ProjRoot%\build\VStudio\build\%Configuration%\winfsp-tests-x86.exe" --external --resilient ^
-querydir_buffer_overflow_test
)
if !ERRORLEVEL! neq 0 goto fail if !ERRORLEVEL! neq 0 goto fail
exit /b 0 exit /b 0
:winfsp-tests-x86-external-share :winfsp-tests-x86-external-share
O: O:
fltmc instances -v O: | findstr aswSnx >nul
if !ERRORLEVEL! neq 0 (
"%ProjRoot%\build\VStudio\build\%Configuration%\winfsp-tests-x86.exe" --external --share=winfsp-tests-share=O:\ --resilient ^ "%ProjRoot%\build\VStudio\build\%Configuration%\winfsp-tests-x86.exe" --external --share=winfsp-tests-share=O:\ --resilient ^
-reparse_symlink* -reparse_symlink*
) else (
REM Avast present
"%ProjRoot%\build\VStudio\build\%Configuration%\winfsp-tests-x86.exe" --external --share=winfsp-tests-share=O:\ --resilient ^
-reparse_symlink* -querydir_buffer_overflow_test
)
if !ERRORLEVEL! neq 0 goto fail if !ERRORLEVEL! neq 0 goto fail
exit /b 0 exit /b 0
@ -380,14 +415,28 @@ exit /b 0
:winfsp-tests-dotnet-external :winfsp-tests-dotnet-external
Q: Q:
fltmc instances -v Q: | findstr aswSnx >nul
if !ERRORLEVEL! neq 0 (
"%ProjRoot%\build\VStudio\build\%Configuration%\winfsp-tests-x64.exe" --external --resilient "%ProjRoot%\build\VStudio\build\%Configuration%\winfsp-tests-x64.exe" --external --resilient
) else (
REM Avast present
"%ProjRoot%\build\VStudio\build\%Configuration%\winfsp-tests-x64.exe" --external --resilient ^
-querydir_buffer_overflow_test
)
if !ERRORLEVEL! neq 0 goto fail if !ERRORLEVEL! neq 0 goto fail
exit /b 0 exit /b 0
:winfsp-tests-dotnet-external-share :winfsp-tests-dotnet-external-share
Q: Q:
fltmc instances -v Q: | findstr aswSnx >nul
if !ERRORLEVEL! neq 0 (
"%ProjRoot%\build\VStudio\build\%Configuration%\winfsp-tests-x64.exe" --external --share=winfsp-tests-share=Q:\ --resilient ^ "%ProjRoot%\build\VStudio\build\%Configuration%\winfsp-tests-x64.exe" --external --share=winfsp-tests-share=Q:\ --resilient ^
-reparse_symlink* -reparse_symlink*
) else (
REM Avast present
"%ProjRoot%\build\VStudio\build\%Configuration%\winfsp-tests-x64.exe" --external --share=winfsp-tests-share=Q:\ --resilient ^
-reparse_symlink* -querydir_buffer_overflow_test
)
if !ERRORLEVEL! neq 0 goto fail if !ERRORLEVEL! neq 0 goto fail
exit /b 0 exit /b 0
@ -407,6 +456,35 @@ if !ERRORLEVEL! neq 0 goto fail
if !ERRORLEVEL! neq 0 goto fail if !ERRORLEVEL! neq 0 goto fail
exit /b 0 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 :winfstest-memfs-dotnet-disk
Q: Q:
call "%ProjRoot%\ext\test\winfstest\run-winfstest.bat" call "%ProjRoot%\ext\test\winfstest\run-winfstest.bat"
@ -647,7 +725,7 @@ L:
"%ProjRoot%\build\VStudio\build\%Configuration%\%4.exe" ^ "%ProjRoot%\build\VStudio\build\%Configuration%\%4.exe" ^
--external --resilient --case-insensitive-cmp --share-prefix="\%1\%TMP::=$%\%1\test" ^ --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 ^ -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 -exec_rename_dir_test ^
-reparse* -stream* -reparse* -stream*
if !ERRORLEVEL! neq 0 set RunSampleTestExit=1 if !ERRORLEVEL! neq 0 set RunSampleTestExit=1
popd popd
@ -681,6 +759,63 @@ call "%ProjRoot%\tools\fsreg" -u %1
rmdir /s/q "%TMP%\%1" rmdir /s/q "%TMP%\%1"
exit /b !RunSampleTestExit! 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_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 ^
-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
call :winfsp-tests-x64-external-share
if !ERRORLEVEL! neq 0 goto fail
exit /b 0
:avast-tests-x86
call :winfsp-tests-x86-external
if !ERRORLEVEL! neq 0 goto fail
call :winfsp-tests-x86-external-share
if !ERRORLEVEL! neq 0 goto fail
exit /b 0
:avast-tests-dotnet
call :winfsp-tests-dotnet-external
if !ERRORLEVEL! neq 0 goto fail
call :winfsp-tests-dotnet-external-share
if !ERRORLEVEL! neq 0 goto fail
exit /b 0
:leak-test :leak-test
for /F "tokens=1,2 delims=:" %%i in ('verifier /query ^| findstr ^ for /F "tokens=1,2 delims=:" %%i in ('verifier /query ^| findstr ^
/c:"Current Pool Allocations:" ^ /c:"Current Pool Allocations:" ^

View 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.

View File

@ -44,6 +44,9 @@ NTSTATUS SvcStart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
ULONG FileInfoTimeout = INFINITE; ULONG FileInfoTimeout = INFINITE;
ULONG MaxFileNodes = 1024; ULONG MaxFileNodes = 1024;
ULONG MaxFileSize = 16 * 1024 * 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 FileSystemName = 0;
PWSTR MountPoint = 0; PWSTR MountPoint = 0;
PWSTR VolumePrefix = 0; PWSTR VolumePrefix = 0;
@ -75,9 +78,18 @@ NTSTATUS SvcStart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
case L'm': case L'm':
argtos(MountPoint); argtos(MountPoint);
break; break;
case L'M':
argtol(SlowioMaxDelay);
break;
case L'n': case L'n':
argtol(MaxFileNodes); argtol(MaxFileNodes);
break; break;
case L'P':
argtol(SlowioPercentDelay);
break;
case L'R':
argtol(SlowioRarefyDelay);
break;
case L'S': case L'S':
argtos(RootSddl); argtos(RootSddl);
break; break;
@ -130,6 +142,9 @@ NTSTATUS SvcStart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
FileInfoTimeout, FileInfoTimeout,
MaxFileNodes, MaxFileNodes,
MaxFileSize, MaxFileSize,
SlowioMaxDelay,
SlowioPercentDelay,
SlowioRarefyDelay,
FileSystemName, FileSystemName,
VolumePrefix, VolumePrefix,
RootSddl, RootSddl,
@ -189,6 +204,9 @@ usage:
" -t FileInfoTimeout [millis]\n" " -t FileInfoTimeout [millis]\n"
" -n MaxFileNodes\n" " -n MaxFileNodes\n"
" -s MaxFileSize [bytes]\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" " -F FileSystemName\n"
" -S RootSddl [file rights: FA, etc; NO generic rights: GA, etc.]\n" " -S RootSddl [file rights: FA, etc; NO generic rights: GA, etc.]\n"
" -u \\Server\\Share [UNC prefix (single backslash)]\n" " -u \\Server\\Share [UNC prefix (single backslash)]\n"

View File

@ -23,6 +23,9 @@
#include <map> #include <map>
#include <unordered_map> #include <unordered_map>
/* SLOWIO */
#include <thread>
#define MEMFS_MAX_PATH 512 #define MEMFS_MAX_PATH 512
FSP_FSCTL_STATIC_ASSERT(MEMFS_MAX_PATH > MAX_PATH, FSP_FSCTL_STATIC_ASSERT(MEMFS_MAX_PATH > MAX_PATH,
"MEMFS_MAX_PATH must be greater than 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 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 * Define the DEBUG_BUFFER_CHECK macro on Windows 8 or above. This includes
* a check for the Write buffer to ensure that it is read-only. * a check for the Write buffer to ensure that it is read-only.
@ -281,6 +289,12 @@ typedef struct _MEMFS
MEMFS_FILE_NODE_MAP *FileNodeMap; MEMFS_FILE_NODE_MAP *FileNodeMap;
ULONG MaxFileNodes; ULONG MaxFileNodes;
ULONG MaxFileSize; ULONG MaxFileSize;
#ifdef MEMFS_SLOWIO
ULONG SlowioMaxDelay;
ULONG SlowioPercentDelay;
ULONG SlowioRarefyDelay;
volatile LONG SlowioThreadsRunning;
#endif
UINT16 VolumeLabelLength; UINT16 VolumeLabelLength;
WCHAR VolumeLabel[32]; WCHAR VolumeLabel[32];
} MEMFS; } MEMFS;
@ -646,6 +660,126 @@ VOID MemfsFileNodeMapEnumerateFree(MEMFS_FILE_NODE_MAP_ENUM_CONTEXT *Context)
free(Context->FileNodes); 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 * FSP_FILE_SYSTEM_INTERFACE
*/ */
@ -1029,6 +1163,27 @@ static NTSTATUS Read(FSP_FILE_SYSTEM *FileSystem,
if (EndOffset > FileNode->FileInfo.FileSize) if (EndOffset > FileNode->FileInfo.FileSize)
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)); memcpy(Buffer, (PUINT8)FileNode->FileData + Offset, (size_t)(EndOffset - Offset));
*PBytesTransferred = (ULONG)(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)); memcpy((PUINT8)FileNode->FileData + Offset, Buffer, (size_t)(EndOffset - Offset));
*PBytesTransferred = (ULONG)(EndOffset - Offset); *PBytesTransferred = (ULONG)(EndOffset - Offset);
@ -1451,6 +1627,26 @@ static NTSTATUS ReadDirectory(FSP_FILE_SYSTEM *FileSystem,
ReadDirectoryEnumFn, &Context)) ReadDirectoryEnumFn, &Context))
FspFileSystemAddDirInfo(0, Buffer, Length, PBytesTransferred); 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; return STATUS_SUCCESS;
} }
@ -1752,6 +1948,9 @@ NTSTATUS MemfsCreateFunnel(
ULONG FileInfoTimeout, ULONG FileInfoTimeout,
ULONG MaxFileNodes, ULONG MaxFileNodes,
ULONG MaxFileSize, ULONG MaxFileSize,
ULONG SlowioMaxDelay,
ULONG SlowioPercentDelay,
ULONG SlowioRarefyDelay,
PWSTR FileSystemName, PWSTR FileSystemName,
PWSTR VolumePrefix, PWSTR VolumePrefix,
PWSTR RootSddl, PWSTR RootSddl,
@ -1793,6 +1992,12 @@ NTSTATUS MemfsCreateFunnel(
AllocationUnit = MEMFS_SECTOR_SIZE * MEMFS_SECTORS_PER_ALLOCATION_UNIT; AllocationUnit = MEMFS_SECTOR_SIZE * MEMFS_SECTORS_PER_ALLOCATION_UNIT;
Memfs->MaxFileSize = (ULONG)((MaxFileSize + AllocationUnit - 1) / AllocationUnit * AllocationUnit); 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); Result = MemfsFileNodeMapCreate(CaseInsensitive, &Memfs->FileNodeMap);
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
{ {
@ -1895,12 +2100,21 @@ VOID MemfsDelete(MEMFS *Memfs)
NTSTATUS MemfsStart(MEMFS *Memfs) NTSTATUS MemfsStart(MEMFS *Memfs)
{ {
#ifdef MEMFS_SLOWIO
Memfs->SlowioThreadsRunning = 0;
#endif
return FspFileSystemStartDispatcher(Memfs->FileSystem, 0); return FspFileSystemStartDispatcher(Memfs->FileSystem, 0);
} }
VOID MemfsStop(MEMFS *Memfs) VOID MemfsStop(MEMFS *Memfs)
{ {
FspFileSystemStopDispatcher(Memfs->FileSystem); FspFileSystemStopDispatcher(Memfs->FileSystem);
#ifdef MEMFS_SLOWIO
while (Memfs->SlowioThreadsRunning)
Sleep(1);
#endif
} }
FSP_FILE_SYSTEM *MemfsFileSystem(MEMFS *Memfs) FSP_FILE_SYSTEM *MemfsFileSystem(MEMFS *Memfs)

View File

@ -34,12 +34,26 @@ enum
}; };
#define MemfsCreate(Flags, FileInfoTimeout, MaxFileNodes, MaxFileSize, VolumePrefix, RootSddl, PMemfs)\ #define MemfsCreate(Flags, FileInfoTimeout, MaxFileNodes, MaxFileSize, VolumePrefix, RootSddl, PMemfs)\
MemfsCreateFunnel(Flags, FileInfoTimeout, MaxFileNodes, MaxFileSize, 0, VolumePrefix, RootSddl, PMemfs) MemfsCreateFunnel(\
Flags,\
FileInfoTimeout,\
MaxFileNodes,\
MaxFileSize,\
0/*SlowioMaxDelay*/,\
0/*SlowioPercentDelay*/,\
0/*SlowioRarefyDelay*/,\
0/*FileSystemName*/,\
VolumePrefix,\
RootSddl,\
PMemfs)
NTSTATUS MemfsCreateFunnel( NTSTATUS MemfsCreateFunnel(
ULONG Flags, ULONG Flags,
ULONG FileInfoTimeout, ULONG FileInfoTimeout,
ULONG MaxFileNodes, ULONG MaxFileNodes,
ULONG MaxFileSize, ULONG MaxFileSize,
ULONG SlowioMaxDelay,
ULONG SlowioPercentDelay,
ULONG SlowioRarefyDelay,
PWSTR FileSystemName, PWSTR FileSystemName,
PWSTR VolumePrefix, PWSTR VolumePrefix,
PWSTR RootSddl, PWSTR RootSddl,

View File

@ -30,6 +30,8 @@
#include <unistd.h> #include <unistd.h>
#endif #endif
#define PTFS_UTIMENS
#define FSNAME "passthrough" #define FSNAME "passthrough"
#define PROGNAME "passthrough-fuse" #define PROGNAME "passthrough-fuse"
@ -112,12 +114,14 @@ static int ptfs_truncate(const char *path, fuse_off_t size)
return -1 != truncate(path, size) ? 0 : -errno; return -1 != truncate(path, size) ? 0 : -errno;
} }
#if !defined(PTFS_UTIMENS)
static int ptfs_utime(const char *path, struct fuse_utimbuf *timbuf) static int ptfs_utime(const char *path, struct fuse_utimbuf *timbuf)
{ {
ptfs_impl_fullpath(path); ptfs_impl_fullpath(path);
return -1 != utime(path, timbuf) ? 0 : -errno; return -1 != utime(path, timbuf) ? 0 : -errno;
} }
#endif
static int ptfs_open(const char *path, struct fuse_file_info *fi) 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); conn->want |= (conn->capable & FSP_FUSE_CAP_READDIR_PLUS);
#endif #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) #if defined(FSP_FUSE_CAP_CASE_INSENSITIVE)
conn->want |= (conn->capable & FSP_FUSE_CAP_CASE_INSENSITIVE); conn->want |= (conn->capable & FSP_FUSE_CAP_CASE_INSENSITIVE);
#endif #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; 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) ? 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 = static struct fuse_operations ptfs_ops =
{ {
ptfs_getattr, .getattr = ptfs_getattr,
0, //getdir .mkdir = ptfs_mkdir,
0, //readlink .unlink = ptfs_unlink,
0, //mknod .rmdir = ptfs_rmdir,
ptfs_mkdir, .rename = ptfs_rename,
ptfs_unlink, .chmod = ptfs_chmod,
ptfs_rmdir, .chown = ptfs_chown,
0, //symlink .truncate = ptfs_truncate,
ptfs_rename, #if !defined(PTFS_UTIMENS)
0, //link .utime = ptfs_utime,
ptfs_chmod, #endif
ptfs_chown, .open = ptfs_open,
ptfs_truncate, .read = ptfs_read,
ptfs_utime, .write = ptfs_write,
ptfs_open, .statfs = ptfs_statfs,
ptfs_read, .release = ptfs_release,
ptfs_write, .fsync = ptfs_fsync,
ptfs_statfs, .opendir = ptfs_opendir,
0, //flush .readdir = ptfs_readdir,
ptfs_release, .releasedir = ptfs_releasedir,
ptfs_fsync, .init = ptfs_init,
0, //setxattr .create = ptfs_create,
0, //getxattr .ftruncate = ptfs_ftruncate,
0, //listxattr .fgetattr = ptfs_fgetattr,
0, //removexattr #if defined(PTFS_UTIMENS)
ptfs_opendir, .utimens = ptfs_utimens,
ptfs_readdir, #endif
ptfs_releasedir, #if defined(_WIN64) || defined(_WIN32)
0, //fsyncdir .setcrtime = ptfs_setcrtime,
ptfs_init, #endif
0, //destroy #if defined(FSP_FUSE_USE_STAT_EX)
0, //access .chflags = ptfs_chflags,
ptfs_create, #endif
ptfs_ftruncate,
ptfs_fgetattr,
}; };
static void usage(void) static void usage(void)

View File

@ -99,7 +99,7 @@
</PrecompiledHeader> </PrecompiledHeader>
<WarningLevel>Level3</WarningLevel> <WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization> <Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>FSP_FUSE_USE_STAT_EX;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck> <SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(MSBuildProgramFiles32)\WinFsp\inc\fuse;$(MSBuildProgramFiles32)\WinFsp\inc</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>$(MSBuildProgramFiles32)\WinFsp\inc\fuse;$(MSBuildProgramFiles32)\WinFsp\inc</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary> <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
@ -118,7 +118,7 @@
</PrecompiledHeader> </PrecompiledHeader>
<WarningLevel>Level3</WarningLevel> <WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization> <Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>FSP_FUSE_USE_STAT_EX;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck> <SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(MSBuildProgramFiles32)\WinFsp\inc\fuse;$(MSBuildProgramFiles32)\WinFsp\inc</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>$(MSBuildProgramFiles32)\WinFsp\inc\fuse;$(MSBuildProgramFiles32)\WinFsp\inc</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary> <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
@ -139,7 +139,7 @@
<Optimization>MaxSpeed</Optimization> <Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking> <FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions> <IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>FSP_FUSE_USE_STAT_EX;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck> <SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(MSBuildProgramFiles32)\WinFsp\inc\fuse;$(MSBuildProgramFiles32)\WinFsp\inc</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>$(MSBuildProgramFiles32)\WinFsp\inc\fuse;$(MSBuildProgramFiles32)\WinFsp\inc</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary> <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
@ -162,7 +162,7 @@
<Optimization>MaxSpeed</Optimization> <Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking> <FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions> <IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>FSP_FUSE_USE_STAT_EX;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck> <SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(MSBuildProgramFiles32)\WinFsp\inc\fuse;$(MSBuildProgramFiles32)\WinFsp\inc</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>$(MSBuildProgramFiles32)\WinFsp\inc\fuse;$(MSBuildProgramFiles32)\WinFsp\inc</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary> <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

View File

@ -1,5 +1,5 @@
/** /**
* @file passthrough-fuse.c * @file winposix.c
* *
* @copyright 2015-2017 Bill Zissimopoulos * @copyright 2015-2017 Bill Zissimopoulos
*/ */
@ -36,6 +36,40 @@ struct _DIR
char path[]; 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 int maperror(int winerrno);
static inline void *error0(void) static inline void *error0(void)
@ -151,28 +185,22 @@ int fstat(int fd, struct fuse_stat *stbuf)
{ {
HANDLE h = (HANDLE)(intptr_t)fd; HANDLE h = (HANDLE)(intptr_t)fd;
BY_HANDLE_FILE_INFORMATION FileInfo; BY_HANDLE_FILE_INFORMATION FileInfo;
UINT64 CreationTime, LastAccessTime, LastWriteTime;
if (!GetFileInformationByHandle(h, &FileInfo)) if (!GetFileInformationByHandle(h, &FileInfo))
return error(); 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); memset(stbuf, 0, sizeof *stbuf);
stbuf->st_mode = 0777 | stbuf->st_mode = 0777 |
((FileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? 0040000/* S_IFDIR */ : 0); ((FileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? 0040000/* S_IFDIR */ : 0);
stbuf->st_nlink = 1; stbuf->st_nlink = 1;
stbuf->st_size = ((UINT64)FileInfo.nFileSizeHigh << 32) | ((UINT64)FileInfo.nFileSizeLow); stbuf->st_size = ((UINT64)FileInfo.nFileSizeHigh << 32) | ((UINT64)FileInfo.nFileSizeLow);
stbuf->st_atim.tv_sec = LastAccessTime / 10000000; FspPosixFileTimeToUnixTime(*(PUINT64)&FileInfo.ftCreationTime, (void *)&stbuf->st_birthtim);
stbuf->st_atim.tv_nsec = LastAccessTime % 10000000 * 100; FspPosixFileTimeToUnixTime(*(PUINT64)&FileInfo.ftLastAccessTime, (void *)&stbuf->st_atim);
stbuf->st_mtim.tv_sec = LastWriteTime / 10000000; FspPosixFileTimeToUnixTime(*(PUINT64)&FileInfo.ftLastWriteTime, (void *)&stbuf->st_mtim);
stbuf->st_mtim.tv_nsec = LastWriteTime % 10000000 * 100; FspPosixFileTimeToUnixTime(*(PUINT64)&FileInfo.ftLastWriteTime, (void *)&stbuf->st_ctim);
stbuf->st_ctim.tv_sec = LastWriteTime / 10000000; #if defined(FSP_FUSE_USE_STAT_EX)
stbuf->st_ctim.tv_nsec = LastWriteTime % 10000000 * 100; stbuf->st_flags = MapFileAttributesToFlags(FileInfo.dwFileAttributes);
stbuf->st_birthtim.tv_sec = CreationTime / 10000000; #endif
stbuf->st_birthtim.tv_nsec = CreationTime % 10000000 * 100;
return 0; return 0;
} }
@ -272,6 +300,21 @@ int lchown(const char *path, fuse_uid_t uid, fuse_gid_t gid)
return 0; 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) int truncate(const char *path, fuse_off_t size)
{ {
HANDLE h = CreateFileA(path, HANDLE h = CreateFileA(path,
@ -290,6 +333,23 @@ int truncate(const char *path, fuse_off_t size)
int utime(const char *path, const struct fuse_utimbuf *timbuf) int utime(const char *path, const struct fuse_utimbuf *timbuf)
{ {
if (0 == timbuf)
return utimensat(AT_FDCWD, path, 0);
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);
}
}
int utimensat(int dirfd, const char *path, const struct fuse_timespec times[2])
{
/* ignore dirfd and assume that it is always AT_FDCWD */
HANDLE h = CreateFileA(path, HANDLE h = CreateFileA(path,
FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
0, 0,
@ -297,8 +357,18 @@ int utime(const char *path, const struct fuse_utimbuf *timbuf)
if (INVALID_HANDLE_VALUE == h) if (INVALID_HANDLE_VALUE == h)
return error(); return error();
UINT64 LastAccessTime = timbuf->actime * 10000000 + 116444736000000000; UINT64 LastAccessTime, LastWriteTime;
UINT64 LastWriteTime = timbuf->modtime * 10000000 + 116444736000000000; if (0 == times)
{
FILETIME FileTime;
GetSystemTimeAsFileTime(&FileTime);
LastAccessTime = LastWriteTime = *(PUINT64)&FileTime;
}
else
{
FspPosixUnixTimeToFileTime((void *)&times[0], &LastAccessTime);
FspPosixUnixTimeToFileTime((void *)&times[1], &LastWriteTime);
}
int res = SetFileTime(h, int res = SetFileTime(h,
0, (PFILETIME)&LastAccessTime, (PFILETIME)&LastWriteTime) ? 0 : error(); 0, (PFILETIME)&LastAccessTime, (PFILETIME)&LastWriteTime) ? 0 : error();
@ -308,6 +378,26 @@ int utime(const char *path, const struct fuse_utimbuf *timbuf)
return res; 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) int unlink(const char *path)
{ {
if (!DeleteFileA(path)) if (!DeleteFileA(path))
@ -388,7 +478,6 @@ void rewinddir(DIR *dirp)
struct dirent *readdir(DIR *dirp) struct dirent *readdir(DIR *dirp)
{ {
WIN32_FIND_DATAA FindData; WIN32_FIND_DATAA FindData;
UINT64 CreationTime, LastAccessTime, LastWriteTime;
struct fuse_stat *stbuf = &dirp->de.d_stat; struct fuse_stat *stbuf = &dirp->de.d_stat;
if (INVALID_HANDLE_VALUE == dirp->fh) if (INVALID_HANDLE_VALUE == dirp->fh)
@ -407,23 +496,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); memset(stbuf, 0, sizeof *stbuf);
stbuf->st_mode = 0777 | stbuf->st_mode = 0777 |
((FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? 0040000/* S_IFDIR */ : 0); ((FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? 0040000/* S_IFDIR */ : 0);
stbuf->st_nlink = 1; stbuf->st_nlink = 1;
stbuf->st_size = ((UINT64)FindData.nFileSizeHigh << 32) | ((UINT64)FindData.nFileSizeLow); stbuf->st_size = ((UINT64)FindData.nFileSizeHigh << 32) | ((UINT64)FindData.nFileSizeLow);
stbuf->st_atim.tv_sec = LastAccessTime / 10000000; FspPosixFileTimeToUnixTime(*(PUINT64)&FindData.ftCreationTime, (void *)&stbuf->st_birthtim);
stbuf->st_atim.tv_nsec = LastAccessTime % 10000000 * 100; FspPosixFileTimeToUnixTime(*(PUINT64)&FindData.ftLastAccessTime, (void *)&stbuf->st_atim);
stbuf->st_mtim.tv_sec = LastWriteTime / 10000000; FspPosixFileTimeToUnixTime(*(PUINT64)&FindData.ftLastWriteTime, (void *)&stbuf->st_mtim);
stbuf->st_mtim.tv_nsec = LastWriteTime % 10000000 * 100; FspPosixFileTimeToUnixTime(*(PUINT64)&FindData.ftLastWriteTime, (void *)&stbuf->st_ctim);
stbuf->st_ctim.tv_sec = LastWriteTime / 10000000; #if defined(FSP_FUSE_USE_STAT_EX)
stbuf->st_ctim.tv_nsec = LastWriteTime % 10000000 * 100; stbuf->st_flags = MapFileAttributesToFlags(FindData.dwFileAttributes);
stbuf->st_birthtim.tv_sec = CreationTime / 10000000; #endif
stbuf->st_birthtim.tv_nsec = CreationTime % 10000000 * 100;
strcpy(dirp->de.d_name, FindData.cFileName); strcpy(dirp->de.d_name, FindData.cFileName);

View File

@ -27,6 +27,7 @@
#define O_TRUNC _O_TRUNC #define O_TRUNC _O_TRUNC
#define PATH_MAX 1024 #define PATH_MAX 1024
#define AT_FDCWD -2
typedef struct _DIR DIR; typedef struct _DIR DIR;
struct dirent struct dirent
@ -50,8 +51,11 @@ int close(int fd);
int lstat(const char *path, struct fuse_stat *stbuf); int lstat(const char *path, struct fuse_stat *stbuf);
int chmod(const char *path, fuse_mode_t mode); int chmod(const char *path, fuse_mode_t mode);
int lchown(const char *path, fuse_uid_t uid, fuse_gid_t gid); 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 truncate(const char *path, fuse_off_t size);
int utime(const char *path, const struct fuse_utimbuf *timbuf); int utime(const char *path, const struct fuse_utimbuf *timbuf);
int utimensat(int dirfd, const char *path, const struct fuse_timespec times[2]);
int setcrtime(const char *path, const struct fuse_timespec *tv);
int unlink(const char *path); int unlink(const char *path);
int rename(const char *oldpath, const char *newpath); int rename(const char *oldpath, const char *newpath);

View File

@ -202,6 +202,12 @@ static void querydir_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout, UL
ASSERT(INVALID_HANDLE_VALUE == Handle); ASSERT(INVALID_HANDLE_VALUE == Handle);
ASSERT(ERROR_FILE_NOT_FOUND == GetLastError()); ASSERT(ERROR_FILE_NOT_FOUND == GetLastError());
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\DOES-NOT-EXIST*",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
Handle = FindFirstFileW(FilePath, &FindData);
ASSERT(INVALID_HANDLE_VALUE == Handle);
ASSERT(ERROR_FILE_NOT_FOUND == GetLastError());
times[1] = GetTickCount(); times[1] = GetTickCount();
FspDebugLog(__FUNCTION__ "(Flags=%lx, Prefix=\"%S\", FileInfoTimeout=%ld, SleepTimeout=%ld): %ldms\n", FspDebugLog(__FUNCTION__ "(Flags=%lx, Prefix=\"%S\", FileInfoTimeout=%ld, SleepTimeout=%ld): %ldms\n",
Flags, Prefix, FileInfoTimeout, SleepTimeout, times[1] - times[0]); Flags, Prefix, FileInfoTimeout, SleepTimeout, times[1] - times[0]);

View File

@ -291,22 +291,22 @@ void setfileinfo_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout)
ASSERT(Success); ASSERT(Success);
ASSERT(FILE_ATTRIBUTE_HIDDEN == FileInfo.dwFileAttributes); ASSERT(FILE_ATTRIBUTE_HIDDEN == FileInfo.dwFileAttributes);
*(PUINT64)&FileTime = 0x4200000042ULL; *(PUINT64)&FileTime = 116444736000000000ULL + 0x4200000042ULL;
Success = SetFileTime(Handle, 0, &FileTime, &FileTime); Success = SetFileTime(Handle, 0, &FileTime, &FileTime);
ASSERT(Success); ASSERT(Success);
Success = GetFileInformationByHandle(Handle, &FileInfo); Success = GetFileInformationByHandle(Handle, &FileInfo);
ASSERT(Success); ASSERT(Success);
ASSERT(*(PUINT64)&FileInfo0.ftCreationTime == *(PUINT64)&FileInfo.ftCreationTime); ASSERT(*(PUINT64)&FileInfo0.ftCreationTime == *(PUINT64)&FileInfo.ftCreationTime);
ASSERT(0x4200000042ULL == *(PUINT64)&FileInfo.ftLastAccessTime); ASSERT(116444736000000000ULL + 0x4200000042ULL == *(PUINT64)&FileInfo.ftLastAccessTime);
ASSERT(0x4200000042ULL == *(PUINT64)&FileInfo.ftLastWriteTime); ASSERT(116444736000000000ULL + 0x4200000042ULL == *(PUINT64)&FileInfo.ftLastWriteTime);
Success = SetFileTime(Handle, &FileTime, 0, 0); Success = SetFileTime(Handle, &FileTime, 0, 0);
ASSERT(Success); ASSERT(Success);
Success = GetFileInformationByHandle(Handle, &FileInfo); Success = GetFileInformationByHandle(Handle, &FileInfo);
ASSERT(Success); ASSERT(Success);
ASSERT(0x4200000042ULL == *(PUINT64)&FileInfo.ftCreationTime); ASSERT(116444736000000000ULL + 0x4200000042ULL == *(PUINT64)&FileInfo.ftCreationTime);
Offset = SetFilePointer(Handle, 42, 0, 0); Offset = SetFilePointer(Handle, 42, 0, 0);
ASSERT(42 == Offset); ASSERT(42 == Offset);

View File

@ -35,11 +35,15 @@ void *memfs_start_ex(ULONG Flags, ULONG FileInfoTimeout)
MEMFS *Memfs; MEMFS *Memfs;
NTSTATUS Result; NTSTATUS Result;
Result = MemfsCreate( Result = MemfsCreateFunnel(
(OptCaseInsensitive ? MemfsCaseInsensitive : 0) | Flags, (OptCaseInsensitive ? MemfsCaseInsensitive : 0) | Flags,
FileInfoTimeout, FileInfoTimeout,
1024, 1024,
1024 * 1024, 1024 * 1024,
50, /*SlowioMaxDelay*/
10, /*SlowioPercentDelay*/
5, /*SlowioRarefyDelay*/
0,
MemfsNet == Flags ? L"\\memfs\\share" : 0, MemfsNet == Flags ? L"\\memfs\\share" : 0,
0, 0,
&Memfs); &Memfs);

View File

@ -1194,22 +1194,22 @@ static void stream_setfileinfo_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoT
ASSERT(Success); ASSERT(Success);
ASSERT(FILE_ATTRIBUTE_HIDDEN == FileInfo.dwFileAttributes); ASSERT(FILE_ATTRIBUTE_HIDDEN == FileInfo.dwFileAttributes);
*(PUINT64)&FileTime = 0x4200000042ULL; *(PUINT64)&FileTime = 116444736000000000ULL + 0x4200000042ULL;
Success = SetFileTime(StreamHandle, 0, &FileTime, &FileTime); Success = SetFileTime(StreamHandle, 0, &FileTime, &FileTime);
ASSERT(Success); ASSERT(Success);
Success = GetFileInformationByHandle(StreamHandle, &FileInfo); Success = GetFileInformationByHandle(StreamHandle, &FileInfo);
ASSERT(Success); ASSERT(Success);
ASSERT(*(PUINT64)&FileInfo0.ftCreationTime == *(PUINT64)&FileInfo.ftCreationTime); ASSERT(*(PUINT64)&FileInfo0.ftCreationTime == *(PUINT64)&FileInfo.ftCreationTime);
ASSERT(0x4200000042ULL == *(PUINT64)&FileInfo.ftLastAccessTime); ASSERT(116444736000000000ULL + 0x4200000042ULL == *(PUINT64)&FileInfo.ftLastAccessTime);
ASSERT(0x4200000042ULL == *(PUINT64)&FileInfo.ftLastWriteTime); ASSERT(116444736000000000ULL + 0x4200000042ULL == *(PUINT64)&FileInfo.ftLastWriteTime);
Success = SetFileTime(StreamHandle, &FileTime, 0, 0); Success = SetFileTime(StreamHandle, &FileTime, 0, 0);
ASSERT(Success); ASSERT(Success);
Success = GetFileInformationByHandle(StreamHandle, &FileInfo); Success = GetFileInformationByHandle(StreamHandle, &FileInfo);
ASSERT(Success); ASSERT(Success);
ASSERT(0x4200000042ULL == *(PUINT64)&FileInfo.ftCreationTime); ASSERT(116444736000000000ULL + 0x4200000042ULL == *(PUINT64)&FileInfo.ftCreationTime);
Offset = SetFilePointer(StreamHandle, 42, 0, 0); Offset = SetFilePointer(StreamHandle, 42, 0, 0);
ASSERT(42 == Offset); ASSERT(42 == Offset);
@ -1238,9 +1238,9 @@ static void stream_setfileinfo_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoT
Success = GetFileInformationByHandle(Handle, &FileInfo); Success = GetFileInformationByHandle(Handle, &FileInfo);
ASSERT(Success); ASSERT(Success);
ASSERT(0 != (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)); ASSERT(0 != (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN));
ASSERT(0x4200000042ULL == *(PUINT64)&FileInfo.ftLastAccessTime); ASSERT(116444736000000000ULL + 0x4200000042ULL == *(PUINT64)&FileInfo.ftLastAccessTime);
ASSERT(0x4200000042ULL == *(PUINT64)&FileInfo.ftLastWriteTime); ASSERT(116444736000000000ULL + 0x4200000042ULL == *(PUINT64)&FileInfo.ftLastWriteTime);
ASSERT(0x4200000042ULL == *(PUINT64)&FileInfo.ftCreationTime); ASSERT(116444736000000000ULL + 0x4200000042ULL == *(PUINT64)&FileInfo.ftCreationTime);
ASSERT(0 == FileInfo.nFileSizeLow); ASSERT(0 == FileInfo.nFileSizeLow);
ASSERT(0 == FileInfo.nFileSizeHigh); ASSERT(0 == FileInfo.nFileSizeHigh);