2 * ext_attr.c --- extended attribute blocks
4 * Copyright (C) 2001 Andreas Gruenbacher, <a.gruenbacher@computer.org>
6 * Copyright (C) 2002 Theodore Ts'o.
9 * This file may be redistributed under the terms of the GNU Library
10 * General Public License, version 2.
24 #include "ext2_ext_attr.h"
28 #define NAME_HASH_SHIFT 5
29 #define VALUE_HASH_SHIFT 16
32 * ext2_xattr_hash_entry()
34 * Compute the hash of an extended attribute.
36 __u32 ext2fs_ext_attr_hash_entry(struct ext2_ext_attr_entry *entry, void *data)
39 char *name = ((char *) entry) + sizeof(struct ext2_ext_attr_entry);
42 for (n = 0; n < entry->e_name_len; n++) {
43 hash = (hash << NAME_HASH_SHIFT) ^
44 (hash >> (8*sizeof(hash) - NAME_HASH_SHIFT)) ^
48 /* The hash needs to be calculated on the data in little-endian. */
49 if (entry->e_value_block == 0 && entry->e_value_size != 0) {
50 __u32 *value = (__u32 *)data;
51 for (n = (entry->e_value_size + EXT2_EXT_ATTR_ROUND) >>
52 EXT2_EXT_ATTR_PAD_BITS; n; n--) {
53 hash = (hash << VALUE_HASH_SHIFT) ^
54 (hash >> (8*sizeof(hash) - VALUE_HASH_SHIFT)) ^
55 ext2fs_le32_to_cpu(*value++);
62 #undef NAME_HASH_SHIFT
63 #undef VALUE_HASH_SHIFT
65 #define BLOCK_HASH_SHIFT 16
67 * Re-compute the extended attribute hash value after an entry has changed.
69 static void ext2fs_attr_rehash(struct ext2_ext_attr_header *header,
70 struct ext2_ext_attr_entry *entry)
72 struct ext2_ext_attr_entry *here;
75 entry->e_hash = ext2fs_ext_attr_hash_entry(entry, (char *)header +
78 here = ENTRY(header+1);
79 while (!EXT2_EXT_IS_LAST_ENTRY(here)) {
81 /* Block is not shared if an entry's hash value == 0 */
85 hash = (hash << BLOCK_HASH_SHIFT) ^
86 (hash >> (8*sizeof(hash) - BLOCK_HASH_SHIFT)) ^
88 here = EXT2_EXT_ATTR_NEXT(here);
90 header->h_hash = hash;
93 errcode_t ext2fs_read_ext_attr2(ext2_filsys fs, blk64_t block, void *buf)
97 retval = io_channel_read_blk64(fs->io, block, 1, buf);
100 #ifdef WORDS_BIGENDIAN
101 ext2fs_swap_ext_attr(buf, buf, fs->blocksize, 1);
106 errcode_t ext2fs_read_ext_attr(ext2_filsys fs, blk_t block, void *buf)
108 return ext2fs_read_ext_attr2(fs, block, buf);
111 errcode_t ext2fs_write_ext_attr2(ext2_filsys fs, blk64_t block, void *inbuf)
115 #ifdef WORDS_BIGENDIAN
118 retval = ext2fs_get_mem(fs->blocksize, &buf);
122 ext2fs_swap_ext_attr(buf, inbuf, fs->blocksize, 1);
124 write_buf = (char *) inbuf;
126 retval = io_channel_write_blk64(fs->io, block, 1, write_buf);
127 #ifdef WORDS_BIGENDIAN
128 ext2fs_free_mem(&buf);
131 ext2fs_mark_changed(fs);
135 errcode_t ext2fs_write_ext_attr(ext2_filsys fs, blk_t block, void *inbuf)
137 return ext2fs_write_ext_attr2(fs, block, inbuf);
141 * This function adjusts the reference count of the EA block.
143 errcode_t ext2fs_adjust_ea_refcount2(ext2_filsys fs, blk64_t blk,
144 char *block_buf, int adjust,
148 struct ext2_ext_attr_header *header;
151 if ((blk >= ext2fs_blocks_count(fs->super)) ||
152 (blk < fs->super->s_first_data_block))
153 return EXT2_ET_BAD_EA_BLOCK_NUM;
156 retval = ext2fs_get_mem(fs->blocksize, &buf);
162 retval = ext2fs_read_ext_attr2(fs, blk, block_buf);
166 header = BHDR(block_buf);
167 if (header->h_magic != EXT2_EXT_ATTR_MAGIC)
168 return EXT2_ET_EA_BAD_MAGIC;
170 header->h_refcount += adjust;
172 *newcount = header->h_refcount;
174 retval = ext2fs_write_ext_attr2(fs, blk, block_buf);
180 ext2fs_free_mem(&buf);
184 errcode_t ext2fs_adjust_ea_refcount(ext2_filsys fs, blk_t blk,
185 char *block_buf, int adjust,
188 return ext2fs_adjust_ea_refcount2(fs, blk, block_buf, adjust, newcount);
191 struct ext2_attr_info {
198 struct ext2_attr_search {
199 struct ext2_ext_attr_entry *first;
202 struct ext2_ext_attr_entry *here;
206 struct ext2_attr_ibody_find {
208 struct ext2_attr_search s;
211 struct ext2_attr_block_find {
212 struct ext2_attr_search s;
216 void ext2fs_attr_shift_entries(struct ext2_ext_attr_entry *entry,
217 int value_offs_shift, char *to,
220 struct ext2_ext_attr_entry *last = entry;
222 /* Adjust the value offsets of the entries */
223 for (; !EXT2_EXT_IS_LAST_ENTRY(last); last = EXT2_EXT_ATTR_NEXT(last)) {
224 if (!last->e_value_block && last->e_value_size) {
225 last->e_value_offs = last->e_value_offs +
229 /* Shift the entries by n bytes and zero freed space in inode */
230 memmove(to, from, n);
232 memset(from, 0, to - from);
236 * This function returns the free space present in the inode or the EA block.
237 * total is number of bytes taken up by the EA entries and is used to shift
238 * the EAs in ext2fs_expand_extra_isize().
240 int ext2fs_attr_free_space(struct ext2_ext_attr_entry *last,
241 int *min_offs, char *base, int *total)
243 for (; !EXT2_EXT_IS_LAST_ENTRY(last); last = EXT2_EXT_ATTR_NEXT(last)) {
244 *total += EXT2_EXT_ATTR_LEN(last->e_name_len);
245 if (!last->e_value_block && last->e_value_size) {
246 int offs = last->e_value_offs;
247 if (offs < *min_offs)
252 return *min_offs - ((char *)last - base) - sizeof(__u32);
255 static errcode_t ext2fs_attr_check_names(struct ext2_ext_attr_entry *entry,
258 while (!EXT2_EXT_IS_LAST_ENTRY(entry)) {
259 struct ext2_ext_attr_entry *next = EXT2_EXT_ATTR_NEXT(entry);
260 if ((char *)next >= end)
261 return EXT2_ET_EA_BAD_ENTRIES;
267 static errcode_t ext2fs_attr_find_entry(struct ext2_ext_attr_entry **pentry,
268 int name_index, const char *name,
269 int size, int sorted)
271 struct ext2_ext_attr_entry *entry;
276 return EXT2_ET_EA_BAD_NAME;
278 name_len = strlen(name);
280 for (; !EXT2_EXT_IS_LAST_ENTRY(entry);
281 entry = EXT2_EXT_ATTR_NEXT(entry)) {
282 cmp = name_index - entry->e_name_index;
284 cmp = name_len - entry->e_name_len;
286 cmp = memcmp(name, entry->e_name, name_len);
287 if (cmp <= 0 && (sorted || cmp == 0))
292 return cmp ? EXT2_ET_EA_NAME_NOT_FOUND : 0;
295 static errcode_t ext2fs_attr_block_find(ext2_filsys fs,struct ext2_inode *inode,
296 struct ext2_attr_info *i,
297 struct ext2_attr_block_find *bs)
299 struct ext2_ext_attr_header *header;
302 if (inode->i_file_acl) {
303 /* The inode already has an extended attribute block. */
304 error = ext2fs_get_mem(fs->blocksize, &bs->block);
307 error = ext2fs_read_ext_attr(fs, inode->i_file_acl, bs->block);
311 header = BHDR(bs->block);
312 if (header->h_magic != EXT2_EXT_ATTR_MAGIC) {
313 error = EXT2_ET_EA_BAD_MAGIC;
317 /* Find the named attribute. */
318 bs->s.base = bs->block;
319 bs->s.first = (struct ext2_ext_attr_entry *)(header + 1);
320 bs->s.end = bs->block + fs->blocksize;
321 bs->s.here = bs->s.first;
322 error = ext2fs_attr_find_entry(&bs->s.here, i->name_index,
323 i->name, fs->blocksize, 1);
324 if (error && error != EXT2_ET_EA_NAME_NOT_FOUND)
326 bs->s.not_found = error;
331 if (error && bs->block)
332 ext2fs_free_mem(&bs->block);
336 static errcode_t ext2fs_attr_ibody_find(ext2_filsys fs,
337 struct ext2_inode_large *inode,
338 struct ext2_attr_info *i,
339 struct ext2_attr_ibody_find *is)
345 if (EXT2_INODE_SIZE(fs->super) == EXT2_GOOD_OLD_INODE_SIZE)
348 if (inode->i_extra_isize == 0)
350 eamagic = IHDR(inode);
352 start = (char *)inode + EXT2_GOOD_OLD_INODE_SIZE +
353 inode->i_extra_isize + sizeof(__u32);
354 is->s.first = (struct ext2_ext_attr_entry *)start;
356 is->s.here = is->s.first;
357 is->s.end = (char *)inode + EXT2_INODE_SIZE(fs->super);
358 if (*eamagic == EXT2_EXT_ATTR_MAGIC) {
359 error = ext2fs_attr_check_names((struct ext2_ext_attr_entry *)
363 /* Find the named attribute. */
364 error = ext2fs_attr_find_entry(&is->s.here, i->name_index,
366 (char *)is->s.base, 0);
367 if (error && error != EXT2_ET_EA_NAME_NOT_FOUND)
369 is->s.not_found = error;
375 static errcode_t ext2fs_attr_set_entry(ext2_filsys fs, struct ext2_attr_info *i,
376 struct ext2_attr_search *s)
378 struct ext2_ext_attr_entry *last;
379 int free, min_offs = s->end - s->base, name_len = strlen(i->name);
381 /* Compute min_offs and last. */
382 for (last = s->first; !EXT2_EXT_IS_LAST_ENTRY(last);
383 last = EXT2_EXT_ATTR_NEXT(last)) {
384 if (!last->e_value_block && last->e_value_size) {
385 int offs = last->e_value_offs;
391 free = min_offs - ((char *)last - s->base) - sizeof(__u32);
394 if (!s->here->e_value_block && s->here->e_value_size) {
395 int size = s->here->e_value_size;
396 free += EXT2_EXT_ATTR_SIZE(size);
398 free += EXT2_EXT_ATTR_LEN(name_len);
401 if (free < EXT2_EXT_ATTR_LEN(name_len) +
402 EXT2_EXT_ATTR_SIZE(i->value_len))
403 return EXT2_ET_EA_NO_SPACE;
406 if (i->value && s->not_found) {
407 /* Insert the new name. */
408 int size = EXT2_EXT_ATTR_LEN(name_len);
409 int rest = (char *)last - (char *)s->here + sizeof(__u32);
411 memmove((char *)s->here + size, s->here, rest);
412 memset(s->here, 0, size);
413 s->here->e_name_index = i->name_index;
414 s->here->e_name_len = name_len;
415 memcpy(s->here->e_name, i->name, name_len);
417 if (!s->here->e_value_block && s->here->e_value_size) {
418 char *first_val = s->base + min_offs;
419 int offs = s->here->e_value_offs;
420 char *val = s->base + offs;
421 int size = EXT2_EXT_ATTR_SIZE(s->here->e_value_size);
424 size == EXT2_EXT_ATTR_SIZE(i->value_len)) {
425 /* The old and the new value have the same
426 size. Just replace. */
427 s->here->e_value_size = i->value_len;
428 memset(val + size - EXT2_EXT_ATTR_PAD, 0,
429 EXT2_EXT_ATTR_PAD); /* Clear pad bytes */
430 memcpy(val, i->value, i->value_len);
434 /* Remove the old value. */
435 memmove(first_val + size, first_val, val - first_val);
436 memset(first_val, 0, size);
437 s->here->e_value_size = 0;
438 s->here->e_value_offs = 0;
441 /* Adjust all value offsets. */
443 while (!EXT2_EXT_IS_LAST_ENTRY(last)) {
444 int o = last->e_value_offs;
446 if (!last->e_value_block &&
447 last->e_value_size && o < offs)
448 last->e_value_offs = o + size;
449 last = EXT2_EXT_ATTR_NEXT(last);
453 /* Remove the old name. */
454 int size = EXT2_EXT_ATTR_LEN(name_len);
456 last = ENTRY((char *)last - size);
457 memmove((char *)s->here, (char *)s->here + size,
458 (char *)last - (char *)s->here + sizeof(__u32));
459 memset(last, 0, size);
464 /* Insert the new value. */
465 s->here->e_value_size = i->value_len;
467 int size = EXT2_EXT_ATTR_SIZE(i->value_len);
468 char *val = s->base + min_offs - size;
470 s->here->e_value_offs = min_offs - size;
471 memset(val + size - EXT2_EXT_ATTR_PAD, 0,
472 EXT2_EXT_ATTR_PAD); /* Clear the pad bytes. */
473 memcpy(val, i->value, i->value_len);
480 static errcode_t ext2fs_attr_block_set(ext2_filsys fs, struct ext2_inode *inode,
481 struct ext2_attr_info *i,
482 struct ext2_attr_block_find *bs)
484 struct ext2_attr_search *s = &bs->s;
485 char *new_buf = NULL, *old_block = NULL;
490 if (i->value && i->value_len > fs->blocksize)
491 return EXT2_ET_EA_NO_SPACE;
494 if (BHDR(s->base)->h_refcount != 1) {
495 int offset = (char *)s->here - bs->block;
497 /* Decrement the refcount of the shared block */
499 BHDR(s->base)->h_refcount -= 1;
501 error = ext2fs_get_mem(fs->blocksize, &s->base);
505 memcpy(s->base, bs->block, fs->blocksize);
506 s->first = ENTRY(BHDR(s->base)+1);
507 BHDR(s->base)->h_refcount = 1;
508 s->here = ENTRY(s->base + offset);
509 s->end = s->base + fs->blocksize;
512 error = ext2fs_get_mem(fs->blocksize, &s->base);
516 memset(s->base, 0, fs->blocksize);
517 BHDR(s->base)->h_magic = EXT2_EXT_ATTR_MAGIC;
518 BHDR(s->base)->h_blocks = 1;
519 BHDR(s->base)->h_refcount = 1;
520 s->first = ENTRY(BHDR(s->base)+1);
521 s->here = ENTRY(BHDR(s->base)+1);
522 s->end = s->base + fs->blocksize;
525 error = ext2fs_attr_set_entry(fs, i, s);
529 if (!EXT2_EXT_IS_LAST_ENTRY(s->first))
530 ext2fs_attr_rehash(BHDR(s->base), s->here);
532 if (!EXT2_EXT_IS_LAST_ENTRY(s->first)) {
533 if (bs->block && bs->block == s->base) {
534 /* We are modifying this block in-place */
536 blk = inode->i_file_acl;
537 error = ext2fs_write_ext_attr(fs, blk, s->base);
541 /* We need to allocate a new block */
542 error = ext2fs_new_block(fs, 0, 0, &blk);
545 ext2fs_block_alloc_stats(fs, blk, 1);
546 error = ext2fs_write_ext_attr(fs, blk, s->base);
551 BHDR(s->base)->h_refcount -= 1;
552 error = ext2fs_write_ext_attr(fs,
561 /* Update the i_blocks if we added a new EA block */
562 if (!inode->i_file_acl && new_buf)
563 inode->i_blocks += fs->blocksize / 512;
564 /* Update the inode. */
565 inode->i_file_acl = new_buf ? blk : 0;
569 ext2fs_free_mem(&s->base);
573 static errcode_t ext2fs_attr_ibody_set(ext2_filsys fs,
574 struct ext2_inode_large *inode,
575 struct ext2_attr_info *i,
576 struct ext2_attr_ibody_find *is)
579 struct ext2_attr_search *s = &is->s;
582 if (EXT2_INODE_SIZE(fs->super) == EXT2_GOOD_OLD_INODE_SIZE)
583 return EXT2_ET_EA_NO_SPACE;
585 error = ext2fs_attr_set_entry(fs, i, s);
589 eamagic = IHDR(inode);
590 if (!EXT2_EXT_IS_LAST_ENTRY(s->first))
591 *eamagic = EXT2_EXT_ATTR_MAGIC;
595 return ext2fs_write_inode_full(fs, is->ino, (struct ext2_inode *)inode,
596 EXT2_INODE_SIZE(fs->super));
602 } ext2_attr_index_prefix[] = {
603 [EXT2_ATTR_INDEX_USER] = { EXT2_ATTR_INDEX_USER_PREFIX,
604 sizeof(EXT2_ATTR_INDEX_USER_PREFIX) },
605 [EXT2_ATTR_INDEX_POSIX_ACL_ACCESS] = {
606 EXT2_ATTR_INDEX_POSIX_ACL_ACCESS_PREFIX,
607 sizeof(EXT2_ATTR_INDEX_POSIX_ACL_ACCESS_PREFIX) },
608 [EXT2_ATTR_INDEX_POSIX_ACL_DEFAULT] = {
609 EXT2_ATTR_INDEX_POSIX_ACL_DEFAULT_PREFIX,
610 sizeof(EXT2_ATTR_INDEX_POSIX_ACL_DEFAULT_PREFIX) },
611 [EXT2_ATTR_INDEX_TRUSTED] = { EXT2_ATTR_INDEX_TRUSTED_PREFIX,
612 sizeof(EXT2_ATTR_INDEX_TRUSTED_PREFIX) },
613 [EXT2_ATTR_INDEX_LUSTRE] = { EXT2_ATTR_INDEX_LUSTRE_PREFIX,
614 sizeof(EXT2_ATTR_INDEX_LUSTRE_PREFIX) },
615 [EXT2_ATTR_INDEX_SECURITY] = { EXT2_ATTR_INDEX_SECURITY_PREFIX,
616 sizeof(EXT2_ATTR_INDEX_SECURITY_PREFIX)},
620 errcode_t ext2fs_attr_set(ext2_filsys fs, ext2_ino_t ino,
621 struct ext2_inode *inode,
622 int name_index, const char *name, const char *value,
623 int value_len, int flags)
625 struct ext2_inode_large *inode_large = NULL;
626 struct ext2_attr_info i = {
627 .name_index = name_index,
630 .value_len = value_len,
632 struct ext2_attr_ibody_find is = {
634 .s = { .not_found = -ENODATA, },
636 struct ext2_attr_block_find bs = {
637 .s = { .not_found = -ENODATA, },
642 return EXT2_ET_EA_BAD_NAME;
643 if (strlen(name) > 255)
644 return EXT2_ET_EA_NAME_TOO_BIG;
646 /* If the prefix is still present, skip it */
647 if (strncmp(name, ext2_attr_index_prefix[name_index].str,
648 ext2_attr_index_prefix[name_index].len) == 0)
649 i.name += ext2_attr_index_prefix[name_index].len;
651 if (EXT2_INODE_SIZE(fs->super) > EXT2_GOOD_OLD_INODE_SIZE) {
652 inode_large = (struct ext2_inode_large *)inode;
654 error = ext2fs_attr_ibody_find(fs, inode_large, &i, &is);
658 if (is.s.not_found) {
659 error = ext2fs_attr_block_find(fs, inode, &i, &bs);
664 if (is.s.not_found && bs.s.not_found) {
665 error = EXT2_ET_EA_NAME_NOT_FOUND;
666 if (flags & XATTR_REPLACE)
672 error = EXT2_ET_EA_NAME_EXISTS;
673 if (flags & XATTR_CREATE)
678 if (!is.s.not_found &&
679 (EXT2_INODE_SIZE(fs->super) > EXT2_GOOD_OLD_INODE_SIZE))
680 error = ext2fs_attr_ibody_set(fs, inode_large, &i, &is);
681 else if (!bs.s.not_found)
682 error = ext2fs_attr_block_set(fs, inode, &i, &bs);
684 if (EXT2_INODE_SIZE(fs->super) > EXT2_GOOD_OLD_INODE_SIZE)
685 error = ext2fs_attr_ibody_set(fs, inode_large, &i, &is);
686 if (!error && !bs.s.not_found) {
688 error = ext2fs_attr_block_set(fs, inode, &i, &bs);
689 } else if (error == EXT2_ET_EA_NO_SPACE) {
690 error = ext2fs_attr_block_set(fs, inode, &i, &bs);
693 if (!is.s.not_found) {
695 if (EXT2_INODE_SIZE(fs->super) >
696 EXT2_GOOD_OLD_INODE_SIZE)
697 error = ext2fs_attr_ibody_set(fs,
698 inode_large, &i, &is);
707 static errcode_t ext2fs_attr_check_block(ext2_filsys fs, char *buffer)
709 if (BHDR(buffer)->h_magic != (EXT2_EXT_ATTR_MAGIC) ||
710 BHDR(buffer)->h_blocks != 1)
711 return EXT2_ET_EA_BAD_MAGIC;
713 return ext2fs_attr_check_names((struct ext2_ext_attr_entry *)
715 buffer + fs->blocksize);
718 static errcode_t ext2fs_attr_block_get(ext2_filsys fs, struct ext2_inode *inode,
719 int name_index, const char *name,
720 void *buffer, size_t buffer_size,
723 struct ext2_ext_attr_header *header = NULL;
724 struct ext2_ext_attr_entry *entry;
725 char *block_buf = NULL;
728 error = EXT2_ET_EA_NAME_NOT_FOUND;
729 if (!inode->i_file_acl)
732 error = ext2fs_get_mem(fs->blocksize, &block_buf);
735 error = ext2fs_read_ext_attr(fs, inode->i_file_acl, block_buf);
739 error = ext2fs_attr_check_block(fs, block_buf);
743 header = BHDR(block_buf);
744 entry = (struct ext2_ext_attr_entry *)(header + 1);
745 error = ext2fs_attr_find_entry(&entry, name_index, name,
750 *easize = entry->e_value_size;
752 if (entry->e_value_size > buffer_size) {
753 error = EXT2_ET_EA_TOO_BIG;
756 memcpy(buffer, block_buf + entry->e_value_offs,
757 entry->e_value_size);
762 ext2fs_free_mem(&block_buf);
766 static errcode_t ext2fs_attr_ibody_get(ext2_filsys fs,
767 struct ext2_inode_large *inode,
768 int name_index, const char *name,
769 void *buffer, size_t buffer_size,
772 struct ext2_ext_attr_entry *entry;
777 if (EXT2_INODE_SIZE(fs->super) == EXT2_GOOD_OLD_INODE_SIZE)
778 return EXT2_ET_EA_NAME_NOT_FOUND;
780 eamagic = IHDR(inode);
781 error = ext2fs_attr_check_block(fs, buffer);
785 start = (char *)inode + EXT2_GOOD_OLD_INODE_SIZE +
786 inode->i_extra_isize + sizeof(__u32);
787 entry = (struct ext2_ext_attr_entry *)start;
788 end = (char *)inode + EXT2_INODE_SIZE(fs->super);
789 error = ext2fs_attr_check_names(entry, end);
792 error = ext2fs_attr_find_entry(&entry, name_index, name,
793 end - (char *)entry, 0);
797 *easize = entry->e_value_size;
799 if (entry->e_value_size > buffer_size) {
800 error = EXT2_ET_EA_TOO_BIG;
803 memcpy(buffer, start + entry->e_value_offs,entry->e_value_size);
811 errcode_t ext2fs_attr_get(ext2_filsys fs, struct ext2_inode *inode,
812 int name_index, const char *name, char *buffer,
813 size_t buffer_size, int *easize)
817 error = ext2fs_attr_ibody_get(fs, (struct ext2_inode_large *)inode,
818 name_index, name, buffer, buffer_size,
820 if (error == EXT2_ET_EA_NAME_NOT_FOUND)
821 error = ext2fs_attr_block_get(fs, inode, name_index, name,
822 buffer, buffer_size, easize);
827 int ext2fs_attr_get_next_attr(struct ext2_ext_attr_entry *entry, int name_index,
828 char *buffer, int buffer_size, int start)
830 const int prefix_len = ext2_attr_index_prefix[name_index].len;
833 if (!start && !EXT2_EXT_IS_LAST_ENTRY(entry))
834 entry = EXT2_EXT_ATTR_NEXT(entry);
836 for (; !EXT2_EXT_IS_LAST_ENTRY(entry);
837 entry = EXT2_EXT_ATTR_NEXT(entry)) {
840 if (name_index == entry->e_name_index)
843 if (EXT2_EXT_IS_LAST_ENTRY(entry))
846 total_len = prefix_len + entry->e_name_len + 1;
847 if (buffer && total_len <= buffer_size) {
848 memcpy(buffer, ext2_attr_index_prefix[name_index].str,
850 memcpy(buffer + prefix_len, entry->e_name, entry->e_name_len);
851 buffer[prefix_len + entry->e_name_len] = '\0';
857 errcode_t ext2fs_expand_extra_isize(ext2_filsys fs, ext2_ino_t ino,
858 struct ext2_inode_large *inode,
859 int new_extra_isize, int *ret,
862 struct ext2_inode *inode_buf = NULL;
863 __u32 *eamagic = NULL;
864 struct ext2_ext_attr_header *header = NULL;
865 struct ext2_ext_attr_entry *entry = NULL, *last = NULL;
866 struct ext2_attr_ibody_find is = {
868 .s = { .not_found = EXT2_ET_EA_NO_SPACE, },
870 struct ext2_attr_block_find bs = {
871 .s = { .not_found = EXT2_ET_EA_NO_SPACE, },
873 char *start, *end, *block_buf = NULL, *buffer =NULL, *b_entry_name=NULL;
874 int total_ino = 0, total_blk, free, offs, tried_min_extra_isize = 0;
875 int s_min_extra_isize = fs->super->s_min_extra_isize;
879 *needed_size = new_extra_isize;
880 error = ext2fs_get_mem(fs->blocksize, &block_buf);
885 error = ext2fs_get_mem(EXT2_INODE_SIZE(fs->super), &inode_buf);
889 error = ext2fs_read_inode_full(fs, ino, inode_buf,
890 EXT2_INODE_SIZE(fs->super));
894 inode = (struct ext2_inode_large *)inode_buf;
898 if (inode->i_extra_isize >= new_extra_isize)
901 eamagic = IHDR(inode);
902 start = (char *)inode + EXT2_GOOD_OLD_INODE_SIZE + inode->i_extra_isize;
903 /* No extended attributes present */
904 if (*eamagic != EXT2_EXT_ATTR_MAGIC) {
906 EXT2_INODE_SIZE(fs->super) - EXT2_GOOD_OLD_INODE_SIZE -
907 inode->i_extra_isize);
908 inode->i_extra_isize = new_extra_isize;
914 start += sizeof(__u32);
915 end = (char *)inode + EXT2_INODE_SIZE(fs->super);
916 last = entry = (struct ext2_ext_attr_entry *)start;
918 /* Consider space takenup by magic number */
919 total_ino = sizeof(__u32);
920 free = ext2fs_attr_free_space(last, &offs, start, &total_ino);
922 /* Enough free space available in the inode for expansion */
923 if (free >= new_extra_isize) {
924 ext2fs_attr_shift_entries(entry,
925 inode->i_extra_isize - new_extra_isize,
927 EXT2_GOOD_OLD_INODE_SIZE +
929 start - sizeof(__u32), total_ino);
930 inode->i_extra_isize = new_extra_isize;
936 if (inode->i_file_acl) {
937 error = ext2fs_read_ext_attr(fs, inode->i_file_acl, block_buf);
941 header = BHDR(block_buf);
942 if (header->h_magic != EXT2_EXT_ATTR_MAGIC) {
943 error = EXT2_ET_EA_BAD_MAGIC;
946 end = block_buf + fs->blocksize;
947 last = entry = (struct ext2_ext_attr_entry *)(header+1);
948 start = (char *)entry;
950 free = ext2fs_attr_free_space(last, &offs, start, &total_blk);
951 if (free < new_extra_isize) {
952 if (!tried_min_extra_isize && s_min_extra_isize) {
953 tried_min_extra_isize++;
954 new_extra_isize = s_min_extra_isize;
958 *ret = EXT2_EXPAND_EISIZE_NOSPC;
959 error = EXT2_ET_EA_NO_SPACE;
963 if (ret && *ret == EXT2_EXPAND_EISIZE_UNSAFE) {
964 *ret = EXT2_EXPAND_EISIZE_NEW_BLOCK;
968 free = fs->blocksize;
971 while (new_extra_isize > 0) {
972 int offs, size, entry_size;
973 struct ext2_ext_attr_entry *small_entry = NULL;
974 struct ext2_attr_info i = {
978 unsigned int total_size, shift_bytes, temp = ~0U, extra_isize=0;
980 start = (char *)inode + EXT2_GOOD_OLD_INODE_SIZE +
981 inode->i_extra_isize + sizeof(__u32);
982 end = (char *)inode + EXT2_INODE_SIZE(fs->super);
983 last = (struct ext2_ext_attr_entry *)start;
985 /* Find the entry best suited to be pushed into EA block */
987 for (; !EXT2_EXT_IS_LAST_ENTRY(last);
988 last = EXT2_EXT_ATTR_NEXT(last)) {
989 total_size = EXT2_EXT_ATTR_SIZE(last->e_value_size) +
990 EXT2_EXT_ATTR_LEN(last->e_name_len);
991 if (total_size <= free && total_size < temp) {
992 if (total_size < new_extra_isize) {
1001 if (entry == NULL) {
1003 entry = small_entry;
1005 if (!tried_min_extra_isize &&
1006 s_min_extra_isize) {
1007 tried_min_extra_isize++;
1008 new_extra_isize = s_min_extra_isize;
1012 *ret = EXT2_EXPAND_EISIZE_NOSPC;
1013 error = EXT2_ET_EA_NO_SPACE;
1017 offs = entry->e_value_offs;
1018 size = entry->e_value_size;
1019 entry_size = EXT2_EXT_ATTR_LEN(entry->e_name_len);
1020 i.name_index = entry->e_name_index;
1021 error = ext2fs_get_mem(size, &buffer);
1024 error = ext2fs_get_mem(entry->e_name_len + 1, &b_entry_name);
1027 /* Save the entry name and the entry value */
1028 memcpy((char *)buffer, (char *)start + offs,
1029 EXT2_EXT_ATTR_SIZE(size));
1030 memcpy((char *)b_entry_name, (char *)entry->e_name,
1032 b_entry_name[entry->e_name_len] = '\0';
1033 i.name = b_entry_name;
1035 error = ext2fs_attr_ibody_find(fs, inode, &i, &is);
1039 error = ext2fs_attr_set_entry(fs, &i, &is.s);
1043 entry = (struct ext2_ext_attr_entry *)start;
1044 if (entry_size + EXT2_EXT_ATTR_SIZE(size) >= new_extra_isize)
1045 shift_bytes = new_extra_isize;
1047 shift_bytes = entry_size + EXT2_EXT_ATTR_SIZE(size);
1048 ext2fs_attr_shift_entries(entry,
1049 inode->i_extra_isize - shift_bytes,
1050 (char *)inode +EXT2_GOOD_OLD_INODE_SIZE+
1051 extra_isize + shift_bytes,
1052 start - sizeof(__u32),
1053 total_ino - entry_size);
1055 extra_isize += shift_bytes;
1056 new_extra_isize -= shift_bytes;
1058 *needed_size = new_extra_isize;
1059 inode->i_extra_isize = extra_isize;
1061 i.name = b_entry_name;
1064 error = ext2fs_attr_block_find(fs, (struct ext2_inode *)inode,
1069 /* Add entry which was removed from the inode into the block */
1070 error = ext2fs_attr_block_set(fs, (struct ext2_inode *)inode,
1077 error = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)inode,
1078 EXT2_INODE_SIZE(fs->super));
1081 ext2fs_free_mem(&inode_buf);
1083 ext2fs_free_mem(&block_buf);
1085 ext2fs_free_mem(&buffer);
1087 ext2fs_free_mem(&b_entry_name);