All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] btrfs-fuse: Add listxattr and getxattr interface
@ 2021-11-23  7:37 hmsjwzb
  0 siblings, 0 replies; only message in thread
From: hmsjwzb @ 2021-11-23  7:37 UTC (permalink / raw)
  Cc: quwenruo.btrfs, linux-btrfs, hmsjwzb

Signed-off-by: hmsjwzb <hmsjwzb@zoho.com>
---
 inode.c         |  32 +++++++++++
 inode.h         |   7 +++
 main.c          | 140 ++++++++++++++++++++++++++++++++++++++++++++++++
 ondisk_format.h |   1 +
 4 files changed, 180 insertions(+)

diff --git a/inode.c b/inode.c
index 6ed6279..5ea023e 100644
--- a/inode.c
+++ b/inode.c
@@ -9,6 +9,38 @@
 #include "hash.h"
 #include "messages.h"
 
+struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_fs_info *fs_info,
+							struct btrfs_path *path,
+							const char *name, int name_len)
+{
+	struct btrfs_dir_item *dir_item;
+	unsigned long name_ptr;
+	u32 total_len;
+	u32 cur = 0;
+	u32 this_len;
+	struct extent_buffer *leaf;
+
+	leaf = path->nodes[0];
+	dir_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dir_item);
+
+	total_len = btrfs_item_size_nr(leaf, path->slots[0]);
+	while (cur < total_len) {
+		this_len = sizeof(*dir_item) +
+			btrfs_dir_name_len(leaf, dir_item) +
+			btrfs_dir_data_len(leaf, dir_item);
+		name_ptr = (unsigned long)(dir_item + 1);
+
+		if (btrfs_dir_name_len(leaf, dir_item) == name_len &&
+		    memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0)
+			return dir_item;
+
+		cur += this_len;
+		dir_item = (struct btrfs_dir_item *)((char *)dir_item +
+							this_len);
+	}
+	return NULL;
+}
+
 int btrfs_lookup_one_name(struct btrfs_fs_info *fs_info,
 			  struct btrfs_inode *dir, const char *name,
 			  size_t name_len, struct btrfs_inode *inode_ret)
diff --git a/inode.h b/inode.h
index 4515efd..f4cae8e 100644
--- a/inode.h
+++ b/inode.h
@@ -27,6 +27,12 @@ struct btrfs_inode {
 	u8 file_type;
 };
 
+/*
+ * Match one dir item name
+ */
+struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_fs_info *fs_info,
+							struct btrfs_path *path,
+							const char *name, int name_len);
 /*
  * Lookup one name for @dir.
  *
@@ -132,4 +138,5 @@ static inline u32 btrfs_type_to_imode(u8 btrfs_ft)
 
 int btrfs_stat(struct btrfs_fs_info *fs_info, struct btrfs_inode *inode,
 	       struct stat *stbuf);
+
 #endif
diff --git a/main.c b/main.c
index 3735d36..5e8828c 100644
--- a/main.c
+++ b/main.c
@@ -10,6 +10,7 @@
 #include "super.h"
 #include "inode.h"
 #include "data.h"
+#include "hash.h"
 
 static struct btrfs_fs_info *global_info = NULL;
 
@@ -190,6 +191,143 @@ static void btrfs_fuse_destroy(void *private_data)
 	btrfs_exit();
 }
 
+static int btrfs_fuse_listxattr(const char *pathname, char *list, size_t size)
+{
+	struct btrfs_key key;
+	struct btrfs_fs_info *fs_info = global_info;
+	struct btrfs_inode inode = {};
+	struct btrfs_path path;
+	size_t size_left = size;
+	int ret =  0;
+	size_t total_size = 0;
+
+	ret = btrfs_resolve_path(fs_info, pathname, strlen(pathname), &inode);
+	if (ret < 0)
+		return ret;
+
+	btrfs_init_path(&path);
+	key.objectid = inode.ino;
+	key.type = BTRFS_XATTR_ITEM_KEY;
+	key.offset = 0;
+
+	ret = __btrfs_search_slot(fs_info->default_root, &path, &key);
+	if (ret < 0)
+		return ret;
+
+	while (1) {
+		struct extent_buffer *leaf;
+		int slot;
+		struct btrfs_dir_item *di;
+		struct btrfs_key found_key;
+		u32 item_size;
+		u32 cur;
+
+		leaf = path.nodes[0];
+		slot = path.slots[0];
+		if (slot >= btrfs_header_nritems(leaf)) {
+			ret = btrfs_next_leaf(&path);
+			if (ret < 0)
+				goto err;
+			else if (ret > 0)
+				break;
+			continue;
+		}
+
+		btrfs_item_key_to_cpu(leaf, &found_key, slot);
+
+		if (found_key.objectid != key.objectid)
+			break;
+		if (found_key.type > BTRFS_XATTR_ITEM_KEY)
+			break;
+		if (found_key.type < BTRFS_XATTR_ITEM_KEY)
+			goto next_item;
+
+		di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item);
+		item_size = btrfs_item_size_nr(leaf, slot);
+		cur = 0;
+		while (cur < item_size) {
+			u16 name_len = btrfs_dir_name_len(leaf, di);
+			u16 data_len = btrfs_dir_data_len(leaf, di);
+			u32 this_len = sizeof(*di) + name_len + data_len;
+			unsigned long name_ptr = (unsigned long)(di + 1);
+
+			total_size += name_len + 1;
+
+			if (!size)
+				goto next;
+
+			if (!list || (name_len + 1) > size_left) {
+				ret = -ERANGE;
+				goto err;
+			}
+
+			read_extent_buffer(leaf, list, name_ptr, name_len);
+			list[name_len] = '\0';
+
+			size_left -= name_len + 1;
+			list += name_len + 1;
+next:
+			cur += this_len;
+			di = (struct btrfs_dir_item *)((char *)di + this_len);
+		}
+next_item:
+		path.slots[0]++;
+	}
+	ret = total_size;
+err:
+	return ret;
+}
+
+int btrfs_fuse_getxattr(const char *pathname, const char *name, char *value, size_t size)
+{
+	struct btrfs_key key;
+	struct btrfs_dir_item *di;
+	struct btrfs_fs_info *fs_info = global_info;
+	struct btrfs_root *root = fs_info->default_root;
+	struct extent_buffer *leaf;
+	struct btrfs_inode inode = {};
+	struct btrfs_path path;
+	int ret = 0;
+	unsigned long data_ptr;
+
+	memset(&path, 0, sizeof(path));
+	ret = btrfs_resolve_path(fs_info, pathname, strlen(pathname), &inode);
+	if (ret < 0)
+		return ret;
+
+	key.objectid = inode.ino;
+	key.type = BTRFS_XATTR_ITEM_KEY;
+	key.offset = btrfs_name_hash(name, strlen(name));
+	ret = __btrfs_search_slot(root, &path, &key);
+	if (ret != 0)
+		return ret;
+	di = btrfs_match_dir_item_name(fs_info, &path, name, strlen(name));
+	if (!di) {
+		ret = -ENODATA;
+		goto out;
+	}
+
+	leaf = path.nodes[0];
+	if (!size) {
+		ret = btrfs_dir_data_len(leaf, di);
+		goto out;
+	}
+
+	if (btrfs_dir_data_len(leaf, di) > size) {
+		ret = -ERANGE;
+		goto out;
+	}
+
+	data_ptr = (unsigned long)((char *)(di + 1) +
+					btrfs_dir_name_len(leaf, di));
+	read_extent_buffer(leaf, value, data_ptr,
+			btrfs_dir_data_len(leaf, di));
+	ret = btrfs_dir_data_len(leaf, di);
+
+out:
+	return ret;
+}
+
 static const struct fuse_operations btrfs_fuse_ops = {
 	.statfs		= btrfs_fuse_statfs,
 	.getattr	= btrfs_fuse_getattr,
@@ -201,6 +339,8 @@ static const struct fuse_operations btrfs_fuse_ops = {
 	.readdir	= btrfs_fuse_readdir,
 	.init		= btrfs_fuse_init,
 	.destroy	= btrfs_fuse_destroy,
+	.listxattr	= btrfs_fuse_listxattr,
+	.getxattr	= btrfs_fuse_getxattr,
 };
 
 void usage(void)
diff --git a/ondisk_format.h b/ondisk_format.h
index 510c69d..7da533e 100644
--- a/ondisk_format.h
+++ b/ondisk_format.h
@@ -59,6 +59,7 @@ enum btrfs_csum_type {
 
 /* A subset of needed key types for read-only operations */
 #define BTRFS_INODE_ITEM_KEY		1
+#define BTRFS_XATTR_ITEM_KEY		24
 #define BTRFS_DIR_ITEM_KEY		84
 #define BTRFS_DIR_INDEX_KEY		96
 #define BTRFS_EXTENT_DATA_KEY		108
-- 
2.25.1


^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2021-11-23  7:53 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-11-23  7:37 [PATCH] btrfs-fuse: Add listxattr and getxattr interface hmsjwzb

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.