mirror of
https://github.com/trapexit/mergerfs.git
synced 2024-11-25 09:41:43 +08:00
add copy_file_range support
This commit is contained in:
parent
c8e178bf71
commit
8cb7195c3e
|
@ -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.
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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]))
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
71
src/fuse_copy_file_range.cpp
Normal file
71
src/fuse_copy_file_range.cpp
Normal file
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
Copyright (c) 2019, Antonio SJ Musumeci <trapexit@spawn.link>
|
||||
|
||||
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 <fuse.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
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<FileInfo*>(ffi_in_->fh);
|
||||
FileInfo *fi_out = reinterpret_cast<FileInfo*>(ffi_out_->fh);
|
||||
|
||||
return l::copy_file_range(fi_in->fd,
|
||||
offset_in_,
|
||||
fi_out->fd,
|
||||
offset_out_,
|
||||
size_,
|
||||
flags_);
|
||||
}
|
||||
}
|
30
src/fuse_copy_file_range.hpp
Normal file
30
src/fuse_copy_file_range.hpp
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
Copyright (c) 2019, Antonio SJ Musumeci <trapexit@spawn.link>
|
||||
|
||||
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);
|
||||
}
|
109
src/mergerfs.cpp
109
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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user