2 * Copyright (c) 2015 Grzegorz Kostka (kostka.grzegorz@gmail.com)
3 * Copyright (c) 2015 Kaho Ng (ngkaho1234@gmail.com)
7 * Copyright (c) 2012 Martin Sucha
8 * Copyright (c) 2012 Frantisek Princ
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
15 * - Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * - Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * - The name of the author may not be used to endorse or promote products
21 * derived from this software without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 /** @addtogroup lwext4
40 * @brief Extended Attribute manipulation.
43 #include "ext4_config.h"
44 #include "ext4_types.h"
46 #include "ext4_errno.h"
47 #include "ext4_blockdev.h"
48 #include "ext4_super.h"
49 #include "ext4_debug.h"
50 #include "ext4_block_group.h"
51 #include "ext4_balloc.h"
52 #include "ext4_inode.h"
53 #include "ext4_extent.h"
60 * @brief Extended Attribute Manipulation
63 #define NAME_HASH_SHIFT 5
64 #define VALUE_HASH_SHIFT 16
67 ext4_xattr_compute_hash(struct ext4_xattr_header *header,
68 struct ext4_xattr_entry *entry)
71 char *name = EXT4_XATTR_NAME(entry);
74 for (n = 0; n < entry->e_name_len; n++) {
75 hash = (hash << NAME_HASH_SHIFT) ^
76 (hash >> (8*sizeof(hash) - NAME_HASH_SHIFT)) ^
80 if (entry->e_value_block == 0 && entry->e_value_size != 0) {
81 uint32_t *value = (uint32_t *)((char *)header +
82 to_le16(entry->e_value_offs));
83 for (n = (to_le32(entry->e_value_size) +
84 EXT4_XATTR_ROUND) >> EXT4_XATTR_PAD_BITS; n; n--) {
85 hash = (hash << VALUE_HASH_SHIFT) ^
86 (hash >> (8*sizeof(hash) - VALUE_HASH_SHIFT)) ^
90 entry->e_hash = to_le32(hash);
93 static int ext4_xattr_item_cmp(struct ext4_xattr_item *a,
94 struct ext4_xattr_item *b)
97 result = a->name_index - b->name_index;
101 result = a->name_len - b->name_len;
105 return memcmp(a->name, b->name, a->name_len);
108 RB_GENERATE_INTERNAL(ext4_xattr_tree,
114 static struct ext4_xattr_item *
115 ext4_xattr_item_alloc(uint8_t name_index,
119 struct ext4_xattr_item *item;
120 item = malloc(sizeof(struct ext4_xattr_item) +
125 item->name_index = name_index;
126 item->name = (char *)(item + 1);
127 item->name_len = name_len;
131 memset(&item->node, 0, sizeof(item->node));
132 memcpy(item->name, name, name_len);
138 ext4_xattr_item_alloc_data(struct ext4_xattr_item *item,
143 ext4_assert(!item->data);
144 data = malloc(data_size);
149 memcpy(data, orig_data, data_size);
152 item->data_size = data_size;
157 ext4_xattr_item_free_data(struct ext4_xattr_item *item)
159 ext4_assert(item->data);
166 ext4_xattr_item_resize_data(struct ext4_xattr_item *item,
167 size_t new_data_size)
169 if (new_data_size != item->data_size) {
171 new_data = realloc(item->data, new_data_size);
175 item->data = new_data;
176 item->data_size = new_data_size;
182 ext4_xattr_item_free(struct ext4_xattr_item *item)
185 ext4_xattr_item_free_data(item);
191 static void *ext4_xattr_entry_data(struct ext4_xattr_ref *xattr_ref,
192 struct ext4_xattr_entry *entry,
197 struct ext4_xattr_ibody_header *header;
198 struct ext4_xattr_entry *first_entry;
199 uint16_t inode_size = ext4_get16(&xattr_ref->fs->sb,
201 header = EXT4_XATTR_IHDR(xattr_ref->inode_ref->inode);
202 first_entry = EXT4_XATTR_IFIRST(header);
204 ret = (void *)((char *)first_entry + to_le16(entry->e_value_offs));
205 if ((char *)ret + EXT4_XATTR_SIZE(to_le32(entry->e_value_size))
206 - (char *)xattr_ref->inode_ref->inode >
211 uint32_t block_size =
212 ext4_sb_get_block_size(&xattr_ref->fs->sb);
213 ret = (void *)((char *)xattr_ref->block.data +
214 to_le16(entry->e_value_offs));
215 if ((char *)ret + EXT4_XATTR_SIZE(to_le32(entry->e_value_size))
216 - (char *)xattr_ref->block.data >
223 static int ext4_xattr_block_fetch(struct ext4_xattr_ref *xattr_ref)
228 struct ext4_xattr_entry *entry = NULL;
230 ext4_assert(xattr_ref->block.data);
231 entry = EXT4_XATTR_BFIRST(&xattr_ref->block);
233 size_rem = ext4_sb_get_block_size(&xattr_ref->fs->sb);
234 for(;size_rem > 0 && !EXT4_XATTR_IS_LAST_ENTRY(entry);
235 entry = EXT4_XATTR_NEXT(entry),
236 size_rem -= EXT4_XATTR_LEN(entry->e_name_len)) {
237 struct ext4_xattr_item *item;
238 char *e_name = EXT4_XATTR_NAME(entry);
240 data = ext4_xattr_entry_data(xattr_ref, entry,
247 item = ext4_xattr_item_alloc(entry->e_name_index,
249 (size_t)entry->e_name_len);
254 if (ext4_xattr_item_alloc_data(item,
256 to_le32(entry->e_value_size))
258 ext4_xattr_item_free(item);
262 RB_INSERT(ext4_xattr_tree, &xattr_ref->root, item);
263 xattr_ref->ea_size += item->data_size;
270 static int ext4_xattr_inode_fetch(struct ext4_xattr_ref *xattr_ref)
275 struct ext4_xattr_ibody_header *header = NULL;
276 struct ext4_xattr_entry *entry = NULL;
277 uint16_t inode_size = ext4_get16(&xattr_ref->fs->sb,
280 header = EXT4_XATTR_IHDR(xattr_ref->inode_ref->inode);
281 entry = EXT4_XATTR_IFIRST(header);
283 size_rem = inode_size -
284 EXT4_GOOD_OLD_INODE_SIZE -
285 xattr_ref->inode_ref->inode->extra_isize;
286 for(;size_rem > 0 && !EXT4_XATTR_IS_LAST_ENTRY(entry);
287 entry = EXT4_XATTR_NEXT(entry),
288 size_rem -= EXT4_XATTR_LEN(entry->e_name_len)) {
289 struct ext4_xattr_item *item;
290 char *e_name = EXT4_XATTR_NAME(entry);
292 data = ext4_xattr_entry_data(xattr_ref, entry,
299 item = ext4_xattr_item_alloc(entry->e_name_index,
301 (size_t)entry->e_name_len);
306 if (ext4_xattr_item_alloc_data(item,
308 to_le32(entry->e_value_size))
310 ext4_xattr_item_free(item);
314 RB_INSERT(ext4_xattr_tree, &xattr_ref->root, item);
315 xattr_ref->ea_size += item->data_size;
322 static int ext4_xattr_fetch(struct ext4_xattr_ref *xattr_ref)
325 uint16_t inode_size = ext4_get16(&xattr_ref->fs->sb,
327 if (inode_size > EXT4_GOOD_OLD_INODE_SIZE) {
328 ret = ext4_xattr_inode_fetch(xattr_ref);
334 if (xattr_ref->block_loaded)
335 ret = ext4_xattr_block_fetch(xattr_ref);
337 xattr_ref->dirty = false;
341 static struct ext4_xattr_item *
342 ext4_xattr_lookup_item(struct ext4_xattr_ref *xattr_ref,
347 struct ext4_xattr_item tmp, *ret;
348 tmp.name_index = name_index;
350 tmp.name_len = name_len;
351 ret = RB_FIND(ext4_xattr_tree, &xattr_ref->root,
357 ext4_xattr_purge_items(struct ext4_xattr_ref *xattr_ref)
359 struct ext4_xattr_item *item, *save_item;
360 RB_FOREACH_SAFE(item,
364 RB_REMOVE(ext4_xattr_tree, &xattr_ref->root, item);
365 ext4_xattr_item_free(item);
367 xattr_ref->ea_size = 0;
371 ext4_xattr_inode_space(struct ext4_xattr_ref *xattr_ref)
373 uint16_t inode_size = ext4_get16(&xattr_ref->fs->sb,
375 uint16_t size_rem = inode_size -
376 EXT4_GOOD_OLD_INODE_SIZE -
377 xattr_ref->inode_ref->inode->extra_isize;
382 ext4_xattr_block_space(struct ext4_xattr_ref *xattr_ref)
384 return ext4_sb_get_block_size(&xattr_ref->fs->sb);
388 ext4_xattr_write_to_disk(struct ext4_xattr_ref *xattr_ref)
391 struct ext4_xattr_item *item, *save_item;
392 size_t inode_size_rem, block_size_rem;
393 inode_size_rem = ext4_xattr_inode_space(xattr_ref);
394 block_size_rem = ext4_xattr_block_space(xattr_ref);
396 if (xattr_ref->dirty) {
397 RB_FOREACH_SAFE(item,
401 /*This should not fail!*/
402 ext4_assert(inode_size_rem + block_size_rem);
403 if (inode_size_rem) {
407 xattr_ref->dirty = false;
412 int ext4_fs_get_xattr_ref(struct ext4_fs *fs,
413 struct ext4_inode_ref *inode_ref,
414 struct ext4_xattr_ref *ref)
417 uint64_t xattr_block;
418 xattr_block = ext4_inode_get_file_acl(inode_ref->inode,
422 rc = ext4_block_get(fs->bdev,
423 &inode_ref->block, xattr_block);
427 ref->block_loaded = true;
429 ref->block_loaded = false;
431 ref->inode_ref = inode_ref;
434 rc = ext4_xattr_fetch(ref);
436 ext4_xattr_purge_items(ref);
438 ext4_block_set(fs->bdev, &inode_ref->block);
440 ref->block_loaded = false;
446 void ext4_fs_put_xattr_ref(struct ext4_xattr_ref *ref)
448 if (ref->block_loaded) {
449 ext4_block_set(ref->fs->bdev, &ref->block);
450 ref->block_loaded = false;
452 ext4_xattr_purge_items(ref);
453 ref->inode_ref = NULL;