diff options
| author | ngkaho1234 <ngkaho1234@gmail.com> | 2015-10-04 03:40:14 +0800 |
|---|---|---|
| committer | ngkaho1234 <ngkaho1234@gmail.com> | 2015-10-04 03:40:14 +0800 |
| commit | f8c7281bf53970f2250bc03cb9dada3b80302614 (patch) | |
| tree | 8ab19314400224da1c546ee89e205d0290bb4861 | |
| parent | 9190df910a2ba3d6d1c27989a5b1ab525da02a01 (diff) | |
Experimental EA supports.
| -rw-r--r-- | lwext4/ext4.c | 26 | ||||
| -rw-r--r-- | lwext4/ext4_types.h | 82 | ||||
| -rw-r--r-- | lwext4/ext4_xattr.c | 225 | ||||
| -rw-r--r-- | lwext4/ext4_xattr.h | 21 |
4 files changed, 354 insertions, 0 deletions
diff --git a/lwext4/ext4.c b/lwext4/ext4.c index 99ba961..1926484 100644 --- 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 @@ static int ext4_generic_open2(ext4_file *f, const char *path, int flags, 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); diff --git a/lwext4/ext4_types.h b/lwext4/ext4_types.h index bb6d4db..549ad24 100644 --- a/lwext4/ext4_types.h +++ b/lwext4/ext4_types.h @@ -628,6 +628,88 @@ struct ext4_hash_info { 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 diff --git a/lwext4/ext4_xattr.c b/lwext4/ext4_xattr.c new file mode 100644 index 0000000..9c458eb --- /dev/null +++ b/lwext4/ext4_xattr.c @@ -0,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; +} + diff --git a/lwext4/ext4_xattr.h b/lwext4/ext4_xattr.h new file mode 100644 index 0000000..17615d8 --- /dev/null +++ b/lwext4/ext4_xattr.h @@ -0,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 |
