aboutsummaryrefslogtreecommitdiffstats
path: root/lib/fuse.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/fuse.c')
-rw-r--r--lib/fuse.c108
1 files changed, 108 insertions, 0 deletions
diff --git a/lib/fuse.c b/lib/fuse.c
index 68b61ce..333fdc7 100644
--- a/lib/fuse.c
+++ b/lib/fuse.c
@@ -1507,6 +1507,29 @@ static void set_stat(struct fuse *f, fuse_ino_t nodeid, struct stat *stbuf)
stbuf->st_gid = f->conf.gid;
}
+#ifdef HAVE_STATX
+static void set_statx(struct fuse *f, fuse_ino_t nodeid, struct statx *stxbuf)
+{
+ if (!f->conf.use_ino)
+ stxbuf->stx_ino = nodeid;
+ if (f->conf.set_mode) {
+ if (f->conf.dmask && S_ISDIR(stxbuf->stx_mode))
+ stxbuf->stx_mode = (stxbuf->stx_mode & S_IFMT) |
+ (0777 & ~f->conf.dmask);
+ else if (f->conf.fmask)
+ stxbuf->stx_mode = (stxbuf->stx_mode & S_IFMT) |
+ (0777 & ~f->conf.fmask);
+ else
+ stxbuf->stx_mode = (stxbuf->stx_mode & S_IFMT) |
+ (0777 & ~f->conf.umask);
+ }
+ if (f->conf.set_uid)
+ stxbuf->stx_uid = f->conf.uid;
+ if (f->conf.set_gid)
+ stxbuf->stx_gid = f->conf.gid;
+}
+#endif
+
static struct fuse *req_fuse(fuse_req_t req)
{
return (struct fuse *) fuse_req_userdata(req);
@@ -2312,6 +2335,39 @@ off_t fuse_fs_lseek(struct fuse_fs *fs, const char *path, off_t off, int whence,
return fs->op.lseek(path, off, whence, fi);
}
+#ifdef HAVE_STATX
+int fuse_fs_statx(struct fuse_fs *fs, const char *path, int flags, int mask,
+ struct statx *stxbuf, struct fuse_file_info *fi)
+{
+ fuse_get_context()->private_data = fs->user_data;
+ if (fs->op.statx) {
+ if (fs->debug) {
+ char buf[10];
+
+ fuse_log(FUSE_LOG_DEBUG, "statx[%s] %s %d %d\n",
+ file_info_string(fi, buf, sizeof(buf)), path,
+ flags, mask);
+ }
+ return fs->op.statx(path, flags, mask, stxbuf, fi);
+ }
+
+ return -ENOSYS;
+}
+#else
+int fuse_fs_statx(struct fuse_fs *fs, const char *path, int flags, int mask,
+ struct statx *stxbuf, struct fuse_file_info *fi)
+{
+ (void)fs;
+ (void)path;
+ (void)flags;
+ (void)mask;
+ (void)stxbuf;
+ (void)fi;
+
+ return -ENOSYS;
+}
+#endif
+
static int is_open(struct fuse *f, fuse_ino_t dir, const char *name)
{
struct node *node;
@@ -4361,6 +4417,55 @@ static void fuse_lib_lseek(fuse_req_t req, fuse_ino_t ino, off_t off, int whence
reply_err(req, res);
}
+#ifdef HAVE_STATX
+static void fuse_lib_statx(fuse_req_t req, fuse_ino_t ino, int flags, int mask,
+ struct fuse_file_info *fi)
+{
+ struct fuse *f = req_fuse_prepare(req);
+ struct statx stxbuf;
+ char *path;
+ int err;
+
+ memset(&stxbuf, 0, sizeof(stxbuf));
+
+ if (fi != NULL)
+ err = get_path_nullok(f, ino, &path);
+ else
+ err = get_path(f, ino, &path);
+
+ if (!err) {
+ struct fuse_intr_data d;
+
+ if (!path)
+ flags |= AT_EMPTY_PATH;
+ fuse_prepare_interrupt(f, req, &d);
+ err = fuse_fs_statx(f->fs, path, flags, mask, &stxbuf, fi);
+ fuse_finish_interrupt(f, req, &d);
+ free_path(f, ino, path);
+ }
+ if (!err) {
+ struct node *node;
+
+ pthread_mutex_lock(&f->lock);
+ node = get_node(f, ino);
+ if (node->is_hidden && stxbuf.stx_nlink > 0)
+ stxbuf.stx_nlink--;
+ if (f->conf.auto_cache) {
+ struct stat stbuf;
+
+ stbuf.st_mtime = stxbuf.stx_mtime.tv_nsec;
+ ST_MTIM_NSEC(&stbuf) = stxbuf.stx_mtime.tv_nsec;
+ stbuf.st_size = stxbuf.stx_size;
+ update_stat(node, &stbuf);
+ }
+ pthread_mutex_unlock(&f->lock);
+ set_statx(f, ino, &stxbuf);
+ fuse_reply_statx(req, 0, &stxbuf, f->conf.attr_timeout);
+ } else
+ reply_err(req, err);
+}
+#endif
+
static int clean_delay(struct fuse *f)
{
/*
@@ -4459,6 +4564,9 @@ static struct fuse_lowlevel_ops fuse_path_ops = {
.fallocate = fuse_lib_fallocate,
.copy_file_range = fuse_lib_copy_file_range,
.lseek = fuse_lib_lseek,
+#ifdef HAVE_STATX
+ .statx = fuse_lib_statx,
+#endif
};
int fuse_notify_poll(struct fuse_pollhandle *ph)