shithub: lwext4

Download patch

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