2 * Copyright (c) 2015 Grzegorz Kostka (kostka.grzegorz@gmail.com)
3 * Copyright (c) 2015 Kaho Ng (ngkaho1234@gmail.com)
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 /** @addtogroup lwext4
34 * @brief Extended Attribute manipulation.
37 #include "ext4_config.h"
38 #include "ext4_debug.h"
39 #include "ext4_errno.h"
40 #include "ext4_misc.h"
41 #include "ext4_types.h"
43 #include "ext4_balloc.h"
44 #include "ext4_block_group.h"
45 #include "ext4_blockdev.h"
46 #include "ext4_crc32.h"
48 #include "ext4_inode.h"
49 #include "ext4_super.h"
50 #include "ext4_trans.h"
51 #include "ext4_xattr.h"
58 * @brief Extended Attribute Manipulation
61 #define NAME_HASH_SHIFT 5
62 #define VALUE_HASH_SHIFT 16
64 static inline void ext4_xattr_compute_hash(struct ext4_xattr_header *header,
65 struct ext4_xattr_entry *entry)
68 char *name = EXT4_XATTR_NAME(entry);
71 for (n = 0; n < entry->e_name_len; n++) {
72 hash = (hash << NAME_HASH_SHIFT) ^
73 (hash >> (8 * sizeof(hash) - NAME_HASH_SHIFT)) ^ *name++;
76 if (entry->e_value_block == 0 && entry->e_value_size != 0) {
78 (uint32_t *)((char *)header + to_le16(entry->e_value_offs));
79 for (n = (to_le32(entry->e_value_size) + EXT4_XATTR_ROUND) >>
82 hash = (hash << VALUE_HASH_SHIFT) ^
83 (hash >> (8 * sizeof(hash) - VALUE_HASH_SHIFT)) ^
87 entry->e_hash = to_le32(hash);
90 #define BLOCK_HASH_SHIFT 16
95 * Re-compute the extended attribute hash value after an entry has changed.
97 static void ext4_xattr_rehash(struct ext4_xattr_header *header,
98 struct ext4_xattr_entry *entry)
100 struct ext4_xattr_entry *here;
103 ext4_xattr_compute_hash(header, entry);
104 here = EXT4_XATTR_ENTRY(header + 1);
105 while (!EXT4_XATTR_IS_LAST_ENTRY(here)) {
107 /* Block is not shared if an entry's hash value == 0 */
111 hash = (hash << BLOCK_HASH_SHIFT) ^
112 (hash >> (8 * sizeof(hash) - BLOCK_HASH_SHIFT)) ^
113 to_le32(here->e_hash);
114 here = EXT4_XATTR_NEXT(here);
116 header->h_hash = to_le32(hash);
119 #if CONFIG_META_CSUM_ENABLE
120 static uint32_t ext4_xattr_block_checksum(struct ext4_inode_ref *inode_ref,
121 ext4_fsblk_t blocknr,
122 struct ext4_xattr_header *header)
124 uint32_t checksum = 0;
125 uint64_t le64_blocknr = blocknr;
126 struct ext4_sblock *sb = &inode_ref->fs->sb;
128 if (ext4_sb_feature_ro_com(sb, EXT4_FRO_COM_METADATA_CSUM)) {
129 uint32_t orig_checksum;
131 /* Preparation: temporarily set bg checksum to 0 */
132 orig_checksum = header->h_checksum;
133 header->h_checksum = 0;
134 /* First calculate crc32 checksum against fs uuid */
136 ext4_crc32c(EXT4_CRC32_INIT, sb->uuid, sizeof(sb->uuid));
137 /* Then calculate crc32 checksum block number */
139 ext4_crc32c(checksum, &le64_blocknr, sizeof(le64_blocknr));
140 /* Finally calculate crc32 checksum against
141 * the entire xattr block */
143 ext4_crc32c(checksum, header, ext4_sb_get_block_size(sb));
144 header->h_checksum = orig_checksum;
149 #define ext4_xattr_block_checksum(...) 0
152 static void ext4_xattr_set_block_checksum(struct ext4_inode_ref *inode_ref,
153 ext4_fsblk_t blocknr __unused,
154 struct ext4_xattr_header *header)
156 struct ext4_sblock *sb = &inode_ref->fs->sb;
157 if (!ext4_sb_feature_ro_com(sb, EXT4_FRO_COM_METADATA_CSUM))
161 ext4_xattr_block_checksum(inode_ref, blocknr, header);
164 struct xattr_prefix {
169 static const struct xattr_prefix prefix_tbl[] = {
170 {"user.", EXT4_XATTR_INDEX_USER},
171 {"system.posix_acl_access", EXT4_XATTR_INDEX_POSIX_ACL_ACCESS},
172 {"system.posix_acl_default", EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT},
173 {"trusted.", EXT4_XATTR_INDEX_TRUSTED},
174 {"security.", EXT4_XATTR_INDEX_SECURITY},
175 {"system.", EXT4_XATTR_INDEX_SYSTEM},
176 {"system.richacl", EXT4_XATTR_INDEX_RICHACL},
180 const char *ext4_extract_xattr_name(const char *full_name, size_t full_name_len,
181 uint8_t *name_index, size_t *name_len,
185 ext4_assert(name_index);
190 if (!full_name_len) {
197 for (i = 0; prefix_tbl[i].prefix; i++) {
198 size_t prefix_len = strlen(prefix_tbl[i].prefix);
199 if (full_name_len >= prefix_len &&
200 !memcmp(full_name, prefix_tbl[i].prefix, prefix_len)) {
202 prefix_tbl[i].prefix[prefix_len - 1] == '.';
203 *name_index = prefix_tbl[i].name_index;
205 *name_len = full_name_len - prefix_len;
207 if (!(full_name_len - prefix_len) && require_name)
212 return full_name + prefix_len;
223 const char *ext4_get_xattr_name_prefix(uint8_t name_index,
224 size_t *ret_prefix_len)
228 for (i = 0; prefix_tbl[i].prefix; i++) {
229 size_t prefix_len = strlen(prefix_tbl[i].prefix);
230 if (prefix_tbl[i].name_index == name_index) {
232 *ret_prefix_len = prefix_len;
234 return prefix_tbl[i].prefix;
243 static const char ext4_xattr_empty_value;
246 * @brief Insert/Remove/Modify the given entry
248 * @param i The information of the given EA entry
249 * @param s Search context block
250 * @param dry_run Do not modify the content of the buffer
252 * @return Return EOK when finished, ENOSPC when there is no enough space
254 static int ext4_xattr_set_entry(struct ext4_xattr_info *i,
255 struct ext4_xattr_search *s, bool dry_run)
257 struct ext4_xattr_entry *last;
258 size_t free, min_offs = (char *)s->end - (char *)s->base,
259 name_len = i->name_len;
262 * If the entry is going to be removed but not found, return 0 to
265 if (!i->value && s->not_found)
268 /* Compute min_offs and last. */
270 for (; !EXT4_XATTR_IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) {
271 if (last->e_value_size) {
272 size_t offs = to_le16(last->e_value_offs);
278 /* Calculate free space in the block. */
279 free = min_offs - ((char *)last - (char *)s->base) - sizeof(uint32_t);
281 free += EXT4_XATTR_SIZE(s->here->e_value_size) +
282 EXT4_XATTR_LEN(s->here->e_name_len);
285 /* See whether there is enough space to hold new entry */
287 EXT4_XATTR_SIZE(i->value_len) + EXT4_XATTR_LEN(name_len))
291 /* Return EOK now if we do not intend to modify the content. */
295 /* First remove the old entry's data part */
297 size_t value_offs = to_le16(s->here->e_value_offs);
298 void *value = (char *)s->base + value_offs;
299 void *first_value = (char *)s->base + min_offs;
301 EXT4_XATTR_SIZE(to_le32(s->here->e_value_size));
304 /* Remove the data part. */
305 memmove((char *)first_value + value_size, first_value,
306 (char *)value - (char *)first_value);
308 /* Zero the gap created */
309 memset(first_value, 0, value_size);
312 * Calculate the new min_offs after removal of the old
315 min_offs += value_size;
319 * Adjust the value offset of entries which has value offset
320 * prior to the s->here. The offset of these entries won't be
321 * shifted if the size of the entry we removed is zero.
323 for (last = s->first; !EXT4_XATTR_IS_LAST_ENTRY(last);
324 last = EXT4_XATTR_NEXT(last)) {
325 size_t offs = to_le16(last->e_value_offs);
327 /* For zero-value-length entry, offs will be zero. */
328 if (offs < value_offs)
329 last->e_value_offs = to_le16(offs + value_size);
333 /* If caller wants us to insert... */
337 value_offs = min_offs - EXT4_XATTR_SIZE(i->value_len);
342 struct ext4_xattr_entry *here = s->here;
344 /* Reuse the current entry we have got */
345 here->e_value_offs = to_le16(value_offs);
346 here->e_value_size = to_le32(i->value_len);
348 /* Insert a new entry */
349 last->e_name_len = (uint8_t)name_len;
350 last->e_name_index = i->name_index;
351 last->e_value_offs = to_le16(value_offs);
352 last->e_value_block = 0;
353 last->e_value_size = to_le32(i->value_len);
354 memcpy(EXT4_XATTR_NAME(last), i->name, name_len);
356 /* Set valid last entry indicator */
357 *(uint32_t *)EXT4_XATTR_NEXT(last) = 0;
362 /* Insert the value's part */
364 memcpy((char *)s->base + value_offs, i->value,
367 /* Clear the padding bytes if there is */
368 if (EXT4_XATTR_SIZE(i->value_len) != i->value_len)
369 memset((char *)s->base + value_offs +
371 0, EXT4_XATTR_SIZE(i->value_len) -
377 /* Remove the whole entry */
378 shift_offs = (char *)EXT4_XATTR_NEXT(s->here) - (char *)s->here;
379 memmove(s->here, EXT4_XATTR_NEXT(s->here),
380 (char *)last + sizeof(uint32_t) -
381 (char *)EXT4_XATTR_NEXT(s->here));
383 /* Zero the gap created */
384 memset((char *)last - shift_offs + sizeof(uint32_t), 0,
393 static inline bool ext4_xattr_is_empty(struct ext4_xattr_search *s)
395 if (!EXT4_XATTR_IS_LAST_ENTRY(s->first))
402 * @brief Find the entry according to given information
404 * @param i The information of the EA entry to be found,
405 * including name_index, name and the length of name
406 * @param s Search context block
408 static void ext4_xattr_find_entry(struct ext4_xattr_info *i,
409 struct ext4_xattr_search *s)
411 struct ext4_xattr_entry *entry = NULL;
417 * Find the wanted EA entry by simply comparing the namespace,
418 * name and the length of name.
420 for (entry = s->first; !EXT4_XATTR_IS_LAST_ENTRY(entry);
421 entry = EXT4_XATTR_NEXT(entry)) {
422 size_t name_len = entry->e_name_len;
423 const char *name = EXT4_XATTR_NAME(entry);
424 if (name_len == i->name_len &&
425 entry->e_name_index == i->name_index &&
426 !memcmp(name, i->name, name_len)) {
428 s->not_found = false;
429 i->value_len = to_le32(entry->e_value_size);
431 i->value = (char *)s->base +
432 to_le16(entry->e_value_offs);
442 * @brief Check whether the xattr block's content is valid
444 * @param inode_ref Inode reference
445 * @param block The block buffer to be validated
447 * @return true if @block is valid, false otherwise.
449 static bool ext4_xattr_is_block_valid(struct ext4_inode_ref *inode_ref,
450 struct ext4_block *block)
453 void *base = block->data,
454 *end = block->data + ext4_sb_get_block_size(&inode_ref->fs->sb);
455 size_t min_offs = (char *)end - (char *)base;
456 struct ext4_xattr_header *header = EXT4_XATTR_BHDR(block);
457 struct ext4_xattr_entry *entry = EXT4_XATTR_BFIRST(block);
460 * Check whether the magic number in the header is correct.
462 if (header->h_magic != to_le32(EXT4_XATTR_MAGIC))
466 * The in-kernel filesystem driver only supports 1 block currently.
468 if (header->h_blocks != to_le32(1))
472 * Check if those entries are maliciously corrupted to inflict harm
475 for (; !EXT4_XATTR_IS_LAST_ENTRY(entry);
476 entry = EXT4_XATTR_NEXT(entry)) {
477 if (!to_le32(entry->e_value_size) &&
478 to_le16(entry->e_value_offs))
481 if ((char *)base + to_le16(entry->e_value_offs) +
482 to_le32(entry->e_value_size) >
487 * The name length field should also be correct,
488 * also there should be an 4-byte zero entry at the
491 if ((char *)EXT4_XATTR_NEXT(entry) + sizeof(uint32_t) >
495 if (to_le32(entry->e_value_size)) {
496 size_t offs = to_le16(entry->e_value_offs);
502 * Entry field and data field do not override each other.
504 if ((char *)base + min_offs < (char *)entry + sizeof(uint32_t))
511 * @brief Check whether the inode buffer's content is valid
513 * @param inode_ref Inode reference
515 * @return true if the inode buffer is valid, false otherwise.
517 static bool ext4_xattr_is_ibody_valid(struct ext4_inode_ref *inode_ref)
521 struct ext4_fs *fs = inode_ref->fs;
522 struct ext4_xattr_ibody_header *iheader;
523 struct ext4_xattr_entry *entry;
524 size_t inode_size = ext4_get16(&fs->sb, inode_size);
526 iheader = EXT4_XATTR_IHDR(&fs->sb, inode_ref->inode);
527 entry = EXT4_XATTR_IFIRST(iheader);
529 end = (char *)inode_ref->inode + inode_size;
530 min_offs = (char *)end - (char *)base;
533 * Check whether the magic number in the header is correct.
535 if (iheader->h_magic != to_le32(EXT4_XATTR_MAGIC))
539 * Check if those entries are maliciously corrupted to inflict harm
542 for (; !EXT4_XATTR_IS_LAST_ENTRY(entry);
543 entry = EXT4_XATTR_NEXT(entry)) {
544 if (!to_le32(entry->e_value_size) &&
545 to_le16(entry->e_value_offs))
548 if ((char *)base + to_le16(entry->e_value_offs) +
549 to_le32(entry->e_value_size) >
554 * The name length field should also be correct,
555 * also there should be an 4-byte zero entry at the
558 if ((char *)EXT4_XATTR_NEXT(entry) + sizeof(uint32_t) >
562 if (to_le32(entry->e_value_size)) {
563 size_t offs = to_le16(entry->e_value_offs);
569 * Entry field and data field do not override each other.
571 if ((char *)base + min_offs < (char *)entry + sizeof(uint32_t))
578 * @brief An EA entry finder for inode buffer
580 struct ext4_xattr_finder {
582 * @brief The information of the EA entry to be find
584 struct ext4_xattr_info i;
587 * @brief Search context block of the current search
589 struct ext4_xattr_search s;
592 * @brief Inode reference to the corresponding inode
594 struct ext4_inode_ref *inode_ref;
597 static void ext4_xattr_ibody_initialize(struct ext4_inode_ref *inode_ref)
599 struct ext4_xattr_ibody_header *header;
600 struct ext4_fs *fs = inode_ref->fs;
602 ext4_inode_get_extra_isize(&fs->sb, inode_ref->inode);
603 size_t inode_size = ext4_get16(&fs->sb, inode_size);
607 header = EXT4_XATTR_IHDR(&fs->sb, inode_ref->inode);
608 memset(header, 0, inode_size - EXT4_GOOD_OLD_INODE_SIZE - extra_isize);
609 header->h_magic = to_le32(EXT4_XATTR_MAGIC);
610 inode_ref->dirty = true;
614 * @brief Initialize a given xattr block
616 * @param inode_ref Inode reference
617 * @param block xattr block buffer
619 static void ext4_xattr_block_initialize(struct ext4_inode_ref *inode_ref,
620 struct ext4_block *block)
622 struct ext4_xattr_header *header;
623 struct ext4_fs *fs = inode_ref->fs;
625 memset(block->data, 0, ext4_sb_get_block_size(&fs->sb));
627 header = EXT4_XATTR_BHDR(block);
628 header->h_magic = to_le32(EXT4_XATTR_MAGIC);
629 header->h_refcount = to_le32(1);
630 header->h_blocks = to_le32(1);
632 ext4_trans_set_block_dirty(block->buf);
635 static void ext4_xattr_block_init_search(struct ext4_inode_ref *inode_ref,
636 struct ext4_xattr_search *s,
637 struct ext4_block *block)
639 s->base = block->data;
640 s->end = block->data + ext4_sb_get_block_size(&inode_ref->fs->sb);
641 s->first = EXT4_XATTR_BFIRST(block);
647 * @brief Find an EA entry inside a xattr block
649 * @param inode_ref Inode reference
650 * @param finder The caller-provided finder block with
652 * @param block The block buffer to be looked into
654 * @return Return EOK no matter the entry is found or not.
655 * If the IO operation or the buffer validation failed,
656 * return other value.
658 static int ext4_xattr_block_find_entry(struct ext4_inode_ref *inode_ref,
659 struct ext4_xattr_finder *finder,
660 struct ext4_block *block)
664 /* Initialize the caller-given finder */
665 finder->inode_ref = inode_ref;
666 memset(&finder->s, 0, sizeof(finder->s));
671 /* Check the validity of the buffer */
672 if (!ext4_xattr_is_block_valid(inode_ref, block))
675 ext4_xattr_block_init_search(inode_ref, &finder->s, block);
676 ext4_xattr_find_entry(&finder->i, &finder->s);
681 * @brief Find an EA entry inside an inode's extra space
683 * @param inode_ref Inode reference
684 * @param finder The caller-provided finder block with
687 * @return Return EOK no matter the entry is found or not.
688 * If the IO operation or the buffer validation failed,
689 * return other value.
691 static int ext4_xattr_ibody_find_entry(struct ext4_inode_ref *inode_ref,
692 struct ext4_xattr_finder *finder)
694 struct ext4_fs *fs = inode_ref->fs;
695 struct ext4_xattr_ibody_header *iheader;
697 ext4_inode_get_extra_isize(&fs->sb, inode_ref->inode);
698 size_t inode_size = ext4_get16(&fs->sb, inode_size);
700 /* Initialize the caller-given finder */
701 finder->inode_ref = inode_ref;
702 memset(&finder->s, 0, sizeof(finder->s));
705 * If there is no extra inode space
706 * set ext4_xattr_ibody_finder::s::not_found to true and return EOK
709 finder->s.not_found = true;
713 /* Check the validity of the buffer */
714 if (!ext4_xattr_is_ibody_valid(inode_ref))
717 iheader = EXT4_XATTR_IHDR(&fs->sb, inode_ref->inode);
718 finder->s.base = EXT4_XATTR_IFIRST(iheader);
719 finder->s.end = (char *)inode_ref->inode + inode_size;
720 finder->s.first = EXT4_XATTR_IFIRST(iheader);
721 ext4_xattr_find_entry(&finder->i, &finder->s);
726 * @brief Try to allocate a block holding EA entries.
728 * @param inode_ref Inode reference
732 static int ext4_xattr_try_alloc_block(struct ext4_inode_ref *inode_ref)
736 ext4_fsblk_t xattr_block = 0;
738 ext4_inode_get_file_acl(inode_ref->inode, &inode_ref->fs->sb);
741 * Only allocate a xattr block when there is no xattr block
745 ext4_fsblk_t goal = ext4_fs_inode_to_goal_block(inode_ref);
747 ret = ext4_balloc_alloc_block(inode_ref, goal, &xattr_block);
751 ext4_inode_set_file_acl(inode_ref->inode, &inode_ref->fs->sb,
760 * @brief Try to free a block holding EA entries.
762 * @param inode_ref Inode reference
766 static void ext4_xattr_try_free_block(struct ext4_inode_ref *inode_ref)
768 ext4_fsblk_t xattr_block;
770 ext4_inode_get_file_acl(inode_ref->inode, &inode_ref->fs->sb);
772 * Free the xattr block used by the inode when there is one.
775 ext4_inode_set_file_acl(inode_ref->inode, &inode_ref->fs->sb,
777 ext4_balloc_free_block(inode_ref, xattr_block);
778 inode_ref->dirty = true;
783 * @brief Put a list of EA entries into a caller-provided buffer
784 * In order to make sure that @list buffer can fit in the data,
785 * the routine should be called twice.
787 * @param inode_ref Inode reference
788 * @param list A caller-provided buffer to hold a list of EA entries.
789 * If list == NULL, list_len will contain the size of
790 * the buffer required to hold these entries
791 * @param list_len The length of the data written to @list
794 int ext4_xattr_list(struct ext4_inode_ref *inode_ref,
795 struct ext4_xattr_list_entry *list, size_t *list_len)
799 struct ext4_fs *fs = inode_ref->fs;
800 struct ext4_xattr_ibody_header *iheader;
802 ext4_inode_get_extra_isize(&fs->sb, inode_ref->inode);
803 struct ext4_block block;
804 bool block_loaded = false;
805 ext4_fsblk_t xattr_block = 0;
806 struct ext4_xattr_entry *entry;
807 struct ext4_xattr_list_entry *list_prev = NULL;
808 xattr_block = ext4_inode_get_file_acl(inode_ref->inode, &fs->sb);
811 * If there is extra inode space and the xattr buffer in the
814 if (extra_isize && ext4_xattr_is_ibody_valid(inode_ref)) {
815 iheader = EXT4_XATTR_IHDR(&fs->sb, inode_ref->inode);
816 entry = EXT4_XATTR_IFIRST(iheader);
819 * The format of the list should be like this:
821 * name_len indicates the length in bytes of the name
822 * of the EA entry. The string is null-terminated.
824 * list->name => (char *)(list + 1);
825 * list->next => (void *)((char *)(list + 1) + name_len + 1);
827 for (; !EXT4_XATTR_IS_LAST_ENTRY(entry);
828 entry = EXT4_XATTR_NEXT(entry)) {
829 size_t name_len = entry->e_name_len;
831 list->name_index = entry->e_name_index;
832 list->name_len = name_len;
833 list->name = (char *)(list + 1);
834 memcpy(list->name, EXT4_XATTR_NAME(entry),
838 list_prev->next = list;
841 list = (struct ext4_xattr_list_entry
842 *)(list->name + name_len + 1);
846 * Size calculation by pointer arithmetics.
849 (char *)((struct ext4_xattr_list_entry *)0 + 1) +
851 (char *)(struct ext4_xattr_list_entry *)0;
856 * If there is a xattr block used by the inode
859 ret = ext4_trans_block_get(fs->bdev, &block, xattr_block);
866 * As we don't allow the content in the block being invalid,
869 if (!ext4_xattr_is_block_valid(inode_ref, &block)) {
874 entry = EXT4_XATTR_BFIRST(&block);
877 * The format of the list should be like this:
879 * name_len indicates the length in bytes of the name
880 * of the EA entry. The string is null-terminated.
882 * list->name => (char *)(list + 1);
883 * list->next => (void *)((char *)(list + 1) + name_len + 1);
885 * Same as above actually.
887 for (; !EXT4_XATTR_IS_LAST_ENTRY(entry);
888 entry = EXT4_XATTR_NEXT(entry)) {
889 size_t name_len = entry->e_name_len;
891 list->name_index = entry->e_name_index;
892 list->name_len = name_len;
893 list->name = (char *)(list + 1);
894 memcpy(list->name, EXT4_XATTR_NAME(entry),
898 list_prev->next = list;
901 list = (struct ext4_xattr_list_entry
902 *)(list->name + name_len + 1);
906 * Size calculation by pointer arithmetics.
909 (char *)((struct ext4_xattr_list_entry *)0 + 1) +
911 (char *)(struct ext4_xattr_list_entry *)0;
915 list_prev->next = NULL;
917 if (ret == EOK && list_len)
921 ext4_block_set(fs->bdev, &block);
927 * @brief Query EA entry's value with given name-index and name
929 * @param inode_ref Inode reference
930 * @param name_index Name-index
931 * @param name Name of the EA entry to be queried
932 * @param name_len Length of name in bytes
933 * @param buf Output buffer to hold content
934 * @param buf_len Output buffer's length
935 * @param data_len The length of data of the EA entry found
939 int ext4_xattr_get(struct ext4_inode_ref *inode_ref, uint8_t name_index,
940 const char *name, size_t name_len, void *buf, size_t buf_len,
944 struct ext4_xattr_finder ibody_finder;
945 struct ext4_xattr_finder block_finder;
946 struct ext4_xattr_info i;
947 size_t value_len = 0;
948 size_t value_offs = 0;
949 struct ext4_fs *fs = inode_ref->fs;
950 ext4_fsblk_t xattr_block;
951 xattr_block = ext4_inode_get_file_acl(inode_ref->inode, &fs->sb);
953 i.name_index = name_index;
955 i.name_len = name_len;
962 ret = ext4_xattr_ibody_find_entry(inode_ref, &ibody_finder);
966 if (!ibody_finder.s.not_found) {
967 value_len = to_le32(ibody_finder.s.here->e_value_size);
968 value_offs = to_le32(ibody_finder.s.here->e_value_offs);
969 if (buf_len && buf) {
971 (char *)ibody_finder.s.base + value_offs;
972 memcpy(buf, data_loc,
973 (buf_len < value_len) ? buf_len : value_len);
976 struct ext4_block block;
978 /* Return ENODATA if there is no EA block */
985 ret = ext4_trans_block_get(fs->bdev, &block, xattr_block);
989 ret = ext4_xattr_block_find_entry(inode_ref, &block_finder,
992 ext4_block_set(fs->bdev, &block);
996 /* Return ENODATA if entry is not found */
997 if (block_finder.s.not_found) {
998 ext4_block_set(fs->bdev, &block);
1003 value_len = to_le32(block_finder.s.here->e_value_size);
1004 value_offs = to_le32(block_finder.s.here->e_value_offs);
1005 if (buf_len && buf) {
1007 (char *)block_finder.s.base + value_offs;
1008 memcpy(buf, data_loc,
1009 (buf_len < value_len) ? buf_len : value_len);
1013 * Free the xattr block buffer returned by
1014 * ext4_xattr_block_find_entry.
1016 ext4_block_set(fs->bdev, &block);
1020 if (ret == EOK && data_len)
1021 *data_len = value_len;
1027 * @brief Try to copy the content of an xattr block to a newly-allocated
1028 * block. If the operation fails, the block buffer provided by
1029 * caller will be freed
1031 * @param inode_ref Inode reference
1032 * @param block The block buffer reference
1033 * @param new_block The newly-allocated block buffer reference
1034 * @param orig_block The block number of @block
1035 * @param allocated a new block is allocated
1037 * @return Error code
1039 static int ext4_xattr_copy_new_block(struct ext4_inode_ref *inode_ref,
1040 struct ext4_block *block,
1041 struct ext4_block *new_block,
1042 ext4_fsblk_t *orig_block, bool *allocated)
1045 ext4_fsblk_t xattr_block = 0;
1046 struct ext4_xattr_header *header;
1047 struct ext4_fs *fs = inode_ref->fs;
1048 header = EXT4_XATTR_BHDR(block);
1051 *orig_block = block->lb_id;
1056 /* Only do copy when a block is referenced by more than one inode. */
1057 if (to_le32(header->h_refcount) > 1) {
1058 ext4_fsblk_t goal = ext4_fs_inode_to_goal_block(inode_ref);
1060 /* Allocate a new block to be used by this inode */
1061 ret = ext4_balloc_alloc_block(inode_ref, goal, &xattr_block);
1065 ret = ext4_trans_block_get(fs->bdev, new_block, xattr_block);
1069 /* Copy the content of the whole block */
1070 memcpy(new_block->data, block->data,
1071 ext4_sb_get_block_size(&inode_ref->fs->sb));
1074 * Decrement the reference count of the original xattr block
1077 header->h_refcount = to_le32(to_le32(header->h_refcount) - 1);
1078 ext4_trans_set_block_dirty(block->buf);
1079 ext4_trans_set_block_dirty(new_block->buf);
1081 header = EXT4_XATTR_BHDR(new_block);
1082 header->h_refcount = to_le32(1);
1090 ext4_balloc_free_block(inode_ref, xattr_block);
1093 * Modify the in-inode pointer to point to the new xattr block
1095 ext4_inode_set_file_acl(inode_ref->inode, &fs->sb, xattr_block);
1096 inode_ref->dirty = true;
1104 * @brief Given an EA entry's name, remove the EA entry
1106 * @param inode_ref Inode reference
1107 * @param name_index Name-index
1108 * @param name Name of the EA entry to be removed
1109 * @param name_len Length of name in bytes
1111 * @return Error code
1113 int ext4_xattr_remove(struct ext4_inode_ref *inode_ref, uint8_t name_index,
1114 const char *name, size_t name_len)
1117 struct ext4_block block;
1118 struct ext4_xattr_finder ibody_finder;
1119 struct ext4_xattr_finder block_finder;
1120 bool use_block = false;
1121 bool block_loaded = false;
1122 struct ext4_xattr_info i;
1123 struct ext4_fs *fs = inode_ref->fs;
1124 ext4_fsblk_t xattr_block;
1126 xattr_block = ext4_inode_get_file_acl(inode_ref->inode, &fs->sb);
1128 i.name_index = name_index;
1130 i.name_len = name_len;
1137 ret = ext4_xattr_ibody_find_entry(inode_ref, &ibody_finder);
1141 if (ibody_finder.s.not_found && xattr_block) {
1142 ret = ext4_trans_block_get(fs->bdev, &block, xattr_block);
1146 block_loaded = true;
1148 ret = ext4_xattr_block_find_entry(inode_ref, &block_finder,
1153 /* Return ENODATA if entry is not found */
1154 if (block_finder.s.not_found) {
1162 bool allocated = false;
1163 struct ext4_block new_block;
1166 * There will be no effect when the xattr block is only referenced
1169 ret = ext4_xattr_copy_new_block(inode_ref, &block, &new_block,
1170 &xattr_block, &allocated);
1175 /* Prevent double-freeing */
1176 block_loaded = false;
1180 ret = ext4_xattr_block_find_entry(inode_ref, &block_finder,
1185 /* Now remove the entry */
1186 ext4_xattr_set_entry(&i, &block_finder.s, false);
1188 if (ext4_xattr_is_empty(&block_finder.s)) {
1189 ext4_block_set(fs->bdev, &new_block);
1190 ext4_xattr_try_free_block(inode_ref);
1192 struct ext4_xattr_header *header =
1193 EXT4_XATTR_BHDR(&new_block);
1194 header = EXT4_XATTR_BHDR(&new_block);
1195 ext4_assert(block_finder.s.first);
1196 ext4_xattr_rehash(header, block_finder.s.first);
1197 ext4_xattr_set_block_checksum(inode_ref,
1201 ext4_trans_set_block_dirty(new_block.buf);
1202 ext4_block_set(fs->bdev, &new_block);
1206 /* Now remove the entry */
1207 ext4_xattr_set_entry(&i, &block_finder.s, false);
1208 inode_ref->dirty = true;
1212 ext4_block_set(fs->bdev, &block);
1218 * @brief Insert/overwrite an EA entry into/in a xattr block
1220 * @param inode_ref Inode reference
1221 * @param i The information of the given EA entry
1223 * @return Error code
1225 static int ext4_xattr_block_set(struct ext4_inode_ref *inode_ref,
1226 struct ext4_xattr_info *i,
1230 bool allocated = false;
1231 struct ext4_fs *fs = inode_ref->fs;
1232 struct ext4_block block, new_block;
1233 ext4_fsblk_t orig_xattr_block;
1235 orig_xattr_block = ext4_inode_get_file_acl(inode_ref->inode, &fs->sb);
1237 ext4_assert(i->value);
1238 if (!orig_xattr_block) {
1239 struct ext4_xattr_search s;
1240 struct ext4_xattr_header *header;
1242 /* If insertion of new entry is not allowed... */
1248 ret = ext4_xattr_try_alloc_block(inode_ref);
1253 ext4_inode_get_file_acl(inode_ref->inode, &fs->sb);
1254 ret = ext4_trans_block_get(fs->bdev, &block, orig_xattr_block);
1256 ext4_xattr_try_free_block(inode_ref);
1260 ext4_xattr_block_initialize(inode_ref, &block);
1261 ext4_xattr_block_init_search(inode_ref, &s, &block);
1263 ret = ext4_xattr_set_entry(i, &s, false);
1265 header = EXT4_XATTR_BHDR(&block);
1267 ext4_assert(s.here);
1268 ext4_assert(s.first);
1269 ext4_xattr_compute_hash(header, s.here);
1270 ext4_xattr_rehash(header, s.first);
1271 ext4_xattr_set_block_checksum(inode_ref,
1274 ext4_trans_set_block_dirty(block.buf);
1276 ext4_block_set(fs->bdev, &block);
1278 ext4_xattr_try_free_block(inode_ref);
1281 struct ext4_xattr_finder finder;
1282 struct ext4_xattr_header *header;
1284 ret = ext4_trans_block_get(fs->bdev, &block, orig_xattr_block);
1288 header = EXT4_XATTR_BHDR(&block);
1291 * Consider the following case when insertion of new
1292 * entry is not allowed
1294 if (to_le32(header->h_refcount) > 1 && no_insert) {
1296 * There are other people referencing the
1299 ret = ext4_xattr_block_find_entry(inode_ref, &finder, &block);
1301 ext4_block_set(fs->bdev, &block);
1304 if (finder.s.not_found) {
1305 ext4_block_set(fs->bdev, &block);
1312 * There will be no effect when the xattr block is only referenced
1315 ret = ext4_xattr_copy_new_block(inode_ref, &block, &new_block,
1316 &orig_xattr_block, &allocated);
1318 ext4_block_set(fs->bdev, &block);
1323 ext4_block_set(fs->bdev, &block);
1327 ret = ext4_xattr_block_find_entry(inode_ref, &finder, &block);
1329 ext4_block_set(fs->bdev, &block);
1333 ret = ext4_xattr_set_entry(i, &finder.s, false);
1335 header = EXT4_XATTR_BHDR(&block);
1337 ext4_assert(finder.s.here);
1338 ext4_assert(finder.s.first);
1339 ext4_xattr_compute_hash(header, finder.s.here);
1340 ext4_xattr_rehash(header, finder.s.first);
1341 ext4_xattr_set_block_checksum(inode_ref,
1344 ext4_trans_set_block_dirty(block.buf);
1346 ext4_block_set(fs->bdev, &block);
1353 * @brief Remove an EA entry from a xattr block
1355 * @param inode_ref Inode reference
1356 * @param i The information of the given EA entry
1358 * @return Error code
1360 static int ext4_xattr_block_remove(struct ext4_inode_ref *inode_ref,
1361 struct ext4_xattr_info *i)
1364 bool allocated = false;
1365 const void *value = i->value;
1366 struct ext4_fs *fs = inode_ref->fs;
1367 struct ext4_xattr_finder finder;
1368 struct ext4_block block, new_block;
1369 struct ext4_xattr_header *header;
1370 ext4_fsblk_t orig_xattr_block;
1371 orig_xattr_block = ext4_inode_get_file_acl(inode_ref->inode, &fs->sb);
1373 ext4_assert(orig_xattr_block);
1374 ret = ext4_trans_block_get(fs->bdev, &block, orig_xattr_block);
1379 * There will be no effect when the xattr block is only referenced
1382 ret = ext4_xattr_copy_new_block(inode_ref, &block, &new_block,
1383 &orig_xattr_block, &allocated);
1385 ext4_block_set(fs->bdev, &block);
1390 ext4_block_set(fs->bdev, &block);
1394 ext4_xattr_block_find_entry(inode_ref, &finder, &block);
1396 if (!finder.s.not_found) {
1398 ret = ext4_xattr_set_entry(i, &finder.s, false);
1401 header = EXT4_XATTR_BHDR(&block);
1402 ext4_assert(finder.s.first);
1403 ext4_xattr_rehash(header, finder.s.first);
1404 ext4_xattr_set_block_checksum(inode_ref,
1407 ext4_trans_set_block_dirty(block.buf);
1410 ext4_block_set(fs->bdev, &block);
1416 * @brief Insert an EA entry into a given inode reference
1418 * @param inode_ref Inode reference
1419 * @param name_index Name-index
1420 * @param name Name of the EA entry to be inserted
1421 * @param name_len Length of name in bytes
1422 * @param value Input buffer to hold content
1423 * @param value_len Length of input content
1425 * @return Error code
1427 int ext4_xattr_set(struct ext4_inode_ref *inode_ref, uint8_t name_index,
1428 const char *name, size_t name_len, const void *value,
1432 struct ext4_fs *fs = inode_ref->fs;
1433 struct ext4_xattr_finder ibody_finder;
1434 struct ext4_xattr_info i;
1435 bool block_found = false;
1436 ext4_fsblk_t orig_xattr_block;
1437 size_t extra_isize =
1438 ext4_inode_get_extra_isize(&fs->sb, inode_ref->inode);
1440 i.name_index = name_index;
1442 i.name_len = name_len;
1443 i.value = (value_len) ? value : &ext4_xattr_empty_value;
1444 i.value_len = value_len;
1448 orig_xattr_block = ext4_inode_get_file_acl(inode_ref->inode, &fs->sb);
1451 * Even if entry is not found, search context block inside the
1452 * finder is still valid and can be used to insert entry.
1454 ret = ext4_xattr_ibody_find_entry(inode_ref, &ibody_finder);
1456 ext4_xattr_ibody_initialize(inode_ref);
1457 ext4_xattr_ibody_find_entry(inode_ref, &ibody_finder);
1460 if (ibody_finder.s.not_found) {
1461 if (orig_xattr_block) {
1463 ret = ext4_xattr_block_set(inode_ref, &i, true);
1466 else if (ret == ENODATA)
1468 else if (ret != EOK)
1476 /* Only try to set entry in ibody if inode is sufficiently large */
1478 ret = ext4_xattr_set_entry(&i, &ibody_finder.s, false);
1482 if (ret == ENOSPC) {
1484 ret = ext4_xattr_block_set(inode_ref, &i, false);
1485 ibody_finder.i.value = NULL;
1486 ext4_xattr_set_entry(&ibody_finder.i,
1487 &ibody_finder.s, false);
1488 inode_ref->dirty = true;
1491 } else if (ret == EOK) {
1493 ret = ext4_xattr_block_remove(inode_ref, &i);
1495 inode_ref->dirty = true;