[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1348286469-31690-4-git-send-email-wenqing.lz@taobao.com>
Date: Sat, 22 Sep 2012 12:00:51 +0800
From: Zheng Liu <gnehzuil.liu@...il.com>
To: linux-ext4@...r.kernel.org
Cc: tytso@....edu, Zheng Liu <wenqing.lz@...bao.com>
Subject: [PATCH 03/21 v5] libext2fs: add functions to operate extend attribute
From: Zheng Liu <wenqing.lz@...bao.com>
We need to define some functions to operate extend attribte due to inline data
needs to change it.
Signed-off-by: Zheng Liu <wenqing.lz@...bao.com>
---
lib/ext2fs/ext2_ext_attr.h | 30 ++++++++
lib/ext2fs/ext2fs.h | 13 ++++
lib/ext2fs/ext_attr.c | 169 ++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 212 insertions(+), 0 deletions(-)
diff --git a/lib/ext2fs/ext2_ext_attr.h b/lib/ext2fs/ext2_ext_attr.h
index bbb0aaa..de60097 100644
--- a/lib/ext2fs/ext2_ext_attr.h
+++ b/lib/ext2fs/ext2_ext_attr.h
@@ -15,6 +15,10 @@
/* Maximum number of references to one attribute block */
#define EXT2_EXT_ATTR_REFCOUNT_MAX 1024
+/* Name indexes */
+#define EXT4_EXT_ATTR_INDEX_SYSTEM 7
+#define EXT4_EXT_ATTR_SYSTEM_DATA "data"
+
struct ext2_ext_attr_header {
__u32 h_magic; /* magic number for identification */
__u32 h_refcount; /* reference count */
@@ -25,6 +29,10 @@ struct ext2_ext_attr_header {
__u32 h_reserved[3]; /* zero right now */
};
+struct ext2_ext_attr_ibody_header {
+ __u32 h_magic;
+};
+
struct ext2_ext_attr_entry {
__u8 e_name_len; /* length of name */
__u8 e_name_index; /* attribute name index */
@@ -57,6 +65,28 @@ struct ext2_ext_attr_entry {
#define EXT2_XATTR_SIZE(size) \
(((size) + EXT2_EXT_ATTR_ROUND) & ~EXT2_EXT_ATTR_ROUND)
+#define IHDR(inode) \
+ ((struct ext2_ext_attr_ibody_header *) \
+ ((void *)inode + \
+ EXT2_GOOD_OLD_INODE_SIZE + \
+ inode->i_extra_isize))
+#define IFIRST(hdr) ((struct ext2_ext_attr_entry *)((hdr)+1))
+
+struct ext2_ext_attr_info {
+ int name_index;
+ const char *name;
+ const void *value;
+ size_t value_len;
+};
+
+struct ext2_ext_attr_search {
+ struct ext2_ext_attr_entry *first;
+ void *base;
+ void *end;
+ struct ext2_ext_attr_entry *here;
+ int not_found;
+};
+
#ifdef __KERNEL__
# ifdef CONFIG_EXT2_FS_EXT_ATTR
extern int ext2_get_ext_attr(struct inode *, const char *, char *, size_t, int);
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index 8714f58..b076c3c 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -1132,6 +1132,19 @@ extern errcode_t ext2fs_adjust_ea_refcount3(ext2_filsys fs, blk64_t blk,
char *block_buf,
int adjust, __u32 *newcount,
ext2_ino_t inum);
+extern errcode_t ext2fs_ibody_find_ext_attr(ext2_filsys fs,
+ struct ext2_inode_large *inode,
+ struct ext2_ext_attr_info *i,
+ struct ext2_ext_attr_search *s);
+extern errcode_t ext2fs_find_entry_ext_attr(struct ext2_ext_attr_entry **pentry,
+ int name_index, const char *name,
+ size_t size, int sorted);
+extern errcode_t ext2fs_set_entry_ext_attr(struct ext2_ext_attr_info *i,
+ struct ext2_ext_attr_search *s);
+extern int ext2fs_ibody_get_ext_attr(ext2_filsys fs,
+ struct ext2_inode_large *inode,
+ int name_index, const char *name,
+ void *buffer, size_t buf_len);
/* extent.c */
extern errcode_t ext2fs_extent_header_verify(void *ptr, int size);
diff --git a/lib/ext2fs/ext_attr.c b/lib/ext2fs/ext_attr.c
index 9649a14..c663f31 100644
--- a/lib/ext2fs/ext_attr.c
+++ b/lib/ext2fs/ext_attr.c
@@ -186,3 +186,172 @@ errcode_t ext2fs_adjust_ea_refcount(ext2_filsys fs, blk_t blk,
return ext2fs_adjust_ea_refcount2(fs, blk, block_buf, adjust,
newcount);
}
+
+errcode_t ext2fs_find_entry_ext_attr(struct ext2_ext_attr_entry **pentry,
+ int name_index, const char *name,
+ size_t size, int sorted)
+{
+ struct ext2_ext_attr_entry *entry;
+ size_t name_len;
+ int cmp;
+
+ name_len = strlen(name);
+ for (entry = *pentry; !EXT2_EXT_IS_LAST_ENTRY(entry);
+ entry = EXT2_EXT_ATTR_NEXT(entry)) {
+ cmp = name_index - entry->e_name_index;
+ if (!cmp)
+ cmp = name_len - entry->e_name_len;
+ if (!cmp)
+ cmp = memcmp(name, EXT2_EXT_ATTR_NAME(entry),
+ name_len);
+ if (!cmp)
+ break;
+ }
+ *pentry = entry;
+
+ return cmp;
+}
+
+errcode_t ext2fs_ibody_find_ext_attr(ext2_filsys fs,
+ struct ext2_inode_large *inode,
+ struct ext2_ext_attr_info *i,
+ struct ext2_ext_attr_search *s)
+{
+ struct ext2_ext_attr_ibody_header *header;
+ int error;
+
+ if (inode->i_extra_isize == 0)
+ return 0;
+ header = IHDR(inode);
+ s->base = s->first = IFIRST(header);
+ s->here = s->first;
+ s->end = (void *)inode + EXT2_INODE_SIZE(fs->super);
+ error = ext2fs_find_entry_ext_attr(&s->here, i->name_index,
+ i->name, s->end -
+ (void *)s->base, 0);
+ s->not_found = error;
+ return 0;
+}
+
+extern int ext2fs_ibody_get_ext_attr(ext2_filsys fs,
+ struct ext2_inode_large *inode,
+ int name_index, const char *name,
+ void *buffer, size_t buf_len)
+{
+ struct ext2_ext_attr_ibody_header *header;
+ struct ext2_ext_attr_entry *entry;
+ size_t size;
+ void *end;
+ int error;
+
+ header = IHDR(inode);
+ entry = IFIRST(header);
+ end = (void *)inode + EXT2_INODE_SIZE(fs->super);
+ error = ext2fs_find_entry_ext_attr(&entry, name_index, name,
+ end - (void *)entry, 0);
+ if (error)
+ return error;
+ size = ext2fs_le32_to_cpu(entry->e_value_size);
+ if (buffer) {
+ if (size > buf_len)
+ return error;
+ memcpy(buffer, (void *)IFIRST(header) +
+ ext2fs_le16_to_cpu(entry->e_value_offs), size);
+ }
+ error = size;
+
+ return error;
+}
+
+errcode_t ext2fs_set_entry_ext_attr(struct ext2_ext_attr_info *i,
+ struct ext2_ext_attr_search *s)
+{
+ struct ext2_ext_attr_entry *last;
+ size_t free, min_offs = s->end - s->base, name_len = strlen(i->name);
+
+ last = s->first;
+ for (; !EXT2_EXT_IS_LAST_ENTRY(last); last = EXT2_EXT_ATTR_NEXT(last)) {
+ if (!last->e_value_block && last->e_value_size) {
+ size_t offs = ext2fs_le16_to_cpu(last->e_value_offs);
+ if (offs < min_offs)
+ min_offs = offs;
+ }
+ }
+ free = min_offs - ((void *)last - s->base) - sizeof(__u32);
+ if (!s->not_found) {
+ if (!s->here->e_value_block & s->here->e_value_size) {
+ size_t size = ext2fs_le32_to_cpu(s->here->e_value_size);
+ free += EXT2_EXT_ATTR_SIZE(size);
+ }
+ free += EXT2_EXT_ATTR_LEN(name_len);
+ }
+ if (i->value) {
+ if (free < EXT2_EXT_ATTR_SIZE(i->value_len) ||
+ free < EXT2_EXT_ATTR_LEN(name_len) +
+ EXT2_EXT_ATTR_SIZE(i->value_len))
+ return -1;
+ }
+ if (i->value && s->not_found) {
+ size_t size = EXT2_EXT_ATTR_LEN(name_len);
+ size_t rest = (void *)last - (void *)s->here + sizeof(__u32);
+ memmove((void *)s->here + size, s->here, rest);
+ memset(s->here, 0, size);
+ s->here->e_name_index = i->name_index;
+ s->here->e_name_len = name_len;
+ memcpy(EXT2_EXT_ATTR_NAME(s->here),
+ EXT2_EXT_ATTR_NAME(i), name_len);
+ } else {
+ if (!s->here->e_value_block && s->here->e_value_size) {
+ void *first_val = s->base + min_offs;
+ size_t offs = ext2fs_le16_to_cpu(s->here->e_value_offs);
+ void *val = s->base + offs;
+ size_t size = EXT2_EXT_ATTR_SIZE(
+ ext2fs_le32_to_cpu(s->here->e_value_size));
+
+ if (i->value && size == EXT2_EXT_ATTR_SIZE(i->value_len)) {
+ s->here->e_value_size =
+ ext2fs_cpu_to_le32(i->value_len);
+ memset(val + size - EXT2_EXT_ATTR_PAD, 0,
+ EXT2_EXT_ATTR_PAD);
+ memcpy(val, i->value, i->value_len);
+ return 0;
+ }
+
+ memmove(first_val + size, first_val, val - first_val);
+ memset(first_val, 0, size);
+ s->here->e_value_size = 0;
+ s->here->e_value_offs = 0;
+ min_offs += size;
+
+ last = s->first;
+ while (!EXT2_EXT_IS_LAST_ENTRY(last)) {
+ size_t o = ext2fs_le16_to_cpu(last->e_value_offs);
+ if (!last->e_value_block &&
+ last->e_value_size && o < offs)
+ last->e_value_offs =
+ ext2fs_cpu_to_le16(o + size);
+ last = EXT2_EXT_ATTR_NEXT(last);
+ }
+ }
+ if (!i->value) {
+ size_t size = EXT2_EXT_ATTR_LEN(name_len);
+ last = (struct ext2_ext_attr_entry *)last - size;
+ memmove(s->here, (void *)s->here + size,
+ (void *)last - (void *)s->here + sizeof(__u32));
+ memset(last, 0, size);
+ }
+ }
+
+ if (i->value) {
+ s->here->e_value_size = ext2fs_cpu_to_le32(i->value_len);
+ if (i->value_len) {
+ size_t size = EXT2_EXT_ATTR_SIZE(i->value_len);
+ void *val = s->base + min_offs - size;
+ s->here->e_value_offs = ext2fs_cpu_to_le16(min_offs - size);
+ memset(val + size - EXT2_EXT_ATTR_PAD, 0,
+ EXT2_EXT_ATTR_PAD);
+ memcpy(val, i->value, i->value_len);
+ }
+ }
+ return 0;
+}
--
1.7.4.1
--
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Powered by blists - more mailing lists