From ab3f3d282752b60b240f013d72402276ff16a1fe Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Wed, 18 Jul 2018 04:11:20 -0700 Subject: [PATCH] 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 =