Whamcloud - gitweb
Overhaul extended attribute handling. Should now be correct with
[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 Public
10  * License.
11  * %End-Header%
12  */
13
14 #include <stdio.h>
15 #if HAVE_UNISTD_H
16 #include <unistd.h>
17 #endif
18 #include <string.h>
19 #include <time.h>
20
21 #include "ext2_fs.h"
22 #include "ext2_ext_attr.h"
23
24 #include "ext2fs.h"
25
26 #ifdef EXT2FS_ENABLE_SWAPFS
27 void ext2fs_swap_ext_attr(ext2_filsys fs, char *to, char *from)
28 {
29         struct ext2_ext_attr_header *from_header =
30                 (struct ext2_ext_attr_header *)from;
31         struct ext2_ext_attr_header *to_header =
32                 (struct ext2_ext_attr_header *)to;
33         struct ext2_ext_attr_entry *from_entry, *to_entry;
34         char *from_end = (char *)from_header + fs->blocksize;
35         int n;
36
37         if (to_header != from_header)
38                 memcpy(to_header, from_header, fs->blocksize);
39
40         to_header->h_magic    = ext2fs_swab32(from_header->h_magic);
41         to_header->h_blocks   = ext2fs_swab32(from_header->h_blocks);
42         to_header->h_refcount = ext2fs_swab32(from_header->h_refcount);
43         for (n=0; n<4; n++)
44                 to_header->h_reserved[n] =
45                         ext2fs_swab32(from_header->h_reserved[n]);
46         
47         from_entry = (struct ext2_ext_attr_entry *)(from_header+1);
48         to_entry   = (struct ext2_ext_attr_entry *)(to_header+1);
49         while ((char *)from_entry < from_end && *(__u32 *)from_entry) {
50                 to_entry->e_value_offs  =       
51                         ext2fs_swab16(from_entry->e_value_offs);
52                 to_entry->e_value_block =       
53                         ext2fs_swab32(from_entry->e_value_block);
54                 to_entry->e_value_size  =       
55                         ext2fs_swab32(from_entry->e_value_size);
56                 from_entry = EXT2_EXT_ATTR_NEXT(from_entry);
57                 to_entry   = EXT2_EXT_ATTR_NEXT(to_entry);
58         }
59 }
60 #endif
61
62 errcode_t ext2fs_read_ext_attr(ext2_filsys fs, blk_t block, void *buf)
63 {
64         errcode_t       retval;
65
66         retval = io_channel_read_blk(fs->io, block, 1, buf);
67         if (retval)
68                 return retval;
69 #ifdef EXT2FS_ENABLE_SWAPFS
70         if ((fs->flags & (EXT2_FLAG_SWAP_BYTES|
71                           EXT2_FLAG_SWAP_BYTES_READ)) != 0)
72                 ext2fs_swap_ext_attr(fs, buf, buf);
73 #endif
74         return 0;
75 }
76
77 errcode_t ext2fs_write_ext_attr(ext2_filsys fs, blk_t block, void *inbuf)
78 {
79         errcode_t       retval;
80         char            *write_buf;
81         char            *buf = NULL;
82
83 #ifdef EXT2FS_ENABLE_SWAPFS
84         if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
85             (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)) {
86                 retval = ext2fs_get_mem(fs->blocksize, (void **) &buf);
87                 if (retval)
88                         return retval;
89                 write_buf = buf;
90                 ext2fs_swap_ext_attr(fs, buf, inbuf);
91         } else
92 #endif
93                 write_buf = (char *) inbuf;
94         retval = io_channel_write_blk(fs->io, block, 1, write_buf);
95         if (buf)
96                 ext2fs_free_mem((void **) &buf);
97         if (!retval)
98                 ext2fs_mark_changed(fs);
99         return retval;
100 }
101
102 /*
103  * This function adjusts the reference count of the EA block.
104  */
105 errcode_t ext2fs_adjust_ea_refcount(ext2_filsys fs, blk_t blk,
106                                     char *block_buf, int adjust,
107                                     __u32 *newcount)
108 {
109         errcode_t       retval;
110         struct ext2_ext_attr_header *header;
111         char    *buf = 0;
112
113         if ((blk >= fs->super->s_blocks_count) ||
114             (blk < fs->super->s_first_data_block))
115                 return EXT2_ET_BAD_EA_BLOCK_NUM;
116
117         if (!block_buf) {
118                 retval = ext2fs_get_mem(fs->blocksize, (void **) &buf);
119                 if (retval)
120                         return retval;
121                 block_buf = buf;
122         }
123
124         retval = ext2fs_read_ext_attr(fs, blk, block_buf);
125         if (retval)
126                 goto errout;
127
128         header = (struct ext2_ext_attr_header *) block_buf;
129         header->h_refcount += adjust;
130         if (newcount)
131                 *newcount = header->h_refcount;
132
133         retval = ext2fs_write_ext_attr(fs, blk, block_buf);
134         if (retval)
135                 goto errout;
136
137 errout:
138         if (buf)
139                 ext2fs_free_mem((void **) &buf);
140         return retval;
141 }