ref: ce0087be0d06ad6efc332ba0c8146aa29d439b2d
parent: f8c7281bf53970f2250bc03cb9dada3b80302614
author: ngkaho1234 <[email protected]>
date: Sun Oct 4 14:49:04 EDT 2015
EA supports code rewritten with the view of providing EA modification supports.
--- a/lwext4/ext4.c
+++ b/lwext4/ext4.c
@@ -736,23 +736,10 @@
{
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);
}
}
--- /dev/null
+++ b/lwext4/ext4_rbtree.c
@@ -1,0 +1,462 @@
+/*
+ Red Black Trees
+ (C) 1999 Andrea Arcangeli <[email protected]>
+ (C) 2002 David Woodhouse <[email protected]>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ linux/lib/rbtree.c
+*/
+#include "ext4_rbtree.h"
+
+static void __ext4_rb_rotate_left(struct ext4_rb_node *node, struct ext4_rb_root *root)
+{
+ struct ext4_rb_node *right = node->ext4_rb_right;
+ struct ext4_rb_node *parent = ext4_rb_parent(node);
+
+ if ((node->ext4_rb_right = right->ext4_rb_left))
+ ext4_rb_set_parent(right->ext4_rb_left, node);
+ right->ext4_rb_left = node;
+
+ ext4_rb_set_parent(right, parent);
+
+ if (parent) {
+ if (node == parent->ext4_rb_left)
+ parent->ext4_rb_left = right;
+ else
+ parent->ext4_rb_right = right;
+ } else
+ root->ext4_rb_node = right;
+ ext4_rb_set_parent(node, right);
+}
+
+static void __ext4_rb_rotate_right(struct ext4_rb_node *node, struct ext4_rb_root *root)
+{
+ struct ext4_rb_node *left = node->ext4_rb_left;
+ struct ext4_rb_node *parent = ext4_rb_parent(node);
+
+ if ((node->ext4_rb_left = left->ext4_rb_right))
+ ext4_rb_set_parent(left->ext4_rb_right, node);
+ left->ext4_rb_right = node;
+
+ ext4_rb_set_parent(left, parent);
+
+ if (parent) {
+ if (node == parent->ext4_rb_right)
+ parent->ext4_rb_right = left;
+ else
+ parent->ext4_rb_left = left;
+ } else
+ root->ext4_rb_node = left;
+ ext4_rb_set_parent(node, left);
+}
+
+void ext4_rb_insert_color(struct ext4_rb_node *node, struct ext4_rb_root *root)
+{
+ struct ext4_rb_node *parent, *gparent;
+
+ while ((parent = ext4_rb_parent(node)) && ext4_rb_is_red(parent)) {
+ gparent = ext4_rb_parent(parent);
+
+ if (parent == gparent->ext4_rb_left) {
+ {
+ register struct ext4_rb_node *uncle =
+ gparent->ext4_rb_right;
+ if (uncle && ext4_rb_is_red(uncle)) {
+ ext4_rb_set_black(uncle);
+ ext4_rb_set_black(parent);
+ ext4_rb_set_red(gparent);
+ node = gparent;
+ continue;
+ }
+ }
+
+ if (parent->ext4_rb_right == node) {
+ register struct ext4_rb_node *tmp;
+ __ext4_rb_rotate_left(parent, root);
+ tmp = parent;
+ parent = node;
+ node = tmp;
+ }
+
+ ext4_rb_set_black(parent);
+ ext4_rb_set_red(gparent);
+ __ext4_rb_rotate_right(gparent, root);
+ } else {
+ {
+ register struct ext4_rb_node *uncle =
+ gparent->ext4_rb_left;
+ if (uncle && ext4_rb_is_red(uncle)) {
+ ext4_rb_set_black(uncle);
+ ext4_rb_set_black(parent);
+ ext4_rb_set_red(gparent);
+ node = gparent;
+ continue;
+ }
+ }
+
+ if (parent->ext4_rb_left == node) {
+ register struct ext4_rb_node *tmp;
+ __ext4_rb_rotate_right(parent, root);
+ tmp = parent;
+ parent = node;
+ node = tmp;
+ }
+
+ ext4_rb_set_black(parent);
+ ext4_rb_set_red(gparent);
+ __ext4_rb_rotate_left(gparent, root);
+ }
+ }
+
+ ext4_rb_set_black(root->ext4_rb_node);
+}
+
+static void __ext4_rb_erase_color(struct ext4_rb_node *node, struct ext4_rb_node *parent,
+ struct ext4_rb_root *root)
+{
+ struct ext4_rb_node *other;
+
+ while ((!node || ext4_rb_is_black(node)) && node != root->ext4_rb_node) {
+ if (parent->ext4_rb_left == node) {
+ other = parent->ext4_rb_right;
+ if (ext4_rb_is_red(other)) {
+ ext4_rb_set_black(other);
+ ext4_rb_set_red(parent);
+ __ext4_rb_rotate_left(parent, root);
+ other = parent->ext4_rb_right;
+ }
+ if ((!other->ext4_rb_left ||
+ ext4_rb_is_black(other->ext4_rb_left)) &&
+ (!other->ext4_rb_right ||
+ ext4_rb_is_black(other->ext4_rb_right))) {
+ ext4_rb_set_red(other);
+ node = parent;
+ parent = ext4_rb_parent(node);
+ } else {
+ if (!other->ext4_rb_right ||
+ ext4_rb_is_black(other->ext4_rb_right)) {
+ ext4_rb_set_black(other->ext4_rb_left);
+ ext4_rb_set_red(other);
+ __ext4_rb_rotate_right(other, root);
+ other = parent->ext4_rb_right;
+ }
+ ext4_rb_set_color(other, ext4_rb_color(parent));
+ ext4_rb_set_black(parent);
+ ext4_rb_set_black(other->ext4_rb_right);
+ __ext4_rb_rotate_left(parent, root);
+ node = root->ext4_rb_node;
+ break;
+ }
+ } else {
+ other = parent->ext4_rb_left;
+ if (ext4_rb_is_red(other)) {
+ ext4_rb_set_black(other);
+ ext4_rb_set_red(parent);
+ __ext4_rb_rotate_right(parent, root);
+ other = parent->ext4_rb_left;
+ }
+ if ((!other->ext4_rb_left ||
+ ext4_rb_is_black(other->ext4_rb_left)) &&
+ (!other->ext4_rb_right ||
+ ext4_rb_is_black(other->ext4_rb_right))) {
+ ext4_rb_set_red(other);
+ node = parent;
+ parent = ext4_rb_parent(node);
+ } else {
+ if (!other->ext4_rb_left ||
+ ext4_rb_is_black(other->ext4_rb_left)) {
+ ext4_rb_set_black(other->ext4_rb_right);
+ ext4_rb_set_red(other);
+ __ext4_rb_rotate_left(other, root);
+ other = parent->ext4_rb_left;
+ }
+ ext4_rb_set_color(other, ext4_rb_color(parent));
+ ext4_rb_set_black(parent);
+ ext4_rb_set_black(other->ext4_rb_left);
+ __ext4_rb_rotate_right(parent, root);
+ node = root->ext4_rb_node;
+ break;
+ }
+ }
+ }
+ if (node)
+ ext4_rb_set_black(node);
+}
+
+void __ext4_rb_erase(struct ext4_rb_node *node, struct ext4_rb_root *root)
+{
+ struct ext4_rb_node *child, *parent;
+ int color;
+
+ if (!node->ext4_rb_left)
+ child = node->ext4_rb_right;
+ else if (!node->ext4_rb_right)
+ child = node->ext4_rb_left;
+ else {
+ struct ext4_rb_node *old = node, *left;
+
+ node = node->ext4_rb_right;
+ while ((left = node->ext4_rb_left) != NULL)
+ node = left;
+
+ if (ext4_rb_parent(old)) {
+ if (ext4_rb_parent(old)->ext4_rb_left == old)
+ ext4_rb_parent(old)->ext4_rb_left = node;
+ else
+ ext4_rb_parent(old)->ext4_rb_right = node;
+ } else
+ root->ext4_rb_node = node;
+
+ child = node->ext4_rb_right;
+ parent = ext4_rb_parent(node);
+ color = ext4_rb_color(node);
+
+ if (parent == old) {
+ parent = node;
+ } else {
+ if (child)
+ ext4_rb_set_parent(child, parent);
+ parent->ext4_rb_left = child;
+
+ node->ext4_rb_right = old->ext4_rb_right;
+ ext4_rb_set_parent(old->ext4_rb_right, node);
+ }
+
+ node->ext4_rb_parent_color = old->ext4_rb_parent_color;
+ node->ext4_rb_left = old->ext4_rb_left;
+ ext4_rb_set_parent(old->ext4_rb_left, node);
+
+ goto color;
+ }
+
+ parent = ext4_rb_parent(node);
+ color = ext4_rb_color(node);
+
+ if (child)
+ ext4_rb_set_parent(child, parent);
+ if (parent) {
+ if (parent->ext4_rb_left == node)
+ parent->ext4_rb_left = child;
+ else
+ parent->ext4_rb_right = child;
+ } else
+ root->ext4_rb_node = child;
+
+color:
+ if (color == EXT4_RB_BLACK)
+ __ext4_rb_erase_color(child, parent, root);
+}
+
+static void ext4_rb_augment_path(struct ext4_rb_node *node, ext4_rb_augment_f func,
+ void *data)
+{
+ struct ext4_rb_node *parent;
+
+up:
+ func(node, data);
+ parent = ext4_rb_parent(node);
+ if (!parent)
+ return;
+
+ if (node == parent->ext4_rb_left && parent->ext4_rb_right)
+ func(parent->ext4_rb_right, data);
+ else if (parent->ext4_rb_left)
+ func(parent->ext4_rb_left, data);
+
+ node = parent;
+ goto up;
+}
+
+/*
+ * after inserting @node into the tree, update the tree to account for
+ * both the new entry and any damage done by rebalance
+ */
+void ext4_rb_augment_insert(struct ext4_rb_node *node, ext4_rb_augment_f func,
+ void *data)
+{
+ if (node->ext4_rb_left)
+ node = node->ext4_rb_left;
+ else if (node->ext4_rb_right)
+ node = node->ext4_rb_right;
+
+ ext4_rb_augment_path(node, func, data);
+}
+
+/*
+ * before removing the node, find the deepest node on the rebalance path
+ * that will still be there after @node gets removed
+ */
+struct ext4_rb_node *ext4_rb_augment_erase_begin(struct ext4_rb_node *node)
+{
+ struct ext4_rb_node *deepest;
+
+ if (!node->ext4_rb_right && !node->ext4_rb_left)
+ deepest = ext4_rb_parent(node);
+ else if (!node->ext4_rb_right)
+ deepest = node->ext4_rb_left;
+ else if (!node->ext4_rb_left)
+ deepest = node->ext4_rb_right;
+ else {
+ deepest = ext4_rb_next(node);
+ if (deepest->ext4_rb_right)
+ deepest = deepest->ext4_rb_right;
+ else if (ext4_rb_parent(deepest) != node)
+ deepest = ext4_rb_parent(deepest);
+ }
+
+ return deepest;
+}
+
+/*
+ * after removal, update the tree to account for the removed entry
+ * and any rebalance damage.
+ */
+void ext4_rb_augment_erase_end(struct ext4_rb_node *node, ext4_rb_augment_f func,
+ void *data)
+{
+ if (node)
+ ext4_rb_augment_path(node, func, data);
+}
+
+/*
+ * This function returns the first node (in sort order) of the tree.
+ */
+struct ext4_rb_node *ext4_rb_first(const struct ext4_rb_root *root)
+{
+ struct ext4_rb_node *n;
+
+ n = root->ext4_rb_node;
+ if (!n)
+ return NULL;
+ while (n->ext4_rb_left)
+ n = n->ext4_rb_left;
+ return n;
+}
+
+struct ext4_rb_node *ext4_rb_last(const struct ext4_rb_root *root)
+{
+ struct ext4_rb_node *n;
+
+ n = root->ext4_rb_node;
+ if (!n)
+ return NULL;
+ while (n->ext4_rb_right)
+ n = n->ext4_rb_right;
+ return n;
+}
+
+struct ext4_rb_node *ext4_rb_next(const struct ext4_rb_node *node)
+{
+ struct ext4_rb_node *parent;
+
+ if (ext4_rb_parent(node) == node)
+ return NULL;
+
+ /* If we have a right-hand child, go down and then left as far
+ as we can. */
+ if (node->ext4_rb_right) {
+ node = node->ext4_rb_right;
+ while (node->ext4_rb_left)
+ node = node->ext4_rb_left;
+ return (struct ext4_rb_node *)node;
+ }
+
+ /* No right-hand children. Everything down and left is
+ smaller than us, so any 'next' node must be in the general
+ direction of our parent. Go up the tree; any time the
+ ancestor is a right-hand child of its parent, keep going
+ up. First time it's a left-hand child of its parent, said
+ parent is our 'next' node. */
+ while ((parent = ext4_rb_parent(node)) && node == parent->ext4_rb_right)
+ node = parent;
+
+ return parent;
+}
+
+struct ext4_rb_node *ext4_rb_prev(const struct ext4_rb_node *node)
+{
+ struct ext4_rb_node *parent;
+
+ if (ext4_rb_parent(node) == node)
+ return NULL;
+
+ /* If we have a left-hand child, go down and then right as far
+ as we can. */
+ if (node->ext4_rb_left) {
+ node = node->ext4_rb_left;
+ while (node->ext4_rb_right)
+ node = node->ext4_rb_right;
+ return (struct ext4_rb_node *)node;
+ }
+
+ /* No left-hand children. Go up till we find an ancestor which
+ is a right-hand child of its parent */
+ while ((parent = ext4_rb_parent(node)) && node == parent->ext4_rb_left)
+ node = parent;
+
+ return parent;
+}
+
+void ext4_rb_replace_node(struct ext4_rb_node *victim, struct ext4_rb_node *new,
+ struct ext4_rb_root *root)
+{
+ struct ext4_rb_node *parent = ext4_rb_parent(victim);
+
+ /* Set the surrounding nodes to point to the replacement */
+ if (parent) {
+ if (victim == parent->ext4_rb_left)
+ parent->ext4_rb_left = new;
+ else
+ parent->ext4_rb_right = new;
+ } else {
+ root->ext4_rb_node = new;
+ }
+ if (victim->ext4_rb_left)
+ ext4_rb_set_parent(victim->ext4_rb_left, new);
+ if (victim->ext4_rb_right)
+ ext4_rb_set_parent(victim->ext4_rb_right, new);
+
+ /* Copy the pointers/colour from the victim to the replacement */
+ *new = *victim;
+}
+
+void ext4_rb_erase(struct ext4_rb_node *node, struct ext4_rb_root *root)
+{
+ __ext4_rb_erase(node, root);
+}
+
+void ext4_rb_insert(struct ext4_rb_root *root, struct ext4_rb_node *node,
+ int (*cmp)(struct ext4_rb_node *, struct ext4_rb_node *))
+{
+ struct ext4_rb_node **new = &(root->ext4_rb_node), *parent = NULL;
+
+ /* Figure out where to put new node */
+ while (*new) {
+ int result = cmp(node, *new);
+
+ parent = *new;
+ if (result < 0) {
+ new = &((*new)->ext4_rb_left);
+ } else if (result > 0) {
+ new = &((*new)->ext4_rb_right);
+ } else
+ return;
+ }
+
+ /* Add new node and rebalance tree. */
+ ext4_rb_link_node(node, parent, new);
+ ext4_rb_insert_color(node, root);
+}
--- /dev/null
+++ b/lwext4/ext4_rbtree.h
@@ -1,0 +1,201 @@
+/*
+ Red Black Trees
+ (C) 1999 Andrea Arcangeli <[email protected]>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ linux/include/linux/rbtree.h
+
+ To use rbtrees you'll have to implement your own insert and search cores.
+ This will avoid us to use callbacks and to drop drammatically performances.
+ I know it's not the cleaner way, but in C (not in C++) to get
+ performances and genericity...
+
+ Some example of insert and search follows here. The search is a plain
+ normal search over an ordered tree. The insert instead must be implemented
+ in two steps: First, the code must insert the element in order as a red leaf
+ in the tree, and then the support library function ext4_rb_insert_color() must
+ be called. Such function will do the not trivial work to rebalance the
+ rbtree, if necessary.
+
+-----------------------------------------------------------------------
+static inline struct page * ext4_rb_search_page_cache(struct inode * inode,
+ unsigned long offset)
+{
+ struct ext4_rb_node * n = inode->i_ext4_rb_page_cache.ext4_rb_node;
+ struct page * page;
+
+ while (n)
+ {
+ page = ext4_rb_entry(n, struct page, ext4_rb_page_cache);
+
+ if (offset < page->offset)
+ n = n->ext4_rb_left;
+ else if (offset > page->offset)
+ n = n->ext4_rb_right;
+ else
+ return page;
+ }
+ return NULL;
+}
+
+static inline struct page * __ext4_rb_insert_page_cache(struct inode * inode,
+ unsigned long offset,
+ struct ext4_rb_node * node)
+{
+ struct ext4_rb_node ** p = &inode->i_ext4_rb_page_cache.ext4_rb_node;
+ struct ext4_rb_node * parent = NULL;
+ struct page * page;
+
+ while (*p)
+ {
+ parent = *p;
+ page = ext4_rb_entry(parent, struct page, ext4_rb_page_cache);
+
+ if (offset < page->offset)
+ p = &(*p)->ext4_rb_left;
+ else if (offset > page->offset)
+ p = &(*p)->ext4_rb_right;
+ else
+ return page;
+ }
+
+ ext4_rb_link_node(node, parent, p);
+
+ return NULL;
+}
+
+static inline struct page * ext4_rb_insert_page_cache(struct inode * inode,
+ unsigned long offset,
+ struct ext4_rb_node * node)
+{
+ struct page * ret;
+ if ((ret = __ext4_rb_insert_page_cache(inode, offset, node)))
+ goto out;
+ ext4_rb_insert_color(node, &inode->i_ext4_rb_page_cache);
+ out:
+ return ret;
+}
+-----------------------------------------------------------------------
+*/
+
+#ifndef EXT4_RBTREE_H_
+#define EXT4_RBTREE_H_
+
+#include <stddef.h>
+#include <stdbool.h>
+
+#ifndef offsetof
+#define offsetof(type, member) ((size_t) & ((type *)0)->member)
+#endif
+#ifndef container_of
+#define container_of(ptr, type, member) \
+ ((type *)((char *)(ptr) - (unsigned long)(&((type *)0)->member)))
+#endif
+
+struct ext4_rb_node
+{
+ unsigned long ext4_rb_parent_color;
+#define EXT4_RB_RED 0
+#define EXT4_RB_BLACK 1
+ struct ext4_rb_node *ext4_rb_right;
+ struct ext4_rb_node *ext4_rb_left;
+};
+/* The alignment might seem pointless, but allegedly CRIS needs it */
+
+struct ext4_rb_root
+{
+ struct ext4_rb_node *ext4_rb_node;
+};
+
+#define ext4_rb_parent(r) ((struct ext4_rb_node *)((r)->ext4_rb_parent_color & ~3))
+#define ext4_rb_color(r) ((r)->ext4_rb_parent_color & 1)
+#define ext4_rb_is_red(r) (!ext4_rb_color(r))
+#define ext4_rb_is_black(r) ext4_rb_color(r)
+#define ext4_rb_set_red(r) \
+ do { \
+ (r)->ext4_rb_parent_color &= ~1; \
+ } while (0)
+#define ext4_rb_set_black(r) \
+ do { \
+ (r)->ext4_rb_parent_color |= 1; \
+ } while (0)
+
+static inline void ext4_rb_set_parent(struct ext4_rb_node *rb, struct ext4_rb_node *p)
+{
+ rb->ext4_rb_parent_color =
+ (rb->ext4_rb_parent_color & 3) | (unsigned long)p;
+}
+static inline void ext4_rb_set_color(struct ext4_rb_node *rb, int color)
+{
+ rb->ext4_rb_parent_color = (rb->ext4_rb_parent_color & ~1) | color;
+}
+
+#define EXT4_RB_ROOT \
+ (struct ext4_rb_root) \
+ { \
+ NULL, \
+ }
+#define ext4_rb_entry(ptr, type, member) container_of(ptr, type, member)
+
+#define EXT4_RB_EMPTY_ROOT(root) ((root)->ext4_rb_node == NULL)
+#define EXT4_RB_EMPTY_NODE(node) (ext4_rb_parent(node) == node)
+#define EXT4_RB_CLEAR_NODE(node) (ext4_rb_set_parent(node, node))
+
+static inline void ext4_rb_init_node(struct ext4_rb_node *rb)
+{
+ rb->ext4_rb_parent_color = 0;
+ rb->ext4_rb_right = NULL;
+ rb->ext4_rb_left = NULL;
+ EXT4_RB_CLEAR_NODE(rb);
+}
+
+extern void ext4_rb_insert_color(struct ext4_rb_node *, struct ext4_rb_root *);
+extern void ext4_rb_erase(struct ext4_rb_node *, struct ext4_rb_root *);
+
+typedef void (*ext4_rb_augment_f)(struct ext4_rb_node *node, void *data);
+
+extern void ext4_rb_augment_insert(struct ext4_rb_node *node, ext4_rb_augment_f func,
+ void *data);
+extern struct ext4_rb_node *ext4_rb_augment_erase_begin(struct ext4_rb_node *node);
+extern void ext4_rb_augment_erase_end(struct ext4_rb_node *node, ext4_rb_augment_f func,
+ void *data);
+
+/* Find logical next and previous nodes in a tree */
+extern struct ext4_rb_node *ext4_rb_next(const struct ext4_rb_node *);
+extern struct ext4_rb_node *ext4_rb_prev(const struct ext4_rb_node *);
+extern struct ext4_rb_node *ext4_rb_first(const struct ext4_rb_root *);
+extern struct ext4_rb_node *ext4_rb_last(const struct ext4_rb_root *);
+
+/* Fast replacement of a single node without remove/rebalance/add/rebalance */
+extern void ext4_rb_replace_node(struct ext4_rb_node *victim, struct ext4_rb_node *new,
+ struct ext4_rb_root *root);
+
+static inline void ext4_rb_link_node(struct ext4_rb_node *node,
+ struct ext4_rb_node *parent,
+ struct ext4_rb_node **ext4_rb_link)
+{
+ node->ext4_rb_parent_color = (unsigned long)parent;
+ node->ext4_rb_left = node->ext4_rb_right = NULL;
+
+ *ext4_rb_link = node;
+}
+
+extern void ext4_rb_erase(struct ext4_rb_node *, struct ext4_rb_root *);
+
+extern void ext4_rb_insert(struct ext4_rb_root *, struct ext4_rb_node *,
+ int (*)(struct ext4_rb_node *, struct ext4_rb_node *));
+
+#endif /* EXT4_RBTREE_H_ */
--- a/lwext4/ext4_types.h
+++ b/lwext4/ext4_types.h
@@ -44,6 +44,7 @@
#include "ext4_config.h"
#include "ext4_blockdev.h"
+#include "ext4_rbtree.h"
#include <stdint.h>
@@ -670,10 +671,22 @@
uint32_t e_hash; /* hash value of name and value */
} __attribute__((packed));
+struct ext4_xattr_item {
+ uint8_t name_index;
+ char *name;
+ size_t name_len;
+ void *data;
+ size_t data_size;
+
+ struct ext4_rb_node node;
+};
+
struct ext4_xattr_ref {
bool block_loaded;
struct ext4_block block;
struct ext4_inode_ref *inode_ref;
+ struct ext4_rb_root root;
+ bool dirty;
struct ext4_fs *fs;
};
--- a/lwext4/ext4_xattr.c
+++ b/lwext4/ext4_xattr.c
@@ -7,13 +7,155 @@
#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>
+#include <stdlib.h>
+static int ext4_xattr_item_cmp(struct ext4_rb_node *a_,
+ struct ext4_rb_node *b_)
+{
+ struct ext4_xattr_item *a, *b;
+ int result;
+ a = container_of(a_, struct ext4_xattr_item, node);
+ b = container_of(b_, struct ext4_xattr_item, node);
+ result = a->name_index - b->name_index;
+ if (result)
+ return result;
+
+ result = a->name_len - b->name_len;
+ if (result)
+ return result;
+
+ return memcmp(a->name, b->name, a->name_len);
+}
+
+static struct ext4_xattr_item *
+ext4_xattr_item_lookup(struct ext4_rb_root *root,
+ uint8_t name_index,
+ char *name,
+ size_t name_len)
+{
+ struct ext4_rb_node *new = root->ext4_rb_node;
+
+ /* Figure out where to put new node */
+ while (new) {
+ struct ext4_xattr_item *item =
+ container_of(new, struct ext4_xattr_item, node);
+ int result = name_index - item->name_index;
+ if (!result) {
+ result = name_len - item->name_len;
+ if (!result)
+ result = memcmp(name,
+ item->name, name_len);
+
+ }
+
+ if (result < 0)
+ new = new->ext4_rb_left;
+ else if (result > 0)
+ new = new->ext4_rb_right;
+ else
+ return item;
+
+ }
+
+ return NULL;
+}
+
+static void
+ext4_xattr_item_insert(struct ext4_rb_root *root,
+ struct ext4_xattr_item *item)
+{
+ ext4_rb_insert(root, &item->node, ext4_xattr_item_cmp);
+}
+
+static void
+ext4_xattr_item_remove(struct ext4_rb_root *root,
+ struct ext4_xattr_item *item)
+{
+ ext4_rb_erase(&item->node, root);
+}
+
+
+static struct ext4_xattr_item *
+ext4_xattr_item_alloc(uint8_t name_index,
+ char *name,
+ size_t name_len)
+{
+ struct ext4_xattr_item *item;
+ item = malloc(sizeof(struct ext4_xattr_item) +
+ name_len);
+ if (!item)
+ return NULL;
+
+ item->name_index = name_index;
+ item->name = (char *)(item + 1);
+ item->name_len = name_len;
+ item->data = NULL;
+ item->data_size = 0;
+
+ memset(&item->node, 0, sizeof(item->node));
+ memcpy(item->name, name, name_len);
+
+ return item;
+}
+
+static int
+ext4_xattr_item_alloc_data(struct ext4_xattr_item *item,
+ void *orig_data,
+ size_t data_size)
+{
+ void *data = NULL;
+ ext4_assert(!item->data);
+ data = malloc(data_size);
+ if (!data)
+ return ENOMEM;
+
+ if (orig_data)
+ memcpy(data, orig_data, data_size);
+
+ item->data = data;
+ item->data_size = data_size;
+ return EOK;
+}
+
+static void
+ext4_xattr_item_free_data(struct ext4_xattr_item *item)
+{
+ ext4_assert(item->data);
+ free(item->data);
+ item->data = NULL;
+ item->data_size = 0;
+}
+
+static int
+ext4_xattr_item_resize_data(struct ext4_xattr_item *item,
+ size_t new_data_size)
+{
+ if (new_data_size != item->data_size) {
+ void *new_data;
+ new_data = realloc(item->data, new_data_size);
+ if (!new_data)
+ return ENOMEM;
+
+ item->data = new_data;
+ item->data_size = new_data_size;
+ }
+ return EOK;
+}
+
+static void
+ext4_xattr_item_free(struct ext4_xattr_item *item)
+{
+ if (item->data)
+ ext4_xattr_item_free_data(item);
+
+ free(item);
+}
+
+
static void *ext4_xattr_entry_data(struct ext4_xattr_ref *xattr_ref,
struct ext4_xattr_entry *entry,
bool in_inode)
@@ -46,16 +188,10 @@
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)
+static int ext4_xattr_block_fetch(struct ext4_xattr_ref *xattr_ref)
{
+ int ret = EOK;
size_t size_rem;
- bool entry_found = false;
void *data;
struct ext4_xattr_entry *entry = NULL;
@@ -66,49 +202,45 @@
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);
+ struct ext4_xattr_item *item;
+ char *e_name = (char *)(entry + 1);
+
+ data = ext4_xattr_entry_data(xattr_ref, entry,
+ false);
+ if (!data) {
+ ret = EIO;
+ goto Finish;
}
- if (!diff) {
- entry_found = true;
- break;
+
+ item = ext4_xattr_item_alloc(entry->e_name_index,
+ e_name,
+ (size_t)entry->e_name_len);
+ if (!item) {
+ ret = ENOMEM;
+ goto Finish;
}
- }
- if (!entry_found)
- return ENOENT;
+ if (ext4_xattr_item_alloc_data(item,
+ data,
+ to_le32(entry->e_value_size)
+ != EOK)) {
+ ext4_xattr_item_free(item);
+ ret = ENOMEM;
+ goto Finish;
+ }
+ ext4_xattr_item_insert(&xattr_ref->root,
+ item);
- 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;
+Finish:
+ return ret;
}
-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)
+static int ext4_xattr_inode_fetch(struct ext4_xattr_ref *xattr_ref)
{
void *data;
size_t size_rem;
- bool entry_found = false;
+ int ret = EOK;
struct ext4_xattr_ibody_header *header = NULL;
struct ext4_xattr_entry *entry = NULL;
uint16_t inode_size = ext4_get16(&xattr_ref->fs->sb,
@@ -123,73 +255,72 @@
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);
+ struct ext4_xattr_item *item;
+ char *e_name = (char *)(entry + 1);
+
+ data = ext4_xattr_entry_data(xattr_ref, entry,
+ true);
+ if (!data) {
+ ret = EIO;
+ goto Finish;
}
- if (!diff) {
- entry_found = true;
- break;
+
+ item = ext4_xattr_item_alloc(entry->e_name_index,
+ e_name,
+ (size_t)entry->e_name_len);
+ if (!item) {
+ ret = ENOMEM;
+ goto Finish;
}
- }
- if (!entry_found)
- return ENOENT;
+ if (ext4_xattr_item_alloc_data(item,
+ data,
+ to_le32(entry->e_value_size)
+ != EOK)) {
+ ext4_xattr_item_free(item);
+ ret = ENOMEM;
+ goto Finish;
+ }
+ ext4_xattr_item_insert(&xattr_ref->root,
+ item);
- 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;
+Finish:
+ return ret;
}
-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)
+static int ext4_xattr_fetch(struct ext4_xattr_ref *xattr_ref)
{
- int ret = ENOENT;
+ int ret = EOK;
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)
+ ret = ext4_xattr_inode_fetch(xattr_ref);
+ if (ret != EOK)
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);
+ ret = ext4_xattr_block_fetch(xattr_ref);
+
+ xattr_ref->dirty = false;
return ret;
}
+static void
+ext4_xattr_purge_items(struct ext4_xattr_ref *xattr_ref)
+{
+ struct ext4_rb_node *node;
+ while ((node = ext4_rb_first(&xattr_ref->root))) {
+ struct ext4_xattr_item *item = ext4_rb_entry(
+ node, struct ext4_xattr_item, node);
+ ext4_xattr_item_remove(&xattr_ref->root, item);
+ ext4_xattr_item_free(item);
+ }
+}
+
int ext4_fs_get_xattr_ref(struct ext4_fs *fs,
struct ext4_inode_ref *inode_ref,
struct ext4_xattr_ref *ref)
@@ -198,6 +329,7 @@
uint64_t xattr_block;
xattr_block = ext4_inode_get_file_acl(inode_ref->inode,
&fs->sb);
+ memset(&ref->root, 0, sizeof(ref->root));
if (xattr_block) {
rc = ext4_block_get(fs->bdev,
&inode_ref->block, xattr_block);
@@ -210,6 +342,16 @@
ref->inode_ref = inode_ref;
ref->fs = fs;
+
+ rc = ext4_xattr_fetch(ref);
+ if (rc != EOK) {
+ ext4_xattr_purge_items(ref);
+ if (xattr_block)
+ ext4_block_set(fs->bdev, &inode_ref->block);
+
+ ref->block_loaded = false;
+ return rc;
+ }
return EOK;
}
@@ -219,6 +361,7 @@
ext4_block_set(ref->fs->bdev, &ref->block);
ref->block_loaded = false;
}
+ ext4_xattr_purge_items(ref);
ref->inode_ref = NULL;
ref->fs = NULL;
}
--- a/lwext4/ext4_xattr.h
+++ b/lwext4/ext4_xattr.h
@@ -10,12 +10,4 @@
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