]> git.ipfire.org Git - thirdparty/e2fsprogs.git/blob - lib/ext2fs/ext_attr.c
Merge branch 'maint' into next
[thirdparty/e2fsprogs.git] / lib / ext2fs / ext_attr.c
1 /*
2 * ext_attr.c --- extended attribute blocks
3 *
4 * Copyright (C) 2001 Andreas Gruenbacher, <a.gruenbacher@computer.org>
5 *
6 * Copyright (C) 2002 Theodore Ts'o.
7 *
8 * %Begin-Header%
9 * This file may be redistributed under the terms of the GNU Library
10 * General Public License, version 2.
11 * %End-Header%
12 */
13
14 #include "config.h"
15 #include <stdio.h>
16 #if HAVE_UNISTD_H
17 #include <unistd.h>
18 #endif
19 #include <string.h>
20 #include <time.h>
21
22 #include "ext2_fs.h"
23 #include "ext2_ext_attr.h"
24
25 #include "ext2fs.h"
26
27 #define NAME_HASH_SHIFT 5
28 #define VALUE_HASH_SHIFT 16
29
30 /*
31 * ext2_xattr_hash_entry()
32 *
33 * Compute the hash of an extended attribute.
34 */
35 __u32 ext2fs_ext_attr_hash_entry(struct ext2_ext_attr_entry *entry, void *data)
36 {
37 __u32 hash = 0;
38 char *name = ((char *) entry) + sizeof(struct ext2_ext_attr_entry);
39 int n;
40
41 for (n = 0; n < entry->e_name_len; n++) {
42 hash = (hash << NAME_HASH_SHIFT) ^
43 (hash >> (8*sizeof(hash) - NAME_HASH_SHIFT)) ^
44 *name++;
45 }
46
47 /* The hash needs to be calculated on the data in little-endian. */
48 if (entry->e_value_block == 0 && entry->e_value_size != 0) {
49 __u32 *value = (__u32 *)data;
50 for (n = (entry->e_value_size + EXT2_EXT_ATTR_ROUND) >>
51 EXT2_EXT_ATTR_PAD_BITS; n; n--) {
52 hash = (hash << VALUE_HASH_SHIFT) ^
53 (hash >> (8*sizeof(hash) - VALUE_HASH_SHIFT)) ^
54 ext2fs_le32_to_cpu(*value++);
55 }
56 }
57
58 return hash;
59 }
60
61 static errcode_t check_ext_attr_header(struct ext2_ext_attr_header *header)
62 {
63 if ((header->h_magic != EXT2_EXT_ATTR_MAGIC_v1 &&
64 header->h_magic != EXT2_EXT_ATTR_MAGIC) ||
65 header->h_blocks != 1)
66 return EXT2_ET_BAD_EA_HEADER;
67
68 return 0;
69 }
70
71 #undef NAME_HASH_SHIFT
72 #undef VALUE_HASH_SHIFT
73
74 errcode_t ext2fs_read_ext_attr3(ext2_filsys fs, blk64_t block, void *buf,
75 ext2_ino_t inum)
76 {
77 int csum_failed = 0;
78 errcode_t retval;
79
80 retval = io_channel_read_blk64(fs->io, block, 1, buf);
81 if (retval)
82 return retval;
83
84 if (!(fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) &&
85 !ext2fs_ext_attr_block_csum_verify(fs, inum, block, buf))
86 csum_failed = 1;
87
88 #ifdef WORDS_BIGENDIAN
89 ext2fs_swap_ext_attr(buf, buf, fs->blocksize, 1);
90 #endif
91
92 retval = check_ext_attr_header(buf);
93 if (retval == 0 && csum_failed)
94 retval = EXT2_ET_EXT_ATTR_CSUM_INVALID;
95
96 return retval;
97 }
98
99 errcode_t ext2fs_read_ext_attr2(ext2_filsys fs, blk64_t block, void *buf)
100 {
101 return ext2fs_read_ext_attr3(fs, block, buf, 0);
102 }
103
104 errcode_t ext2fs_read_ext_attr(ext2_filsys fs, blk_t block, void *buf)
105 {
106 return ext2fs_read_ext_attr2(fs, block, buf);
107 }
108
109 errcode_t ext2fs_write_ext_attr3(ext2_filsys fs, blk64_t block, void *inbuf,
110 ext2_ino_t inum)
111 {
112 errcode_t retval;
113 char *write_buf;
114
115 #ifdef WORDS_BIGENDIAN
116 retval = ext2fs_get_mem(fs->blocksize, &write_buf);
117 if (retval)
118 return retval;
119 ext2fs_swap_ext_attr(write_buf, inbuf, fs->blocksize, 1);
120 #else
121 write_buf = (char *) inbuf;
122 #endif
123
124 retval = ext2fs_ext_attr_block_csum_set(fs, inum, block,
125 (struct ext2_ext_attr_header *)write_buf);
126 if (retval)
127 return retval;
128
129 retval = io_channel_write_blk64(fs->io, block, 1, write_buf);
130 #ifdef WORDS_BIGENDIAN
131 ext2fs_free_mem(&write_buf);
132 #endif
133 if (!retval)
134 ext2fs_mark_changed(fs);
135 return retval;
136 }
137
138 errcode_t ext2fs_write_ext_attr2(ext2_filsys fs, blk64_t block, void *inbuf)
139 {
140 return ext2fs_write_ext_attr3(fs, block, inbuf, 0);
141 }
142
143 errcode_t ext2fs_write_ext_attr(ext2_filsys fs, blk_t block, void *inbuf)
144 {
145 return ext2fs_write_ext_attr2(fs, block, inbuf);
146 }
147
148 /*
149 * This function adjusts the reference count of the EA block.
150 */
151 errcode_t ext2fs_adjust_ea_refcount3(ext2_filsys fs, blk64_t blk,
152 char *block_buf, int adjust,
153 __u32 *newcount, ext2_ino_t inum)
154 {
155 errcode_t retval;
156 struct ext2_ext_attr_header *header;
157 char *buf = 0;
158
159 if ((blk >= ext2fs_blocks_count(fs->super)) ||
160 (blk < fs->super->s_first_data_block))
161 return EXT2_ET_BAD_EA_BLOCK_NUM;
162
163 if (!block_buf) {
164 retval = ext2fs_get_mem(fs->blocksize, &buf);
165 if (retval)
166 return retval;
167 block_buf = buf;
168 }
169
170 retval = ext2fs_read_ext_attr3(fs, blk, block_buf, inum);
171 if (retval)
172 goto errout;
173
174 header = (struct ext2_ext_attr_header *) block_buf;
175 header->h_refcount += adjust;
176 if (newcount)
177 *newcount = header->h_refcount;
178
179 retval = ext2fs_write_ext_attr3(fs, blk, block_buf, inum);
180 if (retval)
181 goto errout;
182
183 errout:
184 if (buf)
185 ext2fs_free_mem(&buf);
186 return retval;
187 }
188
189 errcode_t ext2fs_adjust_ea_refcount2(ext2_filsys fs, blk64_t blk,
190 char *block_buf, int adjust,
191 __u32 *newcount)
192 {
193 return ext2fs_adjust_ea_refcount3(fs, blk, block_buf, adjust,
194 newcount, 0);
195 }
196
197 errcode_t ext2fs_adjust_ea_refcount(ext2_filsys fs, blk_t blk,
198 char *block_buf, int adjust,
199 __u32 *newcount)
200 {
201 return ext2fs_adjust_ea_refcount2(fs, blk, block_buf, adjust,
202 newcount);
203 }
204
205 /* Manipulate the contents of extended attribute regions */
206 struct ext2_xattr {
207 char *name;
208 void *value;
209 size_t value_len;
210 };
211
212 struct ext2_xattr_handle {
213 errcode_t magic;
214 ext2_filsys fs;
215 struct ext2_xattr *attrs;
216 size_t length, count;
217 ext2_ino_t ino;
218 int dirty;
219 };
220
221 static errcode_t ext2fs_xattrs_expand(struct ext2_xattr_handle *h,
222 unsigned int expandby)
223 {
224 struct ext2_xattr *new_attrs;
225 errcode_t err;
226
227 err = ext2fs_get_arrayzero(h->length + expandby,
228 sizeof(struct ext2_xattr), &new_attrs);
229 if (err)
230 return err;
231
232 memcpy(new_attrs, h->attrs, h->length * sizeof(struct ext2_xattr));
233 ext2fs_free_mem(&h->attrs);
234 h->length += expandby;
235 h->attrs = new_attrs;
236
237 return 0;
238 }
239
240 struct ea_name_index {
241 int index;
242 const char *name;
243 };
244
245 /* Keep these names sorted in order of decreasing specificity. */
246 static struct ea_name_index ea_names[] = {
247 {3, "system.posix_acl_default"},
248 {2, "system.posix_acl_access"},
249 {8, "system.richacl"},
250 {6, "security."},
251 {4, "trusted."},
252 {7, "system."},
253 {1, "user."},
254 {0, NULL},
255 };
256
257 static int find_ea_index(char *fullname, char **name, int *index);
258
259 /* Push empty attributes to the end and inlinedata to the front. */
260 static int attr_compare(const void *a, const void *b)
261 {
262 const struct ext2_xattr *xa = a, *xb = b;
263 char *xa_suffix, *xb_suffix;
264 int xa_idx, xb_idx;
265 int cmp;
266
267 if (xa->name == NULL)
268 return +1;
269 else if (xb->name == NULL)
270 return -1;
271 else if (!strcmp(xa->name, "system.data"))
272 return -1;
273 else if (!strcmp(xb->name, "system.data"))
274 return +1;
275
276 /*
277 * Duplicate the kernel's sorting algorithm because xattr blocks
278 * require sorted keys.
279 */
280 xa_suffix = xa->name;
281 xb_suffix = xb->name;
282 xa_idx = xb_idx = 0;
283 find_ea_index(xa->name, &xa_suffix, &xa_idx);
284 find_ea_index(xb->name, &xb_suffix, &xb_idx);
285 cmp = xa_idx - xb_idx;
286 if (cmp)
287 return cmp;
288 cmp = strlen(xa_suffix) - strlen(xb_suffix);
289 if (cmp)
290 return cmp;
291 cmp = strcmp(xa_suffix, xb_suffix);
292 return cmp;
293 }
294
295 static const char *find_ea_prefix(int index)
296 {
297 struct ea_name_index *e;
298
299 for (e = ea_names; e->name; e++)
300 if (e->index == index)
301 return e->name;
302
303 return NULL;
304 }
305
306 static int find_ea_index(char *fullname, char **name, int *index)
307 {
308 struct ea_name_index *e;
309
310 for (e = ea_names; e->name; e++) {
311 if (memcmp(fullname, e->name, strlen(e->name)) == 0) {
312 *name = (char *)fullname + strlen(e->name);
313 *index = e->index;
314 return 1;
315 }
316 }
317 return 0;
318 }
319
320 errcode_t ext2fs_free_ext_attr(ext2_filsys fs, ext2_ino_t ino,
321 struct ext2_inode_large *inode)
322 {
323 struct ext2_ext_attr_header *header;
324 void *block_buf = NULL;
325 blk64_t blk;
326 errcode_t err;
327 struct ext2_inode_large i;
328
329 /* Read inode? */
330 if (inode == NULL) {
331 err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&i,
332 sizeof(struct ext2_inode_large));
333 if (err)
334 return err;
335 inode = &i;
336 }
337
338 /* Do we already have an EA block? */
339 blk = ext2fs_file_acl_block(fs, (struct ext2_inode *)inode);
340 if (blk == 0)
341 return 0;
342
343 /* Find block, zero it, write back */
344 if ((blk < fs->super->s_first_data_block) ||
345 (blk >= ext2fs_blocks_count(fs->super))) {
346 err = EXT2_ET_BAD_EA_BLOCK_NUM;
347 goto out;
348 }
349
350 err = ext2fs_get_mem(fs->blocksize, &block_buf);
351 if (err)
352 goto out;
353
354 err = ext2fs_read_ext_attr3(fs, blk, block_buf, ino);
355 if (err)
356 goto out2;
357
358 /* We only know how to deal with v2 EA blocks */
359 header = (struct ext2_ext_attr_header *) block_buf;
360 if (header->h_magic != EXT2_EXT_ATTR_MAGIC) {
361 err = EXT2_ET_BAD_EA_HEADER;
362 goto out2;
363 }
364
365 header->h_refcount--;
366 err = ext2fs_write_ext_attr3(fs, blk, block_buf, ino);
367 if (err)
368 goto out2;
369
370 /* Erase link to block */
371 ext2fs_file_acl_block_set(fs, (struct ext2_inode *)inode, 0);
372 if (header->h_refcount == 0)
373 ext2fs_block_alloc_stats2(fs, blk, -1);
374 err = ext2fs_iblk_sub_blocks(fs, (struct ext2_inode *)inode, 1);
375 if (err)
376 goto out2;
377
378 /* Write inode? */
379 if (inode == &i) {
380 err = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&i,
381 sizeof(struct ext2_inode_large));
382 if (err)
383 goto out2;
384 }
385
386 out2:
387 ext2fs_free_mem(&block_buf);
388 out:
389 return err;
390 }
391
392 static errcode_t prep_ea_block_for_write(ext2_filsys fs, ext2_ino_t ino,
393 struct ext2_inode_large *inode)
394 {
395 struct ext2_ext_attr_header *header;
396 void *block_buf = NULL;
397 blk64_t blk, goal;
398 errcode_t err;
399
400 /* Do we already have an EA block? */
401 blk = ext2fs_file_acl_block(fs, (struct ext2_inode *)inode);
402 if (blk != 0) {
403 if ((blk < fs->super->s_first_data_block) ||
404 (blk >= ext2fs_blocks_count(fs->super))) {
405 err = EXT2_ET_BAD_EA_BLOCK_NUM;
406 goto out;
407 }
408
409 err = ext2fs_get_mem(fs->blocksize, &block_buf);
410 if (err)
411 goto out;
412
413 err = ext2fs_read_ext_attr3(fs, blk, block_buf, ino);
414 if (err)
415 goto out2;
416
417 /* We only know how to deal with v2 EA blocks */
418 header = (struct ext2_ext_attr_header *) block_buf;
419 if (header->h_magic != EXT2_EXT_ATTR_MAGIC) {
420 err = EXT2_ET_BAD_EA_HEADER;
421 goto out2;
422 }
423
424 /* Single-user block. We're done here. */
425 if (header->h_refcount == 1)
426 goto out2;
427
428 /* We need to CoW the block. */
429 header->h_refcount--;
430 err = ext2fs_write_ext_attr3(fs, blk, block_buf, ino);
431 if (err)
432 goto out2;
433 } else {
434 /* No block, we must increment i_blocks */
435 err = ext2fs_iblk_add_blocks(fs, (struct ext2_inode *)inode,
436 1);
437 if (err)
438 goto out;
439 }
440
441 /* Allocate a block */
442 goal = ext2fs_find_inode_goal(fs, ino, (struct ext2_inode *)inode, 0);
443 err = ext2fs_alloc_block2(fs, goal, NULL, &blk);
444 if (err)
445 goto out2;
446 ext2fs_file_acl_block_set(fs, (struct ext2_inode *)inode, blk);
447 out2:
448 if (block_buf)
449 ext2fs_free_mem(&block_buf);
450 out:
451 return err;
452 }
453
454
455 static errcode_t write_xattrs_to_buffer(struct ext2_xattr_handle *handle,
456 struct ext2_xattr **pos,
457 void *entries_start,
458 unsigned int storage_size,
459 unsigned int value_offset_correction,
460 int write_hash)
461 {
462 struct ext2_xattr *x = *pos;
463 struct ext2_ext_attr_entry *e = entries_start;
464 char *end = (char *) entries_start + storage_size;
465 char *shortname;
466 unsigned int entry_size, value_size;
467 int idx, ret;
468
469 memset(entries_start, 0, storage_size);
470 /* For all remaining x... */
471 for (; x < handle->attrs + handle->length; x++) {
472 if (!x->name)
473 continue;
474
475 /* Calculate index and shortname position */
476 shortname = x->name;
477 ret = find_ea_index(x->name, &shortname, &idx);
478
479 /* Calculate entry and value size */
480 entry_size = (sizeof(*e) + strlen(shortname) +
481 EXT2_EXT_ATTR_PAD - 1) &
482 ~(EXT2_EXT_ATTR_PAD - 1);
483 value_size = ((x->value_len + EXT2_EXT_ATTR_PAD - 1) /
484 EXT2_EXT_ATTR_PAD) * EXT2_EXT_ATTR_PAD;
485
486 /*
487 * Would entry collide with value?
488 * Note that we must leave sufficient room for a (u32)0 to
489 * mark the end of the entries.
490 */
491 if ((char *)e + entry_size + sizeof(__u32) > end - value_size)
492 break;
493
494 /* Fill out e appropriately */
495 e->e_name_len = strlen(shortname);
496 e->e_name_index = (ret ? idx : 0);
497 e->e_value_offs = end - value_size - (char *)entries_start +
498 value_offset_correction;
499 e->e_value_block = 0;
500 e->e_value_size = x->value_len;
501
502 /* Store name and value */
503 end -= value_size;
504 memcpy((char *)e + sizeof(*e), shortname, e->e_name_len);
505 memcpy(end, x->value, e->e_value_size);
506
507 if (write_hash)
508 e->e_hash = ext2fs_ext_attr_hash_entry(e, end);
509 else
510 e->e_hash = 0;
511
512 e = EXT2_EXT_ATTR_NEXT(e);
513 *(__u32 *)e = 0;
514 }
515 *pos = x;
516
517 return 0;
518 }
519
520 errcode_t ext2fs_xattrs_write(struct ext2_xattr_handle *handle)
521 {
522 struct ext2_xattr *x;
523 struct ext2_inode_large *inode;
524 char *start, *block_buf = NULL;
525 struct ext2_ext_attr_header *header;
526 __u32 ea_inode_magic;
527 blk64_t blk;
528 unsigned int storage_size;
529 unsigned int i;
530 errcode_t err;
531
532 EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EA_HANDLE);
533 i = EXT2_INODE_SIZE(handle->fs->super);
534 if (i < sizeof(*inode))
535 i = sizeof(*inode);
536 err = ext2fs_get_memzero(i, &inode);
537 if (err)
538 return err;
539
540 err = ext2fs_read_inode_full(handle->fs, handle->ino,
541 (struct ext2_inode *)inode,
542 EXT2_INODE_SIZE(handle->fs->super));
543 if (err)
544 goto out;
545
546 /* If extra_isize isn't set, we need to set it now */
547 if (inode->i_extra_isize == 0 &&
548 EXT2_INODE_SIZE(handle->fs->super) > EXT2_GOOD_OLD_INODE_SIZE) {
549 char *p = (char *)inode;
550 size_t extra = handle->fs->super->s_want_extra_isize;
551
552 if (extra == 0)
553 extra = sizeof(__u32);
554 memset(p + EXT2_GOOD_OLD_INODE_SIZE, 0, extra);
555 inode->i_extra_isize = extra;
556 }
557
558 /*
559 * Force the inlinedata attr to the front and the empty entries
560 * to the end.
561 */
562 x = handle->attrs;
563 qsort(x, handle->length, sizeof(struct ext2_xattr), attr_compare);
564
565 /* Does the inode have space for EA? */
566 if (inode->i_extra_isize < sizeof(inode->i_extra_isize) ||
567 EXT2_INODE_SIZE(handle->fs->super) <= EXT2_GOOD_OLD_INODE_SIZE +
568 inode->i_extra_isize +
569 sizeof(__u32))
570 goto write_ea_block;
571
572 /* Write the inode EA */
573 ea_inode_magic = EXT2_EXT_ATTR_MAGIC;
574 memcpy(((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
575 inode->i_extra_isize, &ea_inode_magic, sizeof(__u32));
576 storage_size = EXT2_INODE_SIZE(handle->fs->super) -
577 EXT2_GOOD_OLD_INODE_SIZE - inode->i_extra_isize -
578 sizeof(__u32);
579 start = ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
580 inode->i_extra_isize + sizeof(__u32);
581
582 err = write_xattrs_to_buffer(handle, &x, start, storage_size, 0, 0);
583 if (err)
584 goto out;
585
586 write_ea_block:
587 /* Are we done? */
588 if (x >= handle->attrs + handle->count)
589 goto skip_ea_block;
590
591 /* Write the EA block */
592 err = ext2fs_get_memzero(handle->fs->blocksize, &block_buf);
593 if (err)
594 goto out;
595
596 storage_size = handle->fs->blocksize -
597 sizeof(struct ext2_ext_attr_header);
598 start = block_buf + sizeof(struct ext2_ext_attr_header);
599
600 err = write_xattrs_to_buffer(handle, &x, start, storage_size,
601 start - block_buf, 1);
602 if (err)
603 goto out2;
604
605 if (x < handle->attrs + handle->length) {
606 err = EXT2_ET_EA_NO_SPACE;
607 goto out2;
608 }
609
610 /* Write a header on the EA block */
611 header = (struct ext2_ext_attr_header *) block_buf;
612 header->h_magic = EXT2_EXT_ATTR_MAGIC;
613 header->h_refcount = 1;
614 header->h_blocks = 1;
615
616 /* Get a new block for writing */
617 err = prep_ea_block_for_write(handle->fs, handle->ino, inode);
618 if (err)
619 goto out2;
620
621 /* Finally, write the new EA block */
622 blk = ext2fs_file_acl_block(handle->fs,
623 (struct ext2_inode *)inode);
624 err = ext2fs_write_ext_attr3(handle->fs, blk, block_buf,
625 handle->ino);
626 if (err)
627 goto out2;
628
629 skip_ea_block:
630 blk = ext2fs_file_acl_block(handle->fs, (struct ext2_inode *)inode);
631 if (!block_buf && blk) {
632 /* xattrs shrunk, free the block */
633 err = ext2fs_free_ext_attr(handle->fs, handle->ino, inode);
634 if (err)
635 goto out;
636 }
637
638 /* Write the inode */
639 err = ext2fs_write_inode_full(handle->fs, handle->ino,
640 (struct ext2_inode *)inode,
641 EXT2_INODE_SIZE(handle->fs->super));
642 if (err)
643 goto out2;
644
645 out2:
646 ext2fs_free_mem(&block_buf);
647 out:
648 ext2fs_free_mem(&inode);
649 handle->dirty = 0;
650 return err;
651 }
652
653 static errcode_t read_xattrs_from_buffer(struct ext2_xattr_handle *handle,
654 struct ext2_ext_attr_entry *entries,
655 unsigned int storage_size,
656 char *value_start,
657 size_t *nr_read)
658 {
659 struct ext2_xattr *x;
660 struct ext2_ext_attr_entry *entry, *end;
661 const char *prefix;
662 unsigned int remain, prefix_len;
663 errcode_t err;
664 unsigned int values_size = storage_size +
665 ((char *)entries - value_start);
666
667 x = handle->attrs;
668 while (x->name)
669 x++;
670
671 /* find the end */
672 end = entries;
673 remain = storage_size;
674 while (remain >= sizeof(struct ext2_ext_attr_entry) &&
675 !EXT2_EXT_IS_LAST_ENTRY(end)) {
676
677 /* header eats this space */
678 remain -= sizeof(struct ext2_ext_attr_entry);
679
680 /* is attribute name valid? */
681 if (EXT2_EXT_ATTR_SIZE(end->e_name_len) > remain)
682 return EXT2_ET_EA_BAD_NAME_LEN;
683
684 /* attribute len eats this space */
685 remain -= EXT2_EXT_ATTR_SIZE(end->e_name_len);
686 end = EXT2_EXT_ATTR_NEXT(end);
687 }
688
689 entry = entries;
690 remain = storage_size;
691 while (remain >= sizeof(struct ext2_ext_attr_entry) &&
692 !EXT2_EXT_IS_LAST_ENTRY(entry)) {
693 __u32 hash;
694
695 /* header eats this space */
696 remain -= sizeof(struct ext2_ext_attr_entry);
697
698 /* attribute len eats this space */
699 remain -= EXT2_EXT_ATTR_SIZE(entry->e_name_len);
700
701 /* check value size */
702 if (entry->e_value_size > remain)
703 return EXT2_ET_EA_BAD_VALUE_SIZE;
704
705 if (entry->e_value_offs + entry->e_value_size > values_size)
706 return EXT2_ET_EA_BAD_VALUE_OFFSET;
707
708 if (entry->e_value_size > 0 &&
709 value_start + entry->e_value_offs <
710 (char *)end + sizeof(__u32))
711 return EXT2_ET_EA_BAD_VALUE_OFFSET;
712
713 /* e_value_block must be 0 in inode's ea */
714 if (entry->e_value_block != 0)
715 return EXT2_ET_BAD_EA_BLOCK_NUM;
716
717 hash = ext2fs_ext_attr_hash_entry(entry, value_start +
718 entry->e_value_offs);
719
720 /* e_hash may be 0 in older inode's ea */
721 if (entry->e_hash != 0 && entry->e_hash != hash)
722 return EXT2_ET_BAD_EA_HASH;
723
724 remain -= entry->e_value_size;
725
726 /* Allocate space for more attrs? */
727 if (x == handle->attrs + handle->length) {
728 err = ext2fs_xattrs_expand(handle, 4);
729 if (err)
730 return err;
731 x = handle->attrs + handle->length - 4;
732 }
733
734 /* Extract name/value */
735 prefix = find_ea_prefix(entry->e_name_index);
736 prefix_len = (prefix ? strlen(prefix) : 0);
737 err = ext2fs_get_memzero(entry->e_name_len + prefix_len + 1,
738 &x->name);
739 if (err)
740 return err;
741 if (prefix)
742 memcpy(x->name, prefix, prefix_len);
743 if (entry->e_name_len)
744 memcpy(x->name + prefix_len,
745 (char *)entry + sizeof(*entry),
746 entry->e_name_len);
747
748 err = ext2fs_get_mem(entry->e_value_size, &x->value);
749 if (err)
750 return err;
751 x->value_len = entry->e_value_size;
752 memcpy(x->value, value_start + entry->e_value_offs,
753 entry->e_value_size);
754 x++;
755 (*nr_read)++;
756 entry = EXT2_EXT_ATTR_NEXT(entry);
757 }
758
759 return 0;
760 }
761
762 static void xattrs_free_keys(struct ext2_xattr_handle *h)
763 {
764 struct ext2_xattr *a = h->attrs;
765 size_t i;
766
767 for (i = 0; i < h->length; i++) {
768 if (a[i].name)
769 ext2fs_free_mem(&a[i].name);
770 if (a[i].value)
771 ext2fs_free_mem(&a[i].value);
772 }
773 h->count = 0;
774 }
775
776 errcode_t ext2fs_xattrs_read(struct ext2_xattr_handle *handle)
777 {
778 struct ext2_inode_large *inode;
779 struct ext2_ext_attr_header *header;
780 __u32 ea_inode_magic;
781 unsigned int storage_size;
782 char *start, *block_buf = NULL;
783 blk64_t blk;
784 size_t i;
785 errcode_t err;
786
787 EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EA_HANDLE);
788 i = EXT2_INODE_SIZE(handle->fs->super);
789 if (i < sizeof(*inode))
790 i = sizeof(*inode);
791 err = ext2fs_get_memzero(i, &inode);
792 if (err)
793 return err;
794
795 err = ext2fs_read_inode_full(handle->fs, handle->ino,
796 (struct ext2_inode *)inode,
797 EXT2_INODE_SIZE(handle->fs->super));
798 if (err)
799 goto out;
800
801 xattrs_free_keys(handle);
802
803 /* Does the inode have space for EA? */
804 if (inode->i_extra_isize < sizeof(inode->i_extra_isize) ||
805 EXT2_INODE_SIZE(handle->fs->super) <= EXT2_GOOD_OLD_INODE_SIZE +
806 inode->i_extra_isize +
807 sizeof(__u32))
808 goto read_ea_block;
809
810 /* Look for EA in the inode */
811 memcpy(&ea_inode_magic, ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
812 inode->i_extra_isize, sizeof(__u32));
813 if (ea_inode_magic == EXT2_EXT_ATTR_MAGIC) {
814 storage_size = EXT2_INODE_SIZE(handle->fs->super) -
815 EXT2_GOOD_OLD_INODE_SIZE - inode->i_extra_isize -
816 sizeof(__u32);
817 start = ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
818 inode->i_extra_isize + sizeof(__u32);
819
820 err = read_xattrs_from_buffer(handle,
821 (struct ext2_ext_attr_entry *) start, storage_size,
822 start, &handle->count);
823 if (err)
824 goto out;
825 }
826
827 read_ea_block:
828 /* Look for EA in a separate EA block */
829 blk = ext2fs_file_acl_block(handle->fs, (struct ext2_inode *)inode);
830 if (blk != 0) {
831 if ((blk < handle->fs->super->s_first_data_block) ||
832 (blk >= ext2fs_blocks_count(handle->fs->super))) {
833 err = EXT2_ET_BAD_EA_BLOCK_NUM;
834 goto out;
835 }
836
837 err = ext2fs_get_mem(handle->fs->blocksize, &block_buf);
838 if (err)
839 goto out;
840
841 err = ext2fs_read_ext_attr3(handle->fs, blk, block_buf,
842 handle->ino);
843 if (err)
844 goto out3;
845
846 /* We only know how to deal with v2 EA blocks */
847 header = (struct ext2_ext_attr_header *) block_buf;
848 if (header->h_magic != EXT2_EXT_ATTR_MAGIC) {
849 err = EXT2_ET_BAD_EA_HEADER;
850 goto out3;
851 }
852
853 /* Read EAs */
854 storage_size = handle->fs->blocksize -
855 sizeof(struct ext2_ext_attr_header);
856 start = block_buf + sizeof(struct ext2_ext_attr_header);
857 err = read_xattrs_from_buffer(handle,
858 (struct ext2_ext_attr_entry *) start, storage_size,
859 block_buf, &handle->count);
860 if (err)
861 goto out3;
862
863 ext2fs_free_mem(&block_buf);
864 }
865
866 ext2fs_free_mem(&block_buf);
867 ext2fs_free_mem(&inode);
868 return 0;
869
870 out3:
871 ext2fs_free_mem(&block_buf);
872 out:
873 ext2fs_free_mem(&inode);
874 return err;
875 }
876
877 errcode_t ext2fs_xattrs_iterate(struct ext2_xattr_handle *h,
878 int (*func)(char *name, char *value,
879 size_t value_len, void *data),
880 void *data)
881 {
882 struct ext2_xattr *x;
883 int ret;
884
885 EXT2_CHECK_MAGIC(h, EXT2_ET_MAGIC_EA_HANDLE);
886 for (x = h->attrs; x < h->attrs + h->length; x++) {
887 if (!x->name)
888 continue;
889
890 ret = func(x->name, x->value, x->value_len, data);
891 if (ret & XATTR_CHANGED)
892 h->dirty = 1;
893 if (ret & XATTR_ABORT)
894 return 0;
895 }
896
897 return 0;
898 }
899
900 errcode_t ext2fs_xattr_get(struct ext2_xattr_handle *h, const char *key,
901 void **value, size_t *value_len)
902 {
903 struct ext2_xattr *x;
904 char *val;
905 errcode_t err;
906
907 EXT2_CHECK_MAGIC(h, EXT2_ET_MAGIC_EA_HANDLE);
908 for (x = h->attrs; x < h->attrs + h->length; x++) {
909 if (!x->name)
910 continue;
911
912 if (strcmp(x->name, key) == 0) {
913 err = ext2fs_get_mem(x->value_len, &val);
914 if (err)
915 return err;
916 memcpy(val, x->value, x->value_len);
917 *value = val;
918 *value_len = x->value_len;
919 return 0;
920 }
921 }
922
923 return EXT2_ET_EA_KEY_NOT_FOUND;
924 }
925
926 errcode_t ext2fs_xattr_inode_max_size(ext2_filsys fs, ext2_ino_t ino,
927 size_t *size)
928 {
929 struct ext2_ext_attr_entry *entry;
930 struct ext2_inode_large *inode;
931 __u32 ea_inode_magic;
932 unsigned int minoff;
933 char *start;
934 size_t i;
935 errcode_t err;
936
937 i = EXT2_INODE_SIZE(fs->super);
938 if (i < sizeof(*inode))
939 i = sizeof(*inode);
940 err = ext2fs_get_memzero(i, &inode);
941 if (err)
942 return err;
943
944 err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)inode,
945 EXT2_INODE_SIZE(fs->super));
946 if (err)
947 goto out;
948
949 /* Does the inode have size for EA? */
950 if (EXT2_INODE_SIZE(fs->super) <= EXT2_GOOD_OLD_INODE_SIZE +
951 inode->i_extra_isize +
952 sizeof(__u32)) {
953 err = EXT2_ET_INLINE_DATA_NO_SPACE;
954 goto out;
955 }
956
957 minoff = EXT2_INODE_SIZE(fs->super) - sizeof(*inode) - sizeof(__u32);
958 memcpy(&ea_inode_magic, ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
959 inode->i_extra_isize, sizeof(__u32));
960 if (ea_inode_magic == EXT2_EXT_ATTR_MAGIC) {
961 /* has xattrs. calculate the size */
962 start= ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
963 inode->i_extra_isize + sizeof(__u32);
964 entry = (struct ext2_ext_attr_entry *) start;
965 while (!EXT2_EXT_IS_LAST_ENTRY(entry)) {
966 if (!entry->e_value_block && entry->e_value_size) {
967 unsigned int offs = entry->e_value_offs;
968 if (offs < minoff)
969 minoff = offs;
970 }
971 entry = EXT2_EXT_ATTR_NEXT(entry);
972 }
973 *size = minoff - ((char *)entry - (char *)start) - sizeof(__u32);
974 } else {
975 /* no xattr. return a maximum size */
976 *size = EXT2_EXT_ATTR_SIZE(minoff -
977 EXT2_EXT_ATTR_LEN(strlen("data")) -
978 EXT2_EXT_ATTR_ROUND - sizeof(__u32));
979 }
980
981 out:
982 ext2fs_free_mem(&inode);
983 return err;
984 }
985
986 errcode_t ext2fs_xattr_set(struct ext2_xattr_handle *handle,
987 const char *key,
988 const void *value,
989 size_t value_len)
990 {
991 struct ext2_xattr *x, *last_empty;
992 char *new_value;
993 errcode_t err;
994
995 EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EA_HANDLE);
996 last_empty = NULL;
997 for (x = handle->attrs; x < handle->attrs + handle->length; x++) {
998 if (!x->name) {
999 last_empty = x;
1000 continue;
1001 }
1002
1003 /* Replace xattr */
1004 if (strcmp(x->name, key) == 0) {
1005 err = ext2fs_get_mem(value_len, &new_value);
1006 if (err)
1007 return err;
1008 memcpy(new_value, value, value_len);
1009 ext2fs_free_mem(&x->value);
1010 x->value = new_value;
1011 x->value_len = value_len;
1012 handle->dirty = 1;
1013 return 0;
1014 }
1015 }
1016
1017 /* Add attr to empty slot */
1018 if (last_empty) {
1019 err = ext2fs_get_mem(strlen(key) + 1, &last_empty->name);
1020 if (err)
1021 return err;
1022 strcpy(last_empty->name, key);
1023
1024 err = ext2fs_get_mem(value_len, &last_empty->value);
1025 if (err)
1026 return err;
1027 memcpy(last_empty->value, value, value_len);
1028 last_empty->value_len = value_len;
1029 handle->dirty = 1;
1030 handle->count++;
1031 return 0;
1032 }
1033
1034 /* Expand array, append slot */
1035 err = ext2fs_xattrs_expand(handle, 4);
1036 if (err)
1037 return err;
1038
1039 x = handle->attrs + handle->length - 4;
1040 err = ext2fs_get_mem(strlen(key) + 1, &x->name);
1041 if (err)
1042 return err;
1043 strcpy(x->name, key);
1044
1045 err = ext2fs_get_mem(value_len, &x->value);
1046 if (err)
1047 return err;
1048 memcpy(x->value, value, value_len);
1049 x->value_len = value_len;
1050 handle->dirty = 1;
1051 handle->count++;
1052 return 0;
1053 }
1054
1055 errcode_t ext2fs_xattr_remove(struct ext2_xattr_handle *handle,
1056 const char *key)
1057 {
1058 struct ext2_xattr *x;
1059
1060 EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EA_HANDLE);
1061 for (x = handle->attrs; x < handle->attrs + handle->length; x++) {
1062 if (!x->name)
1063 continue;
1064
1065 if (strcmp(x->name, key) == 0) {
1066 ext2fs_free_mem(&x->name);
1067 ext2fs_free_mem(&x->value);
1068 x->value_len = 0;
1069 handle->dirty = 1;
1070 handle->count--;
1071 return 0;
1072 }
1073 }
1074
1075 /* no key found, success! */
1076 return 0;
1077 }
1078
1079 errcode_t ext2fs_xattrs_open(ext2_filsys fs, ext2_ino_t ino,
1080 struct ext2_xattr_handle **handle)
1081 {
1082 struct ext2_xattr_handle *h;
1083 errcode_t err;
1084
1085 if (!ext2fs_has_feature_xattr(fs->super) &&
1086 !ext2fs_has_feature_inline_data(fs->super))
1087 return EXT2_ET_MISSING_EA_FEATURE;
1088
1089 err = ext2fs_get_memzero(sizeof(*h), &h);
1090 if (err)
1091 return err;
1092
1093 h->magic = EXT2_ET_MAGIC_EA_HANDLE;
1094 h->length = 4;
1095 err = ext2fs_get_arrayzero(h->length, sizeof(struct ext2_xattr),
1096 &h->attrs);
1097 if (err) {
1098 ext2fs_free_mem(&h);
1099 return err;
1100 }
1101 h->count = 0;
1102 h->ino = ino;
1103 h->fs = fs;
1104 *handle = h;
1105 return 0;
1106 }
1107
1108 errcode_t ext2fs_xattrs_close(struct ext2_xattr_handle **handle)
1109 {
1110 struct ext2_xattr_handle *h = *handle;
1111 errcode_t err;
1112
1113 EXT2_CHECK_MAGIC(h, EXT2_ET_MAGIC_EA_HANDLE);
1114 if (h->dirty) {
1115 err = ext2fs_xattrs_write(h);
1116 if (err)
1117 return err;
1118 }
1119
1120 xattrs_free_keys(h);
1121 ext2fs_free_mem(&h->attrs);
1122 ext2fs_free_mem(handle);
1123 return 0;
1124 }
1125
1126 errcode_t ext2fs_xattrs_count(struct ext2_xattr_handle *handle, size_t *count)
1127 {
1128 EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EA_HANDLE);
1129 *count = handle->count;
1130 return 0;
1131 }