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
62 static int ext4_xattr_item_cmp(struct ext4_xattr_item *a,
63 struct ext4_xattr_item *b)
66 result = a->name_index - b->name_index;
70 result = a->name_len - b->name_len;
74 return memcmp(a->name, b->name, a->name_len);
77 RB_GENERATE_INTERNAL(ext4_xattr_tree,
83 static struct ext4_xattr_item *
84 ext4_xattr_item_alloc(uint8_t name_index,
88 struct ext4_xattr_item *item;
89 item = malloc(sizeof(struct ext4_xattr_item) +
94 item->name_index = name_index;
95 item->name = (char *)(item + 1);
96 item->name_len = name_len;
100 memset(&item->node, 0, sizeof(item->node));
101 memcpy(item->name, name, name_len);
107 ext4_xattr_item_alloc_data(struct ext4_xattr_item *item,
112 ext4_assert(!item->data);
113 data = malloc(data_size);
118 memcpy(data, orig_data, data_size);
121 item->data_size = data_size;
126 ext4_xattr_item_free_data(struct ext4_xattr_item *item)
128 ext4_assert(item->data);
135 ext4_xattr_item_resize_data(struct ext4_xattr_item *item,
136 size_t new_data_size)
138 if (new_data_size != item->data_size) {
140 new_data = realloc(item->data, new_data_size);
144 item->data = new_data;
145 item->data_size = new_data_size;
151 ext4_xattr_item_free(struct ext4_xattr_item *item)
154 ext4_xattr_item_free_data(item);
160 static void *ext4_xattr_entry_data(struct ext4_xattr_ref *xattr_ref,
161 struct ext4_xattr_entry *entry,
166 struct ext4_xattr_ibody_header *header;
167 struct ext4_xattr_entry *first_entry;
168 uint16_t inode_size = ext4_get16(&xattr_ref->fs->sb,
170 header = EXT4_XATTR_IHDR(xattr_ref->inode_ref->inode);
171 first_entry = EXT4_XATTR_IFIRST(header);
173 ret = (void *)((char *)first_entry + to_le16(entry->e_value_offs));
174 if ((char *)ret + EXT4_XATTR_SIZE(to_le32(entry->e_value_size))
175 - (char *)xattr_ref->inode_ref->inode >
180 uint32_t block_size =
181 ext4_sb_get_block_size(&xattr_ref->fs->sb);
182 ret = (void *)((char *)xattr_ref->block.data +
183 to_le16(entry->e_value_offs));
184 if ((char *)ret + EXT4_XATTR_SIZE(to_le32(entry->e_value_size))
185 - (char *)xattr_ref->block.data >
192 static int ext4_xattr_block_fetch(struct ext4_xattr_ref *xattr_ref)
197 struct ext4_xattr_entry *entry = NULL;
199 ext4_assert(xattr_ref->block.data);
200 entry = EXT4_XATTR_BFIRST(&xattr_ref->block);
202 size_rem = ext4_sb_get_block_size(&xattr_ref->fs->sb);
203 for(;size_rem > 0 && !EXT4_XATTR_IS_LAST_ENTRY(entry);
204 entry = EXT4_XATTR_NEXT(entry),
205 size_rem -= EXT4_XATTR_LEN(entry->e_name_len)) {
206 struct ext4_xattr_item *item;
207 char *e_name = (char *)(entry + 1);
209 data = ext4_xattr_entry_data(xattr_ref, entry,
216 item = ext4_xattr_item_alloc(entry->e_name_index,
218 (size_t)entry->e_name_len);
223 if (ext4_xattr_item_alloc_data(item,
225 to_le32(entry->e_value_size))
227 ext4_xattr_item_free(item);
231 RB_INSERT(ext4_xattr_tree, &xattr_ref->root, item);
232 xattr_ref->ea_size += item->data_size;
239 static int ext4_xattr_inode_fetch(struct ext4_xattr_ref *xattr_ref)
244 struct ext4_xattr_ibody_header *header = NULL;
245 struct ext4_xattr_entry *entry = NULL;
246 uint16_t inode_size = ext4_get16(&xattr_ref->fs->sb,
249 header = EXT4_XATTR_IHDR(xattr_ref->inode_ref->inode);
250 entry = EXT4_XATTR_IFIRST(header);
252 size_rem = inode_size -
253 EXT4_GOOD_OLD_INODE_SIZE -
254 xattr_ref->inode_ref->inode->extra_isize;
255 for(;size_rem > 0 && !EXT4_XATTR_IS_LAST_ENTRY(entry);
256 entry = EXT4_XATTR_NEXT(entry),
257 size_rem -= EXT4_XATTR_LEN(entry->e_name_len)) {
258 struct ext4_xattr_item *item;
259 char *e_name = (char *)(entry + 1);
261 data = ext4_xattr_entry_data(xattr_ref, entry,
268 item = ext4_xattr_item_alloc(entry->e_name_index,
270 (size_t)entry->e_name_len);
275 if (ext4_xattr_item_alloc_data(item,
277 to_le32(entry->e_value_size))
279 ext4_xattr_item_free(item);
283 RB_INSERT(ext4_xattr_tree, &xattr_ref->root, item);
284 xattr_ref->ea_size += item->data_size;
291 static int ext4_xattr_fetch(struct ext4_xattr_ref *xattr_ref)
294 uint16_t inode_size = ext4_get16(&xattr_ref->fs->sb,
296 if (inode_size > EXT4_GOOD_OLD_INODE_SIZE) {
297 ret = ext4_xattr_inode_fetch(xattr_ref);
303 if (xattr_ref->block_loaded)
304 ret = ext4_xattr_block_fetch(xattr_ref);
306 xattr_ref->dirty = false;
310 static struct ext4_xattr_item *
311 ext4_xattr_lookup_item(struct ext4_xattr_ref *xattr_ref,
316 struct ext4_xattr_item tmp, *ret;
317 tmp.name_index = name_index;
319 tmp.name_len = name_len;
320 ret = RB_FIND(ext4_xattr_tree, &xattr_ref->root,
326 ext4_xattr_purge_items(struct ext4_xattr_ref *xattr_ref)
328 struct ext4_xattr_item *item, *save_item;
329 RB_FOREACH_SAFE(item,
333 RB_REMOVE(ext4_xattr_tree, &xattr_ref->root, item);
334 ext4_xattr_item_free(item);
336 xattr_ref->ea_size = 0;
339 int ext4_fs_get_xattr_ref(struct ext4_fs *fs,
340 struct ext4_inode_ref *inode_ref,
341 struct ext4_xattr_ref *ref)
344 uint64_t xattr_block;
345 xattr_block = ext4_inode_get_file_acl(inode_ref->inode,
349 rc = ext4_block_get(fs->bdev,
350 &inode_ref->block, xattr_block);
354 ref->block_loaded = true;
356 ref->block_loaded = false;
358 ref->inode_ref = inode_ref;
361 rc = ext4_xattr_fetch(ref);
363 ext4_xattr_purge_items(ref);
365 ext4_block_set(fs->bdev, &inode_ref->block);
367 ref->block_loaded = false;
373 void ext4_fs_put_xattr_ref(struct ext4_xattr_ref *ref)
375 if (ref->block_loaded) {
376 ext4_block_set(ref->fs->bdev, &ref->block);
377 ref->block_loaded = false;
379 ext4_xattr_purge_items(ref);
380 ref->inode_ref = NULL;