diff --git a/README.md b/README.md index 94fafb78..4784fff4 100644 --- a/README.md +++ b/README.md @@ -195,7 +195,7 @@ When using policies which are based on a branch's available space the base path | action | chmod, chown, link, removexattr, rename, rmdir, setxattr, truncate, unlink, utimens | | create | create, mkdir, mknod, symlink | | search | access, getattr, getxattr, ioctl (directories), listxattr, open, readlink | -| N/A | fchmod, fchown, futimens, ftruncate, fallocate, fgetattr, fsync, ioctl (files), read, readdir, release, statfs, write | +| N/A | fchmod, fchown, futimens, ftruncate, fallocate, fgetattr, fsync, ioctl (files), read, readdir, release, statfs, write, copy_file_range | In cases where something may be searched (to confirm a directory exists across all source mounts) **getattr** will be used. diff --git a/libfuse/include/fuse.h b/libfuse/include/fuse.h index 7b0ad013..c29effba 100644 --- a/libfuse/include/fuse.h +++ b/libfuse/include/fuse.h @@ -608,6 +608,30 @@ struct fuse_operations { */ int (*fallocate) (const char *, int, off_t, off_t, struct fuse_file_info *); + + /** + * Copy a range of data from one file to another + * + * Performs an optimized copy between two file descriptors without + * the + * additional cost of transferring data through the FUSE kernel + * module + * to user space (glibc) and then back into the FUSE filesystem + * again. + * + * In case this method is not implemented, glibc falls back to + * reading + * data from the source and writing to the destination. Effectively + * doing an inefficient copy of the data. + */ + ssize_t (*copy_file_range)(const char *path_in, + struct fuse_file_info *fi_in, + off_t offset_in, + const char *path_out, + struct fuse_file_info *fi_out, + off_t offset_out, + size_t size, + int flags); }; /** Extra context that may be needed by some filesystems @@ -923,6 +947,12 @@ void fuse_fs_destroy(struct fuse_fs *fs); int fuse_fs_prepare_hide(struct fuse_fs *fs, const char *path, uint64_t *fh); int fuse_fs_free_hide(struct fuse_fs *fs, uint64_t fh); +ssize_t fuse_fs_copy_file_range(struct fuse_fs *fs, + const char *path_in, + struct fuse_file_info *fi_in, off_t off_in, + const char *path_out, + struct fuse_file_info *fi_out, off_t off_out, + size_t len, int flags); int fuse_notify_poll(struct fuse_pollhandle *ph); diff --git a/libfuse/include/fuse_lowlevel.h b/libfuse/include/fuse_lowlevel.h index aa31d90e..f76faa32 100644 --- a/libfuse/include/fuse_lowlevel.h +++ b/libfuse/include/fuse_lowlevel.h @@ -1021,6 +1021,52 @@ struct fuse_lowlevel_ops { */ void (*fallocate) (fuse_req_t req, fuse_ino_t ino, int mode, off_t offset, off_t length, struct fuse_file_info *fi); + + /** + * Copy a range of data from one file to another + * + * Performs an optimized copy between two file descriptors without + * the + * additional cost of transferring data through the FUSE kernel + * module + * to user space (glibc) and then back into the FUSE filesystem + * again. + * + * In case this method is not implemented, glibc falls back to + * reading + * data from the source and writing to the destination. Effectively + * doing an inefficient copy of the data. + * + * If this request is answered with an error code of ENOSYS, this is + * treated as a permanent failure with error code EOPNOTSUPP, + * i.e. all + * future copy_file_range() requests will fail with EOPNOTSUPP + * without + * being send to the filesystem process. + * + * Valid replies: + * fuse_reply_write + * fuse_reply_err + * + * @param req request handle + * @param ino_in the inode number of the source file + * @param off_in starting point from were the data should be read + * @param fi_in file information of the source file + * @param ino_out the inode number of the destination file + * @param off_out starting point where the data should be written + * @param fi_out file information of the destination file + * @param len maximum size of the data to copy + * @param flags passed along with the copy_file_range() syscall + */ + void (*copy_file_range)(fuse_req_t req, + fuse_ino_t ino_in, + off_t off_in, + struct fuse_file_info *fi_in, + fuse_ino_t ino_out, + off_t off_out, + struct fuse_file_info *fi_out, + size_t len, + int flags); }; /** diff --git a/libfuse/lib/fuse.c b/libfuse/lib/fuse.c index 08da510f..d9c46eff 100644 --- a/libfuse/lib/fuse.c +++ b/libfuse/lib/fuse.c @@ -2296,7 +2296,32 @@ int fuse_fs_fallocate(struct fuse_fs *fs, const char *path, int mode, return -ENOSYS; } -static +ssize_t +fuse_fs_copy_file_range(struct fuse_fs *fs_, + const char *path_in_, + struct fuse_file_info *ffi_in_, + off_t off_in_, + const char *path_out_, + struct fuse_file_info *ffi_out_, + off_t off_out_, + size_t len_, + int flags_) +{ + fuse_get_context()->private_data = fs_->user_data; + + if(fs_->op.copy_file_range == NULL) + return -ENOSYS; + + return fs_->op.copy_file_range(path_in_, + ffi_in_, + off_in_, + path_out_, + ffi_out_, + off_out_, + len_, + flags_); +} + int node_open(const struct node *node_) { @@ -3675,6 +3700,61 @@ static void fuse_lib_removexattr(fuse_req_t req, fuse_ino_t ino, reply_err(req, err); } +static +void +fuse_lib_copy_file_range(fuse_req_t req_, + fuse_ino_t nodeid_in_, + off_t off_in_, + struct fuse_file_info *ffi_in_, + fuse_ino_t nodeid_out_, + off_t off_out_, + struct fuse_file_info *ffi_out_, + size_t len_, + int flags_) +{ + int err; + ssize_t rv; + char *path_in; + char *path_out; + struct fuse *f; + struct fuse_intr_data d; + + f = req_fuse_prepare(req_); + + err = get_path_nullok(f,nodeid_in_,&path_in); + if(err) + return reply_err(req_,err); + + err = get_path_nullok(f,nodeid_out_,&path_out); + if(err) + { + free_path(f,nodeid_in_,path_in); + return reply_err(req_,err); + } + + fuse_prepare_interrupt(f,req_,&d); + + rv = fuse_fs_copy_file_range(f->fs, + path_in, + ffi_in_, + off_in_, + path_out, + ffi_out_, + off_out_, + len_, + flags_); + + fuse_finish_interrupt(f,req_,&d); + + if(rv >= 0) + fuse_reply_write(req_,rv); + else + reply_err(req_,rv); + + free_path(f,nodeid_in_,path_in); + free_path(f,nodeid_out_,path_out); +} + static struct lock *locks_conflict(struct node *node, const struct lock *lock) { struct lock *l; @@ -4113,45 +4193,46 @@ int fuse_clean_cache(struct fuse *f) } static struct fuse_lowlevel_ops fuse_path_ops = { - .init = fuse_lib_init, - .destroy = fuse_lib_destroy, - .lookup = fuse_lib_lookup, - .forget = fuse_lib_forget, - .forget_multi = fuse_lib_forget_multi, - .getattr = fuse_lib_getattr, - .setattr = fuse_lib_setattr, - .access = fuse_lib_access, - .readlink = fuse_lib_readlink, - .mknod = fuse_lib_mknod, - .mkdir = fuse_lib_mkdir, - .unlink = fuse_lib_unlink, - .rmdir = fuse_lib_rmdir, - .symlink = fuse_lib_symlink, - .rename = fuse_lib_rename, - .link = fuse_lib_link, - .create = fuse_lib_create, - .open = fuse_lib_open, - .read = fuse_lib_read, - .write_buf = fuse_lib_write_buf, - .flush = fuse_lib_flush, - .release = fuse_lib_release, - .fsync = fuse_lib_fsync, - .opendir = fuse_lib_opendir, - .readdir = fuse_lib_readdir, - .releasedir = fuse_lib_releasedir, - .fsyncdir = fuse_lib_fsyncdir, - .statfs = fuse_lib_statfs, - .setxattr = fuse_lib_setxattr, - .getxattr = fuse_lib_getxattr, - .listxattr = fuse_lib_listxattr, - .removexattr = fuse_lib_removexattr, - .getlk = fuse_lib_getlk, - .setlk = fuse_lib_setlk, - .flock = fuse_lib_flock, - .bmap = fuse_lib_bmap, - .ioctl = fuse_lib_ioctl, - .poll = fuse_lib_poll, - .fallocate = fuse_lib_fallocate, + .init = fuse_lib_init, + .destroy = fuse_lib_destroy, + .lookup = fuse_lib_lookup, + .forget = fuse_lib_forget, + .forget_multi = fuse_lib_forget_multi, + .getattr = fuse_lib_getattr, + .setattr = fuse_lib_setattr, + .access = fuse_lib_access, + .readlink = fuse_lib_readlink, + .mknod = fuse_lib_mknod, + .mkdir = fuse_lib_mkdir, + .unlink = fuse_lib_unlink, + .rmdir = fuse_lib_rmdir, + .symlink = fuse_lib_symlink, + .rename = fuse_lib_rename, + .link = fuse_lib_link, + .create = fuse_lib_create, + .open = fuse_lib_open, + .read = fuse_lib_read, + .write_buf = fuse_lib_write_buf, + .flush = fuse_lib_flush, + .release = fuse_lib_release, + .fsync = fuse_lib_fsync, + .opendir = fuse_lib_opendir, + .readdir = fuse_lib_readdir, + .releasedir = fuse_lib_releasedir, + .fsyncdir = fuse_lib_fsyncdir, + .statfs = fuse_lib_statfs, + .setxattr = fuse_lib_setxattr, + .getxattr = fuse_lib_getxattr, + .listxattr = fuse_lib_listxattr, + .removexattr = fuse_lib_removexattr, + .getlk = fuse_lib_getlk, + .setlk = fuse_lib_setlk, + .flock = fuse_lib_flock, + .bmap = fuse_lib_bmap, + .ioctl = fuse_lib_ioctl, + .poll = fuse_lib_poll, + .fallocate = fuse_lib_fallocate, + .copy_file_range = fuse_lib_copy_file_range, }; int fuse_notify_poll(struct fuse_pollhandle *ph) diff --git a/libfuse/lib/fuse_lowlevel.c b/libfuse/lib/fuse_lowlevel.c index 400f2b52..19ba9836 100644 --- a/libfuse/lib/fuse_lowlevel.c +++ b/libfuse/lib/fuse_lowlevel.c @@ -1962,6 +1962,34 @@ static void do_notify_reply(fuse_req_t req, fuse_ino_t nodeid, nreq->reply(nreq, req, nodeid, inarg, buf); } +static +void +do_copy_file_range(fuse_req_t req_, + fuse_ino_t nodeid_in_, + const void *arg_) + +{ + struct fuse_file_info ffi_in = {0}; + struct fuse_file_info ffi_out = {0}; + struct fuse_copy_file_range_in *arg = (struct fuse_copy_file_range_in*)arg_; + + ffi_in.fh = arg->fh_in; + ffi_out.fh = arg->fh_out; + + if(req_->f->op.copy_file_range == NULL) + fuse_reply_err(req_,ENOSYS); + else + req_->f->op.copy_file_range(req_, + nodeid_in_, + arg->off_in, + &ffi_in, + arg->nodeid_out, + arg->off_out, + &ffi_out, + arg->len, + arg->flags); +} + static int send_notify_iov(struct fuse_ll *f, struct fuse_chan *ch, int notify_code, struct iovec *iov, int count) { @@ -2262,50 +2290,52 @@ int fuse_req_interrupted(fuse_req_t req) static struct { void (*func)(fuse_req_t, fuse_ino_t, const void *); const char *name; -} fuse_ll_ops[] = { - [FUSE_LOOKUP] = { do_lookup, "LOOKUP" }, - [FUSE_FORGET] = { do_forget, "FORGET" }, - [FUSE_GETATTR] = { do_getattr, "GETATTR" }, - [FUSE_SETATTR] = { do_setattr, "SETATTR" }, - [FUSE_READLINK] = { do_readlink, "READLINK" }, - [FUSE_SYMLINK] = { do_symlink, "SYMLINK" }, - [FUSE_MKNOD] = { do_mknod, "MKNOD" }, - [FUSE_MKDIR] = { do_mkdir, "MKDIR" }, - [FUSE_UNLINK] = { do_unlink, "UNLINK" }, - [FUSE_RMDIR] = { do_rmdir, "RMDIR" }, - [FUSE_RENAME] = { do_rename, "RENAME" }, - [FUSE_LINK] = { do_link, "LINK" }, - [FUSE_OPEN] = { do_open, "OPEN" }, - [FUSE_READ] = { do_read, "READ" }, - [FUSE_WRITE] = { do_write, "WRITE" }, - [FUSE_STATFS] = { do_statfs, "STATFS" }, - [FUSE_RELEASE] = { do_release, "RELEASE" }, - [FUSE_FSYNC] = { do_fsync, "FSYNC" }, - [FUSE_SETXATTR] = { do_setxattr, "SETXATTR" }, - [FUSE_GETXATTR] = { do_getxattr, "GETXATTR" }, - [FUSE_LISTXATTR] = { do_listxattr, "LISTXATTR" }, - [FUSE_REMOVEXATTR] = { do_removexattr, "REMOVEXATTR" }, - [FUSE_FLUSH] = { do_flush, "FLUSH" }, - [FUSE_INIT] = { do_init, "INIT" }, - [FUSE_OPENDIR] = { do_opendir, "OPENDIR" }, - [FUSE_READDIR] = { do_readdir, "READDIR" }, - [FUSE_RELEASEDIR] = { do_releasedir, "RELEASEDIR" }, - [FUSE_FSYNCDIR] = { do_fsyncdir, "FSYNCDIR" }, - [FUSE_GETLK] = { do_getlk, "GETLK" }, - [FUSE_SETLK] = { do_setlk, "SETLK" }, - [FUSE_SETLKW] = { do_setlkw, "SETLKW" }, - [FUSE_ACCESS] = { do_access, "ACCESS" }, - [FUSE_CREATE] = { do_create, "CREATE" }, - [FUSE_INTERRUPT] = { do_interrupt, "INTERRUPT" }, - [FUSE_BMAP] = { do_bmap, "BMAP" }, - [FUSE_IOCTL] = { do_ioctl, "IOCTL" }, - [FUSE_POLL] = { do_poll, "POLL" }, - [FUSE_FALLOCATE] = { do_fallocate, "FALLOCATE" }, - [FUSE_DESTROY] = { do_destroy, "DESTROY" }, - [FUSE_NOTIFY_REPLY] = { (void *) 1, "NOTIFY_REPLY" }, - [FUSE_BATCH_FORGET] = { do_batch_forget, "BATCH_FORGET" }, - [CUSE_INIT] = { cuse_lowlevel_init, "CUSE_INIT" }, -}; +} fuse_ll_ops[] = + { + [FUSE_LOOKUP] = { do_lookup, "LOOKUP" }, + [FUSE_FORGET] = { do_forget, "FORGET" }, + [FUSE_GETATTR] = { do_getattr, "GETATTR" }, + [FUSE_SETATTR] = { do_setattr, "SETATTR" }, + [FUSE_READLINK] = { do_readlink, "READLINK" }, + [FUSE_SYMLINK] = { do_symlink, "SYMLINK" }, + [FUSE_MKNOD] = { do_mknod, "MKNOD" }, + [FUSE_MKDIR] = { do_mkdir, "MKDIR" }, + [FUSE_UNLINK] = { do_unlink, "UNLINK" }, + [FUSE_RMDIR] = { do_rmdir, "RMDIR" }, + [FUSE_RENAME] = { do_rename, "RENAME" }, + [FUSE_LINK] = { do_link, "LINK" }, + [FUSE_OPEN] = { do_open, "OPEN" }, + [FUSE_READ] = { do_read, "READ" }, + [FUSE_WRITE] = { do_write, "WRITE" }, + [FUSE_STATFS] = { do_statfs, "STATFS" }, + [FUSE_RELEASE] = { do_release, "RELEASE" }, + [FUSE_FSYNC] = { do_fsync, "FSYNC" }, + [FUSE_SETXATTR] = { do_setxattr, "SETXATTR" }, + [FUSE_GETXATTR] = { do_getxattr, "GETXATTR" }, + [FUSE_LISTXATTR] = { do_listxattr, "LISTXATTR" }, + [FUSE_REMOVEXATTR] = { do_removexattr, "REMOVEXATTR" }, + [FUSE_FLUSH] = { do_flush, "FLUSH" }, + [FUSE_INIT] = { do_init, "INIT" }, + [FUSE_OPENDIR] = { do_opendir, "OPENDIR" }, + [FUSE_READDIR] = { do_readdir, "READDIR" }, + [FUSE_RELEASEDIR] = { do_releasedir, "RELEASEDIR" }, + [FUSE_FSYNCDIR] = { do_fsyncdir, "FSYNCDIR" }, + [FUSE_GETLK] = { do_getlk, "GETLK" }, + [FUSE_SETLK] = { do_setlk, "SETLK" }, + [FUSE_SETLKW] = { do_setlkw, "SETLKW" }, + [FUSE_ACCESS] = { do_access, "ACCESS" }, + [FUSE_CREATE] = { do_create, "CREATE" }, + [FUSE_INTERRUPT] = { do_interrupt, "INTERRUPT" }, + [FUSE_BMAP] = { do_bmap, "BMAP" }, + [FUSE_IOCTL] = { do_ioctl, "IOCTL" }, + [FUSE_POLL] = { do_poll, "POLL" }, + [FUSE_FALLOCATE] = { do_fallocate, "FALLOCATE" }, + [FUSE_DESTROY] = { do_destroy, "DESTROY" }, + [FUSE_NOTIFY_REPLY] = { (void *) 1, "NOTIFY_REPLY" }, + [FUSE_BATCH_FORGET] = { do_batch_forget, "BATCH_FORGET" }, + [FUSE_COPY_FILE_RANGE] = { do_copy_file_range, "COPY_FILE_RANGE" }, + [CUSE_INIT] = { cuse_lowlevel_init, "CUSE_INIT" }, + }; #define FUSE_MAXOP (sizeof(fuse_ll_ops) / sizeof(fuse_ll_ops[0])) diff --git a/man/mergerfs.1 b/man/mergerfs.1 index 1c514a6c..3de97533 100644 --- a/man/mergerfs.1 +++ b/man/mergerfs.1 @@ -467,7 +467,7 @@ T{ N/A T}@T{ fchmod, fchown, futimens, ftruncate, fallocate, fgetattr, fsync, ioctl -(files), read, readdir, release, statfs, write +(files), read, readdir, release, statfs, write, copy_file_range T} .TE .PP diff --git a/src/fuse_copy_file_range.cpp b/src/fuse_copy_file_range.cpp new file mode 100644 index 00000000..83691a4c --- /dev/null +++ b/src/fuse_copy_file_range.cpp @@ -0,0 +1,71 @@ +/* + Copyright (c) 2019, Antonio SJ Musumeci + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#include "errno.hpp" +#include "fileinfo.hpp" +#include "fs_copy_file_range.hpp" + +#include + +#include + +namespace l +{ + static + ssize_t + copy_file_range(const int fd_in_, + off_t offset_in_, + const int fd_out_, + off_t offset_out_, + size_t size_, + int flags_) + { + ssize_t rv; + + rv = fs::copy_file_range(fd_in_, + &offset_in_, + fd_out_, + &offset_out_, + size_, + flags_); + + return ((rv == -1) ? -errno : rv); + } +} + +namespace FUSE +{ + ssize_t + copy_file_range(const char *path_in_, + struct fuse_file_info *ffi_in_, + off_t offset_in_, + const char *path_out_, + struct fuse_file_info *ffi_out_, + off_t offset_out_, + size_t size_, + int flags_) + { + FileInfo *fi_in = reinterpret_cast(ffi_in_->fh); + FileInfo *fi_out = reinterpret_cast(ffi_out_->fh); + + return l::copy_file_range(fi_in->fd, + offset_in_, + fi_out->fd, + offset_out_, + size_, + flags_); + } +} diff --git a/src/fuse_copy_file_range.hpp b/src/fuse_copy_file_range.hpp new file mode 100644 index 00000000..4961c1b5 --- /dev/null +++ b/src/fuse_copy_file_range.hpp @@ -0,0 +1,30 @@ +/* + Copyright (c) 2019, Antonio SJ Musumeci + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#pragma once + +namespace FUSE +{ + ssize_t + copy_file_range(const char *path_in, + struct fuse_file_info *ffi_in, + off_t offset_in, + const char *path_out, + struct fuse_file_info *ffi_out, + off_t offset_out, + size_t size, + int flags); +} diff --git a/src/mergerfs.cpp b/src/mergerfs.cpp index 63479e6d..087655bf 100644 --- a/src/mergerfs.cpp +++ b/src/mergerfs.cpp @@ -22,6 +22,7 @@ #include "fuse_access.hpp" #include "fuse_chmod.hpp" #include "fuse_chown.hpp" +#include "fuse_copy_file_range.hpp" #include "fuse_create.hpp" #include "fuse_destroy.hpp" #include "fuse_fallocate.hpp" @@ -82,64 +83,56 @@ namespace l ops.flag_nopath = true; ops.flag_utime_omit_ok = true; - ops.prepare_hide = FUSE::prepare_hide; - ops.free_hide = FUSE::free_hide; - ops.fchown = FUSE::fchown; - ops.fchmod = FUSE::fchmod; - ops.futimens = FUSE::futimens; - - ops.access = FUSE::access; - ops.bmap = NULL; - ops.chmod = FUSE::chmod; - ops.chown = FUSE::chown; - ops.create = FUSE::create; - ops.destroy = FUSE::destroy; - ops.fallocate = FUSE::fallocate; - ops.fgetattr = FUSE::fgetattr; - ops.flock = NULL; // FUSE::flock; - ops.flush = FUSE::flush; - ops.fsync = FUSE::fsync; - ops.fsyncdir = FUSE::fsyncdir; - ops.ftruncate = FUSE::ftruncate; - ops.getattr = FUSE::getattr; - ops.getdir = NULL; /* deprecated; use readdir */ - ops.getxattr = FUSE::getxattr; - ops.init = FUSE::init; - ops.ioctl = FUSE::ioctl; - ops.link = FUSE::link; - ops.listxattr = FUSE::listxattr; - ops.lock = NULL; - ops.mkdir = FUSE::mkdir; - ops.mknod = FUSE::mknod; - ops.open = FUSE::open; - ops.opendir = FUSE::opendir; - ops.poll = NULL; - ops.read = (nullrw ? - FUSE::read_null : - FUSE::read); - ops.read_buf = (nullrw ? - NULL : - FUSE::read_buf); - ops.readdir = FUSE::readdir; - ops.readlink = FUSE::readlink; - ops.release = FUSE::release; - ops.releasedir = FUSE::releasedir; - ops.removexattr = FUSE::removexattr; - ops.rename = FUSE::rename; - ops.rmdir = FUSE::rmdir; - ops.setxattr = FUSE::setxattr; - ops.statfs = FUSE::statfs; - ops.symlink = FUSE::symlink; - ops.truncate = FUSE::truncate; - ops.unlink = FUSE::unlink; - ops.utime = NULL; /* deprecated; use utimens() */ - ops.utimens = FUSE::utimens; - ops.write = (nullrw ? - FUSE::write_null : - FUSE::write); - ops.write_buf = (nullrw ? - FUSE::write_buf_null : - FUSE::write_buf); + ops.access = FUSE::access; + ops.bmap = NULL; + ops.chmod = FUSE::chmod; + ops.chown = FUSE::chown; + ops.copy_file_range = FUSE::copy_file_range; + ops.create = FUSE::create; + ops.destroy = FUSE::destroy; + ops.fallocate = FUSE::fallocate; + ops.fchmod = FUSE::fchmod; + ops.fchown = FUSE::fchown; + ops.fgetattr = FUSE::fgetattr; + ops.flock = NULL; // FUSE::flock; + ops.flush = FUSE::flush; + ops.free_hide = FUSE::free_hide; + ops.fsync = FUSE::fsync; + ops.fsyncdir = FUSE::fsyncdir; + ops.ftruncate = FUSE::ftruncate; + ops.futimens = FUSE::futimens; + ops.getattr = FUSE::getattr; + ops.getdir = NULL; /* deprecated; use readdir */ + ops.getxattr = FUSE::getxattr; + ops.init = FUSE::init; + ops.ioctl = FUSE::ioctl; + ops.link = FUSE::link; + ops.listxattr = FUSE::listxattr; + ops.lock = NULL; + ops.mkdir = FUSE::mkdir; + ops.mknod = FUSE::mknod; + ops.open = FUSE::open; + ops.opendir = FUSE::opendir; + ops.poll = NULL; + ops.prepare_hide = FUSE::prepare_hide; + ops.read = (nullrw ? FUSE::read_null : FUSE::read); + ops.read_buf = (nullrw ? NULL : FUSE::read_buf); + ops.readdir = FUSE::readdir; + ops.readlink = FUSE::readlink; + ops.release = FUSE::release; + ops.releasedir = FUSE::releasedir; + ops.removexattr = FUSE::removexattr; + ops.rename = FUSE::rename; + ops.rmdir = FUSE::rmdir; + ops.setxattr = FUSE::setxattr; + ops.statfs = FUSE::statfs; + ops.symlink = FUSE::symlink; + ops.truncate = FUSE::truncate; + ops.unlink = FUSE::unlink; + ops.utime = NULL; /* deprecated; use utimens() */ + ops.utimens = FUSE::utimens; + ops.write = (nullrw ? FUSE::write_null : FUSE::write); + ops.write_buf = (nullrw ? FUSE::write_buf_null : FUSE::write_buf); return; }