diff options
author | Kaho Ng <ngkaho1234@gmail.com> | 2016-05-31 08:32:38 +0300 |
---|---|---|
committer | Kaho Ng <ngkaho1234@gmail.com> | 2016-05-31 08:32:38 +0300 |
commit | c29f39b3e3b3eb4358a13ec6b7b76087383b2a81 (patch) | |
tree | 9ab18ab6cceb236fb5f437bfe5bb2d0d2e6e3be0 | |
parent | aa9d21d654e4b2146346aa0db83953bca8497258 (diff) |
EA: ensure Ext2SetEa's insertion order
-rw-r--r-- | Ext3Fsd/ea.c | 20 | ||||
-rw-r--r-- | Ext3Fsd/ext4/ext4_xattr.c | 126 | ||||
-rw-r--r-- | Ext3Fsd/include/linux/ext4_xattr.h | 6 |
3 files changed, 106 insertions, 46 deletions
diff --git a/Ext3Fsd/ea.c b/Ext3Fsd/ea.c index 26e3654..f335f93 100644 --- a/Ext3Fsd/ea.c +++ b/Ext3Fsd/ea.c @@ -576,29 +576,15 @@ Ext2SetEa ( EaName.Buffer = &FullEa->EaName[0]; Status = Ext2WinntError(ret = - ext4_fs_set_xattr(&xattr_ref, + ext4_fs_set_xattr_ordered(&xattr_ref, EXT4_XATTR_INDEX_USER, EaName.Buffer, EaName.Length, &FullEa->EaName[0] + FullEa->EaNameLength + 1, - FullEa->EaValueLength, - TRUE)); - if (!NT_SUCCESS(Status) && ret != -ENODATA) + FullEa->EaValueLength)); + if (!NT_SUCCESS(Status)) __leave; - if (ret == -ENODATA) { - Status = Ext2WinntError( - ext4_fs_set_xattr(&xattr_ref, - EXT4_XATTR_INDEX_USER, - EaName.Buffer, - EaName.Length, - &FullEa->EaName[0] + FullEa->EaNameLength + 1, - FullEa->EaValueLength, - FALSE)); - if (!NT_SUCCESS(Status)) - __leave; - - } } } __finally { diff --git a/Ext3Fsd/ext4/ext4_xattr.c b/Ext3Fsd/ext4/ext4_xattr.c index ef81b8a..3c33b10 100644 --- a/Ext3Fsd/ext4/ext4_xattr.c +++ b/Ext3Fsd/ext4/ext4_xattr.c @@ -218,12 +218,14 @@ static void ext4_xattr_item_insert(struct ext4_xattr_ref *xattr_ref, { rb_insert(&xattr_ref->root, &item->node, ext4_xattr_item_cmp); + list_add_tail(&item->list_node, &xattr_ref->ordered_list); } static void ext4_xattr_item_remove(struct ext4_xattr_ref *xattr_ref, struct ext4_xattr_item *item) { rb_erase(&item->node, &xattr_ref->root); + list_del_init(&item->list_node); } static struct ext4_xattr_item * @@ -239,6 +241,7 @@ ext4_xattr_item_alloc(__u8 name_index, const char *name, size_t name_len) item->name_len = name_len; item->data = NULL; item->data_size = 0; + INIT_LIST_HEAD(&item->list_node); memcpy(item->name, name, name_len); @@ -535,6 +538,70 @@ ext4_xattr_insert_item(struct ext4_xattr_ref *xattr_ref, __u8 name_index, return item; } +static struct ext4_xattr_item * +ext4_xattr_insert_item_ordered(struct ext4_xattr_ref *xattr_ref, __u8 name_index, + const char *name, size_t name_len, const void *data, + size_t data_size, + int *err) +{ + struct ext4_xattr_item *item, *last_item = NULL; + item = ext4_xattr_item_alloc(name_index, name, name_len); + if (!item) { + if (err) + *err = -ENOMEM; + + return NULL; + } + + if (!list_empty(&xattr_ref->ordered_list)) + last_item = list_entry(xattr_ref->ordered_list.prev, + struct ext4_xattr_item, + list_node); + + item->in_inode = TRUE; + if ((xattr_ref->inode_size_rem < + EXT4_XATTR_SIZE(data_size) + + EXT4_XATTR_LEN(item->name_len)) + || + (last_item && !last_item->in_inode)) { + if (xattr_ref->block_size_rem < + EXT4_XATTR_SIZE(data_size) + + EXT4_XATTR_LEN(item->name_len)) { + if (err) + *err = -ENOSPC; + + return NULL; + } + + item->in_inode = FALSE; + } + if (ext4_xattr_item_alloc_data(item, data, data_size) != 0) { + ext4_xattr_item_free(item); + if (err) + *err = -ENOMEM; + + return NULL; + } + ext4_xattr_item_insert(xattr_ref, item); + xattr_ref->ea_size += + EXT4_XATTR_SIZE(item->data_size) + EXT4_XATTR_LEN(item->name_len); + if (item->in_inode) { + xattr_ref->inode_size_rem -= + EXT4_XATTR_SIZE(item->data_size) + + EXT4_XATTR_LEN(item->name_len); + } + else { + xattr_ref->block_size_rem -= + EXT4_XATTR_SIZE(item->data_size) + + EXT4_XATTR_LEN(item->name_len); + } + xattr_ref->dirty = TRUE; + if (err) + *err = 0; + + return item; +} + static int ext4_xattr_remove_item(struct ext4_xattr_ref *xattr_ref, __u8 name_index, const char *name, size_t name_len) @@ -799,7 +866,6 @@ static int ext4_xattr_write_to_disk(struct ext4_xattr_ref *xattr_ref) struct ext4_xattr_header *block_header = NULL; struct ext4_xattr_entry *entry = NULL; struct ext4_xattr_entry *block_entry = NULL; - struct rb_node *first_node; struct ext4_xattr_item *item = NULL; inode_size_rem = ext4_xattr_inode_space(xattr_ref); @@ -858,21 +924,7 @@ static int ext4_xattr_write_to_disk(struct ext4_xattr_ref *xattr_ref) } } - first_node = rb_first(&xattr_ref->root); - if (first_node) - item = container_of(first_node, struct ext4_xattr_item, - node); - - while (item) { - struct rb_node *next_node; - struct ext4_xattr_item *next_item = NULL; - next_node = rb_next(&item->node); - if (next_node) - next_item = container_of(next_node, struct ext4_xattr_item, - node); - else - next_item = NULL; - + list_for_each_entry(item, &xattr_ref->ordered_list, struct ext4_xattr_item, list_node) { if (item->in_inode) { ibody_data = (char *)ibody_data - EXT4_XATTR_SIZE(item->data_size); @@ -886,7 +938,7 @@ static int ext4_xattr_write_to_disk(struct ext4_xattr_ref *xattr_ref) EXT4_XATTR_LEN(item->name_len); xattr_ref->IsOnDiskInodeDirty = TRUE; - goto next_item; + continue; } if (EXT4_XATTR_SIZE(item->data_size) + EXT4_XATTR_LEN(item->name_len) > @@ -908,8 +960,6 @@ static int ext4_xattr_write_to_disk(struct ext4_xattr_ref *xattr_ref) EXT4_XATTR_LEN(item->name_len); block_modified = TRUE; -next_item: - item = next_item; } xattr_ref->dirty = FALSE; if (block_modified) { @@ -932,25 +982,25 @@ void ext4_fs_xattr_iterate(struct ext4_xattr_ref *ref, { struct ext4_xattr_item *item; if (!ref->iter_from) { - struct rb_node *first_node; - first_node = rb_first(&ref->root); - if (first_node) { + struct list_head *first_node; + first_node = ref->ordered_list.next; + if (first_node && first_node != &ref->ordered_list) { ref->iter_from = - container_of(first_node, + list_entry(first_node, struct ext4_xattr_item, - node); + list_node); } } item = ref->iter_from; while (item) { - struct rb_node *next_node; + struct list_head *next_node; struct ext4_xattr_item *next_item; int ret = EXT4_XATTR_ITERATE_CONT; - next_node = rb_next(&item->node); - if (next_node) - next_item = container_of(next_node, struct ext4_xattr_item, - node); + next_node = item->list_node.next; + if (next_node && next_node != &ref->ordered_list) + next_item = list_entry(next_node, struct ext4_xattr_item, + list_node); else next_item = NULL; if (iter) @@ -1002,6 +1052,23 @@ Finish: return ret; } +int ext4_fs_set_xattr_ordered(struct ext4_xattr_ref *ref, __u8 name_index, + const char *name, size_t name_len, const void *data, + size_t data_size) +{ + int ret = 0; + struct ext4_xattr_item *item = + ext4_xattr_lookup_item(ref, name_index, name, name_len); + if (item) { + ret = -EEXIST; + goto Finish; + } + item = ext4_xattr_insert_item_ordered(ref, name_index, name, name_len, + data, data_size, &ret); +Finish: + return ret; +} + int ext4_fs_remove_xattr(struct ext4_xattr_ref *ref, __u8 name_index, const char *name, size_t name_len) { @@ -1055,6 +1122,7 @@ int ext4_fs_get_xattr_ref(PEXT2_IRP_CONTEXT IrpContext, PEXT2_VCB fs, PEXT2_MCB ref->inode_ref = inode_ref; ref->fs = fs; + INIT_LIST_HEAD(&ref->ordered_list); ref->OnDiskInode = Ext2AllocateInode(fs); if (!ref->OnDiskInode) { diff --git a/Ext3Fsd/include/linux/ext4_xattr.h b/Ext3Fsd/include/linux/ext4_xattr.h index 8eaae20..d57949c 100644 --- a/Ext3Fsd/include/linux/ext4_xattr.h +++ b/Ext3Fsd/include/linux/ext4_xattr.h @@ -134,6 +134,7 @@ struct ext4_xattr_item { size_t data_size; struct rb_node node; + struct list_head list_node; }; struct ext4_xattr_ref { @@ -155,6 +156,7 @@ struct ext4_xattr_ref { struct ext4_xattr_item *iter_from; struct rb_root root; + struct list_head ordered_list; }; #define EXT4_XATTR_ITERATE_CONT 0 @@ -170,6 +172,10 @@ int ext4_fs_set_xattr(struct ext4_xattr_ref *ref, __u8 name_index, const char *name, size_t name_len, const void *data, size_t data_size, BOOL replace); +int ext4_fs_set_xattr_ordered(struct ext4_xattr_ref *ref, __u8 name_index, + const char *name, size_t name_len, const void *data, + size_t data_size); + int ext4_fs_remove_xattr(struct ext4_xattr_ref *ref, __u8 name_index, const char *name, size_t name_len); |