[Ocfs2-tools-devel] [PATCH 6/7] libocfs2: iterate all xattr entries of a file
Tiger Yang
tiger.yang at oracle.com
Tue Oct 20 01:42:16 PDT 2009
This patch add iteration function for all xattr entries
related of a file. ocfs2_xattr_iterate will call the callback
function on each xattr entry.
Signed-off-by: Tiger Yang <tiger.yang at oracle.com>
---
include/ocfs2/ocfs2.h | 8 ++
libocfs2/xattr.c | 190 +++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 198 insertions(+), 0 deletions(-)
diff --git a/include/ocfs2/ocfs2.h b/include/ocfs2/ocfs2.h
index 20d391e..f9e5c5a 100644
--- a/include/ocfs2/ocfs2.h
+++ b/include/ocfs2/ocfs2.h
@@ -1264,6 +1264,14 @@ errcode_t ocfs2_block_iterate_inode(ocfs2_filesys *fs,
void *priv_data),
void *priv_data);
+#define OCFS2_XATTR_ABORT 0x01
+#define OCFS2_XATTR_ERROR 0x02
+errcode_t ocfs2_xattr_iterate(ocfs2_cached_inode *ci,
+ int (*func)(ocfs2_cached_inode *ci,
+ struct ocfs2_xattr_entry *xe,
+ void *priv_data),
+ void *priv_data);
+
uint32_t ocfs2_xattr_uuid_hash(unsigned char *uuid);
uint32_t ocfs2_xattr_name_hash(uint32_t uuid_hash, const char *name,
int name_len);
diff --git a/libocfs2/xattr.c b/libocfs2/xattr.c
index d3285c8..dfc3c99 100644
--- a/libocfs2/xattr.c
+++ b/libocfs2/xattr.c
@@ -611,6 +611,165 @@ static int ocfs2_xattr_has_space_inline(ocfs2_cached_inode *ci,
return 0;
}
+static errcode_t ocfs2_xattr_iterate_entries(ocfs2_cached_inode *ci,
+ struct ocfs2_xattr_header *header,
+ int (*func)(ocfs2_cached_inode *ci,
+ struct ocfs2_xattr_entry *xe,
+ void *priv_data),
+ void *priv_data)
+{
+ int i;
+ struct ocfs2_xattr_entry *entry = NULL;
+ errcode_t ret = 0;
+
+ for (i = 0 ; i < header->xh_count; i++) {
+ entry = &header->xh_entries[i];
+ ret = func(ci, entry, priv_data);
+ if (ret == OCFS2_XATTR_ABORT || ret == OCFS2_XATTR_ERROR)
+ return ret;
+ }
+
+ return ret;
+}
+
+static errcode_t ocfs2_xattr_iterate_ibody(ocfs2_cached_inode *ci,
+ int (*func)(ocfs2_cached_inode *ci,
+ struct ocfs2_xattr_entry *xe,
+ void *priv_data),
+ void *priv_data)
+{
+ struct ocfs2_xattr_header *header = NULL;
+ ocfs2_filesys *fs = ci->ci_fs;
+ struct ocfs2_dinode *di = ci->ci_inode;
+ errcode_t ret = 0;
+
+ if (!(di->i_dyn_features & OCFS2_INLINE_XATTR_FL))
+ return ret;
+
+ header = (struct ocfs2_xattr_header *)
+ ((char *)di + fs->fs_blocksize - di->i_xattr_inline_size);
+
+ ret = ocfs2_xattr_iterate_entries(ci, header, func, priv_data);
+
+ return ret;
+}
+
+static errcode_t ocfs2_xattr_iterate_bucket(ocfs2_cached_inode *ci,
+ uint64_t blkno,
+ uint32_t clusters,
+ int (*func)(ocfs2_cached_inode *ci,
+ struct ocfs2_xattr_entry *xe,
+ void *priv_data),
+ void *priv_data)
+{
+ int i;
+ errcode_t ret = 0;
+ char *bucket = NULL;
+ struct ocfs2_xattr_header *xh;
+ ocfs2_filesys *fs = ci->ci_fs;
+ int blk_per_bucket = ocfs2_blocks_per_xattr_bucket(fs);
+ uint32_t bpc = ocfs2_xattr_buckets_per_cluster(fs);
+ uint32_t num_buckets = clusters * bpc;
+
+ ret = ocfs2_malloc_blocks(fs->fs_io, blk_per_bucket, &bucket);
+ if (ret)
+ goto out;
+
+ for (i = 0; i < num_buckets; i++, blkno += blk_per_bucket) {
+ ret = ocfs2_read_xattr_bucket(fs, blkno, bucket);
+ if (ret)
+ goto out;
+
+ xh = (struct ocfs2_xattr_header *)bucket;
+ /*
+ * The real bucket num in this series of blocks is stored
+ * in the 1st bucket.
+ */
+ if (i == 0)
+ num_buckets = xh->xh_num_buckets;
+ ret = ocfs2_xattr_iterate_entries(ci, xh, func, priv_data);
+ }
+
+out:
+ if (bucket)
+ ocfs2_free(&bucket);
+
+ return ret;
+}
+
+static errcode_t ocfs2_xattr_iterate_index_block(ocfs2_cached_inode *ci,
+ struct ocfs2_xattr_block *xb,
+ int (*func)(ocfs2_cached_inode *ci,
+ struct ocfs2_xattr_entry *xe,
+ void *priv_data),
+ void *priv_data)
+{
+ ocfs2_filesys *fs = ci->ci_fs;
+ struct ocfs2_extent_list *el = &xb->xb_attrs.xb_root.xt_list;
+ uint32_t name_hash = UINT_MAX, e_cpos = 0, num_clusters = 0;
+ uint64_t p_blkno = 0;
+ errcode_t ret = 0;
+
+ if (!el->l_next_free_rec)
+ return 0;
+
+ while (name_hash > 0) {
+ ret = ocfs2_xattr_get_rec(fs, xb, name_hash, &p_blkno,
+ &e_cpos, &num_clusters);
+ if (ret)
+ goto out;
+
+ ret = ocfs2_xattr_iterate_bucket(ci, p_blkno, num_clusters,
+ func, priv_data);
+ if (ret)
+ goto out;
+
+ if (e_cpos == 0)
+ break;
+
+ name_hash = e_cpos - 1;
+ }
+
+out:
+ return ret;
+}
+
+static errcode_t ocfs2_xattr_iterate_block(ocfs2_cached_inode *ci,
+ int (*func)(ocfs2_cached_inode *ci,
+ struct ocfs2_xattr_entry *xe,
+ void *priv_data),
+ void *priv_data)
+{
+ char *blk = NULL;
+ ocfs2_filesys *fs = ci->ci_fs;
+ struct ocfs2_dinode *di = ci->ci_inode;
+ struct ocfs2_xattr_block *xb;
+ int ret = 0;
+
+ if (!di->i_xattr_loc)
+ return ret;
+
+ ret = ocfs2_malloc_block(fs->fs_io, &blk);
+ if (ret < 0)
+ return ret;
+
+ ret = ocfs2_read_xattr_block(fs, di->i_xattr_loc, blk);
+ if (ret < 0)
+ return ret;
+
+ xb = (struct ocfs2_xattr_block *)blk;
+ if (xb->xb_flags & OCFS2_XATTR_INDEXED)
+ ret = ocfs2_xattr_iterate_index_block(ci, xb, func, priv_data);
+ else {
+ struct ocfs2_xattr_header *header = &xb->xb_attrs.xb_header;
+ ret = ocfs2_xattr_iterate_entries(ci, header, func, priv_data);
+ }
+
+ ocfs2_free(&blk);
+
+ return ret;
+}
+
static int ocfs2_xattr_find_entry(int name_index,
const char *name,
struct ocfs2_xattr_search *xs)
@@ -3150,3 +3309,34 @@ errcode_t ocfs2_xattr_set(ocfs2_cached_inode *ci,
return OCFS2_ET_INVALID_ARGUMENT;
return ocfs2_xattr_set_generic(ci, name_index, name, buf, count);
}
+
+/*
+ * Iterate the xattr entries on inode 'ci'. If 'func' returns
+ * OCFS2_XATTR_ABORT or OCFS2_XATTR_ERROR, stop iteration.
+ * If OCFS2_XATTR_ERROR, return an error from ocfs2_xattr_iterate.
+ *
+ * If you modify an xattr, you must restart your iteration - there is
+ * no guarantee it is in a consistent state.
+ */
+errcode_t ocfs2_xattr_iterate(ocfs2_cached_inode *ci,
+ int (*func)(ocfs2_cached_inode *ci,
+ struct ocfs2_xattr_entry *xe,
+ void *priv_data),
+ void *priv_data)
+{
+ errcode_t ret = 0;
+ struct ocfs2_super_block *sb = OCFS2_RAW_SB(ci->ci_fs->fs_super);
+ struct ocfs2_dinode *di = ci->ci_inode;
+
+ if (!(sb->s_feature_incompat & OCFS2_FEATURE_INCOMPAT_XATTR))
+ return OCFS2_ET_UNSUPP_FEATURE;
+ if (!(di->i_dyn_features & OCFS2_HAS_XATTR_FL))
+ return OCFS2_ET_XATTR_NODATA;
+
+ ret = ocfs2_xattr_iterate_ibody(ci, func, priv_data);
+ if (ret)
+ ret = ocfs2_xattr_iterate_block(ci, func, priv_data);
+
+ return ret;
+}
+
--
1.5.4.1
More information about the Ocfs2-tools-devel
mailing list