From: Darrick J. Wong <djwong@xxxxxxxxxx> Connect statx to the upper level library. Signed-off-by: "Darrick J. Wong" <djwong@xxxxxxxxxx> --- include/fuse.h | 11 +++++++ lib/fuse.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+) diff --git a/include/fuse.h b/include/fuse.h index a59f43e0701e1a..03af42c9884acd 100644 --- a/include/fuse.h +++ b/include/fuse.h @@ -323,6 +323,7 @@ struct fuse_config { uint64_t reserved[48]; }; +struct statx; /** * The file system operations: @@ -895,6 +896,16 @@ struct fuse_operations { * Flush the entire filesystem to disk. */ int (*syncfs) (const char *path); + + /** + * Return detailed attributes about a file. + * + * File information should be written to the statx struct. + * The size parameter is the size of the statx structure. + */ + int (*statx) (const char *path, uint32_t statx_flags, + uint32_t statx_mask, struct statx *statx, size_t size, + struct fuse_file_info *fi); #endif /* FUSE_USE_VERSION >= 318 */ }; diff --git a/lib/fuse.c b/lib/fuse.c index c3fa6dad589cb0..41e37f2760356c 100644 --- a/lib/fuse.c +++ b/lib/fuse.c @@ -41,6 +41,8 @@ #include <sys/time.h> #include <sys/mman.h> #include <sys/file.h> +#include <sys/stat.h> +#include <sys/sysmacros.h> #define FUSE_NODE_SLAB 1 @@ -2897,6 +2899,24 @@ static int fuse_fs_syncfs(struct fuse_fs *fs, const char *path) return fs->op.syncfs(path); } +static int fuse_fs_statx(struct fuse_fs *fs, const char *path, + uint32_t statx_flags, uint32_t statx_mask, + struct statx *statx, size_t size, + struct fuse_file_info *fi) +{ + fuse_get_context()->private_data = fs->user_data; + if (!fs->op.statx) + return -ENOSYS; + if (fs->debug) { + char buf[10]; + + fuse_log(FUSE_LOG_DEBUG, "statx[%s] 0x%x 0x%x\n", + file_info_string(fi, buf, sizeof(buf)), + statx_flags, statx_mask); + } + return fs->op.statx(path, statx_flags, statx_mask, statx, size, fi); +} + static void fuse_lib_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr, int valid, struct fuse_file_info *fi) { @@ -4703,6 +4723,74 @@ static void fuse_lib_syncfs(fuse_req_t req, fuse_ino_t ino) reply_err(req, err); } +#ifdef STATX_BASIC_STATS +static void from_statx(struct stat *buf, const struct statx *stx) +{ + buf->st_dev = makedev(stx->stx_dev_major, + stx->stx_dev_minor); + buf->st_ino = stx->stx_ino; + buf->st_mode = stx->stx_mode; + buf->st_nlink = stx->stx_nlink; + buf->st_uid = stx->stx_uid; + buf->st_gid = stx->stx_gid; + buf->st_rdev = makedev(stx->stx_rdev_major, + stx->stx_rdev_minor); + buf->st_size = stx->stx_size; + buf->st_blksize = stx->stx_blksize; + buf->st_blocks = stx->stx_blocks; + + buf->st_atime = stx->stx_atime.tv_sec; + buf->st_mtime = stx->stx_mtime.tv_sec; + buf->st_ctime = stx->stx_ctime.tv_sec; + + /* XXX do we care about tv_nsec? */ +} + +static void fuse_lib_statx(fuse_req_t req, fuse_ino_t ino, uint32_t statx_flags, + uint32_t statx_mask, struct fuse_file_info *fi) +{ + struct fuse *f = req_fuse_prepare(req); + struct node *node; + struct fuse_intr_data d; + struct statx statx = { }; + struct stat buf = { }; + char *path; + int err; + + if (fi != NULL) + err = get_path_nullok(f, ino, &path); + else + err = get_path(f, ino, &path); + if (err) { + reply_err(req, err); + return; + } + + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_statx(f->fs, path, statx_flags, statx_mask, &statx, + sizeof(statx), fi); + fuse_finish_interrupt(f, req, &d); + free_path(f, ino, path); + if (err) { + reply_err(req, err); + return; + } + + pthread_mutex_lock(&f->lock); + node = get_node(f, ino); + if (node->is_hidden && statx.stx_nlink > 0) + statx.stx_nlink--; + from_statx(&buf, &statx); + if (f->conf.auto_cache) + update_stat(node, &buf); + pthread_mutex_unlock(&f->lock); + set_stat(f, ino, &buf); + fuse_reply_statx(req, &statx, sizeof(statx), f->conf.attr_timeout); +} +#else +# define fuse_lib_statx NULL +#endif /* STATX_BASIC_STATS */ + static int clean_delay(struct fuse *f) { /* @@ -4802,6 +4890,7 @@ static struct fuse_lowlevel_ops fuse_path_ops = { .copy_file_range = fuse_lib_copy_file_range, .lseek = fuse_lib_lseek, .syncfs = fuse_lib_syncfs, + .statx = fuse_lib_statx, .iomap_begin = fuse_lib_iomap_begin, .iomap_end = fuse_lib_iomap_end, .iomap_ioend = fuse_lib_iomap_ioend,