Browse Source

EA supports code rewritten with the view of providing EA modification

supports.
pull/8/head
ngkaho1234 9 years ago
parent
commit
ce0087be0d
  1. 13
      lwext4/ext4.c
  2. 462
      lwext4/ext4_rbtree.c
  3. 201
      lwext4/ext4_rbtree.h
  4. 13
      lwext4/ext4_types.h
  5. 323
      lwext4/ext4_xattr.c
  6. 8
      lwext4/ext4_xattr.h

13
lwext4/ext4.c

@ -736,23 +736,10 @@ static int ext4_generic_open2(ext4_file *f, const char *path, int flags,
{
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);
}
}

462
lwext4/ext4_rbtree.c

@ -0,0 +1,462 @@
/*
Red Black Trees
(C) 1999 Andrea Arcangeli <andrea@suse.de>
(C) 2002 David Woodhouse <dwmw2@infradead.org>
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);
}

201
lwext4/ext4_rbtree.h

@ -0,0 +1,201 @@
/*
Red Black Trees
(C) 1999 Andrea Arcangeli <andrea@suse.de>
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_ */

13
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 @@ struct ext4_xattr_entry {
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;
};

323
lwext4/ext4_xattr.c

@ -7,12 +7,154 @@
#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,
@ -46,16 +188,10 @@ static void *ext4_xattr_entry_data(struct ext4_xattr_ref *xattr_ref,
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 @@ static int ext4_xattr_block_lookup(struct ext4_xattr_ref *xattr_ref,
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;
struct ext4_xattr_item *item;
char *e_name = (char *)(entry + 1);
data = ext4_xattr_entry_data(xattr_ref, entry,
false);
if (!data)
return EIO;
data = ext4_xattr_entry_data(xattr_ref, entry,
false);
if (!data) {
ret = EIO;
goto Finish;
}
if (found_entry)
*found_entry = entry;
item = ext4_xattr_item_alloc(entry->e_name_index,
e_name,
(size_t)entry->e_name_len);
if (!item) {
ret = ENOMEM;
goto Finish;
}
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);
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 @@ static int ext4_xattr_inode_lookup(struct ext4_xattr_ref *xattr_ref,
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;
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 (!entry_found)
return ENOENT;
data = ext4_xattr_entry_data(xattr_ref, entry,
true);
if (!data)
return EIO;
item = ext4_xattr_item_alloc(entry->e_name_index,
e_name,
(size_t)entry->e_name_len);
if (!item) {
ret = ENOMEM;
goto Finish;
}
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);
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 @@ int ext4_fs_get_xattr_ref(struct ext4_fs *fs,
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 @@ int ext4_fs_get_xattr_ref(struct ext4_fs *fs,
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 @@ void ext4_fs_put_xattr_ref(struct ext4_xattr_ref *ref)
ext4_block_set(ref->fs->bdev, &ref->block);
ref->block_loaded = false;
}
ext4_xattr_purge_items(ref);
ref->inode_ref = NULL;
ref->fs = NULL;
}

8
lwext4/ext4_xattr.h

@ -10,12 +10,4 @@ int ext4_fs_get_xattr_ref(struct ext4_fs *fs,
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

Loading…
Cancel
Save