From e3290a30bc879e1d9eac97f61506b52859fe5662 Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Mon, 16 Jul 2018 09:31:32 -0700 Subject: [PATCH 01/24] fuse3: initial commit --- build/VStudio/winfsp_dll.vcxproj | 7 + build/VStudio/winfsp_dll.vcxproj.filters | 27 ++ inc/fuse3/fuse.h | 334 +++++++++++++++++++++++ inc/fuse3/fuse_common.h | 228 ++++++++++++++++ inc/fuse3/fuse_opt.h | 19 ++ inc/fuse3/winfsp_fuse.h | 78 ++++++ src/dll/fuse3/fuse2to3.c | 283 +++++++++++++++++++ src/dll/fuse3/fuse3.c | 112 ++++++++ src/dll/fuse3/library.h | 35 +++ 9 files changed, 1123 insertions(+) create mode 100644 inc/fuse3/fuse.h create mode 100644 inc/fuse3/fuse_common.h create mode 100644 inc/fuse3/fuse_opt.h create mode 100644 inc/fuse3/winfsp_fuse.h create mode 100644 src/dll/fuse3/fuse2to3.c create mode 100644 src/dll/fuse3/fuse3.c create mode 100644 src/dll/fuse3/library.h diff --git a/build/VStudio/winfsp_dll.vcxproj b/build/VStudio/winfsp_dll.vcxproj index 7e3b7ac4..d5361b80 100644 --- a/build/VStudio/winfsp_dll.vcxproj +++ b/build/VStudio/winfsp_dll.vcxproj @@ -20,6 +20,10 @@ + + + + @@ -28,6 +32,7 @@ + @@ -35,6 +40,8 @@ + + diff --git a/build/VStudio/winfsp_dll.vcxproj.filters b/build/VStudio/winfsp_dll.vcxproj.filters index 73bedbf3..db769319 100644 --- a/build/VStudio/winfsp_dll.vcxproj.filters +++ b/build/VStudio/winfsp_dll.vcxproj.filters @@ -21,6 +21,12 @@ {518cce17-85cd-489c-b4be-920a84c1d73c} + + {12afd2f1-f5ec-4008-b6ef-89cc626019ea} + + + {96091a7b-3923-4a74-9491-3ee230c688f9} + @@ -56,6 +62,21 @@ Include\winfsp + + Include\fuse3 + + + Include\fuse3 + + + Include\fuse3 + + + Include\fuse3 + + + Source\fuse3 + @@ -121,6 +142,12 @@ Source + + Source\fuse3 + + + Source\fuse3 + diff --git a/inc/fuse3/fuse.h b/inc/fuse3/fuse.h new file mode 100644 index 00000000..d6de06bc --- /dev/null +++ b/inc/fuse3/fuse.h @@ -0,0 +1,334 @@ +/** + * @file fuse3/fuse.h + * WinFsp FUSE3 compatible API. + * + * This file is derived from libfuse/include/fuse.h: + * FUSE: Filesystem in Userspace + * Copyright (C) 2001-2007 Miklos Szeredi + * + * @copyright 2015-2018 Bill Zissimopoulos + */ +/* + * This file is part of WinFsp. + * + * You can redistribute it and/or modify it under the terms of the GNU + * General Public License version 3 as published by the Free Software + * Foundation. + * + * Licensees holding a valid commercial license may use this file in + * accordance with the commercial license agreement provided with the + * software. + */ + +#ifndef FUSE_H_ +#define FUSE_H_ + +#include "fuse_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct fuse3; + +enum fuse3_readdir_flags +{ + FUSE_READDIR_PLUS = (1 << 0), +}; + +enum fuse3_fill_dir_flags +{ + FUSE_FILL_DIR_PLUS = (1 << 1), +}; + +typedef int (*fuse3_fill_dir_t)(void *buf, const char *name, + const struct fuse_stat *stbuf, fuse_off_t off, + enum fuse3_fill_dir_flags flags); + +struct fuse3_config +{ + int set_gid; + unsigned int gid; + int set_uid; + unsigned int uid; + int set_mode; + unsigned int umask; + double entry_timeout; + double negative_timeout; + double attr_timeout; + int intr; + int intr_signal; + int remember; + int hard_remove; + int use_ino; + int readdir_ino; + int direct_io; + int kernel_cache; + int auto_cache; + int ac_attr_timeout_set; + double ac_attr_timeout; + int nullpath_ok; + /* private */ + int show_help; + char *modules; + int debug; +}; + +struct fuse3_operations +{ + /* S - supported by WinFsp */ + /* S */ int (*getattr)(const char *path, struct fuse_stat *stbuf, + struct fuse3_file_info *fi); + /* S */ int (*readlink)(const char *path, char *buf, size_t size); + /* S */ int (*mknod)(const char *path, fuse_mode_t mode, fuse_dev_t dev); + /* S */ int (*mkdir)(const char *path, fuse_mode_t mode); + /* S */ int (*unlink)(const char *path); + /* S */ int (*rmdir)(const char *path); + /* S */ int (*symlink)(const char *dstpath, const char *srcpath); + /* S */ int (*rename)(const char *oldpath, const char *newpath, unsigned int flags); + /* _ */ int (*link)(const char *srcpath, const char *dstpath); + /* S */ int (*chmod)(const char *path, fuse_mode_t mode, + struct fuse3_file_info *fi); + /* S */ int (*chown)(const char *path, fuse_uid_t uid, fuse_gid_t gid, + struct fuse3_file_info *fi); + /* S */ int (*truncate)(const char *path, fuse_off_t size, + struct fuse3_file_info *fi); + /* S */ int (*open)(const char *path, struct fuse3_file_info *fi); + /* S */ int (*read)(const char *path, char *buf, size_t size, fuse_off_t off, + struct fuse3_file_info *fi); + /* S */ int (*write)(const char *path, const char *buf, size_t size, fuse_off_t off, + struct fuse3_file_info *fi); + /* S */ int (*statfs)(const char *path, struct fuse_statvfs *stbuf); + /* S */ int (*flush)(const char *path, struct fuse3_file_info *fi); + /* S */ int (*release)(const char *path, struct fuse3_file_info *fi); + /* S */ int (*fsync)(const char *path, int datasync, struct fuse3_file_info *fi); + /* _ */ int (*setxattr)(const char *path, const char *name, const char *value, size_t size, + int flags); + /* _ */ int (*getxattr)(const char *path, const char *name, char *value, size_t size); + /* _ */ int (*listxattr)(const char *path, char *namebuf, size_t size); + /* _ */ int (*removexattr)(const char *path, const char *name); + /* S */ int (*opendir)(const char *path, struct fuse3_file_info *fi); + /* S */ int (*readdir)(const char *path, void *buf, fuse3_fill_dir_t filler, fuse_off_t off, + struct fuse3_file_info *fi, enum fuse3_readdir_flags); + /* S */ int (*releasedir)(const char *path, struct fuse3_file_info *fi); + /* S */ int (*fsyncdir)(const char *path, int datasync, struct fuse3_file_info *fi); + /* S */ void *(*init)(struct fuse3_conn_info *conn, + struct fuse3_config *conf); + /* S */ void (*destroy)(void *data); + /* _ */ int (*access)(const char *path, int mask); + /* S */ int (*create)(const char *path, fuse_mode_t mode, struct fuse3_file_info *fi); + /* _ */ int (*lock)(const char *path, + struct fuse3_file_info *fi, int cmd, struct fuse_flock *lock); + /* S */ int (*utimens)(const char *path, const struct fuse_timespec tv[2], + struct fuse3_file_info *fi); + /* _ */ int (*bmap)(const char *path, size_t blocksize, uint64_t *idx); + /* S */ int (*ioctl)(const char *path, int cmd, void *arg, struct fuse3_file_info *fi, + unsigned int flags, void *data); + /* _ */ int (*poll)(const char *path, struct fuse3_file_info *fi, + struct fuse3_pollhandle *ph, unsigned *reventsp); + /* _ */ int (*write_buf)(const char *path, + struct fuse3_bufvec *buf, fuse_off_t off, struct fuse3_file_info *fi); + /* _ */ int (*read_buf)(const char *path, + struct fuse3_bufvec **bufp, size_t size, fuse_off_t off, struct fuse3_file_info *fi); + /* _ */ int (*flock)(const char *path, struct fuse3_file_info *, int op); + /* _ */ int (*fallocate)(const char *path, int mode, fuse_off_t off, fuse_off_t len, + struct fuse3_file_info *fi); +}; + +struct fuse3_context +{ + struct fuse3 *fuse; + fuse_uid_t uid; + fuse_gid_t gid; + fuse_pid_t pid; + void *private_data; + fuse_mode_t umask; +}; + +#define fuse_main(argc, argv, ops, data)\ + fuse3_main_real(argc, argv, ops, sizeof *(ops), data) + +FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse3_main_real)(struct fsp_fuse_env *env, + int argc, char *argv[], + const struct fuse3_operations *ops, size_t opsize, void *data); +FSP_FUSE_API void FSP_FUSE_API_NAME(fsp_fuse3_lib_help)(struct fsp_fuse_env *env, + struct fuse_args *args); +FSP_FUSE_API struct fuse3 *FSP_FUSE_API_NAME(fsp_fuse3_new_30)(struct fsp_fuse_env *env, + struct fuse_args *args, + const struct fuse3_operations *ops, size_t opsize, void *data); +FSP_FUSE_API struct fuse3 *FSP_FUSE_API_NAME(fsp_fuse3_new)(struct fsp_fuse_env *env, + struct fuse_args *args, + const struct fuse3_operations *ops, size_t opsize, void *data); +FSP_FUSE_API void FSP_FUSE_API_NAME(fsp_fuse3_destroy)(struct fsp_fuse_env *env, + struct fuse3 *f); +FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse3_mount)(struct fsp_fuse_env *env, + struct fuse3 *f, const char *mountpoint); +FSP_FUSE_API void FSP_FUSE_API_NAME(fsp_fuse3_unmount)(struct fsp_fuse_env *env, + struct fuse3 *f); +FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse3_loop)(struct fsp_fuse_env *env, + struct fuse3 *f); +FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse3_loop_mt_31)(struct fsp_fuse_env *env, + struct fuse3 *f, int clone_fd); +FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse3_loop_mt)(struct fsp_fuse_env *env, + struct fuse3 *f, struct fuse3_loop_config *config); +FSP_FUSE_API void FSP_FUSE_API_NAME(fsp_fuse3_exit)(struct fsp_fuse_env *env, + struct fuse3 *f); +FSP_FUSE_API struct fuse3_context *FSP_FUSE_API_NAME(fsp_fuse3_get_context)(struct fsp_fuse_env *env); + +FSP_FUSE_SYM( +int fuse3_main_real(int argc, char *argv[], + const struct fuse3_operations *ops, size_t opsize, void *data), +{ + return FSP_FUSE_API_CALL(fsp_fuse3_main_real) + (fsp_fuse_env(), argc, argv, ops, opsize, data); +}) + +FSP_FUSE_SYM( +void fuse3_lib_help(struct fuse_args *args), +{ + FSP_FUSE_API_CALL(fsp_fuse3_lib_help) + (fsp_fuse_env(), args); +}) + +#if FUSE_USE_VERSION == 30 +FSP_FUSE_SYM( +struct fuse3 *fuse3_new_30(struct fuse_args *args, + const struct fuse3_operations *ops, size_t opsize, void *data), +{ + return FSP_FUSE_API_CALL(fsp_fuse3_new_30) + (fsp_fuse_env(), args, ops, opsize, data); +}) +#define fuse_new(args, op, size, data)\ + fuse3_new_30(args, op, size, data) + +#else +FSP_FUSE_SYM( +struct fuse3 *fuse3_new(struct fuse_args *args, + const struct fuse3_operations *ops, size_t opsize, void *data), +{ + return FSP_FUSE_API_CALL(fsp_fuse3_new) + (fsp_fuse_env(), args, ops, opsize, data); +}) +#endif + +FSP_FUSE_SYM( +void fuse3_destroy(struct fuse3 *f), +{ + FSP_FUSE_API_CALL(fsp_fuse3_destroy) + (fsp_fuse_env(), f); +}) + +FSP_FUSE_SYM( +int fuse3_mount(struct fuse3 *f, const char *mountpoint), +{ + return FSP_FUSE_API_CALL(fsp_fuse3_mount) + (fsp_fuse_env(), f, mountpoint); +}) + +FSP_FUSE_SYM( +void fuse3_unmount(struct fuse3 *f), +{ + FSP_FUSE_API_CALL(fsp_fuse3_unmount) + (fsp_fuse_env(), f); +}) + +FSP_FUSE_SYM( +int fuse3_loop(struct fuse3 *f), +{ + return FSP_FUSE_API_CALL(fsp_fuse3_loop) + (fsp_fuse_env(), f); +}) + +#if FUSE_USE_VERSION < 32 +FSP_FUSE_SYM( +int fuse3_loop_mt_31(struct fuse3 *f, int clone_fd), +{ + return FSP_FUSE_API_CALL(fsp_fuse3_loop_mt_31) + (fsp_fuse_env(), f, clone_fd); +}) +#define fuse_loop_mt(f, clone_fd)\ + fuse3_loop_mt_31(f, clone_fd) + +#else +FSP_FUSE_SYM( +int fuse3_loop_mt(struct fuse3 *f, struct fuse3_loop_config *config), +{ + return FSP_FUSE_API_CALL(fsp_fuse3_loop_mt) + (fsp_fuse_env(), f, config); +}) +#endif + +FSP_FUSE_SYM( +void fuse3_exit(struct fuse3 *f), +{ + FSP_FUSE_API_CALL(fsp_fuse3_exit) + (fsp_fuse_env(), f); +}) + +FSP_FUSE_SYM( +struct fuse3_context *fuse3_get_context(void), +{ + return FSP_FUSE_API_CALL(fsp_fuse3_get_context) + (fsp_fuse_env()); +}) + +FSP_FUSE_SYM( +int fuse3_getgroups(int size, fuse_gid_t list[]), +{ + (void)size; + (void)list; + return -ENOSYS; +}) + +FSP_FUSE_SYM( +int fuse3_interrupted(void), +{ + return 0; +}) + +FSP_FUSE_SYM( +int fuse3_invalidate_path(struct fuse3 *f, const char *path), +{ + (void)f; + (void)path; + return -ENOENT; +}) + +FSP_FUSE_SYM( +int fuse3_notify_poll(struct fuse3_pollhandle *ph), +{ + (void)ph; + return 0; +}) + +FSP_FUSE_SYM( +int fuse3_start_cleanup_thread(struct fuse3 *f), +{ + (void)f; + return 0; +}) + +FSP_FUSE_SYM( +void fuse3_stop_cleanup_thread(struct fuse3 *f), +{ + (void)f; +}) + +FSP_FUSE_SYM( +int fuse3_clean_cache(struct fuse3 *f), +{ + (void)f; + return 600; +}) + +FSP_FUSE_SYM( +struct fuse3_session *fuse3_get_session(struct fuse3 *f), +{ + return (struct fuse3_session *)f; +}) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/inc/fuse3/fuse_common.h b/inc/fuse3/fuse_common.h new file mode 100644 index 00000000..adf135f1 --- /dev/null +++ b/inc/fuse3/fuse_common.h @@ -0,0 +1,228 @@ +/** + * @file fuse3/fuse_common.h + * WinFsp FUSE3 compatible API. + * + * This file is derived from libfuse/include/fuse_common.h: + * FUSE: Filesystem in Userspace + * Copyright (C) 2001-2007 Miklos Szeredi + * + * @copyright 2015-2018 Bill Zissimopoulos + */ +/* + * This file is part of WinFsp. + * + * You can redistribute it and/or modify it under the terms of the GNU + * General Public License version 3 as published by the Free Software + * Foundation. + * + * Licensees holding a valid commercial license may use this file in + * accordance with the commercial license agreement provided with the + * software. + */ + +#ifndef FUSE_COMMON_H_ +#define FUSE_COMMON_H_ + +#include "winfsp_fuse.h" +#include "fuse_opt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define FUSE_MAJOR_VERSION 3 +#define FUSE_MINOR_VERSION 2 +#define FUSE_MAKE_VERSION(maj, min) ((maj) * 10 + (min)) +#define FUSE_VERSION FUSE_MAKE_VERSION(FUSE_MAJOR_VERSION, FUSE_MINOR_VERSION) + +#define FUSE_CAP_ASYNC_READ (1 << 0) +#define FUSE_CAP_POSIX_LOCKS (1 << 1) +#define FUSE_CAP_ATOMIC_O_TRUNC (1 << 3) +#define FUSE_CAP_EXPORT_SUPPORT (1 << 4) +#define FUSE_CAP_DONT_MASK (1 << 6) +#define FUSE_CAP_SPLICE_WRITE (1 << 7) +#define FUSE_CAP_SPLICE_MOVE (1 << 8) +#define FUSE_CAP_SPLICE_READ (1 << 9) +#define FUSE_CAP_FLOCK_LOCKS (1 << 10) +#define FUSE_CAP_IOCTL_DIR (1 << 11) +#define FUSE_CAP_AUTO_INVAL_DATA (1 << 12) +#define FUSE_CAP_READDIRPLUS (1 << 13) +#define FUSE_CAP_READDIRPLUS_AUTO (1 << 14) +#define FUSE_CAP_ASYNC_DIO (1 << 15) +#define FUSE_CAP_WRITEBACK_CACHE (1 << 16) +#define FUSE_CAP_NO_OPEN_SUPPORT (1 << 17) +#define FUSE_CAP_PARALLEL_DIROPS (1 << 18) +#define FUSE_CAP_POSIX_ACL (1 << 19) +#define FUSE_CAP_HANDLE_KILLPRIV (1 << 20) +#define FUSE_CAP_ALLOCATE (1 << 27) /* reserved (OSXFUSE) */ +#define FUSE_CAP_EXCHANGE_DATA (1 << 28) /* reserved (OSXFUSE) */ +#define FUSE_CAP_CASE_INSENSITIVE (1 << 29) /* file system is case insensitive */ +#define FUSE_CAP_VOL_RENAME (1 << 30) /* reserved (OSXFUSE) */ +#define FUSE_CAP_XTIMES (1 << 31) /* reserved (OSXFUSE) */ + +#define FSP_FUSE_CAP_CASE_INSENSITIVE FUSE_CAP_CASE_INSENSITIVE + +#define FUSE_IOCTL_COMPAT (1 << 0) +#define FUSE_IOCTL_UNRESTRICTED (1 << 1) +#define FUSE_IOCTL_RETRY (1 << 2) +#define FUSE_IOCTL_DIR (1 << 4) +#define FUSE_IOCTL_MAX_IOV 256 + +#define FUSE_BUFVEC_INIT(s) \ + ((struct fuse3_bufvec){ 1, 0, 0, { {s, (enum fuse3_buf_flags)0, 0, -1, 0} } }) + +struct fuse3_file_info +{ + int flags; + unsigned int writepage:1; + unsigned int direct_io:1; + unsigned int keep_cache:1; + unsigned int flush:1; + unsigned int nonseekable:1; + unsigned int flock_release:1; + unsigned int padding:27; + uint64_t fh; + uint64_t lock_owner; + uint32_t poll_events; +}; + +struct fuse3_loop_config +{ + int clone_fd; /* ignored */ + unsigned int max_idle_threads; /* ignored */ +}; + +struct fuse3_conn_info +{ + unsigned proto_major; + unsigned proto_minor; + unsigned max_write; + unsigned max_read; + unsigned max_readahead; + unsigned capable; + unsigned want; + unsigned max_background; + unsigned congestion_threshold; + unsigned time_gran; + unsigned reserved[22]; +}; + +enum fuse3_buf_flags +{ + FUSE_BUF_IS_FD = (1 << 1), + FUSE_BUF_FD_SEEK = (1 << 2), + FUSE_BUF_FD_RETRY = (1 << 3), +}; + +enum fuse3_buf_copy_flags +{ + FUSE_BUF_NO_SPLICE = (1 << 1), + FUSE_BUF_FORCE_SPLICE = (1 << 2), + FUSE_BUF_SPLICE_MOVE = (1 << 3), + FUSE_BUF_SPLICE_NONBLOCK = (1 << 4), +}; + +struct fuse3_buf +{ + size_t size; + enum fuse3_buf_flags flags; + void *mem; + int fd; + fuse_off_t pos; +}; + +struct fuse3_bufvec +{ + size_t count; + size_t idx; + size_t off; + struct fuse3_buf buf[1]; +}; + +struct fuse3_session; +struct fuse3_pollhandle; +struct fuse3_conn_info_opts; + +FSP_FUSE_API struct fuse3_conn_info_opts* FSP_FUSE_API_NAME(fsp_fuse3_parse_conn_info_opts)( + struct fsp_fuse_env *env, + struct fuse_args *args); +FSP_FUSE_API void FSP_FUSE_API_NAME(fsp_fuse3_apply_conn_info_opts)(struct fsp_fuse_env *env, + struct fuse3_conn_info_opts *opts, struct fuse3_conn_info *conn); +FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse3_version)(struct fsp_fuse_env *env); +FSP_FUSE_API const char *FSP_FUSE_API_NAME(fsp_fuse3_pkgversion)(struct fsp_fuse_env *env); +FSP_FUSE_API int32_t FSP_FUSE_API_NAME(fsp_fuse_ntstatus_from_errno)(struct fsp_fuse_env *env, + int err); + +FSP_FUSE_SYM( +struct fuse3_conn_info_opts* fuse3_parse_conn_info_opts( + struct fuse_args *args), +{ + return FSP_FUSE_API_CALL(fsp_fuse3_parse_conn_info_opts) + (fsp_fuse_env(), args); +}) + +FSP_FUSE_SYM( +void fuse3_apply_conn_info_opts( + struct fuse3_conn_info_opts *opts, struct fuse3_conn_info *conn), +{ + FSP_FUSE_API_CALL(fsp_fuse3_apply_conn_info_opts) + (fsp_fuse_env(), opts, conn); +}) + +FSP_FUSE_SYM( +int fuse3_version(void), +{ + return FSP_FUSE_API_CALL(fsp_fuse3_version) + (fsp_fuse_env()); +}) + +FSP_FUSE_SYM( +const char *fuse3_pkgversion(void), +{ + return FSP_FUSE_API_CALL(fsp_fuse3_pkgversion) + (fsp_fuse_env()); +}) + +FSP_FUSE_SYM( +void fuse3_pollhandle_destroy(struct fuse3_pollhandle *ph), +{ + (void)ph; +}) + +FSP_FUSE_SYM( +size_t fuse3_buf_size(const struct fuse3_bufvec *bufv), +{ + return 0; +}) + +FSP_FUSE_SYM( +ssize_t fuse3_buf_copy(struct fuse3_bufvec *dst, struct fuse3_bufvec *src, + enum fuse3_buf_copy_flags flags), +{ + return 0; +}) + +FSP_FUSE_SYM( +int fuse3_daemonize(int foreground), +{ + return fsp_fuse_daemonize(foreground); +}) + +FSP_FUSE_SYM( +int fuse3_set_signal_handlers(struct fuse3_session *se), +{ + return fsp_fuse_set_signal_handlers(se); +}) + +FSP_FUSE_SYM( +void fuse3_remove_signal_handlers(struct fuse3_session *se), +{ + (void)se; + fsp_fuse_set_signal_handlers(0); +}) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/inc/fuse3/fuse_opt.h b/inc/fuse3/fuse_opt.h new file mode 100644 index 00000000..289d52f1 --- /dev/null +++ b/inc/fuse3/fuse_opt.h @@ -0,0 +1,19 @@ +/** + * @file fuse3/fuse_opt.h + * WinFsp FUSE3 compatible API. + * + * @copyright 2015-2018 Bill Zissimopoulos + */ +/* + * This file is part of WinFsp. + * + * You can redistribute it and/or modify it under the terms of the GNU + * General Public License version 3 as published by the Free Software + * Foundation. + * + * Licensees holding a valid commercial license may use this file in + * accordance with the commercial license agreement provided with the + * software. + */ + +#include "../fuse/fuse_opt.h" diff --git a/inc/fuse3/winfsp_fuse.h b/inc/fuse3/winfsp_fuse.h new file mode 100644 index 00000000..f8ac0dec --- /dev/null +++ b/inc/fuse3/winfsp_fuse.h @@ -0,0 +1,78 @@ +/** + * @file fuse3/winfsp_fuse.h + * WinFsp FUSE3 compatible API. + * + * @copyright 2015-2018 Bill Zissimopoulos + */ +/* + * This file is part of WinFsp. + * + * You can redistribute it and/or modify it under the terms of the GNU + * General Public License version 3 as published by the Free Software + * Foundation. + * + * Licensees holding a valid commercial license may use this file in + * accordance with the commercial license agreement provided with the + * software. + */ + +#ifndef FUSE3_WINFSP_FUSE_H_INCLUDED +#define FUSE3_WINFSP_FUSE_H_INCLUDED + +#include "../fuse/winfsp_fuse.h" + +#if defined(_WIN64) || defined(_WIN32) +typedef intptr_t ssize_t; +#endif + +#if !defined(WINFSP_DLL_INTERNAL) +#define fuse3 fuse +#define fuse3_apply_conn_info_opts fuse_apply_conn_info_opts +#define fuse3_buf fuse_buf +#define fuse3_buf_copy fuse_buf_copy +#define fuse3_buf_copy_flags fuse_buf_copy_flags +#define fuse3_buf_flags fuse_buf_flags +#define fuse3_buf_size fuse_buf_size +#define fuse3_bufvec fuse_bufvec +#define fuse3_clean_cache fuse_clean_cache +#define fuse3_config fuse_config +#define fuse3_conn_info fuse_conn_info +#define fuse3_conn_info_opts fuse_conn_info_opts +#define fuse3_context fuse_context +#define fuse3_daemonize fuse_daemonize +#define fuse3_destroy fuse_destroy +#define fuse3_exit fuse_exit +#define fuse3_file_info fuse_file_info +#define fuse3_fill_dir_flags fuse_fill_dir_flags +#define fuse3_fill_dir_t fuse_fill_dir_t +#define fuse3_get_context fuse_get_context +#define fuse3_get_session fuse_get_session +#define fuse3_getgroups fuse_getgroups +#define fuse3_interrupted fuse_interrupted +#define fuse3_invalidate_path fuse_invalidate_path +#define fuse3_lib_help fuse_lib_help +#define fuse3_loop fuse_loop +#define fuse3_loop_config fuse_loop_config +#define fuse3_loop_mt fuse_loop_mt +#define fuse3_loop_mt_31 fuse_loop_mt_31 +#define fuse3_main_real fuse_main_real +#define fuse3_mount fuse_mount +#define fuse3_new fuse_new +#define fuse3_new_30 fuse_new_30 +#define fuse3_notify_poll fuse_notify_poll +#define fuse3_operations fuse_operations +#define fuse3_parse_conn_info_opts fuse_parse_conn_info_opts +#define fuse3_pkgversion fuse_pkgversion +#define fuse3_pollhandle fuse_pollhandle +#define fuse3_pollhandle_destroy fuse_pollhandle_destroy +#define fuse3_readdir_flags fuse_readdir_flags +#define fuse3_remove_signal_handlers fuse_remove_signal_handlers +#define fuse3_session fuse_session +#define fuse3_set_signal_handlers fuse_set_signal_handlers +#define fuse3_start_cleanup_thread fuse_start_cleanup_thread +#define fuse3_stop_cleanup_thread fuse_stop_cleanup_thread +#define fuse3_unmount fuse_unmount +#define fuse3_version fuse_version +#endif + +#endif diff --git a/src/dll/fuse3/fuse2to3.c b/src/dll/fuse3/fuse2to3.c new file mode 100644 index 00000000..944a435a --- /dev/null +++ b/src/dll/fuse3/fuse2to3.c @@ -0,0 +1,283 @@ +/** + * @file dll/fuse3/fuse2to3.c + * + * @copyright 2015-2018 Bill Zissimopoulos + */ +/* + * This file is part of WinFsp. + * + * You can redistribute it and/or modify it under the terms of the GNU + * General Public License version 3 as published by the Free Software + * Foundation. + * + * Licensees holding a valid commercial license may use this file in + * accordance with the commercial license agreement provided with the + * software. + */ + +#include + +static int fuse2to3_getattr(const char *path, struct fuse_stat *stbuf) +{ + return -ENOSYS; +} + +static int fuse2to3_readlink(const char *path, char *buf, size_t size) +{ + return -ENOSYS; +} + +static int fuse2to3_mknod(const char *path, fuse_mode_t mode, fuse_dev_t dev) +{ + return -ENOSYS; +} + +static int fuse2to3_mkdir(const char *path, fuse_mode_t mode) +{ + return -ENOSYS; +} + +static int fuse2to3_unlink(const char *path) +{ + return -ENOSYS; +} + +static int fuse2to3_rmdir(const char *path) +{ + return -ENOSYS; +} + +static int fuse2to3_symlink(const char *dstpath, const char *srcpath) +{ + return -ENOSYS; +} + +static int fuse2to3_rename(const char *oldpath, const char *newpath) +{ + return -ENOSYS; +} + +static int fuse2to3_link(const char *srcpath, const char *dstpath) +{ + return -ENOSYS; +} + +static int fuse2to3_chmod(const char *path, fuse_mode_t mode) +{ + return -ENOSYS; +} + +static int fuse2to3_chown(const char *path, fuse_uid_t uid, fuse_gid_t gid) +{ + return -ENOSYS; +} + +static int fuse2to3_truncate(const char *path, fuse_off_t size) +{ + return -ENOSYS; +} + +static int fuse2to3_open(const char *path, struct fuse_file_info *fi) +{ + return -ENOSYS; +} + +static int fuse2to3_read(const char *path, char *buf, size_t size, fuse_off_t off, + struct fuse_file_info *fi) +{ + return -ENOSYS; +} + +static int fuse2to3_write(const char *path, const char *buf, size_t size, fuse_off_t off, + struct fuse_file_info *fi) +{ + return -ENOSYS; +} + +static int fuse2to3_statfs(const char *path, struct fuse_statvfs *stbuf) +{ + return -ENOSYS; +} + +static int fuse2to3_flush(const char *path, struct fuse_file_info *fi) +{ + return -ENOSYS; +} + +static int fuse2to3_release(const char *path, struct fuse_file_info *fi) +{ + return -ENOSYS; +} + +static int fuse2to3_fsync(const char *path, int datasync, struct fuse_file_info *fi) +{ + return -ENOSYS; +} + +static int fuse2to3_setxattr(const char *path, const char *name, const char *value, size_t size, + int flags) +{ + return -ENOSYS; +} + +static int fuse2to3_getxattr(const char *path, const char *name, char *value, size_t size) +{ + return -ENOSYS; +} + +static int fuse2to3_listxattr(const char *path, char *namebuf, size_t size) +{ + return -ENOSYS; +} + +static int fuse2to3_removexattr(const char *path, const char *name) +{ + return -ENOSYS; +} + +static int fuse2to3_opendir(const char *path, struct fuse_file_info *fi) +{ + return -ENOSYS; +} + +static int fuse2to3_readdir(const char *path, void *buf, fuse_fill_dir_t filler, fuse_off_t off, + struct fuse_file_info *fi) +{ + return -ENOSYS; +} + +static int fuse2to3_releasedir(const char *path, struct fuse_file_info *fi) +{ + return -ENOSYS; +} + +static int fuse2to3_fsyncdir(const char *path, int datasync, struct fuse_file_info *fi) +{ + return -ENOSYS; +} + +static void *fuse2to3_init(struct fuse_conn_info *conn) +{ + return 0; +} + +static void fuse2to3_destroy(void *data) +{ +} + +static int fuse2to3_access(const char *path, int mask) +{ + return -ENOSYS; +} + +static int fuse2to3_create(const char *path, fuse_mode_t mode, struct fuse_file_info *fi) +{ + return -ENOSYS; +} + +static int fuse2to3_ftruncate(const char *path, fuse_off_t off, struct fuse_file_info *fi) +{ + return -ENOSYS; +} + +static int fuse2to3_fgetattr(const char *path, struct fuse_stat *stbuf, struct fuse_file_info *fi) +{ + return -ENOSYS; +} + +static int fuse2to3_lock(const char *path, + struct fuse_file_info *fi, int cmd, struct fuse_flock *lock) +{ + return -ENOSYS; +} + +static int fuse2to3_utimens(const char *path, const struct fuse_timespec tv[2]) +{ + return -ENOSYS; +} + +static int fuse2to3_bmap(const char *path, size_t blocksize, uint64_t *idx) +{ + return -ENOSYS; +} + +static int fuse2to3_ioctl(const char *path, int cmd, void *arg, struct fuse_file_info *fi, + unsigned int flags, void *data) +{ + return -ENOSYS; +} + +static int fuse2to3_poll(const char *path, struct fuse_file_info *fi, + struct fuse_pollhandle *ph, unsigned *reventsp) +{ + return -ENOSYS; +} + +static int fuse2to3_write_buf(const char *path, + struct fuse_bufvec *buf, fuse_off_t off, struct fuse_file_info *fi) +{ + return -ENOSYS; +} + +static int fuse2to3_read_buf(const char *path, + struct fuse_bufvec **bufp, size_t size, fuse_off_t off, struct fuse_file_info *fi) +{ + return -ENOSYS; +} + +static int fuse2to3_flock(const char *path, struct fuse_file_info *fi, int op) +{ + return -ENOSYS; +} + +static int fuse2to3_fallocate(const char *path, int mode, fuse_off_t off, fuse_off_t len, + struct fuse_file_info *fi) +{ + return -ENOSYS; +} + +static struct fuse_operations fuse2to3_ops = +{ + .getattr = fuse2to3_getattr, + .readlink = fuse2to3_readlink, + .mknod = fuse2to3_mknod, + .mkdir = fuse2to3_mkdir, + .unlink = fuse2to3_unlink, + .rmdir = fuse2to3_rmdir, + .symlink = fuse2to3_symlink, + .rename = fuse2to3_rename, + .link = fuse2to3_link, + .chmod = fuse2to3_chmod, + .chown = fuse2to3_chown, + .truncate = fuse2to3_truncate, + .open = fuse2to3_open, + .read = fuse2to3_read, + .write = fuse2to3_write, + .statfs = fuse2to3_statfs, + .flush = fuse2to3_flush, + .release = fuse2to3_release, + .fsync = fuse2to3_fsync, + .setxattr = fuse2to3_setxattr, + .getxattr = fuse2to3_getxattr, + .listxattr = fuse2to3_listxattr, + .removexattr = fuse2to3_removexattr, + .opendir = fuse2to3_opendir, + .readdir = fuse2to3_readdir, + .releasedir = fuse2to3_releasedir, + .fsyncdir = fuse2to3_fsyncdir, + .init = fuse2to3_init, + .destroy = fuse2to3_destroy, + .access = fuse2to3_access, + .create = fuse2to3_create, + .ftruncate = fuse2to3_ftruncate, + .fgetattr = fuse2to3_fgetattr, + .lock = fuse2to3_lock, + .utimens = fuse2to3_utimens, + .bmap = fuse2to3_bmap, + .ioctl = fuse2to3_ioctl, + .poll = fuse2to3_poll, + .write_buf = fuse2to3_write_buf, + .read_buf = fuse2to3_read_buf, + .flock = fuse2to3_flock, + .fallocate = fuse2to3_fallocate, +}; diff --git a/src/dll/fuse3/fuse3.c b/src/dll/fuse3/fuse3.c new file mode 100644 index 00000000..32724a71 --- /dev/null +++ b/src/dll/fuse3/fuse3.c @@ -0,0 +1,112 @@ +/** + * @file dll/fuse3/fuse3.c + * + * @copyright 2015-2018 Bill Zissimopoulos + */ +/* + * This file is part of WinFsp. + * + * You can redistribute it and/or modify it under the terms of the GNU + * General Public License version 3 as published by the Free Software + * Foundation. + * + * Licensees holding a valid commercial license may use this file in + * accordance with the commercial license agreement provided with the + * software. + */ + +#include + +FSP_FUSE_API int fsp_fuse3_main_real(struct fsp_fuse_env *env, + int argc, char *argv[], + const struct fuse3_operations *ops, size_t opsize, void *data) +{ + return 0; +} + +FSP_FUSE_API void fsp_fuse3_lib_help(struct fsp_fuse_env *env, + struct fuse_args *args) +{ +} + +FSP_FUSE_API struct fuse3 *fsp_fuse3_new_30(struct fsp_fuse_env *env, + struct fuse_args *args, + const struct fuse3_operations *ops, size_t opsize, void *data) +{ + return 0; +} + +FSP_FUSE_API struct fuse3 *fsp_fuse3_new(struct fsp_fuse_env *env, + struct fuse_args *args, + const struct fuse3_operations *ops, size_t opsize, void *data) +{ + return 0; +} + +FSP_FUSE_API void fsp_fuse3_destroy(struct fsp_fuse_env *env, + struct fuse3 *f) +{ +} + +FSP_FUSE_API int fsp_fuse3_mount(struct fsp_fuse_env *env, + struct fuse3 *f, const char *mountpoint) +{ + return 0; +} + +FSP_FUSE_API void fsp_fuse3_unmount(struct fsp_fuse_env *env, + struct fuse3 *f) +{ +} + +FSP_FUSE_API int fsp_fuse3_loop(struct fsp_fuse_env *env, + struct fuse3 *f) +{ + return 0; +} + +FSP_FUSE_API int fsp_fuse3_loop_mt_31(struct fsp_fuse_env *env, + struct fuse3 *f, int clone_fd) +{ + return 0; +} + +FSP_FUSE_API int fsp_fuse3_loop_mt(struct fsp_fuse_env *env, + struct fuse3 *f, struct fuse3_loop_config *config) +{ + return 0; +} + +FSP_FUSE_API void fsp_fuse3_exit(struct fsp_fuse_env *env, + struct fuse3 *f) +{ +} + +FSP_FUSE_API struct fuse3_context *fsp_fuse3_get_context(struct fsp_fuse_env *env) +{ + return 0; +} + +FSP_FUSE_API struct fuse3_conn_info_opts* fsp_fuse3_parse_conn_info_opts( + struct fsp_fuse_env *env, + struct fuse_args *args) +{ + return 0; +} + +FSP_FUSE_API void fsp_fuse3_apply_conn_info_opts(struct fsp_fuse_env *env, + struct fuse3_conn_info_opts *opts, struct fuse3_conn_info *conn) +{ +} + +FSP_FUSE_API int fsp_fuse3_version(struct fsp_fuse_env *env) +{ + return FUSE_VERSION; +} + +FSP_FUSE_API const char *fsp_fuse3_pkgversion(struct fsp_fuse_env *env) +{ +#define STR(x) #x + return STR(FUSE_MAJOR_VERSION) "." STR(FUSE_MINOR_VERSION); +#undef STR +} diff --git a/src/dll/fuse3/library.h b/src/dll/fuse3/library.h new file mode 100644 index 00000000..5d5983e5 --- /dev/null +++ b/src/dll/fuse3/library.h @@ -0,0 +1,35 @@ +/** + * @file dll/fuse3/library.h + * + * @copyright 2015-2018 Bill Zissimopoulos + */ +/* + * This file is part of WinFsp. + * + * You can redistribute it and/or modify it under the terms of the GNU + * General Public License version 3 as published by the Free Software + * Foundation. + * + * Licensees holding a valid commercial license may use this file in + * accordance with the commercial license agreement provided with the + * software. + */ + +#ifndef WINFSP_DLL_FUSE3_LIBRARY_H_INCLUDED +#define WINFSP_DLL_FUSE3_LIBRARY_H_INCLUDED + +#include +#include +#undef FUSE_H_ +#undef FUSE_COMMON_H_ +#undef FUSE_MAJOR_VERSION +#undef FUSE_MINOR_VERSION +#undef fuse_main +#include + +struct fuse3 +{ + struct fuse3_operations ops; +}; + +#endif From e4077c92e9382e2e89bc5fb7dd3c079cc2175a7c Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Mon, 16 Jul 2018 09:42:15 -0700 Subject: [PATCH 02/24] dll: fuse: ENOSYS has different values on Windows vs Cygwin --- build/VStudio/winfsp_dll.vcxproj | 1 + build/VStudio/winfsp_dll.vcxproj.filters | 3 +++ src/dll/fuse/fuse.c | 2 +- src/dll/fuse/library.h | 1 + src/dll/fuse/shared.h | 23 +++++++++++++++++++++++ src/dll/fuse3/library.h | 1 + 6 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 src/dll/fuse/shared.h diff --git a/build/VStudio/winfsp_dll.vcxproj b/build/VStudio/winfsp_dll.vcxproj index d5361b80..58cb0f3b 100644 --- a/build/VStudio/winfsp_dll.vcxproj +++ b/build/VStudio/winfsp_dll.vcxproj @@ -34,6 +34,7 @@ + diff --git a/build/VStudio/winfsp_dll.vcxproj.filters b/build/VStudio/winfsp_dll.vcxproj.filters index db769319..2ef3f38a 100644 --- a/build/VStudio/winfsp_dll.vcxproj.filters +++ b/build/VStudio/winfsp_dll.vcxproj.filters @@ -77,6 +77,9 @@ Source\fuse3 + + Source\fuse + diff --git a/src/dll/fuse/fuse.c b/src/dll/fuse/fuse.c index d9dbe953..3f67a237 100644 --- a/src/dll/fuse/fuse.c +++ b/src/dll/fuse/fuse.c @@ -383,7 +383,7 @@ static NTSTATUS fsp_fuse_svcstart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv) /* this should always fail with ENOSYS or EINVAL */ err = f->ops.readlink("/", buf, sizeof buf); - f->has_symlinks = -ENOSYS != err; + f->has_symlinks = -enosys(f->env) != err; } /* the FSD does not currently limit these VolumeParams fields; do so here! */ diff --git a/src/dll/fuse/library.h b/src/dll/fuse/library.h index 96e7c962..5d840ce8 100644 --- a/src/dll/fuse/library.h +++ b/src/dll/fuse/library.h @@ -19,6 +19,7 @@ #define WINFSP_DLL_FUSE_LIBRARY_H_INCLUDED #include +#include #include #include diff --git a/src/dll/fuse/shared.h b/src/dll/fuse/shared.h new file mode 100644 index 00000000..1e214323 --- /dev/null +++ b/src/dll/fuse/shared.h @@ -0,0 +1,23 @@ +/** + * @file dll/fuse/shared.h + * + * @copyright 2015-2018 Bill Zissimopoulos + */ +/* + * This file is part of WinFsp. + * + * You can redistribute it and/or modify it under the terms of the GNU + * General Public License version 3 as published by the Free Software + * Foundation. + * + * Licensees holding a valid commercial license may use this file in + * accordance with the commercial license agreement provided with the + * software. + */ + +#ifndef WINFSP_DLL_FUSE_SHARED_H_INCLUDED +#define WINFSP_DLL_FUSE_SHARED_H_INCLUDED + +#define enosys(env) ('C' == (env)->environment ? 88 : 40) + +#endif diff --git a/src/dll/fuse3/library.h b/src/dll/fuse3/library.h index 5d5983e5..459721ef 100644 --- a/src/dll/fuse3/library.h +++ b/src/dll/fuse3/library.h @@ -19,6 +19,7 @@ #define WINFSP_DLL_FUSE3_LIBRARY_H_INCLUDED #include +#include #include #undef FUSE_H_ #undef FUSE_COMMON_H_ From ad1b53e5a4078524c297a64e817db4f500203c74 Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Mon, 16 Jul 2018 09:45:38 -0700 Subject: [PATCH 03/24] dll: fuse: move fsp_fuse_obj_* to sdll/fuse/shared.h --- src/dll/fuse/fuse.c | 29 ----------------------------- src/dll/fuse/library.h | 2 +- src/dll/fuse/shared.h | 29 +++++++++++++++++++++++++++++ src/dll/fuse3/library.h | 2 +- 4 files changed, 31 insertions(+), 31 deletions(-) diff --git a/src/dll/fuse/fuse.c b/src/dll/fuse/fuse.c index 3f67a237..fd7ab673 100644 --- a/src/dll/fuse/fuse.c +++ b/src/dll/fuse/fuse.c @@ -122,35 +122,6 @@ static struct fuse_opt fsp_fuse_core_opts[] = static INIT_ONCE fsp_fuse_initonce = INIT_ONCE_STATIC_INIT; static DWORD fsp_fuse_tlskey = TLS_OUT_OF_INDEXES; -struct fsp_fuse_obj_hdr -{ - void (*dtor)(void *); - __declspec(align(MEMORY_ALLOCATION_ALIGNMENT)) UINT8 ObjectBuf[]; -}; - -static inline void *fsp_fuse_obj_alloc(struct fsp_fuse_env *env, size_t size) -{ - struct fsp_fuse_obj_hdr *hdr; - - hdr = env->memalloc(sizeof(struct fsp_fuse_obj_hdr) + size); - if (0 == hdr) - return 0; - - hdr->dtor = env->memfree; - memset(hdr->ObjectBuf, 0, size); - return hdr->ObjectBuf; -} - -static inline void fsp_fuse_obj_free(void *obj) -{ - if (0 == obj) - return; - - struct fsp_fuse_obj_hdr *hdr = (PVOID)((PUINT8)obj - sizeof(struct fsp_fuse_obj_hdr)); - - hdr->dtor(hdr); -} - static BOOL WINAPI fsp_fuse_initialize( PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context) { diff --git a/src/dll/fuse/library.h b/src/dll/fuse/library.h index 5d840ce8..d5d94d3b 100644 --- a/src/dll/fuse/library.h +++ b/src/dll/fuse/library.h @@ -19,9 +19,9 @@ #define WINFSP_DLL_FUSE_LIBRARY_H_INCLUDED #include -#include #include #include +#include #define FSP_FUSE_LIBRARY_NAME LIBRARY_NAME "-FUSE" diff --git a/src/dll/fuse/shared.h b/src/dll/fuse/shared.h index 1e214323..355ba203 100644 --- a/src/dll/fuse/shared.h +++ b/src/dll/fuse/shared.h @@ -20,4 +20,33 @@ #define enosys(env) ('C' == (env)->environment ? 88 : 40) +struct fsp_fuse_obj_hdr +{ + void (*dtor)(void *); + __declspec(align(MEMORY_ALLOCATION_ALIGNMENT)) UINT8 ObjectBuf[]; +}; + +static inline void *fsp_fuse_obj_alloc(struct fsp_fuse_env *env, size_t size) +{ + struct fsp_fuse_obj_hdr *hdr; + + hdr = env->memalloc(sizeof(struct fsp_fuse_obj_hdr) + size); + if (0 == hdr) + return 0; + + hdr->dtor = env->memfree; + memset(hdr->ObjectBuf, 0, size); + return hdr->ObjectBuf; +} + +static inline void fsp_fuse_obj_free(void *obj) +{ + if (0 == obj) + return; + + struct fsp_fuse_obj_hdr *hdr = (PVOID)((PUINT8)obj - sizeof(struct fsp_fuse_obj_hdr)); + + hdr->dtor(hdr); +} + #endif diff --git a/src/dll/fuse3/library.h b/src/dll/fuse3/library.h index 459721ef..32d39738 100644 --- a/src/dll/fuse3/library.h +++ b/src/dll/fuse3/library.h @@ -19,7 +19,6 @@ #define WINFSP_DLL_FUSE3_LIBRARY_H_INCLUDED #include -#include #include #undef FUSE_H_ #undef FUSE_COMMON_H_ @@ -27,6 +26,7 @@ #undef FUSE_MINOR_VERSION #undef fuse_main #include +#include struct fuse3 { From 27d03d4323a194be86e18d5445b0060d15b46795 Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Mon, 16 Jul 2018 09:50:21 -0700 Subject: [PATCH 04/24] dll: fuse: ENOSYS has different values on Windows vs Cygwin --- src/dll/fuse/fuse_intf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dll/fuse/fuse_intf.c b/src/dll/fuse/fuse_intf.c index 3363a771..7c9a494c 100644 --- a/src/dll/fuse/fuse_intf.c +++ b/src/dll/fuse/fuse_intf.c @@ -266,7 +266,7 @@ loopend:; if (0 != f->ops.getattr) err = f->ops.getattr(PosixHiddenPath, (void *)&stbuf); else - err = -ENOSYS; + err = -enosys(f->env); } while (0 == err && 0 < --maxtries); if (0 == err) @@ -308,7 +308,7 @@ static BOOLEAN fsp_fuse_intf_CheckSymlinkDirectory(FSP_FILE_SYSTEM *FileSystem, if (0 != f->ops.getattr) err = f->ops.getattr(PosixDotPath, (void *)&stbuf); else - err = -ENOSYS; + err = -enosys(f->env); MemFree(PosixDotPath); From 3dc09b2496793214442928e025f866e1a834ad58 Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Mon, 16 Jul 2018 14:21:57 -0700 Subject: [PATCH 05/24] dll: fuse: remove dll/fuse/shared.h --- build/VStudio/winfsp_dll.vcxproj | 1 - build/VStudio/winfsp_dll.vcxproj.filters | 3 -- src/dll/fuse/fuse.c | 2 +- src/dll/fuse/fuse_intf.c | 4 +- src/dll/fuse/library.h | 34 +++++++++++++++- src/dll/fuse/shared.h | 52 ------------------------ src/dll/fuse3/library.h | 4 +- 7 files changed, 37 insertions(+), 63 deletions(-) delete mode 100644 src/dll/fuse/shared.h diff --git a/build/VStudio/winfsp_dll.vcxproj b/build/VStudio/winfsp_dll.vcxproj index 58cb0f3b..d5361b80 100644 --- a/build/VStudio/winfsp_dll.vcxproj +++ b/build/VStudio/winfsp_dll.vcxproj @@ -34,7 +34,6 @@ - diff --git a/build/VStudio/winfsp_dll.vcxproj.filters b/build/VStudio/winfsp_dll.vcxproj.filters index 2ef3f38a..db769319 100644 --- a/build/VStudio/winfsp_dll.vcxproj.filters +++ b/build/VStudio/winfsp_dll.vcxproj.filters @@ -77,9 +77,6 @@ Source\fuse3 - - Source\fuse - diff --git a/src/dll/fuse/fuse.c b/src/dll/fuse/fuse.c index fd7ab673..8eeef824 100644 --- a/src/dll/fuse/fuse.c +++ b/src/dll/fuse/fuse.c @@ -354,7 +354,7 @@ static NTSTATUS fsp_fuse_svcstart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv) /* this should always fail with ENOSYS or EINVAL */ err = f->ops.readlink("/", buf, sizeof buf); - f->has_symlinks = -enosys(f->env) != err; + f->has_symlinks = -ENOSYS_(f->env) != err; } /* the FSD does not currently limit these VolumeParams fields; do so here! */ diff --git a/src/dll/fuse/fuse_intf.c b/src/dll/fuse/fuse_intf.c index 7c9a494c..af082a8b 100644 --- a/src/dll/fuse/fuse_intf.c +++ b/src/dll/fuse/fuse_intf.c @@ -266,7 +266,7 @@ loopend:; if (0 != f->ops.getattr) err = f->ops.getattr(PosixHiddenPath, (void *)&stbuf); else - err = -enosys(f->env); + err = -ENOSYS_(f->env); } while (0 == err && 0 < --maxtries); if (0 == err) @@ -308,7 +308,7 @@ static BOOLEAN fsp_fuse_intf_CheckSymlinkDirectory(FSP_FILE_SYSTEM *FileSystem, if (0 != f->ops.getattr) err = f->ops.getattr(PosixDotPath, (void *)&stbuf); else - err = -enosys(f->env); + err = -ENOSYS_(f->env); MemFree(PosixDotPath); diff --git a/src/dll/fuse/library.h b/src/dll/fuse/library.h index d5d94d3b..32da64ff 100644 --- a/src/dll/fuse/library.h +++ b/src/dll/fuse/library.h @@ -21,7 +21,6 @@ #include #include #include -#include #define FSP_FUSE_LIBRARY_NAME LIBRARY_NAME "-FUSE" @@ -32,6 +31,8 @@ #define FSP_FUSE_HAS_SYMLINKS(f) ((f)->has_symlinks) +#define ENOSYS_(env) ('C' == (env)->environment ? 88 : 40) + struct fuse { struct fsp_fuse_env *env; @@ -103,4 +104,35 @@ NTSTATUS fsp_fuse_get_token_uidgid( #define NFS_SPECFILE_LNK 0x00000000014b4e4c #define NFS_SPECFILE_SOCK 0x000000004B434F53 +/* FUSE obj alloc/free */ + +struct fsp_fuse_obj_hdr +{ + void (*dtor)(void *); + __declspec(align(MEMORY_ALLOCATION_ALIGNMENT)) UINT8 ObjectBuf[]; +}; + +static inline void *fsp_fuse_obj_alloc(struct fsp_fuse_env *env, size_t size) +{ + struct fsp_fuse_obj_hdr *hdr; + + hdr = env->memalloc(sizeof(struct fsp_fuse_obj_hdr) + size); + if (0 == hdr) + return 0; + + hdr->dtor = env->memfree; + memset(hdr->ObjectBuf, 0, size); + return hdr->ObjectBuf; +} + +static inline void fsp_fuse_obj_free(void *obj) +{ + if (0 == obj) + return; + + struct fsp_fuse_obj_hdr *hdr = (PVOID)((PUINT8)obj - sizeof(struct fsp_fuse_obj_hdr)); + + hdr->dtor(hdr); +} + #endif diff --git a/src/dll/fuse/shared.h b/src/dll/fuse/shared.h deleted file mode 100644 index 355ba203..00000000 --- a/src/dll/fuse/shared.h +++ /dev/null @@ -1,52 +0,0 @@ -/** - * @file dll/fuse/shared.h - * - * @copyright 2015-2018 Bill Zissimopoulos - */ -/* - * This file is part of WinFsp. - * - * You can redistribute it and/or modify it under the terms of the GNU - * General Public License version 3 as published by the Free Software - * Foundation. - * - * Licensees holding a valid commercial license may use this file in - * accordance with the commercial license agreement provided with the - * software. - */ - -#ifndef WINFSP_DLL_FUSE_SHARED_H_INCLUDED -#define WINFSP_DLL_FUSE_SHARED_H_INCLUDED - -#define enosys(env) ('C' == (env)->environment ? 88 : 40) - -struct fsp_fuse_obj_hdr -{ - void (*dtor)(void *); - __declspec(align(MEMORY_ALLOCATION_ALIGNMENT)) UINT8 ObjectBuf[]; -}; - -static inline void *fsp_fuse_obj_alloc(struct fsp_fuse_env *env, size_t size) -{ - struct fsp_fuse_obj_hdr *hdr; - - hdr = env->memalloc(sizeof(struct fsp_fuse_obj_hdr) + size); - if (0 == hdr) - return 0; - - hdr->dtor = env->memfree; - memset(hdr->ObjectBuf, 0, size); - return hdr->ObjectBuf; -} - -static inline void fsp_fuse_obj_free(void *obj) -{ - if (0 == obj) - return; - - struct fsp_fuse_obj_hdr *hdr = (PVOID)((PUINT8)obj - sizeof(struct fsp_fuse_obj_hdr)); - - hdr->dtor(hdr); -} - -#endif diff --git a/src/dll/fuse3/library.h b/src/dll/fuse3/library.h index 32d39738..ca74b9a3 100644 --- a/src/dll/fuse3/library.h +++ b/src/dll/fuse3/library.h @@ -18,15 +18,13 @@ #ifndef WINFSP_DLL_FUSE3_LIBRARY_H_INCLUDED #define WINFSP_DLL_FUSE3_LIBRARY_H_INCLUDED -#include -#include +#include #undef FUSE_H_ #undef FUSE_COMMON_H_ #undef FUSE_MAJOR_VERSION #undef FUSE_MINOR_VERSION #undef fuse_main #include -#include struct fuse3 { From ab3f3d282752b60b240f013d72402276ff16a1fe Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Wed, 18 Jul 2018 04:11:20 -0700 Subject: [PATCH 06/24] dll: fuse3: fuse2to3 implementation --- src/dll/fuse/fuse.c | 5 + src/dll/fuse/fuse_intf.c | 3 +- src/dll/fuse/library.h | 10 +- src/dll/fuse3/fuse2to3.c | 303 +++++++++++++++++++++++++++++++++------ 4 files changed, 277 insertions(+), 44 deletions(-) diff --git a/src/dll/fuse/fuse.c b/src/dll/fuse/fuse.c index 8eeef824..3b2f28cf 100644 --- a/src/dll/fuse/fuse.c +++ b/src/dll/fuse/fuse.c @@ -759,6 +759,11 @@ FSP_FUSE_API struct fuse_context *fsp_fuse_get_context(struct fsp_fuse_env *env) return context; } +struct fuse_context *fsp_fuse_get_context_internal(void) +{ + return TlsGetValue(fsp_fuse_tlskey); +} + FSP_FUSE_API int32_t fsp_fuse_ntstatus_from_errno(struct fsp_fuse_env *env, int err) { diff --git a/src/dll/fuse/fuse_intf.c b/src/dll/fuse/fuse_intf.c index af082a8b..084f7e55 100644 --- a/src/dll/fuse/fuse_intf.c +++ b/src/dll/fuse/fuse_intf.c @@ -1617,7 +1617,8 @@ exit: return Result; } -static int fsp_fuse_intf_AddDirInfo(void *buf, const char *name, +/* !static: used by fuse2to3 */ +int fsp_fuse_intf_AddDirInfo(void *buf, const char *name, const struct fuse_stat *stbuf, fuse_off_t off) { struct fuse_dirhandle *dh = buf; diff --git a/src/dll/fuse/library.h b/src/dll/fuse/library.h index 32da64ff..8f8219a5 100644 --- a/src/dll/fuse/library.h +++ b/src/dll/fuse/library.h @@ -25,9 +25,9 @@ #define FSP_FUSE_LIBRARY_NAME LIBRARY_NAME "-FUSE" #define FSP_FUSE_HDR_FROM_CONTEXT(c) \ - (struct fsp_fuse_context_header *)((PUINT8)(c) - sizeof(struct fsp_fuse_context_header)) + ((struct fsp_fuse_context_header *)((PUINT8)(c) - sizeof(struct fsp_fuse_context_header))) #define FSP_FUSE_CONTEXT_FROM_HDR(h) \ - (struct fuse_context *)((PUINT8)(h) + sizeof(struct fsp_fuse_context_header)) + ((struct fuse_context *)((PUINT8)(h) + sizeof(struct fsp_fuse_context_header))) #define FSP_FUSE_HAS_SYMLINKS(f) ((f)->has_symlinks) @@ -61,6 +61,7 @@ struct fuse struct fsp_fuse_context_header { char *PosixPath; + struct fuse3 *fuse3; __declspec(align(MEMORY_ALLOCATION_ALIGNMENT)) UINT8 ContextBuf[]; }; @@ -89,6 +90,9 @@ NTSTATUS fsp_fuse_op_enter(FSP_FILE_SYSTEM *FileSystem, NTSTATUS fsp_fuse_op_leave(FSP_FILE_SYSTEM *FileSystem, FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response); +int fsp_fuse_intf_AddDirInfo(void *buf, const char *name, + const struct fuse_stat *stbuf, fuse_off_t off); + extern FSP_FILE_SYSTEM_INTERFACE fsp_fuse_intf; NTSTATUS fsp_fuse_get_token_uidgid( @@ -135,4 +139,6 @@ static inline void fsp_fuse_obj_free(void *obj) hdr->dtor(hdr); } +struct fuse_context *fsp_fuse_get_context_internal(void); + #endif diff --git a/src/dll/fuse3/fuse2to3.c b/src/dll/fuse3/fuse2to3.c index 944a435a..63e4cd79 100644 --- a/src/dll/fuse3/fuse2to3.c +++ b/src/dll/fuse3/fuse2to3.c @@ -17,223 +17,444 @@ #include +static inline struct fuse3 *fuse2to3_getfuse3(void) +{ + return FSP_FUSE_HDR_FROM_CONTEXT(fsp_fuse_get_context_internal())->fuse3; +} + +static inline void fuse2to3_fi2from3(struct fuse_file_info *fi, struct fuse3_file_info *fi3) +{ + memset(fi, 0, sizeof *fi); + fi->flags = fi3->flags; + fi->writepage = fi3->writepage; + fi->direct_io = fi3->direct_io; + fi->keep_cache = fi3->keep_cache; + fi->flush = fi3->flush; + fi->nonseekable = fi3->nonseekable; + fi->fh = fi3->fh; + fi->lock_owner = fi3->lock_owner; +} + +static inline void fuse2to3_fi3from2(struct fuse3_file_info *fi3, struct fuse_file_info *fi) +{ + memset(fi3, 0, sizeof *fi3); + fi3->flags = fi->flags; + fi3->writepage = fi->writepage; + fi3->direct_io = fi->direct_io; + fi3->keep_cache = fi->keep_cache; + fi3->flush = fi->flush; + fi3->nonseekable = fi->nonseekable; + fi3->fh = fi->fh; + fi3->lock_owner = fi->lock_owner; +} + +static inline void fuse2to3_conn3from2(struct fuse3_conn_info *conn3, struct fuse_conn_info *conn) +{ + memset(conn3, 0, sizeof *conn3); + conn3->proto_major = 7; /* pretend that we are FUSE kernel protocol 7.26 */ + conn3->proto_minor = 26; /* which was current at the time of FUSE 3.2 */ + conn3->max_write = conn->max_write; + conn3->max_read = conn->max_write; + conn3->max_readahead = conn->max_readahead; + conn3->capable = conn->capable; + conn3->want = conn->want; +} + static int fuse2to3_getattr(const char *path, struct fuse_stat *stbuf) { - return -ENOSYS; + struct fuse3 *f3 = fuse2to3_getfuse3(); + return f3->ops.getattr(path, stbuf, 0); } static int fuse2to3_readlink(const char *path, char *buf, size_t size) { - return -ENOSYS; + struct fuse3 *f3 = fuse2to3_getfuse3(); + return f3->ops.readlink(path, buf, size); } static int fuse2to3_mknod(const char *path, fuse_mode_t mode, fuse_dev_t dev) { - return -ENOSYS; + struct fuse3 *f3 = fuse2to3_getfuse3(); + return f3->ops.mknod(path, mode, dev); } static int fuse2to3_mkdir(const char *path, fuse_mode_t mode) { - return -ENOSYS; + struct fuse3 *f3 = fuse2to3_getfuse3(); + return f3->ops.mkdir(path, mode); } static int fuse2to3_unlink(const char *path) { - return -ENOSYS; + struct fuse3 *f3 = fuse2to3_getfuse3(); + return f3->ops.unlink(path); } static int fuse2to3_rmdir(const char *path) { - return -ENOSYS; + struct fuse3 *f3 = fuse2to3_getfuse3(); + return f3->ops.rmdir(path); } static int fuse2to3_symlink(const char *dstpath, const char *srcpath) { - return -ENOSYS; + struct fuse3 *f3 = fuse2to3_getfuse3(); + return f3->ops.symlink(dstpath, srcpath); } static int fuse2to3_rename(const char *oldpath, const char *newpath) { - return -ENOSYS; + struct fuse3 *f3 = fuse2to3_getfuse3(); + return f3->ops.rename(oldpath, newpath, 0); } static int fuse2to3_link(const char *srcpath, const char *dstpath) { - return -ENOSYS; + struct fuse3 *f3 = fuse2to3_getfuse3(); + return f3->ops.link(srcpath, dstpath); } static int fuse2to3_chmod(const char *path, fuse_mode_t mode) { - return -ENOSYS; + struct fuse3 *f3 = fuse2to3_getfuse3(); + return f3->ops.chmod(path, mode, 0); } static int fuse2to3_chown(const char *path, fuse_uid_t uid, fuse_gid_t gid) { - return -ENOSYS; + struct fuse3 *f3 = fuse2to3_getfuse3(); + return f3->ops.chown(path, uid, gid, 0); } static int fuse2to3_truncate(const char *path, fuse_off_t size) { - return -ENOSYS; + struct fuse3 *f3 = fuse2to3_getfuse3(); + return f3->ops.truncate(path, size, 0); } static int fuse2to3_open(const char *path, struct fuse_file_info *fi) { - return -ENOSYS; + struct fuse3 *f3 = fuse2to3_getfuse3(); + struct fuse3_file_info fi3; + fuse2to3_fi3from2(&fi3, fi); + int res = f3->ops.open(path, &fi3); + fuse2to3_fi2from3(fi, &fi3); + return res; } static int fuse2to3_read(const char *path, char *buf, size_t size, fuse_off_t off, struct fuse_file_info *fi) { - return -ENOSYS; + struct fuse3 *f3 = fuse2to3_getfuse3(); + struct fuse3_file_info fi3; + fuse2to3_fi3from2(&fi3, fi); + int res = f3->ops.read(path, buf, size, off, &fi3); + fuse2to3_fi2from3(fi, &fi3); + return res; } static int fuse2to3_write(const char *path, const char *buf, size_t size, fuse_off_t off, struct fuse_file_info *fi) { - return -ENOSYS; + struct fuse3 *f3 = fuse2to3_getfuse3(); + struct fuse3_file_info fi3; + fuse2to3_fi3from2(&fi3, fi); + int res = f3->ops.write(path, buf, size, off, &fi3); + fuse2to3_fi2from3(fi, &fi3); + return res; } static int fuse2to3_statfs(const char *path, struct fuse_statvfs *stbuf) { - return -ENOSYS; + struct fuse3 *f3 = fuse2to3_getfuse3(); + return f3->ops.statfs(path, stbuf); } static int fuse2to3_flush(const char *path, struct fuse_file_info *fi) { - return -ENOSYS; + struct fuse3 *f3 = fuse2to3_getfuse3(); + struct fuse3_file_info fi3; + fuse2to3_fi3from2(&fi3, fi); + int res = f3->ops.flush(path, &fi3); + fuse2to3_fi2from3(fi, &fi3); + return res; } static int fuse2to3_release(const char *path, struct fuse_file_info *fi) { - return -ENOSYS; + struct fuse3 *f3 = fuse2to3_getfuse3(); + struct fuse3_file_info fi3; + fuse2to3_fi3from2(&fi3, fi); + int res = f3->ops.release(path, &fi3); + fuse2to3_fi2from3(fi, &fi3); + return res; } static int fuse2to3_fsync(const char *path, int datasync, struct fuse_file_info *fi) { - return -ENOSYS; + struct fuse3 *f3 = fuse2to3_getfuse3(); + struct fuse3_file_info fi3; + fuse2to3_fi3from2(&fi3, fi); + int res = f3->ops.fsync(path, datasync, &fi3); + fuse2to3_fi2from3(fi, &fi3); + return res; } static int fuse2to3_setxattr(const char *path, const char *name, const char *value, size_t size, int flags) { - return -ENOSYS; + struct fuse3 *f3 = fuse2to3_getfuse3(); + return f3->ops.setxattr(path, name, value, size, flags); } static int fuse2to3_getxattr(const char *path, const char *name, char *value, size_t size) { - return -ENOSYS; + struct fuse3 *f3 = fuse2to3_getfuse3(); + return f3->ops.getxattr(path, name, value, size); } static int fuse2to3_listxattr(const char *path, char *namebuf, size_t size) { - return -ENOSYS; + struct fuse3 *f3 = fuse2to3_getfuse3(); + return f3->ops.listxattr(path, namebuf, size); } static int fuse2to3_removexattr(const char *path, const char *name) { - return -ENOSYS; + struct fuse3 *f3 = fuse2to3_getfuse3(); + return f3->ops.removexattr(path, name); } static int fuse2to3_opendir(const char *path, struct fuse_file_info *fi) { - return -ENOSYS; + struct fuse3 *f3 = fuse2to3_getfuse3(); + struct fuse3_file_info fi3; + fuse2to3_fi3from2(&fi3, fi); + int res = f3->ops.opendir(path, &fi3); + fuse2to3_fi2from3(fi, &fi3); + return res; +} + +static int fuse2to3_filldir(void *buf, const char *name, + const struct fuse_stat *stbuf, fuse_off_t off, + enum fuse3_fill_dir_flags flags) +{ + return 0 != (flags & FUSE_FILL_DIR_PLUS) ? + fsp_fuse_intf_AddDirInfo(buf, name, stbuf, off) : + fsp_fuse_intf_AddDirInfo(buf, name, 0, off); } static int fuse2to3_readdir(const char *path, void *buf, fuse_fill_dir_t filler, fuse_off_t off, struct fuse_file_info *fi) { - return -ENOSYS; + struct fuse3 *f3 = fuse2to3_getfuse3(); + struct fuse_dirhandle *dh = buf; + struct fuse3_file_info fi3; + fuse2to3_fi3from2(&fi3, fi); + int res = f3->ops.readdir(path, buf, &fuse2to3_filldir, off, &fi3, + dh->ReaddirPlus ? FUSE_READDIR_PLUS : 0); + fuse2to3_fi2from3(fi, &fi3); + return res; } static int fuse2to3_releasedir(const char *path, struct fuse_file_info *fi) { - return -ENOSYS; + struct fuse3 *f3 = fuse2to3_getfuse3(); + struct fuse3_file_info fi3; + fuse2to3_fi3from2(&fi3, fi); + int res = f3->ops.releasedir(path, &fi3); + fuse2to3_fi2from3(fi, &fi3); + return res; } static int fuse2to3_fsyncdir(const char *path, int datasync, struct fuse_file_info *fi) { - return -ENOSYS; + struct fuse3 *f3 = fuse2to3_getfuse3(); + struct fuse3_file_info fi3; + fuse2to3_fi3from2(&fi3, fi); + int res = f3->ops.fsyncdir(path, datasync, &fi3); + fuse2to3_fi2from3(fi, &fi3); + return res; } static void *fuse2to3_init(struct fuse_conn_info *conn) { - return 0; + struct fuse_context *context = fsp_fuse_get_context_internal(); + struct fuse *f = context->fuse; + struct fuse3 *f3 = FSP_FUSE_HDR_FROM_CONTEXT(context)->fuse3; + + struct fuse3_conn_info conn3; + fuse2to3_conn3from2(&conn3, conn); + + struct fuse3_config conf3; + memset(&conf3, 0, sizeof conf3); + conf3.set_gid = f->set_gid; + conf3.gid = f->gid; + conf3.set_uid = f->set_uid; + conf3.uid = f->uid; + conf3.set_mode = f->set_umask; + conf3.umask = f->umask; +#if 0 + /* + * Cannot set timeouts because of lack of floating point support. + * + * FUSE uses the `double` type for timeouts. This DLL does not use the standard library + * for a variety of reasons. This means that we cannot easily perform the computations + * below. + * + * If this becomes important (double) floating point values could perhaps be calculated + * using bit tricks. See below: + * - http://locklessinc.com/articles/i2f/ + * - https://stackoverflow.com/a/20308114 + */ + conf3.entry_timeout = f->VolumeParams.DirInfoTimeoutValid ? + f->VolumeParams.DirInfoTimeout / 1000 : f->VolumeParams.FileInfoTimeout / 1000; + conf3.negative_timeout = 0; + conf3.attr_timeout = f->VolumeParams.FileInfoTimeout / 1000; + conf3.ac_attr_timeout = conf3.attr_timeout; +#endif + + void *res = f3->ops.init(&conn3, &conf3); + + conn->max_write = conn3.max_write; + conn->max_readahead = conn3.max_readahead; + conn->want = conn3.want; + + return res; } static void fuse2to3_destroy(void *data) { + struct fuse3 *f3 = fuse2to3_getfuse3(); + f3->ops.destroy(data); } static int fuse2to3_access(const char *path, int mask) { - return -ENOSYS; + struct fuse3 *f3 = fuse2to3_getfuse3(); + return f3->ops.access(path, mask); } static int fuse2to3_create(const char *path, fuse_mode_t mode, struct fuse_file_info *fi) { - return -ENOSYS; + struct fuse3 *f3 = fuse2to3_getfuse3(); + struct fuse3_file_info fi3; + fuse2to3_fi3from2(&fi3, fi); + int res = f3->ops.create(path, mode, &fi3); + fuse2to3_fi2from3(fi, &fi3); + return res; } static int fuse2to3_ftruncate(const char *path, fuse_off_t off, struct fuse_file_info *fi) { - return -ENOSYS; + struct fuse3 *f3 = fuse2to3_getfuse3(); + struct fuse3_file_info fi3; + fuse2to3_fi3from2(&fi3, fi); + int res = f3->ops.truncate(path, off, &fi3); + fuse2to3_fi2from3(fi, &fi3); + return res; } static int fuse2to3_fgetattr(const char *path, struct fuse_stat *stbuf, struct fuse_file_info *fi) { - return -ENOSYS; + struct fuse3 *f3 = fuse2to3_getfuse3(); + struct fuse3_file_info fi3; + fuse2to3_fi3from2(&fi3, fi); + int res = f3->ops.getattr(path, stbuf, &fi3); + fuse2to3_fi2from3(fi, &fi3); + return res; } static int fuse2to3_lock(const char *path, struct fuse_file_info *fi, int cmd, struct fuse_flock *lock) { - return -ENOSYS; + struct fuse3 *f3 = fuse2to3_getfuse3(); + struct fuse3_file_info fi3; + fuse2to3_fi3from2(&fi3, fi); + int res = f3->ops.lock(path, &fi3, cmd, lock); + fuse2to3_fi2from3(fi, &fi3); + return res; } static int fuse2to3_utimens(const char *path, const struct fuse_timespec tv[2]) { - return -ENOSYS; + struct fuse3 *f3 = fuse2to3_getfuse3(); + return f3->ops.utimens(path, tv, 0); } static int fuse2to3_bmap(const char *path, size_t blocksize, uint64_t *idx) { - return -ENOSYS; + struct fuse3 *f3 = fuse2to3_getfuse3(); + return f3->ops.bmap(path, blocksize, idx); } static int fuse2to3_ioctl(const char *path, int cmd, void *arg, struct fuse_file_info *fi, unsigned int flags, void *data) { - return -ENOSYS; + struct fuse3 *f3 = fuse2to3_getfuse3(); + struct fuse3_file_info fi3; + fuse2to3_fi3from2(&fi3, fi); + int res = f3->ops.ioctl(path, cmd, arg, &fi3, flags, data); + fuse2to3_fi2from3(fi, &fi3); + return res; } static int fuse2to3_poll(const char *path, struct fuse_file_info *fi, struct fuse_pollhandle *ph, unsigned *reventsp) { - return -ENOSYS; + struct fuse3 *f3 = fuse2to3_getfuse3(); + struct fuse3_file_info fi3; + fuse2to3_fi3from2(&fi3, fi); + int res = f3->ops.poll(path, &fi3, (struct fuse3_pollhandle *)ph, reventsp); + fuse2to3_fi2from3(fi, &fi3); + return res; } static int fuse2to3_write_buf(const char *path, struct fuse_bufvec *buf, fuse_off_t off, struct fuse_file_info *fi) { - return -ENOSYS; + struct fuse3 *f3 = fuse2to3_getfuse3(); + struct fuse3_file_info fi3; + fuse2to3_fi3from2(&fi3, fi); + int res = f3->ops.write_buf(path, + (struct fuse3_bufvec *)buf, /* revisit if we implement bufvec's */ + off, &fi3); + fuse2to3_fi2from3(fi, &fi3); + return res; } static int fuse2to3_read_buf(const char *path, struct fuse_bufvec **bufp, size_t size, fuse_off_t off, struct fuse_file_info *fi) { - return -ENOSYS; + struct fuse3 *f3 = fuse2to3_getfuse3(); + struct fuse3_file_info fi3; + fuse2to3_fi3from2(&fi3, fi); + int res = f3->ops.read_buf(path, + (struct fuse3_bufvec **)bufp, /* revisit if we implement bufvec's */ + size, off, &fi3); + fuse2to3_fi2from3(fi, &fi3); + return res; } static int fuse2to3_flock(const char *path, struct fuse_file_info *fi, int op) { - return -ENOSYS; + struct fuse3 *f3 = fuse2to3_getfuse3(); + struct fuse3_file_info fi3; + fuse2to3_fi3from2(&fi3, fi); + int res = f3->ops.flock(path, &fi3, op); + fuse2to3_fi2from3(fi, &fi3); + return res; } static int fuse2to3_fallocate(const char *path, int mode, fuse_off_t off, fuse_off_t len, struct fuse_file_info *fi) { - return -ENOSYS; + struct fuse3 *f3 = fuse2to3_getfuse3(); + struct fuse3_file_info fi3; + fuse2to3_fi3from2(&fi3, fi); + int res = f3->ops.fallocate(path, mode, off, len, &fi3); + fuse2to3_fi2from3(fi, &fi3); + return res; } static struct fuse_operations fuse2to3_ops = From 931d201527a670981049f22e970578c0b6426d31 Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Wed, 18 Jul 2018 14:48:10 -0700 Subject: [PATCH 07/24] dll: fuse3: fuse2to3 implementation --- src/dll/fuse3/fuse2to3.c | 188 +++++++++++++++++++++++++++++---------- src/dll/fuse3/fuse3.c | 30 ------- src/dll/fuse3/library.h | 3 + 3 files changed, 146 insertions(+), 75 deletions(-) diff --git a/src/dll/fuse3/fuse2to3.c b/src/dll/fuse3/fuse2to3.c index 63e4cd79..d6f693d4 100644 --- a/src/dll/fuse3/fuse2to3.c +++ b/src/dll/fuse3/fuse2to3.c @@ -280,8 +280,11 @@ static int fuse2to3_fsyncdir(const char *path, int datasync, struct fuse_file_in static void *fuse2to3_init(struct fuse_conn_info *conn) { struct fuse_context *context = fsp_fuse_get_context_internal(); + struct fuse3 *f3 = context->private_data; struct fuse *f = context->fuse; - struct fuse3 *f3 = FSP_FUSE_HDR_FROM_CONTEXT(context)->fuse3; + + FSP_FUSE_HDR_FROM_CONTEXT(context)->fuse3 = f3; + context->private_data = f->data = f3->data; struct fuse3_conn_info conn3; fuse2to3_conn3from2(&conn3, conn); @@ -457,48 +460,143 @@ static int fuse2to3_fallocate(const char *path, int mode, fuse_off_t off, fuse_o return res; } -static struct fuse_operations fuse2to3_ops = +FSP_FUSE_API struct fuse3 *fsp_fuse3_new_30(struct fsp_fuse_env *env, + struct fuse_args *args, + const struct fuse3_operations *ops, size_t opsize, void *data) { - .getattr = fuse2to3_getattr, - .readlink = fuse2to3_readlink, - .mknod = fuse2to3_mknod, - .mkdir = fuse2to3_mkdir, - .unlink = fuse2to3_unlink, - .rmdir = fuse2to3_rmdir, - .symlink = fuse2to3_symlink, - .rename = fuse2to3_rename, - .link = fuse2to3_link, - .chmod = fuse2to3_chmod, - .chown = fuse2to3_chown, - .truncate = fuse2to3_truncate, - .open = fuse2to3_open, - .read = fuse2to3_read, - .write = fuse2to3_write, - .statfs = fuse2to3_statfs, - .flush = fuse2to3_flush, - .release = fuse2to3_release, - .fsync = fuse2to3_fsync, - .setxattr = fuse2to3_setxattr, - .getxattr = fuse2to3_getxattr, - .listxattr = fuse2to3_listxattr, - .removexattr = fuse2to3_removexattr, - .opendir = fuse2to3_opendir, - .readdir = fuse2to3_readdir, - .releasedir = fuse2to3_releasedir, - .fsyncdir = fuse2to3_fsyncdir, - .init = fuse2to3_init, - .destroy = fuse2to3_destroy, - .access = fuse2to3_access, - .create = fuse2to3_create, - .ftruncate = fuse2to3_ftruncate, - .fgetattr = fuse2to3_fgetattr, - .lock = fuse2to3_lock, - .utimens = fuse2to3_utimens, - .bmap = fuse2to3_bmap, - .ioctl = fuse2to3_ioctl, - .poll = fuse2to3_poll, - .write_buf = fuse2to3_write_buf, - .read_buf = fuse2to3_read_buf, - .flock = fuse2to3_flock, - .fallocate = fuse2to3_fallocate, -}; + return 0; +} + +FSP_FUSE_API struct fuse3 *fsp_fuse3_new(struct fsp_fuse_env *env, + struct fuse_args *args, + const struct fuse3_operations *ops, size_t opsize, void *data) +{ + struct fuse3 *f3 = 0; + + if (opsize > sizeof(struct fuse3_operations)) + opsize = sizeof(struct fuse3_operations); + + f3 = fsp_fuse_obj_alloc(env, sizeof *f3); + if (0 == f3) + goto fail; + + for (int argi = 0; args->argc > argi; argi++) + if (-1 == fsp_fuse_opt_add_arg(env, &f3->args, args->argv[argi])) + goto fail; + + memcpy(&f3->ops, ops, opsize); + f3->data = data; + + return f3; + +fail: + if (0 != f3) + fsp_fuse3_destroy(env, f3); + + return 0; +} + +FSP_FUSE_API void fsp_fuse3_destroy(struct fsp_fuse_env *env, + struct fuse3 *f3) +{ + if (0 != f3->fuse) + fsp_fuse_destroy(env, f3->fuse); + + fsp_fuse_opt_free_args(env, &f3->args); + + fsp_fuse_obj_free(f3); +} + +FSP_FUSE_API int fsp_fuse3_mount(struct fsp_fuse_env *env, + struct fuse3 *f3, const char *mountpoint) +{ + struct fuse_chan *ch = 0; + struct fuse *f = 0; + struct fuse_operations fuse2to3_ops = + { + .getattr = 0 != f3->ops.getattr ? fuse2to3_getattr : 0, + .readlink = 0 != f3->ops.readlink ? fuse2to3_readlink : 0, + .mknod = 0 != f3->ops.mknod ? fuse2to3_mknod : 0, + .mkdir = 0 != f3->ops.mkdir ? fuse2to3_mkdir : 0, + .unlink = 0 != f3->ops.unlink ? fuse2to3_unlink : 0, + .rmdir = 0 != f3->ops.rmdir ? fuse2to3_rmdir : 0, + .symlink = 0 != f3->ops.symlink ? fuse2to3_symlink : 0, + .rename = 0 != f3->ops.rename ? fuse2to3_rename : 0, + .link = 0 != f3->ops.link ? fuse2to3_link : 0, + .chmod = 0 != f3->ops.chmod ? fuse2to3_chmod : 0, + .chown = 0 != f3->ops.chown ? fuse2to3_chown : 0, + .truncate = 0 != f3->ops.truncate ? fuse2to3_truncate : 0, + .open = 0 != f3->ops.open ? fuse2to3_open : 0, + .read = 0 != f3->ops.read ? fuse2to3_read : 0, + .write = 0 != f3->ops.write ? fuse2to3_write : 0, + .statfs = 0 != f3->ops.statfs ? fuse2to3_statfs : 0, + .flush = 0 != f3->ops.flush ? fuse2to3_flush : 0, + .release = 0 != f3->ops.release ? fuse2to3_release : 0, + .fsync = 0 != f3->ops.fsync ? fuse2to3_fsync : 0, + .setxattr = 0 != f3->ops.setxattr ? fuse2to3_setxattr : 0, + .getxattr = 0 != f3->ops.getxattr ? fuse2to3_getxattr : 0, + .listxattr = 0 != f3->ops.listxattr ? fuse2to3_listxattr : 0, + .removexattr = 0 != f3->ops.removexattr ? fuse2to3_removexattr : 0, + .opendir = 0 != f3->ops.opendir ? fuse2to3_opendir : 0, + .readdir = 0 != f3->ops.readdir ? fuse2to3_readdir : 0, + .releasedir = 0 != f3->ops.releasedir ? fuse2to3_releasedir : 0, + .fsyncdir = 0 != f3->ops.fsyncdir ? fuse2to3_fsyncdir : 0, + .init = 0 != f3->ops.init ? fuse2to3_init : 0, + .destroy = 0 != f3->ops.destroy ? fuse2to3_destroy : 0, + .access = 0 != f3->ops.access ? fuse2to3_access : 0, + .create = 0 != f3->ops.create ? fuse2to3_create : 0, + .ftruncate = 0 != f3->ops.truncate ? fuse2to3_ftruncate : 0, + .fgetattr = 0 != f3->ops.getattr ? fuse2to3_fgetattr : 0, + .lock = 0 != f3->ops.lock ? fuse2to3_lock : 0, + .utimens = 0 != f3->ops.utimens ? fuse2to3_utimens : 0, + .bmap = 0 != f3->ops.bmap ? fuse2to3_bmap : 0, + .ioctl = 0 != f3->ops.ioctl ? fuse2to3_ioctl : 0, + .poll = 0 != f3->ops.poll ? fuse2to3_poll : 0, + .write_buf = 0 != f3->ops.write_buf ? fuse2to3_write_buf : 0, + .read_buf = 0 != f3->ops.read_buf ? fuse2to3_read_buf : 0, + .flock = 0 != f3->ops.flock ? fuse2to3_flock : 0, + .fallocate = 0 != f3->ops.fallocate ? fuse2to3_fallocate : 0, + }; + + ch = fsp_fuse_mount(env, mountpoint, &f3->args); + if (0 == ch) + goto fail; + + f = fsp_fuse_new(env, ch, &f3->args, &fuse2to3_ops, sizeof fuse2to3_ops, f3); + if (0 == f) + goto fail; + + /* + * Free the fuse_chan which is no longer needed. Note that this behavior is WinFsp-FUSE + * specific, because WinFsp-FUSE only allocates/frees fuse_chan memory during fuse_mount/ + * fuse_unmount and does not perform any actual mounting/unmounting. This would not work + * on a different FUSE implementation. + * + * (Store mountpoint and ch inside struct fuse3 so that they can be freed during fuse_destroy + * in that case.) + */ + fsp_fuse_unmount(env, mountpoint, ch); + + /* Free the args which are no longer needed. */ + fsp_fuse_opt_free_args(env, &f3->args); + + f3->fuse = f; + + return 0; + +fail: + if (0 != f) + fsp_fuse_destroy(env, f); + + if (0 != ch) + fsp_fuse_unmount(env, mountpoint, ch); + + return -1; +} + +FSP_FUSE_API void fsp_fuse3_unmount(struct fsp_fuse_env *env, + struct fuse3 *f3) +{ + fsp_fuse_destroy(env, f3->fuse); + f3->fuse = 0; +} diff --git a/src/dll/fuse3/fuse3.c b/src/dll/fuse3/fuse3.c index 32724a71..268e7f09 100644 --- a/src/dll/fuse3/fuse3.c +++ b/src/dll/fuse3/fuse3.c @@ -29,36 +29,6 @@ FSP_FUSE_API void fsp_fuse3_lib_help(struct fsp_fuse_env *env, { } -FSP_FUSE_API struct fuse3 *fsp_fuse3_new_30(struct fsp_fuse_env *env, - struct fuse_args *args, - const struct fuse3_operations *ops, size_t opsize, void *data) -{ - return 0; -} - -FSP_FUSE_API struct fuse3 *fsp_fuse3_new(struct fsp_fuse_env *env, - struct fuse_args *args, - const struct fuse3_operations *ops, size_t opsize, void *data) -{ - return 0; -} - -FSP_FUSE_API void fsp_fuse3_destroy(struct fsp_fuse_env *env, - struct fuse3 *f) -{ -} - -FSP_FUSE_API int fsp_fuse3_mount(struct fsp_fuse_env *env, - struct fuse3 *f, const char *mountpoint) -{ - return 0; -} - -FSP_FUSE_API void fsp_fuse3_unmount(struct fsp_fuse_env *env, - struct fuse3 *f) -{ -} - FSP_FUSE_API int fsp_fuse3_loop(struct fsp_fuse_env *env, struct fuse3 *f) { diff --git a/src/dll/fuse3/library.h b/src/dll/fuse3/library.h index ca74b9a3..d2f19f26 100644 --- a/src/dll/fuse3/library.h +++ b/src/dll/fuse3/library.h @@ -28,7 +28,10 @@ struct fuse3 { + struct fuse_args args; struct fuse3_operations ops; + void *data; + struct fuse *fuse; }; #endif From 9b79bb24cad4ab3659adc6c1b9639da089d2de20 Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Thu, 19 Jul 2018 04:27:06 -0700 Subject: [PATCH 08/24] dll: fuse3: checkpoint --- inc/fuse3/fuse_common.h | 4 ++-- src/dll/fuse3/fuse3.c | 23 +++++++++++++++-------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/inc/fuse3/fuse_common.h b/inc/fuse3/fuse_common.h index adf135f1..cac1d8ab 100644 --- a/inc/fuse3/fuse_common.h +++ b/inc/fuse3/fuse_common.h @@ -88,8 +88,8 @@ struct fuse3_file_info struct fuse3_loop_config { - int clone_fd; /* ignored */ - unsigned int max_idle_threads; /* ignored */ + int clone_fd; + unsigned int max_idle_threads; }; struct fuse3_conn_info diff --git a/src/dll/fuse3/fuse3.c b/src/dll/fuse3/fuse3.c index 268e7f09..d6844941 100644 --- a/src/dll/fuse3/fuse3.c +++ b/src/dll/fuse3/fuse3.c @@ -30,31 +30,38 @@ FSP_FUSE_API void fsp_fuse3_lib_help(struct fsp_fuse_env *env, } FSP_FUSE_API int fsp_fuse3_loop(struct fsp_fuse_env *env, - struct fuse3 *f) + struct fuse3 *f3) { - return 0; + return 0 == fsp_fuse_loop(env, f3->fuse) ? 0 : -EINVAL/* same on MSVC and Cygwin */; } FSP_FUSE_API int fsp_fuse3_loop_mt_31(struct fsp_fuse_env *env, - struct fuse3 *f, int clone_fd) + struct fuse3 *f3, int clone_fd) { - return 0; + return 0 == fsp_fuse_loop_mt(env, f3->fuse) ? 0 : -EINVAL/* same on MSVC and Cygwin */; } FSP_FUSE_API int fsp_fuse3_loop_mt(struct fsp_fuse_env *env, - struct fuse3 *f, struct fuse3_loop_config *config) + struct fuse3 *f3, struct fuse3_loop_config *config) { - return 0; + return 0 == fsp_fuse_loop_mt(env, f3->fuse) ? 0 : -EINVAL/* same on MSVC and Cygwin */; } FSP_FUSE_API void fsp_fuse3_exit(struct fsp_fuse_env *env, - struct fuse3 *f) + struct fuse3 *f3) { + fsp_fuse_exit(env, f3->fuse); } FSP_FUSE_API struct fuse3_context *fsp_fuse3_get_context(struct fsp_fuse_env *env) { - return 0; + FSP_FSCTL_STATIC_ASSERT( + sizeof(struct fuse_context) == sizeof(struct fuse3_context), + "incompatible structs fuse_context and fuse3_context"); + FSP_FSCTL_STATIC_ASSERT(FIELD_OFFSET( + struct fuse_context, private_data) == FIELD_OFFSET(struct fuse3_context, private_data), + "incompatible structs fuse_context and fuse3_context"); + return (struct fuse3_context *)fsp_fuse_get_context(env); } FSP_FUSE_API struct fuse3_conn_info_opts* fsp_fuse3_parse_conn_info_opts( From 753440e8373473f31ca9313b86faaad25622e3e1 Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Thu, 19 Jul 2018 06:13:48 -0700 Subject: [PATCH 09/24] dll: fuse3: checkpoint --- src/dll/fuse/fuse.c | 39 ++++++++++----------------- src/dll/fuse/library.h | 28 ++++++++++++++++++++ src/dll/fuse3/fuse2to3.c | 57 +++++++++++++++++++++++++++++++++------- 3 files changed, 90 insertions(+), 34 deletions(-) diff --git a/src/dll/fuse/fuse.c b/src/dll/fuse/fuse.c index 3b2f28cf..84a8abc3 100644 --- a/src/dll/fuse/fuse.c +++ b/src/dll/fuse/fuse.c @@ -27,30 +27,7 @@ struct fuse_chan }; #define FSP_FUSE_CORE_OPT(n, f, v) { n, offsetof(struct fsp_fuse_core_opt_data, f), v } - -struct fsp_fuse_core_opt_data -{ - struct fsp_fuse_env *env; - int help, debug; - HANDLE DebugLogHandle; - int set_umask, umask, - set_create_umask, create_umask, - set_uid, uid, - set_gid, gid, - set_attr_timeout, attr_timeout, - rellinks; - int set_FileInfoTimeout, - set_DirInfoTimeout, - set_VolumeInfoTimeout, - set_KeepFileCache; - unsigned ThreadCount; - FSP_FSCTL_VOLUME_PARAMS VolumeParams; - UINT16 VolumeLabelLength; - WCHAR VolumeLabel[sizeof ((FSP_FSCTL_VOLUME_INFO *)0)->VolumeLabel / sizeof(WCHAR)]; -}; -FSP_FSCTL_STATIC_ASSERT( - sizeof ((struct fuse *)0)->VolumeLabel == sizeof ((struct fsp_fuse_core_opt_data *)0)->VolumeLabel, - "fuse::VolumeLabel and fsp_fuse_core_opt_data::VolumeLabel: sizeof must be same."); +#define FSP_FUSE_CORE_OPT_NOHELP_IDX 4 static struct fuse_opt fsp_fuse_core_opts[] = { @@ -546,6 +523,18 @@ static int fsp_fuse_core_opt_proc(void *opt_data0, const char *arg, int key, } } +int fsp_fuse_core_opt_parse(struct fsp_fuse_env *env, + struct fuse_args *args, struct fsp_fuse_core_opt_data *opt_data, + int help) +{ + if (help) + return fsp_fuse_opt_parse(env, args, opt_data, + fsp_fuse_core_opts, fsp_fuse_core_opt_proc); + else + return fsp_fuse_opt_parse(env, args, opt_data, + fsp_fuse_core_opts + FSP_FUSE_CORE_OPT_NOHELP_IDX, fsp_fuse_core_opt_proc); +} + FSP_FUSE_API struct fuse *fsp_fuse_new(struct fsp_fuse_env *env, struct fuse_chan *ch, struct fuse_args *args, const struct fuse_operations *ops, size_t opsize, void *data) @@ -566,7 +555,7 @@ FSP_FUSE_API struct fuse *fsp_fuse_new(struct fsp_fuse_env *env, opt_data.VolumeParams.FileInfoTimeout = 1000; opt_data.VolumeParams.FlushAndPurgeOnCleanup = TRUE; - if (-1 == fsp_fuse_opt_parse(env, args, &opt_data, fsp_fuse_core_opts, fsp_fuse_core_opt_proc)) + if (-1 == fsp_fuse_core_opt_parse(env, args, &opt_data, /*help=*/1)) return 0; if (opt_data.help) return 0; diff --git a/src/dll/fuse/library.h b/src/dll/fuse/library.h index 8f8219a5..8a40b055 100644 --- a/src/dll/fuse/library.h +++ b/src/dll/fuse/library.h @@ -141,4 +141,32 @@ static inline void fsp_fuse_obj_free(void *obj) struct fuse_context *fsp_fuse_get_context_internal(void); +struct fsp_fuse_core_opt_data +{ + struct fsp_fuse_env *env; + int help, debug; + HANDLE DebugLogHandle; + int set_umask, umask, + set_create_umask, create_umask, + set_uid, uid, + set_gid, gid, + set_attr_timeout, attr_timeout, + rellinks; + int set_FileInfoTimeout, + set_DirInfoTimeout, + set_VolumeInfoTimeout, + set_KeepFileCache; + unsigned ThreadCount; + FSP_FSCTL_VOLUME_PARAMS VolumeParams; + UINT16 VolumeLabelLength; + WCHAR VolumeLabel[sizeof ((FSP_FSCTL_VOLUME_INFO *)0)->VolumeLabel / sizeof(WCHAR)]; +}; +FSP_FSCTL_STATIC_ASSERT( + sizeof ((struct fuse *)0)->VolumeLabel == sizeof ((struct fsp_fuse_core_opt_data *)0)->VolumeLabel, + "fuse::VolumeLabel and fsp_fuse_core_opt_data::VolumeLabel: sizeof must be same."); + +int fsp_fuse_core_opt_parse(struct fsp_fuse_env *env, + struct fuse_args *args, struct fsp_fuse_core_opt_data *opt_data, + int help); + #endif diff --git a/src/dll/fuse3/fuse2to3.c b/src/dll/fuse3/fuse2to3.c index d6f693d4..b6a0b1f0 100644 --- a/src/dll/fuse3/fuse2to3.c +++ b/src/dll/fuse3/fuse2to3.c @@ -460,17 +460,44 @@ static int fuse2to3_fallocate(const char *path, int mode, fuse_off_t off, fuse_o return res; } -FSP_FUSE_API struct fuse3 *fsp_fuse3_new_30(struct fsp_fuse_env *env, - struct fuse_args *args, - const struct fuse3_operations *ops, size_t opsize, void *data) +static int fsp_fuse3_copy_args(struct fsp_fuse_env *env, + const struct fuse_args *args, + struct fuse_args *outargs) { + outargs->argc = 0; + outargs->argv = 0; + outargs->allocated = 0; + + for (int argi = 0; args->argc > argi; argi++) + if (-1 == fsp_fuse_opt_add_arg(env, outargs, args->argv[argi])) + goto fail; + return 0; + +fail: + fsp_fuse_opt_free_args(env, outargs); + + return -1; } -FSP_FUSE_API struct fuse3 *fsp_fuse3_new(struct fsp_fuse_env *env, +static struct fuse3 *fsp_fuse3_new_common(struct fsp_fuse_env *env, struct fuse_args *args, - const struct fuse3_operations *ops, size_t opsize, void *data) + const struct fuse3_operations *ops, size_t opsize, void *data, + int help) { + /* preflight args */ + struct fsp_fuse_core_opt_data opt_data; + struct fuse_args pfargs; + memset(&opt_data, 0, sizeof opt_data); + if (-1 == fsp_fuse3_copy_args(env, args, &pfargs)) + return 0; + int optres = fsp_fuse_core_opt_parse(env, &pfargs, &opt_data, /*help=*/1); + fsp_fuse_opt_free_args(env, &pfargs); + if (-1 == optres) + return 0; + if (opt_data.help) + return 0; + struct fuse3 *f3 = 0; if (opsize > sizeof(struct fuse3_operations)) @@ -480,10 +507,8 @@ FSP_FUSE_API struct fuse3 *fsp_fuse3_new(struct fsp_fuse_env *env, if (0 == f3) goto fail; - for (int argi = 0; args->argc > argi; argi++) - if (-1 == fsp_fuse_opt_add_arg(env, &f3->args, args->argv[argi])) - goto fail; - + if (-1 == fsp_fuse3_copy_args(env, args, &f3->args)) + goto fail; memcpy(&f3->ops, ops, opsize); f3->data = data; @@ -496,6 +521,20 @@ fail: return 0; } +FSP_FUSE_API struct fuse3 *fsp_fuse3_new_30(struct fsp_fuse_env *env, + struct fuse_args *args, + const struct fuse3_operations *ops, size_t opsize, void *data) +{ + return fsp_fuse3_new_common(env, args, ops, opsize, data, /*help=*/1); +} + +FSP_FUSE_API struct fuse3 *fsp_fuse3_new(struct fsp_fuse_env *env, + struct fuse_args *args, + const struct fuse3_operations *ops, size_t opsize, void *data) +{ + return fsp_fuse3_new_common(env, args, ops, opsize, data, /*help=*/0); +} + FSP_FUSE_API void fsp_fuse3_destroy(struct fsp_fuse_env *env, struct fuse3 *f3) { From 5cd40ff7ff80f158bd9c86eaeab02dc370564bce Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Thu, 19 Jul 2018 06:39:18 -0700 Subject: [PATCH 10/24] dll: fuse3: fsp_fuse3_lib_help --- src/dll/fuse3/fuse3.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/dll/fuse3/fuse3.c b/src/dll/fuse3/fuse3.c index d6844941..be110b0d 100644 --- a/src/dll/fuse3/fuse3.c +++ b/src/dll/fuse3/fuse3.c @@ -27,6 +27,17 @@ FSP_FUSE_API int fsp_fuse3_main_real(struct fsp_fuse_env *env, FSP_FUSE_API void fsp_fuse3_lib_help(struct fsp_fuse_env *env, struct fuse_args *args) { + char *helpargv[] = + { + "UNKNOWN", + "-h", + 0 + }; + struct fuse_args helpargs = FUSE_ARGS_INIT(2, helpargv); + struct fsp_fuse_core_opt_data opt_data; + + memset(&opt_data, 0, sizeof opt_data); + fsp_fuse_core_opt_parse(env, &helpargs, &opt_data, /*help=*/1); } FSP_FUSE_API int fsp_fuse3_loop(struct fsp_fuse_env *env, From b537c61f3bb33542ba2fbda71f190c5d1f90a430 Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Thu, 19 Jul 2018 12:53:03 -0700 Subject: [PATCH 11/24] dll: fuse3: checkpoint --- inc/fuse3/fuse_common.h | 2 +- src/dll/fuse3/fuse3.c | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/inc/fuse3/fuse_common.h b/inc/fuse3/fuse_common.h index cac1d8ab..ab38644f 100644 --- a/inc/fuse3/fuse_common.h +++ b/inc/fuse3/fuse_common.h @@ -143,7 +143,7 @@ struct fuse3_session; struct fuse3_pollhandle; struct fuse3_conn_info_opts; -FSP_FUSE_API struct fuse3_conn_info_opts* FSP_FUSE_API_NAME(fsp_fuse3_parse_conn_info_opts)( +FSP_FUSE_API struct fuse3_conn_info_opts *FSP_FUSE_API_NAME(fsp_fuse3_parse_conn_info_opts)( struct fsp_fuse_env *env, struct fuse_args *args); FSP_FUSE_API void FSP_FUSE_API_NAME(fsp_fuse3_apply_conn_info_opts)(struct fsp_fuse_env *env, diff --git a/src/dll/fuse3/fuse3.c b/src/dll/fuse3/fuse3.c index be110b0d..3ad995bb 100644 --- a/src/dll/fuse3/fuse3.c +++ b/src/dll/fuse3/fuse3.c @@ -75,11 +75,12 @@ FSP_FUSE_API struct fuse3_context *fsp_fuse3_get_context(struct fsp_fuse_env *en return (struct fuse3_context *)fsp_fuse_get_context(env); } -FSP_FUSE_API struct fuse3_conn_info_opts* fsp_fuse3_parse_conn_info_opts( +FSP_FUSE_API struct fuse3_conn_info_opts *fsp_fuse3_parse_conn_info_opts( struct fsp_fuse_env *env, struct fuse_args *args) { - return 0; + static int dummy; + return (struct fuse3_conn_info_opts *)&dummy; } FSP_FUSE_API void fsp_fuse3_apply_conn_info_opts(struct fsp_fuse_env *env, From 575fe55eb88caa2ff8291d923ba03481edee7895 Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Thu, 19 Jul 2018 14:24:09 -0700 Subject: [PATCH 12/24] dll: fuse3: fsp_fuse3_main_real --- src/dll/fuse3/fuse3.c | 53 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/src/dll/fuse3/fuse3.c b/src/dll/fuse3/fuse3.c index 3ad995bb..5ddf8d65 100644 --- a/src/dll/fuse3/fuse3.c +++ b/src/dll/fuse3/fuse3.c @@ -21,7 +21,58 @@ FSP_FUSE_API int fsp_fuse3_main_real(struct fsp_fuse_env *env, int argc, char *argv[], const struct fuse3_operations *ops, size_t opsize, void *data) { - return 0; + struct fuse_args args = FUSE_ARGS_INIT(argc, argv); + char *mountpoint = 0; + int multithreaded = 0; + int foreground = 0; + struct fuse3 *f3 = 0; + int mounted = 0; + int signal_handlers = 0; + int result; + + result = fsp_fuse_parse_cmdline(env, &args, &mountpoint, &multithreaded, &foreground); + if (-1 == result) + goto exit; + + f3 = fsp_fuse3_new_30(env, &args, ops, opsize, data); + if (0 == f3) + { + result = -1; + goto exit; + } + + result = fsp_fuse3_mount(env, f3, mountpoint); + if (-1 == result) + goto exit; + mounted = 0; + + result = env->daemonize(foreground); + if (-1 == result) + goto exit; + + result = env->set_signal_handlers(f3); + if (-1 == result) + goto exit; + signal_handlers = 1; + + result = multithreaded ? fsp_fuse3_loop_mt(env, f3, 0) : fsp_fuse3_loop(env, f3); + +exit: + if (signal_handlers) + env->set_signal_handlers(0); + + if (mounted) + fsp_fuse3_unmount(env, f3); + + if (0 != f3) + fsp_fuse3_destroy(env, f3); + + env->memfree(mountpoint); + + fsp_fuse_opt_free_args(env, &args); + + /* main() style return: 0 success, 1 error */ + return !!result; } FSP_FUSE_API void fsp_fuse3_lib_help(struct fsp_fuse_env *env, From eb0f03b17b7e2d19d88839c1c832632db3235236 Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Fri, 20 Jul 2018 09:24:22 -0700 Subject: [PATCH 13/24] build: fuse3: installer and pkg-config --- build/VStudio/installer/Product.wxs | 40 ++++++++++++++++++++++++ build/VStudio/winfsp_dll.vcxproj | 23 ++++++++++++++ build/VStudio/winfsp_dll.vcxproj.filters | 3 ++ src/dll/fuse3/fuse3.pc.in | 10 ++++++ 4 files changed, 76 insertions(+) create mode 100644 src/dll/fuse3/fuse3.pc.in diff --git a/build/VStudio/installer/Product.wxs b/build/VStudio/installer/Product.wxs index 1722fdba..54e0e038 100644 --- a/build/VStudio/installer/Product.wxs +++ b/build/VStudio/installer/Product.wxs @@ -281,6 +281,20 @@ + + + + + + + + + + + + + + @@ -309,6 +323,26 @@ KeyPath="yes" /> NOT VersionNT64 + + + + + VersionNT64 + + + + + + NOT VersionNT64 + @@ -493,12 +527,18 @@ + + + + + + diff --git a/build/VStudio/winfsp_dll.vcxproj b/build/VStudio/winfsp_dll.vcxproj index d5361b80..2d3b60bf 100644 --- a/build/VStudio/winfsp_dll.vcxproj +++ b/build/VStudio/winfsp_dll.vcxproj @@ -86,6 +86,29 @@ copy /b $(OutDir)fuse-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse-$(Platfor $(OutDir)fuse-$(PlatformTarget).pc false + + Document + echo arch=$(PlatformTarget) >$(OutDir)fuse3-$(PlatformTarget).pc +copy /b $(OutDir)fuse3-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse3-$(PlatformTarget).pc >nul + echo arch=$(PlatformTarget) >$(OutDir)fuse3-$(PlatformTarget).pc +copy /b $(OutDir)fuse3-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse3-$(PlatformTarget).pc >nul + echo arch=$(PlatformTarget) >$(OutDir)fuse3-$(PlatformTarget).pc +copy /b $(OutDir)fuse3-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse3-$(PlatformTarget).pc >nul + echo arch=$(PlatformTarget) >$(OutDir)fuse3-$(PlatformTarget).pc +copy /b $(OutDir)fuse3-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse3-$(PlatformTarget).pc >nul + Writing fuse3-$(PlatformTarget).pc + Writing fuse3-$(PlatformTarget).pc + Writing fuse3-$(PlatformTarget).pc + Writing fuse3-$(PlatformTarget).pc + $(OutDir)fuse3-$(PlatformTarget).pc + $(OutDir)fuse3-$(PlatformTarget).pc + $(OutDir)fuse3-$(PlatformTarget).pc + $(OutDir)fuse3-$(PlatformTarget).pc + false + false + false + false + diff --git a/build/VStudio/winfsp_dll.vcxproj.filters b/build/VStudio/winfsp_dll.vcxproj.filters index db769319..42c785ce 100644 --- a/build/VStudio/winfsp_dll.vcxproj.filters +++ b/build/VStudio/winfsp_dll.vcxproj.filters @@ -166,5 +166,8 @@ Source\fuse + + Source\fuse3 + \ No newline at end of file diff --git a/src/dll/fuse3/fuse3.pc.in b/src/dll/fuse3/fuse3.pc.in new file mode 100644 index 00000000..0e52f9a2 --- /dev/null +++ b/src/dll/fuse3/fuse3.pc.in @@ -0,0 +1,10 @@ +prefix=${pcfiledir}/.. +incdir=${prefix}/inc/fuse3 +implib=${prefix}/bin/winfsp-${arch}.dll + +Name: fuse3 +Description: WinFsp FUSE3 compatible API +Version: 3.2 +URL: http://www.secfs.net/winfsp/ +Libs: "${implib}" +Cflags: -I"${incdir}" From d43c0c2c85b7e3650a48c9a50adf16161ca4eb54 Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Fri, 20 Jul 2018 09:37:59 -0700 Subject: [PATCH 14/24] inc: fuse3: fix warnings --- inc/fuse3/fuse_common.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/inc/fuse3/fuse_common.h b/inc/fuse3/fuse_common.h index ab38644f..d8f9525a 100644 --- a/inc/fuse3/fuse_common.h +++ b/inc/fuse3/fuse_common.h @@ -192,6 +192,7 @@ void fuse3_pollhandle_destroy(struct fuse3_pollhandle *ph), FSP_FUSE_SYM( size_t fuse3_buf_size(const struct fuse3_bufvec *bufv), { + (void)bufv; return 0; }) @@ -199,6 +200,9 @@ FSP_FUSE_SYM( ssize_t fuse3_buf_copy(struct fuse3_bufvec *dst, struct fuse3_bufvec *src, enum fuse3_buf_copy_flags flags), { + (void)dst; + (void)src; + (void)flags; return 0; }) From 2ff21529d5cec6ef3ce63d28b8ea2b93e5736016 Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Fri, 20 Jul 2018 14:48:25 -0700 Subject: [PATCH 15/24] tst: passthrough-fuse3 --- tst/passthrough-fuse3/.gitignore | 7 + tst/passthrough-fuse3/Makefile | 18 + tst/passthrough-fuse3/README.md | 7 + tst/passthrough-fuse3/passthrough-fuse3.c | 331 +++++++++ tst/passthrough-fuse3/passthrough-fuse3.sln | 28 + .../passthrough-fuse3.vcxproj | 190 ++++++ .../passthrough-fuse3.vcxproj.filters | 21 + tst/passthrough-fuse3/winposix.c | 634 ++++++++++++++++++ tst/passthrough-fuse3/winposix.h | 77 +++ 9 files changed, 1313 insertions(+) create mode 100644 tst/passthrough-fuse3/.gitignore create mode 100644 tst/passthrough-fuse3/Makefile create mode 100644 tst/passthrough-fuse3/README.md create mode 100644 tst/passthrough-fuse3/passthrough-fuse3.c create mode 100644 tst/passthrough-fuse3/passthrough-fuse3.sln create mode 100644 tst/passthrough-fuse3/passthrough-fuse3.vcxproj create mode 100644 tst/passthrough-fuse3/passthrough-fuse3.vcxproj.filters create mode 100644 tst/passthrough-fuse3/winposix.c create mode 100644 tst/passthrough-fuse3/winposix.h diff --git a/tst/passthrough-fuse3/.gitignore b/tst/passthrough-fuse3/.gitignore new file mode 100644 index 00000000..e7b44729 --- /dev/null +++ b/tst/passthrough-fuse3/.gitignore @@ -0,0 +1,7 @@ +build +*.ncb +*.suo +*.vcproj.* +*.vcxproj.user +*.exe +*.install diff --git a/tst/passthrough-fuse3/Makefile b/tst/passthrough-fuse3/Makefile new file mode 100644 index 00000000..e729a044 --- /dev/null +++ b/tst/passthrough-fuse3/Makefile @@ -0,0 +1,18 @@ +usage: + @echo "make cygfuse3|winfsp-fuse3" 1>&2 + @echo "" 1>&2 + @echo " cygfuse3 Link with CYGFUSE3" 1>&2 + @echo " winfsp-fuse3 Link with WinFsp-FUSE3" 1>&2 + @exit 2 + +cygfuse3: passthrough-cygfuse3 + +winfsp-fuse3: passthrough-winfsp-fuse3 + +passthrough-cygfuse3: passthrough-fuse3.c + gcc $^ -o $@ -g -Wall `pkg-config fuse3 --cflags --libs` + +passthrough-winfsp-fuse3: export PKG_CONFIG_PATH=$(PWD)/winfsp.install/lib +passthrough-winfsp-fuse3: passthrough-fuse3.c + ln -nsf "`regtool --wow32 get '/HKLM/Software/WinFsp/InstallDir' | cygpath -au -f -`" winfsp.install + gcc $^ -o $@ -g -Wall `pkg-config fuse3 --cflags --libs` diff --git a/tst/passthrough-fuse3/README.md b/tst/passthrough-fuse3/README.md new file mode 100644 index 00000000..3cf08b70 --- /dev/null +++ b/tst/passthrough-fuse3/README.md @@ -0,0 +1,7 @@ +`Passthrough-fuse3` is a simple FUSE3 file system that passes all file system operations to an underlying file system. + +It can be built with the following tools: + +- Using Visual Studio (`winfsp.sln`). +- Using Cygwin GCC and linking directly with the WinFsp DLL (`make winfsp-fuse3`). +- Using Cygwin GCC and linking to CYGFUSE3 (`make cygfuse3`). diff --git a/tst/passthrough-fuse3/passthrough-fuse3.c b/tst/passthrough-fuse3/passthrough-fuse3.c new file mode 100644 index 00000000..aa72b746 --- /dev/null +++ b/tst/passthrough-fuse3/passthrough-fuse3.c @@ -0,0 +1,331 @@ +/** + * @file passthrough-fuse.c + * + * @copyright 2015-2018 Bill Zissimopoulos + */ +/* + * This file is part of WinFsp. + * + * You can redistribute it and/or modify it under the terms of the GNU + * General Public License version 3 as published by the Free Software + * Foundation. + * + * Licensees holding a valid commercial license may use this file in + * accordance with the commercial license agreement provided with the + * software. + */ + +#include +#include +#include +#include +#include + +#include + +#if defined(_WIN64) || defined(_WIN32) +#include "winposix.h" +#else +#include +#include +#endif + +#define FSNAME "passthrough" +#define PROGNAME "passthrough-fuse" + +#define concat_path(ptfs, fn, fp) (sizeof fp > (unsigned)snprintf(fp, sizeof fp, "%s%s", ptfs->rootdir, fn)) + +#define fi_dirbit (0x8000000000000000ULL) +#define fi_fh(fi, MASK) ((fi)->fh & (MASK)) +#define fi_setfh(fi, FH, MASK) ((fi)->fh = (intptr_t)(FH) | (MASK)) +#define fi_fd(fi) (fi_fh(fi, fi_dirbit) ? \ + dirfd((DIR *)(intptr_t)fi_fh(fi, ~fi_dirbit)) : (int)fi_fh(fi, ~fi_dirbit)) +#define fi_dirp(fi) ((DIR *)(intptr_t)fi_fh(fi, ~fi_dirbit)) +#define fi_setfd(fi, fd) (fi_setfh(fi, fd, 0)) +#define fi_setdirp(fi, dirp) (fi_setfh(fi, dirp, fi_dirbit)) + +#define ptfs_impl_fullpath(n) \ + char full ## n[PATH_MAX]; \ + if (!concat_path(((PTFS *)fuse_get_context()->private_data), n, full ## n))\ + return -ENAMETOOLONG; \ + n = full ## n + +typedef struct +{ + const char *rootdir; +} PTFS; + +static int ptfs_getattr(const char *path, struct fuse_stat *stbuf, struct fuse_file_info *fi) +{ + if (0 == fi) + { + ptfs_impl_fullpath(path); + + return -1 != lstat(path, stbuf) ? 0 : -errno; + } + else + { + int fd = fi_fd(fi); + + return -1 != fstat(fd, stbuf) ? 0 : -errno; + } +} + +static int ptfs_mkdir(const char *path, fuse_mode_t mode) +{ + ptfs_impl_fullpath(path); + + return -1 != mkdir(path, mode) ? 0 : -errno; +} + +static int ptfs_unlink(const char *path) +{ + ptfs_impl_fullpath(path); + + return -1 != unlink(path) ? 0 : -errno; +} + +static int ptfs_rmdir(const char *path) +{ + ptfs_impl_fullpath(path); + + return -1 != rmdir(path) ? 0 : -errno; +} + +static int ptfs_rename(const char *oldpath, const char *newpath, unsigned int flags) +{ + ptfs_impl_fullpath(newpath); + ptfs_impl_fullpath(oldpath); + + return -1 != rename(oldpath, newpath) ? 0 : -errno; +} + +static int ptfs_chmod(const char *path, fuse_mode_t mode, struct fuse_file_info *fi) +{ + ptfs_impl_fullpath(path); + + return -1 != chmod(path, mode) ? 0 : -errno; +} + +static int ptfs_chown(const char *path, fuse_uid_t uid, fuse_gid_t gid, struct fuse_file_info *fi) +{ + ptfs_impl_fullpath(path); + + return -1 != lchown(path, uid, gid) ? 0 : -errno; +} + +static int ptfs_truncate(const char *path, fuse_off_t size, struct fuse_file_info *fi) +{ + if (0 == fi) + { + ptfs_impl_fullpath(path); + + return -1 != truncate(path, size) ? 0 : -errno; + } + else + { + int fd = fi_fd(fi); + + return -1 != ftruncate(fd, size) ? 0 : -errno; + } +} + +static int ptfs_open(const char *path, struct fuse_file_info *fi) +{ + ptfs_impl_fullpath(path); + + int fd; + return -1 != (fd = open(path, fi->flags)) ? (fi_setfd(fi, fd), 0) : -errno; +} + +static int ptfs_read(const char *path, char *buf, size_t size, fuse_off_t off, + struct fuse_file_info *fi) +{ + int fd = fi_fd(fi); + + int nb; + return -1 != (nb = pread(fd, buf, size, off)) ? nb : -errno; +} + +static int ptfs_write(const char *path, const char *buf, size_t size, fuse_off_t off, + struct fuse_file_info *fi) +{ + int fd = fi_fd(fi); + + int nb; + return -1 != (nb = pwrite(fd, buf, size, off)) ? nb : -errno; +} + +static int ptfs_statfs(const char *path, struct fuse_statvfs *stbuf) +{ + ptfs_impl_fullpath(path); + + return -1 != statvfs(path, stbuf) ? 0 : -errno; +} + +static int ptfs_release(const char *path, struct fuse_file_info *fi) +{ + int fd = fi_fd(fi); + + close(fd); + return 0; +} + +static int ptfs_fsync(const char *path, int datasync, struct fuse_file_info *fi) +{ + int fd = fi_fd(fi); + + return -1 != fsync(fd) ? 0 : -errno; +} + +static int ptfs_opendir(const char *path, struct fuse_file_info *fi) +{ + ptfs_impl_fullpath(path); + + DIR *dirp; + return 0 != (dirp = opendir(path)) ? (fi_setdirp(fi, dirp), 0) : -errno; +} + +static int ptfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, fuse_off_t off, + struct fuse_file_info *fi, enum fuse_readdir_flags flags) +{ + DIR *dirp = fi_dirp(fi); + struct dirent *de; + + rewinddir(dirp); + for (;;) + { + errno = 0; + if (0 == (de = readdir(dirp))) + break; +#if defined(_WIN64) || defined(_WIN32) + if (0 != filler(buf, de->d_name, &de->d_stat, 0, FUSE_FILL_DIR_PLUS)) +#else + if (0 != filler(buf, de->d_name, 0, 0, 0)) +#endif + return -ENOMEM; + } + + return -errno; +} + +static int ptfs_releasedir(const char *path, struct fuse_file_info *fi) +{ + DIR *dirp = fi_dirp(fi); + + return -1 != closedir(dirp) ? 0 : -errno; +} + +static void *ptfs_init(struct fuse_conn_info *conn, struct fuse_config *conf) +{ + conn->want |= (conn->capable & FUSE_CAP_READDIRPLUS); + +#if defined(FSP_FUSE_CAP_CASE_INSENSITIVE) + conn->want |= (conn->capable & FSP_FUSE_CAP_CASE_INSENSITIVE); +#endif + + return fuse_get_context()->private_data; +} + +static int ptfs_create(const char *path, fuse_mode_t mode, struct fuse_file_info *fi) +{ + ptfs_impl_fullpath(path); + + int fd; + return -1 != (fd = open(path, fi->flags, mode)) ? (fi_setfd(fi, fd), 0) : -errno; +} + +static int ptfs_utimens(const char *path, const struct fuse_timespec tv[2], struct fuse_file_info *fi) +{ + ptfs_impl_fullpath(path); + + return -1 != utimensat(AT_FDCWD, path, tv, AT_SYMLINK_NOFOLLOW) ? 0 : -errno; +} + +static struct fuse_operations ptfs_ops = +{ + .getattr = ptfs_getattr, + .mkdir = ptfs_mkdir, + .unlink = ptfs_unlink, + .rmdir = ptfs_rmdir, + .rename = ptfs_rename, + .chmod = ptfs_chmod, + .chown = ptfs_chown, + .truncate = ptfs_truncate, + .open = ptfs_open, + .read = ptfs_read, + .write = ptfs_write, + .statfs = ptfs_statfs, + .release = ptfs_release, + .fsync = ptfs_fsync, + .opendir = ptfs_opendir, + .readdir = ptfs_readdir, + .releasedir = ptfs_releasedir, + .init = ptfs_init, + .create = ptfs_create, + .utimens = ptfs_utimens, +}; + +static void usage(void) +{ + fprintf(stderr, "usage: " PROGNAME " [FUSE options] rootdir mountpoint\n"); + exit(2); +} + +int main(int argc, char *argv[]) +{ + PTFS ptfs = { 0 }; + + if (3 <= argc && '-' != argv[argc - 2][0] && '-' != argv[argc - 1][0]) + { + ptfs.rootdir = realpath(argv[argc - 2], 0); /* memory freed at process end */ + argv[argc - 2] = argv[argc - 1]; + argc--; + } + +#if defined(_WIN64) || defined(_WIN32) + /* + * When building for Windows (rather than Cygwin or POSIX OS) + * allow the path to be specified using the --VolumePrefix + * switch using the syntax \\passthrough-fuse\C$\Path. This + * allows us to run the file system under the WinFsp.Launcher + * and start it using commands like: + * + * net use z: \\passthrough-fuse\C$\Path + */ + if (0 == ptfs.rootdir) + for (int argi = 1; argc > argi; argi++) + { + int strncmp(const char *a, const char *b, size_t length); + char *strchr(const char *s, int c); + char *p = 0; + + if (0 == strncmp("--UNC=", argv[argi], sizeof "--UNC=" - 1)) + p = argv[argi] + sizeof "--UNC=" - 1; + else if (0 == strncmp("--VolumePrefix=", argv[argi], sizeof "--VolumePrefix=" - 1)) + p = argv[argi] + sizeof "--VolumePrefix=" - 1; + + if (0 != p && '\\' != p[1]) + { + p = strchr(p + 1, '\\'); + if (0 != p && + ( + ('A' <= p[1] && p[1] <= 'Z') || + ('a' <= p[1] && p[1] <= 'z') + ) && + '$' == p[2]) + { + p[2] = ':'; + ptfs.rootdir = realpath(p + 1, 0); /* memory freed at process end */ + p[2] = '$'; + break; + } + } + } +#endif + + if (0 == ptfs.rootdir) + usage(); + + return fuse_main(argc, argv, &ptfs_ops, &ptfs); +} diff --git a/tst/passthrough-fuse3/passthrough-fuse3.sln b/tst/passthrough-fuse3/passthrough-fuse3.sln new file mode 100644 index 00000000..d562ff36 --- /dev/null +++ b/tst/passthrough-fuse3/passthrough-fuse3.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "passthrough-fuse3", "passthrough-fuse3.vcxproj", "{5E99498C-D30C-48EF-A04A-7977C0305FAC}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {5E99498C-D30C-48EF-A04A-7977C0305FAC}.Debug|x64.ActiveCfg = Debug|x64 + {5E99498C-D30C-48EF-A04A-7977C0305FAC}.Debug|x64.Build.0 = Debug|x64 + {5E99498C-D30C-48EF-A04A-7977C0305FAC}.Debug|x86.ActiveCfg = Debug|Win32 + {5E99498C-D30C-48EF-A04A-7977C0305FAC}.Debug|x86.Build.0 = Debug|Win32 + {5E99498C-D30C-48EF-A04A-7977C0305FAC}.Release|x64.ActiveCfg = Release|x64 + {5E99498C-D30C-48EF-A04A-7977C0305FAC}.Release|x64.Build.0 = Release|x64 + {5E99498C-D30C-48EF-A04A-7977C0305FAC}.Release|x86.ActiveCfg = Release|Win32 + {5E99498C-D30C-48EF-A04A-7977C0305FAC}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/tst/passthrough-fuse3/passthrough-fuse3.vcxproj b/tst/passthrough-fuse3/passthrough-fuse3.vcxproj new file mode 100644 index 00000000..b49187c0 --- /dev/null +++ b/tst/passthrough-fuse3/passthrough-fuse3.vcxproj @@ -0,0 +1,190 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {5E99498C-D30C-48EF-A04A-7977C0305FAC} + Win32Proj + passthroughfuse3 + 8.1 + + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)build\$(Configuration)\ + $(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\ + $(ProjectName)-$(PlatformTarget) + + + true + $(SolutionDir)build\$(Configuration)\ + $(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\ + $(ProjectName)-$(PlatformTarget) + + + false + $(SolutionDir)build\$(Configuration)\ + $(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\ + $(ProjectName)-$(PlatformTarget) + + + false + $(SolutionDir)build\$(Configuration)\ + $(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\ + $(ProjectName)-$(PlatformTarget) + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(MSBuildProgramFiles32)\WinFsp\inc\fuse3;$(MSBuildProgramFiles32)\WinFsp\inc + MultiThreaded + 4996 + + + Console + true + $(MSBuildProgramFiles32)\WinFsp\lib\winfsp-$(PlatformTarget).lib;%(AdditionalDependencies) + winfsp-$(PlatformTarget).dll + + + + + + + Level3 + Disabled + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(MSBuildProgramFiles32)\WinFsp\inc\fuse3;$(MSBuildProgramFiles32)\WinFsp\inc + MultiThreaded + 4996 + + + Console + true + $(MSBuildProgramFiles32)\WinFsp\lib\winfsp-$(PlatformTarget).lib;%(AdditionalDependencies) + winfsp-$(PlatformTarget).dll + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(MSBuildProgramFiles32)\WinFsp\inc\fuse3;$(MSBuildProgramFiles32)\WinFsp\inc + MultiThreaded + 4996 + + + Console + true + true + true + $(MSBuildProgramFiles32)\WinFsp\lib\winfsp-$(PlatformTarget).lib;%(AdditionalDependencies) + winfsp-$(PlatformTarget).dll + + + + + Level3 + + + MaxSpeed + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(MSBuildProgramFiles32)\WinFsp\inc\fuse3;$(MSBuildProgramFiles32)\WinFsp\inc + MultiThreaded + 4996 + + + Console + true + true + true + $(MSBuildProgramFiles32)\WinFsp\lib\winfsp-$(PlatformTarget).lib;%(AdditionalDependencies) + winfsp-$(PlatformTarget).dll + + + + + + + + + + + + + \ No newline at end of file diff --git a/tst/passthrough-fuse3/passthrough-fuse3.vcxproj.filters b/tst/passthrough-fuse3/passthrough-fuse3.vcxproj.filters new file mode 100644 index 00000000..63fc03d5 --- /dev/null +++ b/tst/passthrough-fuse3/passthrough-fuse3.vcxproj.filters @@ -0,0 +1,21 @@ + + + + + {bfbcc136-ea14-4445-8f9b-1fa7f8aedc71} + + + + + Source + + + Source + + + + + Source + + + \ No newline at end of file diff --git a/tst/passthrough-fuse3/winposix.c b/tst/passthrough-fuse3/winposix.c new file mode 100644 index 00000000..c4905670 --- /dev/null +++ b/tst/passthrough-fuse3/winposix.c @@ -0,0 +1,634 @@ +/** + * @file winposix.c + * + * @copyright 2015-2018 Bill Zissimopoulos + */ +/* + * This file is part of WinFsp. + * + * You can redistribute it and/or modify it under the terms of the GNU + * General Public License version 3 as published by the Free Software + * Foundation. + * + * Licensees holding a valid commercial license may use this file in + * accordance with the commercial license agreement provided with the + * software. + */ + +/* + * This is a very simple Windows POSIX layer. It handles all the POSIX + * file API's required to implement passthrough-fuse in POSIX, however + * the API handling is rather unsophisticated. + * + * Ways to improve it: use the FspPosix* API's to properly handle + * file names and security. + */ + +#include +#include +#include +#include "winposix.h" + +struct _DIR +{ + HANDLE h, fh; + struct dirent de; + char path[]; +}; + +#if defined(FSP_FUSE_USE_STAT_EX) +static inline uint32_t MapFileAttributesToFlags(UINT32 FileAttributes) +{ + uint32_t flags = 0; + + if (FileAttributes & FILE_ATTRIBUTE_READONLY) + flags |= FSP_FUSE_UF_READONLY; + if (FileAttributes & FILE_ATTRIBUTE_HIDDEN) + flags |= FSP_FUSE_UF_HIDDEN; + if (FileAttributes & FILE_ATTRIBUTE_SYSTEM) + flags |= FSP_FUSE_UF_SYSTEM; + if (FileAttributes & FILE_ATTRIBUTE_ARCHIVE) + flags |= FSP_FUSE_UF_ARCHIVE; + + return flags; +} + +static inline UINT32 MapFlagsToFileAttributes(uint32_t flags) +{ + UINT32 FileAttributes = 0; + + if (flags & FSP_FUSE_UF_READONLY) + FileAttributes |= FILE_ATTRIBUTE_READONLY; + if (flags & FSP_FUSE_UF_HIDDEN) + FileAttributes |= FILE_ATTRIBUTE_HIDDEN; + if (flags & FSP_FUSE_UF_SYSTEM) + FileAttributes |= FILE_ATTRIBUTE_SYSTEM; + if (flags & FSP_FUSE_UF_ARCHIVE) + FileAttributes |= FILE_ATTRIBUTE_ARCHIVE; + + return FileAttributes; +} +#endif + +static int maperror(int winerrno); + +static inline void *error0(void) +{ + errno = maperror(GetLastError()); + return 0; +} + +static inline int error(void) +{ + errno = maperror(GetLastError()); + return -1; +} + +char *realpath(const char *path, char *resolved) +{ + char *result; + + if (0 == resolved) + { + result = malloc(PATH_MAX); /* sets errno */ + if (0 == result) + return 0; + } + else + result = resolved; + + int err = 0; + DWORD len = GetFullPathNameA(path, PATH_MAX, result, 0); + if (0 == len) + err = GetLastError(); + else if (PATH_MAX < len) + err = ERROR_INVALID_PARAMETER; + + if (0 == err) + { + HANDLE h = CreateFileA(result, + FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + 0, + OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0); + if (INVALID_HANDLE_VALUE != h) + CloseHandle(h); + else + err = GetLastError(); + } + + if (0 != err) + { + if (result != resolved) + free(result); + + errno = maperror(err); + result = 0; + } + + return result; +} + +int statvfs(const char *path, struct fuse_statvfs *stbuf) +{ + char root[PATH_MAX]; + DWORD + VolumeSerialNumber, + MaxComponentLength, + SectorsPerCluster, + BytesPerSector, + NumberOfFreeClusters, + TotalNumberOfClusters; + + if (!GetVolumePathNameA(path, root, PATH_MAX) || + !GetVolumeInformationA(root, 0, 0, &VolumeSerialNumber, &MaxComponentLength, 0, 0, 0) || + !GetDiskFreeSpaceA(root, &SectorsPerCluster, &BytesPerSector, + &NumberOfFreeClusters, &TotalNumberOfClusters)) + { + return error(); + } + + memset(stbuf, 0, sizeof *stbuf); + stbuf->f_bsize = SectorsPerCluster * BytesPerSector; + stbuf->f_frsize = SectorsPerCluster * BytesPerSector; + stbuf->f_blocks = TotalNumberOfClusters; + stbuf->f_bfree = NumberOfFreeClusters; + stbuf->f_bavail = TotalNumberOfClusters; + stbuf->f_fsid = VolumeSerialNumber; + stbuf->f_namemax = MaxComponentLength; + + return 0; +} + +int open(const char *path, int oflag, ...) +{ + static DWORD da[] = { GENERIC_READ, GENERIC_WRITE, GENERIC_READ | GENERIC_WRITE, 0 }; + static DWORD cd[] = { OPEN_EXISTING, OPEN_ALWAYS, TRUNCATE_EXISTING, CREATE_ALWAYS }; + DWORD DesiredAccess = 0 == (oflag & _O_APPEND) ? + da[oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR)] : + (da[oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR)] & ~FILE_WRITE_DATA) | FILE_APPEND_DATA; + DWORD CreationDisposition = (_O_CREAT | _O_EXCL) == (oflag & (_O_CREAT | _O_EXCL)) ? + CREATE_NEW : + cd[(oflag & (_O_CREAT | _O_TRUNC)) >> 8]; + + HANDLE h = CreateFileA(path, + DesiredAccess, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + 0/* default security */, + CreationDisposition, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, 0); + + if (INVALID_HANDLE_VALUE == h) + return error(); + + return (int)(intptr_t)h; +} + +int fstat(int fd, struct fuse_stat *stbuf) +{ + HANDLE h = (HANDLE)(intptr_t)fd; + BY_HANDLE_FILE_INFORMATION FileInfo; + + if (!GetFileInformationByHandle(h, &FileInfo)) + return error(); + + memset(stbuf, 0, sizeof *stbuf); + stbuf->st_mode = 0777 | + ((FileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? 0040000/* S_IFDIR */ : 0); + stbuf->st_nlink = 1; + stbuf->st_size = ((UINT64)FileInfo.nFileSizeHigh << 32) | ((UINT64)FileInfo.nFileSizeLow); + FspPosixFileTimeToUnixTime(*(PUINT64)&FileInfo.ftCreationTime, (void *)&stbuf->st_birthtim); + FspPosixFileTimeToUnixTime(*(PUINT64)&FileInfo.ftLastAccessTime, (void *)&stbuf->st_atim); + FspPosixFileTimeToUnixTime(*(PUINT64)&FileInfo.ftLastWriteTime, (void *)&stbuf->st_mtim); + FspPosixFileTimeToUnixTime(*(PUINT64)&FileInfo.ftLastWriteTime, (void *)&stbuf->st_ctim); +#if defined(FSP_FUSE_USE_STAT_EX) + stbuf->st_flags = MapFileAttributesToFlags(FileInfo.dwFileAttributes); +#endif + + return 0; +} + +int ftruncate(int fd, fuse_off_t size) +{ + HANDLE h = (HANDLE)(intptr_t)fd; + FILE_END_OF_FILE_INFO EndOfFileInfo; + + EndOfFileInfo.EndOfFile.QuadPart = size; + + if (!SetFileInformationByHandle(h, FileEndOfFileInfo, &EndOfFileInfo, sizeof EndOfFileInfo)) + return error(); + + return 0; +} + +int pread(int fd, void *buf, size_t nbyte, fuse_off_t offset) +{ + HANDLE h = (HANDLE)(intptr_t)fd; + OVERLAPPED Overlapped = { 0 }; + DWORD BytesTransferred; + + Overlapped.Offset = (DWORD)offset; + Overlapped.OffsetHigh = (DWORD)(offset >> 32); + + if (!ReadFile(h, buf, (DWORD)nbyte, &BytesTransferred, &Overlapped)) + { + if (ERROR_HANDLE_EOF == GetLastError()) + return 0; + return error(); + } + + return BytesTransferred; +} + +int pwrite(int fd, const void *buf, size_t nbyte, fuse_off_t offset) +{ + HANDLE h = (HANDLE)(intptr_t)fd; + OVERLAPPED Overlapped = { 0 }; + DWORD BytesTransferred; + + Overlapped.Offset = (DWORD)offset; + Overlapped.OffsetHigh = (DWORD)(offset >> 32); + + if (!WriteFile(h, buf, (DWORD)nbyte, &BytesTransferred, &Overlapped)) + return error(); + + return BytesTransferred; +} + +int fsync(int fd) +{ + HANDLE h = (HANDLE)(intptr_t)fd; + + if (!FlushFileBuffers(h)) + return error(); + + return 0; +} + +int close(int fd) +{ + HANDLE h = (HANDLE)(intptr_t)fd; + + if (!CloseHandle(h)) + return error(); + + return 0; +} + +int lstat(const char *path, struct fuse_stat *stbuf) +{ + HANDLE h = CreateFileA(path, + FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + 0, + OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0); + if (INVALID_HANDLE_VALUE == h) + return error(); + + int res = fstat((int)(intptr_t)h, stbuf); + + CloseHandle(h); + + return res; +} + +int chmod(const char *path, fuse_mode_t mode) +{ + /* we do not support file security */ + return 0; +} + +int lchown(const char *path, fuse_uid_t uid, fuse_gid_t gid) +{ + /* we do not support file security */ + return 0; +} + +int lchflags(const char *path, uint32_t flags) +{ +#if defined(FSP_FUSE_USE_STAT_EX) + UINT32 FileAttributes = MapFlagsToFileAttributes(flags); + + if (0 == FileAttributes) + FileAttributes = FILE_ATTRIBUTE_NORMAL; + + if (!SetFileAttributesA(path, FileAttributes)) + return error(); +#endif + + return 0; +} + +int truncate(const char *path, fuse_off_t size) +{ + HANDLE h = CreateFileA(path, + FILE_WRITE_DATA, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + 0, + OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0); + if (INVALID_HANDLE_VALUE == h) + return error(); + + int res = ftruncate((int)(intptr_t)h, size); + + CloseHandle(h); + + return res; +} + +int utime(const char *path, const struct fuse_utimbuf *timbuf) +{ + if (0 == timbuf) + return utimensat(AT_FDCWD, path, 0, AT_SYMLINK_NOFOLLOW); + else + { + struct fuse_timespec times[2]; + times[0].tv_sec = timbuf->actime; + times[0].tv_nsec = 0; + times[1].tv_sec = timbuf->modtime; + times[1].tv_nsec = 0; + return utimensat(AT_FDCWD, path, times, AT_SYMLINK_NOFOLLOW); + } +} + +int utimensat(int dirfd, const char *path, const struct fuse_timespec times[2], int flag) +{ + /* ignore dirfd and assume that it is always AT_FDCWD */ + /* ignore flag and assume that it is always AT_SYMLINK_NOFOLLOW */ + + HANDLE h = CreateFileA(path, + FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + 0, + OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0); + if (INVALID_HANDLE_VALUE == h) + return error(); + + UINT64 LastAccessTime, LastWriteTime; + if (0 == times) + { + FILETIME FileTime; + GetSystemTimeAsFileTime(&FileTime); + LastAccessTime = LastWriteTime = *(PUINT64)&FileTime; + } + else + { + FspPosixUnixTimeToFileTime((void *)×[0], &LastAccessTime); + FspPosixUnixTimeToFileTime((void *)×[1], &LastWriteTime); + } + + int res = SetFileTime(h, + 0, (PFILETIME)&LastAccessTime, (PFILETIME)&LastWriteTime) ? 0 : error(); + + CloseHandle(h); + + return res; +} + +int setcrtime(const char *path, const struct fuse_timespec *tv) +{ + HANDLE h = CreateFileA(path, + FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + 0, + OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0); + if (INVALID_HANDLE_VALUE == h) + return error(); + + UINT64 CreationTime; + FspPosixUnixTimeToFileTime((void *)tv, &CreationTime); + + int res = SetFileTime(h, + (PFILETIME)&CreationTime, 0, 0) ? 0 : error(); + + CloseHandle(h); + + return res; +} + +int unlink(const char *path) +{ + if (!DeleteFileA(path)) + return error(); + + return 0; +} + +int rename(const char *oldpath, const char *newpath) +{ + if (!MoveFileExA(oldpath, newpath, MOVEFILE_REPLACE_EXISTING)) + return error(); + + return 0; +} + +int mkdir(const char *path, fuse_mode_t mode) +{ + if (!CreateDirectoryA(path, 0/* default security */)) + return error(); + + return 0; +} + +int rmdir(const char *path) +{ + if (!RemoveDirectoryA(path)) + return error(); + + return 0; +} + +DIR *opendir(const char *path) +{ + HANDLE h = CreateFileA(path, + FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + 0, + OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0); + if (INVALID_HANDLE_VALUE == h) + return error0(); + + size_t pathlen = strlen(path); + if (0 < pathlen && '/' == path[pathlen - 1]) + pathlen--; + + DIR *dirp = malloc(sizeof *dirp + pathlen + 3); /* sets errno */ + if (0 == dirp) + { + CloseHandle(h); + return 0; + } + + memset(dirp, 0, sizeof *dirp); + dirp->h = h; + dirp->fh = INVALID_HANDLE_VALUE; + memcpy(dirp->path, path, pathlen); + dirp->path[pathlen + 0] = '/'; + dirp->path[pathlen + 1] = '*'; + dirp->path[pathlen + 2] = '\0'; + + return dirp; +} + +int dirfd(DIR *dirp) +{ + return (int)(intptr_t)dirp->h; +} + +void rewinddir(DIR *dirp) +{ + if (INVALID_HANDLE_VALUE != dirp->fh) + { + FindClose(dirp->fh); + dirp->fh = INVALID_HANDLE_VALUE; + } +} + +struct dirent *readdir(DIR *dirp) +{ + WIN32_FIND_DATAA FindData; + struct fuse_stat *stbuf = &dirp->de.d_stat; + + if (INVALID_HANDLE_VALUE == dirp->fh) + { + dirp->fh = FindFirstFileA(dirp->path, &FindData); + if (INVALID_HANDLE_VALUE == dirp->fh) + return error0(); + } + else + { + if (!FindNextFileA(dirp->fh, &FindData)) + { + if (ERROR_NO_MORE_FILES == GetLastError()) + return 0; + return error0(); + } + } + + memset(stbuf, 0, sizeof *stbuf); + stbuf->st_mode = 0777 | + ((FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? 0040000/* S_IFDIR */ : 0); + stbuf->st_nlink = 1; + stbuf->st_size = ((UINT64)FindData.nFileSizeHigh << 32) | ((UINT64)FindData.nFileSizeLow); + FspPosixFileTimeToUnixTime(*(PUINT64)&FindData.ftCreationTime, (void *)&stbuf->st_birthtim); + FspPosixFileTimeToUnixTime(*(PUINT64)&FindData.ftLastAccessTime, (void *)&stbuf->st_atim); + FspPosixFileTimeToUnixTime(*(PUINT64)&FindData.ftLastWriteTime, (void *)&stbuf->st_mtim); + FspPosixFileTimeToUnixTime(*(PUINT64)&FindData.ftLastWriteTime, (void *)&stbuf->st_ctim); +#if defined(FSP_FUSE_USE_STAT_EX) + stbuf->st_flags = MapFileAttributesToFlags(FindData.dwFileAttributes); +#endif + + strcpy(dirp->de.d_name, FindData.cFileName); + + return &dirp->de; +} + +int closedir(DIR *dirp) +{ + if (INVALID_HANDLE_VALUE != dirp->fh) + FindClose(dirp->fh); + + CloseHandle(dirp->h); + free(dirp); + + return 0; +} + +static int maperror(int winerrno) +{ + switch (winerrno) + { + case ERROR_INVALID_FUNCTION: + return EINVAL; + case ERROR_FILE_NOT_FOUND: + return ENOENT; + case ERROR_PATH_NOT_FOUND: + return ENOENT; + case ERROR_TOO_MANY_OPEN_FILES: + return EMFILE; + case ERROR_ACCESS_DENIED: + return EACCES; + case ERROR_INVALID_HANDLE: + return EBADF; + case ERROR_ARENA_TRASHED: + return ENOMEM; + case ERROR_NOT_ENOUGH_MEMORY: + return ENOMEM; + case ERROR_INVALID_BLOCK: + return ENOMEM; + case ERROR_BAD_ENVIRONMENT: + return E2BIG; + case ERROR_BAD_FORMAT: + return ENOEXEC; + case ERROR_INVALID_ACCESS: + return EINVAL; + case ERROR_INVALID_DATA: + return EINVAL; + case ERROR_INVALID_DRIVE: + return ENOENT; + case ERROR_CURRENT_DIRECTORY: + return EACCES; + case ERROR_NOT_SAME_DEVICE: + return EXDEV; + case ERROR_NO_MORE_FILES: + return ENOENT; + case ERROR_LOCK_VIOLATION: + return EACCES; + case ERROR_BAD_NETPATH: + return ENOENT; + case ERROR_NETWORK_ACCESS_DENIED: + return EACCES; + case ERROR_BAD_NET_NAME: + return ENOENT; + case ERROR_FILE_EXISTS: + return EEXIST; + case ERROR_CANNOT_MAKE: + return EACCES; + case ERROR_FAIL_I24: + return EACCES; + case ERROR_INVALID_PARAMETER: + return EINVAL; + case ERROR_NO_PROC_SLOTS: + return EAGAIN; + case ERROR_DRIVE_LOCKED: + return EACCES; + case ERROR_BROKEN_PIPE: + return EPIPE; + case ERROR_DISK_FULL: + return ENOSPC; + case ERROR_INVALID_TARGET_HANDLE: + return EBADF; + case ERROR_WAIT_NO_CHILDREN: + return ECHILD; + case ERROR_CHILD_NOT_COMPLETE: + return ECHILD; + case ERROR_DIRECT_ACCESS_HANDLE: + return EBADF; + case ERROR_NEGATIVE_SEEK: + return EINVAL; + case ERROR_SEEK_ON_DEVICE: + return EACCES; + case ERROR_DIR_NOT_EMPTY: + return ENOTEMPTY; + case ERROR_NOT_LOCKED: + return EACCES; + case ERROR_BAD_PATHNAME: + return ENOENT; + case ERROR_MAX_THRDS_REACHED: + return EAGAIN; + case ERROR_LOCK_FAILED: + return EACCES; + case ERROR_ALREADY_EXISTS: + return EEXIST; + case ERROR_FILENAME_EXCED_RANGE: + return ENOENT; + case ERROR_NESTING_NOT_ALLOWED: + return EAGAIN; + case ERROR_NOT_ENOUGH_QUOTA: + return ENOMEM; + default: + if (ERROR_WRITE_PROTECT <= winerrno && winerrno <= ERROR_SHARING_BUFFER_EXCEEDED) + return EACCES; + else if (ERROR_INVALID_STARTING_CODESEG <= winerrno && winerrno <= ERROR_INFLOOP_IN_RELOC_CHAIN) + return ENOEXEC; + else + return EINVAL; + } +} + +long WinFspLoad(void) +{ + return FspLoad(0); +} diff --git a/tst/passthrough-fuse3/winposix.h b/tst/passthrough-fuse3/winposix.h new file mode 100644 index 00000000..9f3e68f8 --- /dev/null +++ b/tst/passthrough-fuse3/winposix.h @@ -0,0 +1,77 @@ +/** + * @file winposix.h + * + * @copyright 2015-2018 Bill Zissimopoulos + */ +/* + * This file is part of WinFsp. + * + * You can redistribute it and/or modify it under the terms of the GNU + * General Public License version 3 as published by the Free Software + * Foundation. + * + * Licensees holding a valid commercial license may use this file in + * accordance with the commercial license agreement provided with the + * software. + */ + +#ifndef WINPOSIX_H_INCLUDED +#define WINPOSIX_H_INCLUDED + +#define O_RDONLY _O_RDONLY +#define O_WRONLY _O_WRONLY +#define O_RDWR _O_RDWR +#define O_APPEND _O_APPEND +#define O_CREAT _O_CREAT +#define O_EXCL _O_EXCL +#define O_TRUNC _O_TRUNC + +#define PATH_MAX 1024 +#define AT_FDCWD -2 +#define AT_SYMLINK_NOFOLLOW 2 + +typedef struct _DIR DIR; +struct dirent +{ + struct fuse_stat d_stat; + char d_name[255]; +}; + +char *realpath(const char *path, char *resolved); + +int statvfs(const char *path, struct fuse_statvfs *stbuf); + +int open(const char *path, int oflag, ...); +int fstat(int fd, struct fuse_stat *stbuf); +int ftruncate(int fd, fuse_off_t size); +int pread(int fd, void *buf, size_t nbyte, fuse_off_t offset); +int pwrite(int fd, const void *buf, size_t nbyte, fuse_off_t offset); +int fsync(int fd); +int close(int fd); + +int lstat(const char *path, struct fuse_stat *stbuf); +int chmod(const char *path, fuse_mode_t mode); +int lchown(const char *path, fuse_uid_t uid, fuse_gid_t gid); +int lchflags(const char *path, uint32_t flags); +int truncate(const char *path, fuse_off_t size); +int utime(const char *path, const struct fuse_utimbuf *timbuf); +int utimensat(int dirfd, const char *path, const struct fuse_timespec times[2], int flag); +int setcrtime(const char *path, const struct fuse_timespec *tv); +int unlink(const char *path); +int rename(const char *oldpath, const char *newpath); + +int mkdir(const char *path, fuse_mode_t mode); +int rmdir(const char *path); + +DIR *opendir(const char *path); +int dirfd(DIR *dirp); +void rewinddir(DIR *dirp); +struct dirent *readdir(DIR *dirp); +int closedir(DIR *dirp); + +long WinFspLoad(void); +#undef fuse_main +#define fuse_main(argc, argv, ops, data)\ + (WinFspLoad(), fuse_main_real(argc, argv, ops, sizeof *(ops), data)) + +#endif From 558487cd22f50b6234d502fe0c7c7ee873c5dcc4 Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Fri, 20 Jul 2018 15:12:22 -0700 Subject: [PATCH 16/24] installer: passthrough-fuse3 --- build/VStudio/installer/Product.wxs | 34 +++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/build/VStudio/installer/Product.wxs b/build/VStudio/installer/Product.wxs index 54e0e038..47daa725 100644 --- a/build/VStudio/installer/Product.wxs +++ b/build/VStudio/installer/Product.wxs @@ -449,6 +449,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -572,6 +598,14 @@ + + + + + + + + From ea5e031af280a6a37fe6a1aa09364db44d185663 Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Fri, 20 Jul 2018 15:17:47 -0700 Subject: [PATCH 17/24] changelog: add FUSE3 information --- Changelog.asciidoc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Changelog.asciidoc b/Changelog.asciidoc index 239cde22..29bf2d9f 100644 --- a/Changelog.asciidoc +++ b/Changelog.asciidoc @@ -5,9 +5,11 @@ v1.4B2 (2018.2 B2):: Changes since v1.3: +* New FUSE3 API support. FUSE version 3.2 is supported. * New `Control` file system operation allows sending custom control codes to the file system using the Windows `DeviceIoControl` API. * `FlushAndPurgeOnCleanup` has now been added to the .NET API. (GitHub PR #176; thanks @FrKaram.) * New sample file system "airfs" contributed by @JohnOberschelp. +* New sample file system "passthrough-fuse3" passes all operations to an underlying file system. This file system is built using the FUSE3 API. It builds and runs on both Windows and Cygwin. v1.4B1 (2018.2 B1):: From a809b0787e4a8b4af062cd90060e513559e0c145 Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Fri, 20 Jul 2018 15:34:31 -0700 Subject: [PATCH 18/24] changelog: add FUSE3 information --- Changelog.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Changelog.asciidoc b/Changelog.asciidoc index 29bf2d9f..e09dd9db 100644 --- a/Changelog.asciidoc +++ b/Changelog.asciidoc @@ -5,7 +5,7 @@ v1.4B2 (2018.2 B2):: Changes since v1.3: -* New FUSE3 API support. FUSE version 3.2 is supported. +* FUSE3 API (version 3.2) is now available. The FUSE2 API (version 2.8) remains also supported. * New `Control` file system operation allows sending custom control codes to the file system using the Windows `DeviceIoControl` API. * `FlushAndPurgeOnCleanup` has now been added to the .NET API. (GitHub PR #176; thanks @FrKaram.) * New sample file system "airfs" contributed by @JohnOberschelp. From 461266382ac9a937ade3f4be51680d8bc3b5005e Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Fri, 20 Jul 2018 15:35:12 -0700 Subject: [PATCH 19/24] changelog: add FUSE3 information --- Changelog.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Changelog.asciidoc b/Changelog.asciidoc index e09dd9db..36cd3412 100644 --- a/Changelog.asciidoc +++ b/Changelog.asciidoc @@ -5,7 +5,7 @@ v1.4B2 (2018.2 B2):: Changes since v1.3: -* FUSE3 API (version 3.2) is now available. The FUSE2 API (version 2.8) remains also supported. +* FUSE3 API (version 3.2) is now available. The FUSE2 API (version 2.8) also remains supported. * New `Control` file system operation allows sending custom control codes to the file system using the Windows `DeviceIoControl` API. * `FlushAndPurgeOnCleanup` has now been added to the .NET API. (GitHub PR #176; thanks @FrKaram.) * New sample file system "airfs" contributed by @JohnOberschelp. From 307e18fb0da04641b3eec24b9c72e5e51e78c71a Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Fri, 20 Jul 2018 15:44:10 -0700 Subject: [PATCH 20/24] update changelog --- Changelog.asciidoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Changelog.asciidoc b/Changelog.asciidoc index 36cd3412..8bc95d62 100644 --- a/Changelog.asciidoc +++ b/Changelog.asciidoc @@ -6,9 +6,9 @@ v1.4B2 (2018.2 B2):: Changes since v1.3: * FUSE3 API (version 3.2) is now available. The FUSE2 API (version 2.8) also remains supported. -* New `Control` file system operation allows sending custom control codes to the file system using the Windows `DeviceIoControl` API. +* New `Control` file system operation allows sending custom control codes to the file system using the Windows `DeviceIoControl` API. FUSE `ioctl` is also supported. * `FlushAndPurgeOnCleanup` has now been added to the .NET API. (GitHub PR #176; thanks @FrKaram.) -* New sample file system "airfs" contributed by @JohnOberschelp. +* New sample file system "airfs" contributed by @JohnOberschelp. Airfs is an in-memory file system like Memfs on which it is based on; it has received substantial improvements in how the file name space is maintained and has been modified to use modern C++ techniques by John. * New sample file system "passthrough-fuse3" passes all operations to an underlying file system. This file system is built using the FUSE3 API. It builds and runs on both Windows and Cygwin. From 6932d42039c2d32f87bf97b2855dfa680c2edaf1 Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Wed, 25 Jul 2018 08:54:22 -0700 Subject: [PATCH 21/24] dll: fuse3: testing --- src/dll/fuse3/fuse2to3.c | 5 +++-- src/dll/fuse3/fuse3.c | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/dll/fuse3/fuse2to3.c b/src/dll/fuse3/fuse2to3.c index b6a0b1f0..e5eee1de 100644 --- a/src/dll/fuse3/fuse2to3.c +++ b/src/dll/fuse3/fuse2to3.c @@ -56,7 +56,7 @@ static inline void fuse2to3_conn3from2(struct fuse3_conn_info *conn3, struct fus conn3->max_write = conn->max_write; conn3->max_read = conn->max_write; conn3->max_readahead = conn->max_readahead; - conn3->capable = conn->capable; + conn3->capable = (conn->capable & ~FSP_FUSE_CAP_READDIR_PLUS) | FUSE_CAP_READDIRPLUS; conn3->want = conn->want; } @@ -321,7 +321,8 @@ static void *fuse2to3_init(struct fuse_conn_info *conn) conn->max_write = conn3.max_write; conn->max_readahead = conn3.max_readahead; - conn->want = conn3.want; + conn->want = 0 != (conn3.want & FUSE_CAP_READDIRPLUS) ? FSP_FUSE_CAP_READDIR_PLUS : 0; + conn->want |= conn3.want & ~FUSE_CAP_READDIRPLUS; return res; } diff --git a/src/dll/fuse3/fuse3.c b/src/dll/fuse3/fuse3.c index 5ddf8d65..e58d39c7 100644 --- a/src/dll/fuse3/fuse3.c +++ b/src/dll/fuse3/fuse3.c @@ -44,7 +44,7 @@ FSP_FUSE_API int fsp_fuse3_main_real(struct fsp_fuse_env *env, result = fsp_fuse3_mount(env, f3, mountpoint); if (-1 == result) goto exit; - mounted = 0; + mounted = 1; result = env->daemonize(foreground); if (-1 == result) From 4a653a8bc060c56fd5446336ea6b55c512e5a64c Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Wed, 25 Jul 2018 10:04:23 -0700 Subject: [PATCH 22/24] dll: fuse3: testing --- src/dll/fuse/library.h | 2 +- src/dll/fuse3/fuse2to3.c | 10 ++++------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/dll/fuse/library.h b/src/dll/fuse/library.h index 8a40b055..c7b544cb 100644 --- a/src/dll/fuse/library.h +++ b/src/dll/fuse/library.h @@ -56,12 +56,12 @@ struct fuse FSP_FILE_SYSTEM *FileSystem; FSP_SERVICE *Service; /* weak */ volatile int exited; + struct fuse3 *fuse3; }; struct fsp_fuse_context_header { char *PosixPath; - struct fuse3 *fuse3; __declspec(align(MEMORY_ALLOCATION_ALIGNMENT)) UINT8 ContextBuf[]; }; diff --git a/src/dll/fuse3/fuse2to3.c b/src/dll/fuse3/fuse2to3.c index e5eee1de..ead8de3b 100644 --- a/src/dll/fuse3/fuse2to3.c +++ b/src/dll/fuse3/fuse2to3.c @@ -19,7 +19,7 @@ static inline struct fuse3 *fuse2to3_getfuse3(void) { - return FSP_FUSE_HDR_FROM_CONTEXT(fsp_fuse_get_context_internal())->fuse3; + return fsp_fuse_get_context_internal()->fuse->fuse3; } static inline void fuse2to3_fi2from3(struct fuse_file_info *fi, struct fuse3_file_info *fi3) @@ -280,11 +280,8 @@ static int fuse2to3_fsyncdir(const char *path, int datasync, struct fuse_file_in static void *fuse2to3_init(struct fuse_conn_info *conn) { struct fuse_context *context = fsp_fuse_get_context_internal(); - struct fuse3 *f3 = context->private_data; struct fuse *f = context->fuse; - - FSP_FUSE_HDR_FROM_CONTEXT(context)->fuse3 = f3; - context->private_data = f->data = f3->data; + struct fuse3 *f3 = f->fuse3; struct fuse3_conn_info conn3; fuse2to3_conn3from2(&conn3, conn); @@ -602,7 +599,7 @@ FSP_FUSE_API int fsp_fuse3_mount(struct fsp_fuse_env *env, if (0 == ch) goto fail; - f = fsp_fuse_new(env, ch, &f3->args, &fuse2to3_ops, sizeof fuse2to3_ops, f3); + f = fsp_fuse_new(env, ch, &f3->args, &fuse2to3_ops, sizeof fuse2to3_ops, f3->data); if (0 == f) goto fail; @@ -620,6 +617,7 @@ FSP_FUSE_API int fsp_fuse3_mount(struct fsp_fuse_env *env, /* Free the args which are no longer needed. */ fsp_fuse_opt_free_args(env, &f3->args); + f->fuse3 = f3; f3->fuse = f; return 0; From 0d819eb8002e031bb1a8f245fe37fac9a413d115 Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Wed, 25 Jul 2018 10:28:33 -0700 Subject: [PATCH 23/24] dll: fuse3: testing --- src/dll/fuse/fuse_intf.c | 3 ++- src/dll/fuse/library.h | 2 ++ src/dll/fuse3/fuse2to3.c | 20 ++++++++++++++++++-- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/dll/fuse/fuse_intf.c b/src/dll/fuse/fuse_intf.c index 084f7e55..c3fab0d5 100644 --- a/src/dll/fuse/fuse_intf.c +++ b/src/dll/fuse/fuse_intf.c @@ -1427,7 +1427,8 @@ static NTSTATUS fsp_fuse_intf_SetFileSize(FSP_FILE_SYSTEM *FileSystem, return STATUS_SUCCESS; } -static int fsp_fuse_intf_CanDeleteAddDirInfo(void *buf, const char *name, +/* !static: used by fuse2to3 */ +int fsp_fuse_intf_CanDeleteAddDirInfo(void *buf, const char *name, const struct fuse_stat *stbuf, fuse_off_t off) { struct fuse_dirhandle *dh = buf; diff --git a/src/dll/fuse/library.h b/src/dll/fuse/library.h index c7b544cb..03ef9c54 100644 --- a/src/dll/fuse/library.h +++ b/src/dll/fuse/library.h @@ -90,6 +90,8 @@ NTSTATUS fsp_fuse_op_enter(FSP_FILE_SYSTEM *FileSystem, NTSTATUS fsp_fuse_op_leave(FSP_FILE_SYSTEM *FileSystem, FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response); +int fsp_fuse_intf_CanDeleteAddDirInfo(void *buf, const char *name, + const struct fuse_stat *stbuf, fuse_off_t off); int fsp_fuse_intf_AddDirInfo(void *buf, const char *name, const struct fuse_stat *stbuf, fuse_off_t off); diff --git a/src/dll/fuse3/fuse2to3.c b/src/dll/fuse3/fuse2to3.c index ead8de3b..2ba6026f 100644 --- a/src/dll/fuse3/fuse2to3.c +++ b/src/dll/fuse3/fuse2to3.c @@ -235,6 +235,13 @@ static int fuse2to3_opendir(const char *path, struct fuse_file_info *fi) return res; } +static int fuse2to3_candel_filldir(void *buf, const char *name, + const struct fuse_stat *stbuf, fuse_off_t off, + enum fuse3_fill_dir_flags flags) +{ + return fsp_fuse_intf_CanDeleteAddDirInfo(buf, name, 0, off); +} + static int fuse2to3_filldir(void *buf, const char *name, const struct fuse_stat *stbuf, fuse_off_t off, enum fuse3_fill_dir_flags flags) @@ -251,8 +258,17 @@ static int fuse2to3_readdir(const char *path, void *buf, fuse_fill_dir_t filler, struct fuse_dirhandle *dh = buf; struct fuse3_file_info fi3; fuse2to3_fi3from2(&fi3, fi); - int res = f3->ops.readdir(path, buf, &fuse2to3_filldir, off, &fi3, - dh->ReaddirPlus ? FUSE_READDIR_PLUS : 0); + int res; + if (fsp_fuse_intf_CanDeleteAddDirInfo == filler) + res = f3->ops.readdir(path, buf, &fuse2to3_candel_filldir, off, &fi3, 0); + else if (fsp_fuse_intf_AddDirInfo == filler) + res = f3->ops.readdir(path, buf, &fuse2to3_filldir, off, &fi3, + dh->ReaddirPlus ? FUSE_READDIR_PLUS : 0); + else + { + FspDebugLog("fuse2to3_readdir = -ENOSYS (internal error: unknown filler)\n"); + res = -ENOSYS_(f3->fuse->env); + } fuse2to3_fi2from3(fi, &fi3); return res; } From cf699ba441e92cf3c546fe24e39eb3d7556d2d30 Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Wed, 25 Jul 2018 11:29:24 -0700 Subject: [PATCH 24/24] tools: run-tests: passthrough-fuse3 --- tools/run-tests.bat | 41 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/tools/run-tests.bat b/tools/run-tests.bat index 3646f2c6..d60275ed 100755 --- a/tools/run-tests.bat +++ b/tools/run-tests.bat @@ -83,6 +83,10 @@ set opt_tests=^ sample-fsx-passthrough-fuse-x64 ^ sample-passthrough-fuse-x86 ^ sample-fsx-passthrough-fuse-x86 ^ + sample-passthrough-fuse3-x64 ^ + sample-fsx-passthrough-fuse3-x64 ^ + sample-passthrough-fuse3-x86 ^ + sample-fsx-passthrough-fuse3-x86 ^ sample-passthrough-dotnet ^ compat-v1.2-memfs-x64 ^ compat-v1.2-memfs-x86 ^ @@ -707,6 +711,28 @@ call :__run_sample_fsx_fuse_test passthrough-fuse x86 passthrough-fuse-x86 fsx if !ERRORLEVEL! neq 0 goto fail exit /b 0 +:sample-passthrough-fuse3-x64 +call :__run_sample_fuse_test passthrough-fuse3 x64 passthrough-fuse3-x64 winfsp-tests-x64 ^ + "-create_fileattr_test -setfileinfo_test" +if !ERRORLEVEL! neq 0 goto fail +exit /b 0 + +:sample-passthrough-fuse3-x86 +call :__run_sample_fuse_test passthrough-fuse3 x86 passthrough-fuse3-x86 winfsp-tests-x86 ^ + "-create_fileattr_test -setfileinfo_test" +if !ERRORLEVEL! neq 0 goto fail +exit /b 0 + +:sample-fsx-passthrough-fuse3-x64 +call :__run_sample_fsx_fuse_test passthrough-fuse3 x64 passthrough-fuse3-x64 fsx +if !ERRORLEVEL! neq 0 goto fail +exit /b 0 + +:sample-fsx-passthrough-fuse3-x86 +call :__run_sample_fsx_fuse_test passthrough-fuse3 x86 passthrough-fuse3-x86 fsx +if !ERRORLEVEL! neq 0 goto fail +exit /b 0 + :__run_sample_disk_test set RunSampleTestExit=0 call %ProjRoot%\tools\build-sample %Configuration% %2 %1 "%TMP%\%1" @@ -784,11 +810,16 @@ 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%\%4.exe" ^ - --external --resilient --case-insensitive-cmp --share-prefix="\%1\%TMP::=$%\%1\test" ^ - -create_allocation_test -create_notraverse_test -create_backup_test -create_restore_test -create_namelen_test ^ - -getfileinfo_name_test -delete_access_test -delete_mmap_test -rename_flipflop_test -rename_mmap_test -setsecurity_test -querydir_namelen_test -exec_rename_dir_test ^ - -reparse* -stream* +if X%5==XNOEXCL ( + "%ProjRoot%\build\VStudio\build\%Configuration%\%4.exe" ^ + --external --resilient +) else ( + "%ProjRoot%\build\VStudio\build\%Configuration%\%4.exe" ^ + --external --resilient --case-insensitive-cmp --share-prefix="\%1\%TMP::=$%\%1\test" ^ + -create_allocation_test -create_notraverse_test -create_backup_test -create_restore_test -create_namelen_test ^ + -getfileinfo_name_test -delete_access_test -delete_mmap_test -rename_flipflop_test -rename_mmap_test -setsecurity_test -querydir_namelen_test -exec_rename_dir_test ^ + -reparse* -stream* %~5 +) if !ERRORLEVEL! neq 0 set RunSampleTestExit=1 popd echo net use L: /delete