aboutsummaryrefslogtreecommitdiffstats
path: root/lib/fuse_lowlevel.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/fuse_lowlevel.c')
-rw-r--r--lib/fuse_lowlevel.c66
1 files changed, 61 insertions, 5 deletions
diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c
index e4544df..1e45315 100644
--- a/lib/fuse_lowlevel.c
+++ b/lib/fuse_lowlevel.c
@@ -589,7 +589,7 @@ int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *f)
return send_reply_ok(req, &arg, sizeof(arg));
}
-int fuse_reply_write(fuse_req_t req, size_t count)
+static int do_fuse_reply_write(fuse_req_t req, size_t count)
{
struct fuse_write_out arg;
@@ -599,6 +599,28 @@ int fuse_reply_write(fuse_req_t req, size_t count)
return send_reply_ok(req, &arg, sizeof(arg));
}
+static int do_fuse_reply_copy(fuse_req_t req, size_t count)
+{
+ struct fuse_copy_file_range_out arg;
+
+ memset(&arg, 0, sizeof(arg));
+ arg.bytes_copied = count;
+
+ return send_reply_ok(req, &arg, sizeof(arg));
+}
+
+int fuse_reply_write(fuse_req_t req, size_t count)
+{
+ /*
+ * This function is also used by FUSE_COPY_FILE_RANGE and its 64-bit
+ * variant.
+ */
+ if (req->is_copy_file_range_64)
+ return do_fuse_reply_copy(req, count);
+ else
+ return do_fuse_reply_write(req, count);
+}
+
int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
{
return send_reply_ok(req, buf, size);
@@ -2403,11 +2425,9 @@ static void do_fallocate(fuse_req_t req, const fuse_ino_t nodeid,
_do_fallocate(req, nodeid, inarg, NULL);
}
-static void _do_copy_file_range(fuse_req_t req, const fuse_ino_t nodeid_in,
- const void *op_in, const void *in_payload)
+static void copy_file_range_common(fuse_req_t req, const fuse_ino_t nodeid_in,
+ const struct fuse_copy_file_range_in *arg)
{
- (void)in_payload;
- const struct fuse_copy_file_range_in *arg = op_in;
struct fuse_file_info fi_in, fi_out;
memset(&fi_in, 0, sizeof(fi_in));
@@ -2424,12 +2444,46 @@ static void _do_copy_file_range(fuse_req_t req, const fuse_ino_t nodeid_in,
fuse_reply_err(req, ENOSYS);
}
+static void _do_copy_file_range(fuse_req_t req, const fuse_ino_t nodeid_in,
+ const void *op_in, const void *in_payload)
+{
+ const struct fuse_copy_file_range_in *arg = op_in;
+ struct fuse_copy_file_range_in arg_tmp;
+
+ (void) in_payload;
+ /* fuse_write_out can only handle 32bit copy size */
+ if (arg->len > 0xfffff000) {
+ arg_tmp = *arg;
+ arg_tmp.len = 0xfffff000;
+ arg = &arg_tmp;
+ }
+ copy_file_range_common(req, nodeid_in, arg);
+}
+
static void do_copy_file_range(fuse_req_t req, const fuse_ino_t nodeid_in,
const void *inarg)
{
_do_copy_file_range(req, nodeid_in, inarg, NULL);
}
+static void _do_copy_file_range_64(fuse_req_t req, const fuse_ino_t nodeid_in,
+ const void *op_in, const void *in_payload)
+{
+ (void) in_payload;
+ req->is_copy_file_range_64 = 1;
+ /* Limit size on 32bit userspace to avoid conversion overflow */
+ if (sizeof(size_t) == 4)
+ _do_copy_file_range(req, nodeid_in, op_in, NULL);
+ else
+ copy_file_range_common(req, nodeid_in, op_in);
+}
+
+static void do_copy_file_range_64(fuse_req_t req, const fuse_ino_t nodeid_in,
+ const void *inarg)
+{
+ _do_copy_file_range_64(req, nodeid_in, inarg, NULL);
+}
+
/*
* Note that the uint64_t offset in struct fuse_lseek_in is derived from
* linux kernel loff_t and is therefore signed.
@@ -3378,6 +3432,7 @@ static struct {
[FUSE_READDIRPLUS] = { do_readdirplus, "READDIRPLUS"},
[FUSE_RENAME2] = { do_rename2, "RENAME2" },
[FUSE_COPY_FILE_RANGE] = { do_copy_file_range, "COPY_FILE_RANGE" },
+ [FUSE_COPY_FILE_RANGE_64] = { do_copy_file_range_64, "COPY_FILE_RANGE_64" },
[FUSE_LSEEK] = { do_lseek, "LSEEK" },
[FUSE_STATX] = { do_statx, "STATX" },
[CUSE_INIT] = { cuse_lowlevel_init, "CUSE_INIT" },
@@ -3433,6 +3488,7 @@ static struct {
[FUSE_READDIRPLUS] = { _do_readdirplus, "READDIRPLUS" },
[FUSE_RENAME2] = { _do_rename2, "RENAME2" },
[FUSE_COPY_FILE_RANGE] = { _do_copy_file_range, "COPY_FILE_RANGE" },
+ [FUSE_COPY_FILE_RANGE_64] = { _do_copy_file_range_64, "COPY_FILE_RANGE_64" },
[FUSE_LSEEK] = { _do_lseek, "LSEEK" },
[FUSE_STATX] = { _do_statx, "STATX" },
[CUSE_INIT] = { _cuse_lowlevel_init, "CUSE_INIT" },