[PATCH 4/4] libfuse: add upper level statx hooks

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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,





[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [NTFS 3]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [NTFS 3]     [Samba]     [Device Mapper]     [CEPH Development]

  Powered by Linux