aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorYuri Per <yuri@acronis.com>2019-11-03 11:44:31 +0200
committerNikolaus Rath <Nikolaus@rath.org>2019-11-03 09:44:31 +0000
commitd735af94fa54a5555ce725f1d4e6b97b812b6603 (patch)
treecb21ee1eceb66e1c85a5c78ae7aa4a5f9438274a /lib
parentb9c584370aa489ac00b1e8a0454c61f30c0531af (diff)
downloadlibfuse-d735af94fa54a5555ce725f1d4e6b97b812b6603.tar.gz
Implement lseek operation (#457)
Diffstat (limited to 'lib')
-rwxr-xr-xlib/fuse.c43
-rw-r--r--lib/fuse_lowlevel.c25
-rw-r--r--lib/fuse_versionscript2
-rw-r--r--lib/modules/iconv.c14
-rw-r--r--lib/modules/subdir.c14
5 files changed, 98 insertions, 0 deletions
diff --git a/lib/fuse.c b/lib/fuse.c
index 229e139..b0f5b30 100755
--- a/lib/fuse.c
+++ b/lib/fuse.c
@@ -2384,6 +2384,23 @@ ssize_t fuse_fs_copy_file_range(struct fuse_fs *fs, const char *path_in,
return -ENOSYS;
}
+off_t fuse_fs_lseek(struct fuse_fs *fs, const char *path, off_t off, int whence,
+ struct fuse_file_info *fi)
+{
+ fuse_get_context()->private_data = fs->user_data;
+ if (fs->op.lseek) {
+ if (fs->debug) {
+ char buf[10];
+ fuse_log(FUSE_LOG_DEBUG, "lseek[%s] %llu %d\n",
+ file_info_string(fi, buf, sizeof(buf)),
+ (unsigned long long) off, whence);
+ }
+ return fs->op.lseek(path, off, whence, fi);
+ } else {
+ return -ENOSYS;
+ }
+}
+
static int is_open(struct fuse *f, fuse_ino_t dir, const char *name)
{
struct node *node;
@@ -4354,6 +4371,31 @@ static void fuse_lib_copy_file_range(fuse_req_t req, fuse_ino_t nodeid_in,
free_path(f, nodeid_out, path_out);
}
+static void fuse_lib_lseek(fuse_req_t req, fuse_ino_t ino, off_t off, int whence,
+ struct fuse_file_info *fi)
+{
+ struct fuse *f = req_fuse_prepare(req);
+ struct fuse_intr_data d;
+ char *path;
+ int err;
+ off_t res;
+
+ err = get_path(f, ino, &path);
+ if (err) {
+ reply_err(req, err);
+ return;
+ }
+
+ fuse_prepare_interrupt(f, req, &d);
+ res = fuse_fs_lseek(f->fs, path, off, whence, fi);
+ fuse_finish_interrupt(f, req, &d);
+ free_path(f, ino, path);
+ if (res >= 0)
+ fuse_reply_lseek(req, res);
+ else
+ reply_err(req, res);
+}
+
static int clean_delay(struct fuse *f)
{
/*
@@ -4451,6 +4493,7 @@ static struct fuse_lowlevel_ops fuse_path_ops = {
.poll = fuse_lib_poll,
.fallocate = fuse_lib_fallocate,
.copy_file_range = fuse_lib_copy_file_range,
+ .lseek = fuse_lib_lseek,
};
int fuse_notify_poll(struct fuse_pollhandle *ph)
diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c
index f7fbc8f..f2d7038 100644
--- a/lib/fuse_lowlevel.c
+++ b/lib/fuse_lowlevel.c
@@ -1065,6 +1065,16 @@ int fuse_reply_poll(fuse_req_t req, unsigned revents)
return send_reply_ok(req, &arg, sizeof(arg));
}
+int fuse_reply_lseek(fuse_req_t req, off_t off)
+{
+ struct fuse_lseek_out arg;
+
+ memset(&arg, 0, sizeof(arg));
+ arg.offset = off;
+
+ return send_reply_ok(req, &arg, sizeof(arg));
+}
+
static void do_lookup(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
{
char *name = (char *) inarg;
@@ -1867,6 +1877,20 @@ static void do_copy_file_range(fuse_req_t req, fuse_ino_t nodeid_in, const void
fuse_reply_err(req, ENOSYS);
}
+static void do_lseek(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+{
+ struct fuse_lseek_in *arg = (struct fuse_lseek_in *) inarg;
+ struct fuse_file_info fi;
+
+ memset(&fi, 0, sizeof(fi));
+ fi.fh = arg->fh;
+
+ if (req->se->op.lseek)
+ req->se->op.lseek(req, nodeid, arg->offset, arg->whence, &fi);
+ else
+ fuse_reply_err(req, ENOSYS);
+}
+
static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
{
struct fuse_init_in *arg = (struct fuse_init_in *) inarg;
@@ -2471,6 +2495,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_LSEEK] = { do_lseek, "LSEEK" },
[CUSE_INIT] = { cuse_lowlevel_init, "CUSE_INIT" },
};
diff --git a/lib/fuse_versionscript b/lib/fuse_versionscript
index 11ef1f7..160f11d 100644
--- a/lib/fuse_versionscript
+++ b/lib/fuse_versionscript
@@ -127,6 +127,8 @@ FUSE_3.0 {
fuse_cmdline_help;
fuse_apply_conn_info_opts;
fuse_parse_conn_info_opts;
+ fuse_fs_lseek;
+ fuse_reply_lseek;
local:
*;
diff --git a/lib/modules/iconv.c b/lib/modules/iconv.c
index 431d02c..eb5edd8 100644
--- a/lib/modules/iconv.c
+++ b/lib/modules/iconv.c
@@ -554,6 +554,19 @@ static int iconv_bmap(const char *path, size_t blocksize, uint64_t *idx)
return err;
}
+static off_t iconv_lseek(const char *path, off_t off, int whence,
+ struct fuse_file_info *fi)
+{
+ struct iconv *ic = iconv_get();
+ char *newpath;
+ int res = iconv_convpath(ic, path, &newpath, 0);
+ if (!res) {
+ res = fuse_fs_lseek(ic->next, newpath, off, whence, fi);
+ free(newpath);
+ }
+ return res;
+}
+
static void *iconv_init(struct fuse_conn_info *conn,
struct fuse_config *cfg)
{
@@ -612,6 +625,7 @@ static const struct fuse_operations iconv_oper = {
.lock = iconv_lock,
.flock = iconv_flock,
.bmap = iconv_bmap,
+ .lseek = iconv_lseek,
};
static const struct fuse_opt iconv_opts[] = {
diff --git a/lib/modules/subdir.c b/lib/modules/subdir.c
index 23f58f8..616c0ee 100644
--- a/lib/modules/subdir.c
+++ b/lib/modules/subdir.c
@@ -540,6 +540,19 @@ static int subdir_bmap(const char *path, size_t blocksize, uint64_t *idx)
return err;
}
+static off_t subdir_lseek(const char *path, off_t off, int whence,
+ struct fuse_file_info *fi)
+{
+ struct subdir *ic = subdir_get();
+ char *newpath;
+ int res = subdir_addpath(ic, path, &newpath);
+ if (!res) {
+ res = fuse_fs_lseek(ic->next, newpath, off, whence, fi);
+ free(newpath);
+ }
+ return res;
+}
+
static void *subdir_init(struct fuse_conn_info *conn,
struct fuse_config *cfg)
{
@@ -594,6 +607,7 @@ static const struct fuse_operations subdir_oper = {
.lock = subdir_lock,
.flock = subdir_flock,
.bmap = subdir_bmap,
+ .lseek = subdir_lseek,
};
static const struct fuse_opt subdir_opts[] = {