ref: f8c7281bf53970f2250bc03cb9dada3b80302614
parent: 9190df910a2ba3d6d1c27989a5b1ab525da02a01
author: ngkaho1234 <[email protected]>
date: Sat Oct 3 23:40:14 EDT 2015
Experimental EA supports.
--- a/lwext4/ext4.c
+++ b/lwext4/ext4.c
@@ -44,6 +44,7 @@
#include "ext4_inode.h"
#include "ext4_super.h"
#include "ext4_dir_idx.h"
+#include "ext4_xattr.h"
#include "ext4.h"
#include <stdlib.h>
@@ -730,6 +731,31 @@
if (f->flags & O_APPEND)
f->fpos = f->fsize;
+
+ /* FIXME: Debugging code on EA. */
+ {
+ int private_ret;
+ struct ext4_xattr_ref xattr_ref;
+ struct ext4_xattr_entry *found_entry = NULL;
+ void *out_data = NULL;
+ size_t out_len = 0;
+ private_ret = ext4_fs_get_xattr_ref(&f->mp->fs, &ref,
+ &xattr_ref);
+ if (private_ret == EOK) {
+ ext4_dmask_set(EXT4_DEBUG_ALL);
+ private_ret = ext4_xattr_lookup(&xattr_ref,
+ EXT4_XATTR_INDEX_POSIX_ACL_ACCESS,
+ "",
+ 0,
+ &found_entry,
+ &out_data,
+ &out_len);
+ if (private_ret == EOK) {
+ private_ret;
+ }
+ ext4_fs_put_xattr_ref(&xattr_ref);
+ }
+ }
}
r = ext4_fs_put_inode_ref(&ref);
--- a/lwext4/ext4_types.h
+++ b/lwext4/ext4_types.h
@@ -628,6 +628,88 @@
const uint32_t *seed;
};
+/* Extended Attribute(EA) */
+
+/* Magic value in attribute blocks */
+#define EXT4_XATTR_MAGIC 0xEA020000
+
+/* Maximum number of references to one attribute block */
+#define EXT4_XATTR_REFCOUNT_MAX 1024
+
+/* Name indexes */
+#define EXT4_XATTR_INDEX_USER 1
+#define EXT4_XATTR_INDEX_POSIX_ACL_ACCESS 2
+#define EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT 3
+#define EXT4_XATTR_INDEX_TRUSTED 4
+#define EXT4_XATTR_INDEX_LUSTRE 5
+#define EXT4_XATTR_INDEX_SECURITY 6
+#define EXT4_XATTR_INDEX_SYSTEM 7
+#define EXT4_XATTR_INDEX_RICHACL 8
+#define EXT4_XATTR_INDEX_ENCRYPTION 9
+
+struct ext4_xattr_header {
+ uint32_t h_magic; /* magic number for identification */
+ uint32_t h_refcount; /* reference count */
+ uint32_t h_blocks; /* number of disk blocks used */
+ uint32_t h_hash; /* hash value of all attributes */
+ uint32_t h_checksum; /* crc32c(uuid+id+xattrblock) */
+ /* id = inum if refcount=1, blknum otherwise */
+ uint32_t h_reserved[3]; /* zero right now */
+} __attribute__((packed));
+
+struct ext4_xattr_ibody_header {
+ uint32_t h_magic; /* magic number for identification */
+} __attribute__((packed));
+
+struct ext4_xattr_entry {
+ uint8_t e_name_len; /* length of name */
+ uint8_t e_name_index; /* attribute name index */
+ uint16_t e_value_offs; /* offset in disk block of value */
+ uint32_t e_value_block; /* disk block attribute is stored on (n/i) */
+ uint32_t e_value_size; /* size of attribute value */
+ uint32_t e_hash; /* hash value of name and value */
+} __attribute__((packed));
+
+struct ext4_xattr_ref {
+ bool block_loaded;
+ struct ext4_block block;
+ struct ext4_inode_ref *inode_ref;
+ struct ext4_fs *fs;
+};
+
+#define EXT4_GOOD_OLD_INODE_SIZE 128
+
+#define EXT4_XATTR_PAD_BITS 2
+#define EXT4_XATTR_PAD (1<<EXT4_XATTR_PAD_BITS)
+#define EXT4_XATTR_ROUND (EXT4_XATTR_PAD-1)
+#define EXT4_XATTR_LEN(name_len) \
+ (((name_len) + EXT4_XATTR_ROUND + \
+ sizeof(struct ext4_xattr_entry)) & ~EXT4_XATTR_ROUND)
+#define EXT4_XATTR_NEXT(entry) \
+ ((struct ext4_xattr_entry *)( \
+ (char *)(entry) + EXT4_XATTR_LEN((entry)->e_name_len)))
+#define EXT4_XATTR_SIZE(size) \
+ (((size) + EXT4_XATTR_ROUND) & ~EXT4_XATTR_ROUND)
+
+#define EXT4_XATTR_IHDR(raw_inode) \
+ ((struct ext4_xattr_ibody_header *) \
+ ((char *)raw_inode + \
+ EXT4_GOOD_OLD_INODE_SIZE + \
+ (raw_inode)->extra_isize))
+#define EXT4_XATTR_IFIRST(hdr) \
+ ((struct ext4_xattr_entry *)((hdr)+1))
+
+#define EXT4_XATTR_BHDR(block) \
+ ((struct ext4_xattr_header *)((block)->data))
+#define EXT4_XATTR_ENTRY(ptr) \
+ ((struct ext4_xattr_entry *)(ptr))
+#define EXT4_XATTR_BFIRST(block) \
+ EXT4_XATTR_ENTRY(EXT4_XATTR_BHDR(block)+1)
+#define EXT4_XATTR_IS_LAST_ENTRY(entry) \
+ (*(uint32_t *)(entry) == 0)
+
+#define EXT4_ZERO_XATTR_VALUE ((void *)-1)
+
/*****************************************************************************/
#ifdef CONFIG_BIG_ENDIAN
--- /dev/null
+++ b/lwext4/ext4_xattr.c
@@ -1,0 +1,225 @@
+#include "ext4_config.h"
+#include "ext4_types.h"
+#include "ext4_fs.h"
+#include "ext4_errno.h"
+#include "ext4_blockdev.h"
+#include "ext4_super.h"
+#include "ext4_debug.h"
+#include "ext4_block_group.h"
+#include "ext4_balloc.h"
+#include "ext4_bitmap.h"
+#include "ext4_inode.h"
+#include "ext4_ialloc.h"
+#include "ext4_extent.h"
+
+#include <string.h>
+
+static void *ext4_xattr_entry_data(struct ext4_xattr_ref *xattr_ref,
+ struct ext4_xattr_entry *entry,
+ bool in_inode)
+{
+ void *ret;
+ if (in_inode) {
+ struct ext4_xattr_ibody_header *header;
+ struct ext4_xattr_entry *first_entry;
+ uint16_t inode_size = ext4_get16(&xattr_ref->fs->sb,
+ inode_size);
+ header = EXT4_XATTR_IHDR(xattr_ref->inode_ref->inode);
+ first_entry = EXT4_XATTR_IFIRST(header);
+
+ ret = (void *)((char *)first_entry + to_le16(entry->e_value_offs));
+ if ((char *)ret + EXT4_XATTR_SIZE(to_le32(entry->e_value_size))
+ - (char *)xattr_ref->inode_ref->inode >
+ inode_size)
+ ret = NULL;
+
+ } else {
+ uint32_t block_size =
+ ext4_sb_get_block_size(&xattr_ref->fs->sb);
+ ret = (void *)((char *)xattr_ref->block.data +
+ to_le16(entry->e_value_offs));
+ if ((char *)ret + EXT4_XATTR_SIZE(to_le32(entry->e_value_size))
+ - (char *)xattr_ref->block.data >
+ block_size)
+ ret = NULL;
+ }
+ return ret;
+}
+
+static int ext4_xattr_block_lookup(struct ext4_xattr_ref *xattr_ref,
+ uint8_t name_index,
+ char *name,
+ size_t name_len,
+ struct ext4_xattr_entry **found_entry,
+ void **out_data,
+ size_t *out_len)
+{
+ size_t size_rem;
+ bool entry_found = false;
+ void *data;
+ struct ext4_xattr_entry *entry = NULL;
+
+ ext4_assert(xattr_ref->block.data);
+ entry = EXT4_XATTR_BFIRST(&xattr_ref->block);
+
+ size_rem = ext4_sb_get_block_size(&xattr_ref->fs->sb);
+ for(;size_rem > 0 && !EXT4_XATTR_IS_LAST_ENTRY(entry);
+ entry = EXT4_XATTR_NEXT(entry),
+ size_rem -= EXT4_XATTR_LEN(entry->e_name_len)) {
+ int diff = -1;
+ if (name_index == entry->e_name_index &&
+ name_len == entry->e_name_len) {
+ char *e_name = (char *)(entry + 1);
+ diff = memcmp(e_name,
+ name,
+ name_len);
+ }
+ if (!diff) {
+ entry_found = true;
+ break;
+ }
+ }
+ if (!entry_found)
+ return ENOENT;
+
+ data = ext4_xattr_entry_data(xattr_ref, entry,
+ false);
+ if (!data)
+ return EIO;
+
+ if (found_entry)
+ *found_entry = entry;
+
+ if (out_data && out_len) {
+ *out_data = data;
+ *out_len = to_le32(entry->e_value_size);
+ }
+
+ return EOK;
+}
+
+static int ext4_xattr_inode_lookup(struct ext4_xattr_ref *xattr_ref,
+ uint8_t name_index,
+ char *name,
+ size_t name_len,
+ struct ext4_xattr_entry **found_entry,
+ void **out_data,
+ size_t *out_len)
+{
+ void *data;
+ size_t size_rem;
+ bool entry_found = false;
+ struct ext4_xattr_ibody_header *header = NULL;
+ struct ext4_xattr_entry *entry = NULL;
+ uint16_t inode_size = ext4_get16(&xattr_ref->fs->sb,
+ inode_size);
+
+ header = EXT4_XATTR_IHDR(xattr_ref->inode_ref->inode);
+ entry = EXT4_XATTR_IFIRST(header);
+
+ size_rem = inode_size -
+ EXT4_GOOD_OLD_INODE_SIZE -
+ xattr_ref->inode_ref->inode->extra_isize;
+ for(;size_rem > 0 && !EXT4_XATTR_IS_LAST_ENTRY(entry);
+ entry = EXT4_XATTR_NEXT(entry),
+ size_rem -= EXT4_XATTR_LEN(entry->e_name_len)) {
+ int diff = -1;
+ if (name_index == entry->e_name_index &&
+ name_len == entry->e_name_len) {
+ char *e_name = (char *)(entry + 1);
+ diff = memcmp(e_name,
+ name,
+ name_len);
+ }
+ if (!diff) {
+ entry_found = true;
+ break;
+ }
+ }
+ if (!entry_found)
+ return ENOENT;
+
+ data = ext4_xattr_entry_data(xattr_ref, entry,
+ true);
+ if (!data)
+ return EIO;
+
+ if (found_entry)
+ *found_entry = entry;
+
+ if (out_data && out_len) {
+ *out_data = data;
+ *out_len = to_le32(entry->e_value_size);
+ }
+
+ return EOK;
+}
+
+int ext4_xattr_lookup(struct ext4_xattr_ref *xattr_ref,
+ uint8_t name_index,
+ char *name,
+ size_t name_len,
+ struct ext4_xattr_entry **found_entry,
+ void **out_data,
+ size_t *out_len)
+{
+ int ret = ENOENT;
+ uint16_t inode_size = ext4_get16(&xattr_ref->fs->sb,
+ inode_size);
+ if (inode_size > EXT4_GOOD_OLD_INODE_SIZE) {
+ ret = ext4_xattr_inode_lookup(xattr_ref,
+ name_index,
+ name,
+ name_len,
+ found_entry,
+ out_data,
+ out_len);
+ if (ret != ENOENT)
+ return ret;
+
+ }
+
+ if (xattr_ref->block_loaded)
+ ret = ext4_xattr_block_lookup(xattr_ref,
+ name_index,
+ name,
+ name_len,
+ found_entry,
+ out_data,
+ out_len);
+ return ret;
+}
+
+int ext4_fs_get_xattr_ref(struct ext4_fs *fs,
+ struct ext4_inode_ref *inode_ref,
+ struct ext4_xattr_ref *ref)
+{
+ int rc;
+ uint64_t xattr_block;
+ xattr_block = ext4_inode_get_file_acl(inode_ref->inode,
+ &fs->sb);
+ if (xattr_block) {
+ rc = ext4_block_get(fs->bdev,
+ &inode_ref->block, xattr_block);
+ if (rc != EOK)
+ return EIO;
+
+ ref->block_loaded = true;
+ } else
+ ref->block_loaded = false;
+
+ ref->inode_ref = inode_ref;
+ ref->fs = fs;
+ return EOK;
+}
+
+void ext4_fs_put_xattr_ref(struct ext4_xattr_ref *ref)
+{
+ if (ref->block_loaded) {
+ ext4_block_set(ref->fs->bdev, &ref->block);
+ ref->block_loaded = false;
+ }
+ ref->inode_ref = NULL;
+ ref->fs = NULL;
+}
+
--- /dev/null
+++ b/lwext4/ext4_xattr.h
@@ -1,0 +1,21 @@
+#ifndef EXT4_XATTR_H_
+#define EXT4_XATTR_H_
+
+#include "ext4_config.h"
+#include "ext4_types.h"
+
+int ext4_fs_get_xattr_ref(struct ext4_fs *fs,
+ struct ext4_inode_ref *inode_ref,
+ struct ext4_xattr_ref *ref);
+
+void ext4_fs_put_xattr_ref(struct ext4_xattr_ref *ref);
+
+int ext4_xattr_lookup(struct ext4_xattr_ref *xattr_ref,
+ uint8_t name_index,
+ char *name,
+ size_t name_len,
+ struct ext4_xattr_entry **found_entry,
+ void **out_data,
+ size_t *out_len);
+
+#endif