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