1 /*
2 * Copyright (c) 2012 Dave Vasilevsky <dave@vasilevsky.ca>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25 #include "xattr.h"
26
27 #include "fs.h"
28 #include "nonstd.h"
29 #include "swap.h"
30
31 #include <string.h>
32 #include <stdlib.h>
33
34
35 #define SQFS_XATTR_PREFIX_MAX SQUASHFS_XATTR_SECURITY
36
37 typedef struct {
38 const char *pref;
39 size_t len;
40 } sqfs_prefix;
41
42 sqfs_prefix sqfs_xattr_prefixes[] = {
43 {"user.", 5},
44 {"security.", 9},
45 {"trusted.", 8},
46 };
47
48
49 typedef enum {
50 CURS_VSIZE = 1,
51 CURS_VAL = 2,
52 CURS_NEXT = 4
53 } sqfs_xattr_curs;
54
sqfs_xattr_init(sqfs * fs)55 sqfs_err sqfs_xattr_init(sqfs *fs) {
56 sqfs_off_t start = fs->sb.xattr_id_table_start;
57 size_t bread;
58 if (start == SQUASHFS_INVALID_BLK)
59 return SQFS_OK;
60
61 bread = sqfs_pread(fs->fd, &fs->xattr_info, sizeof(fs->xattr_info),
62 start + fs->offset);
63 if (bread != sizeof(fs->xattr_info))
64 return SQFS_ERR;
65 sqfs_swapin_xattr_id_table(&fs->xattr_info);
66
67 return sqfs_table_init(&fs->xattr_table, fs->fd,
68 start + sizeof(fs->xattr_info) + fs->offset, sizeof(struct squashfs_xattr_id),
69 fs->xattr_info.xattr_ids);
70 }
71
sqfs_xattr_open(sqfs * fs,sqfs_inode * inode,sqfs_xattr * x)72 sqfs_err sqfs_xattr_open(sqfs *fs, sqfs_inode *inode, sqfs_xattr *x) {
73 sqfs_err err;
74
75 x->remain = 0; /* assume none exist */
76 if (fs->xattr_info.xattr_ids == 0 || inode->xattr == SQUASHFS_INVALID_XATTR)
77 return SQFS_OK;
78
79 err = sqfs_table_get(&fs->xattr_table, fs, inode->xattr,
80 &x->info);
81 if (err)
82 return SQFS_ERR;
83 sqfs_swapin_xattr_id(&x->info);
84
85 sqfs_md_cursor_inode(&x->c_next, x->info.xattr,
86 fs->xattr_info.xattr_table_start);
87
88 x->fs = fs;
89 x->remain = x->info.count;
90 x->cursors = CURS_NEXT;
91 return SQFS_OK;
92 }
93
sqfs_xattr_read(sqfs_xattr * x)94 sqfs_err sqfs_xattr_read(sqfs_xattr *x) {
95 sqfs_err err;
96
97 if (x->remain == 0)
98 return SQFS_ERR;
99
100 if (!(x->cursors & CURS_NEXT)) {
101 x->ool = false; /* force inline */
102 if ((err = sqfs_xattr_value(x, NULL)))
103 return err;
104 }
105
106 x->c_name = x->c_next;
107 if ((err = sqfs_md_read(x->fs, &x->c_name, &x->entry, sizeof(x->entry))))
108 return err;
109 sqfs_swapin_xattr_entry(&x->entry);
110
111 x->type = x->entry.type & SQUASHFS_XATTR_PREFIX_MASK;
112 x->ool = x->entry.type & SQUASHFS_XATTR_VALUE_OOL;
113 if (x->type > SQFS_XATTR_PREFIX_MAX)
114 return SQFS_ERR;
115
116 --(x->remain);
117 x->cursors = 0;
118 return err;
119 }
120
sqfs_xattr_name_size(sqfs_xattr * x)121 size_t sqfs_xattr_name_size(sqfs_xattr *x) {
122 return x->entry.size + sqfs_xattr_prefixes[x->type].len;
123 }
124
sqfs_xattr_name(sqfs_xattr * x,char * name,bool prefix)125 sqfs_err sqfs_xattr_name(sqfs_xattr *x, char *name, bool prefix) {
126 sqfs_err err;
127
128 if (name && prefix) {
129 sqfs_prefix *p = &sqfs_xattr_prefixes[x->type];
130 memcpy(name, p->pref, p->len);
131 name += p->len;
132 }
133
134 x->c_vsize = x->c_name;
135 err = sqfs_md_read(x->fs, &x->c_vsize, name, x->entry.size);
136 if (err)
137 return err;
138
139 x->cursors |= CURS_VSIZE;
140 return err;
141 }
142
sqfs_xattr_value_size(sqfs_xattr * x,size_t * size)143 sqfs_err sqfs_xattr_value_size(sqfs_xattr *x, size_t *size) {
144 sqfs_err err;
145 if (!(x->cursors & CURS_VSIZE))
146 if ((err = sqfs_xattr_name(x, NULL, false)))
147 return err;
148
149 x->c_val = x->c_vsize;
150 if ((err = sqfs_md_read(x->fs, &x->c_val, &x->val, sizeof(x->val))))
151 return err;
152 sqfs_swapin_xattr_val(&x->val);
153
154 if (x->ool) {
155 uint64_t pos;
156 x->c_next = x->c_val;
157 if ((err = sqfs_md_read(x->fs, &x->c_next, &pos, sizeof(pos))))
158 return err;
159 sqfs_swapin64(&pos);
160 x->cursors |= CURS_NEXT;
161
162 sqfs_md_cursor_inode(&x->c_val, pos,
163 x->fs->xattr_info.xattr_table_start);
164 if ((err = sqfs_md_read(x->fs, &x->c_val, &x->val, sizeof(x->val))))
165 return err;
166 sqfs_swapin_xattr_val(&x->val);
167 }
168
169 if (size)
170 *size = x->val.vsize;
171 x->cursors |= CURS_VAL;
172 return err;
173 }
174
sqfs_xattr_value(sqfs_xattr * x,void * buf)175 sqfs_err sqfs_xattr_value(sqfs_xattr *x, void *buf) {
176 sqfs_err err;
177 sqfs_md_cursor c;
178
179 if (!(x->cursors & CURS_VAL))
180 if ((err = sqfs_xattr_value_size(x, NULL)))
181 return err;
182
183 c = x->c_val;
184 if ((err = sqfs_md_read(x->fs, &c, buf, x->val.vsize)))
185 return err;
186
187 if (!x->ool) {
188 x->c_next = c;
189 x->cursors |= CURS_NEXT;
190 }
191 return err;
192 }
193
sqfs_xattr_find_prefix(const char * name,uint16_t * type)194 static sqfs_err sqfs_xattr_find_prefix(const char *name, uint16_t *type) {
195 int i;
196 for (i = 0; i <= SQFS_XATTR_PREFIX_MAX; ++i) {
197 sqfs_prefix *p = &sqfs_xattr_prefixes[i];
198 if (strncmp(name, p->pref, p->len) == 0) {
199 *type = i;
200 return SQFS_OK;
201 }
202 }
203 return SQFS_ERR;
204 }
205
206 /* FIXME: Indicate EINVAL, ENOMEM? */
sqfs_xattr_find(sqfs_xattr * x,const char * name,bool * found)207 sqfs_err sqfs_xattr_find(sqfs_xattr *x, const char *name, bool *found) {
208 sqfs_err err;
209 char *cmp = NULL;
210 uint16_t type;
211 size_t len;
212
213 if ((err = sqfs_xattr_find_prefix(name, &type))) {
214 /* Consider an invalid prefix to just be not found, or OS X
215 * Finder complains. */
216 *found = false;
217 return SQFS_OK;
218 }
219
220 name += sqfs_xattr_prefixes[type].len;
221 len = strlen(name);
222 if (!(cmp = malloc(len)))
223 return SQFS_ERR;
224
225 while (x->remain) {
226 if ((err = sqfs_xattr_read(x)))
227 goto done;
228 if (x->type != type && x->entry.size != len)
229 continue;
230 if ((err = sqfs_xattr_name(x, cmp, false)))
231 goto done;
232 if (strncmp(name, cmp, len) == 0) {
233 *found = true;
234 goto done;
235 }
236 }
237
238 *found = false;
239
240 done:
241 free(cmp);
242 return err;
243 }
244
sqfs_xattr_lookup(sqfs * fs,sqfs_inode * inode,const char * name,void * buf,size_t * size)245 sqfs_err sqfs_xattr_lookup(sqfs *fs, sqfs_inode *inode, const char *name,
246 void *buf, size_t *size) {
247 sqfs_err err = SQFS_OK;
248
249 sqfs_xattr xattr;
250 if ((err = sqfs_xattr_open(fs, inode, &xattr)))
251 return err;
252
253 bool found = false;
254 if ((err = sqfs_xattr_find(&xattr, name, &found)))
255 return err;
256 if (!found) {
257 *size = 0;
258 return err;
259 }
260
261 size_t real;
262 if ((err = sqfs_xattr_value_size(&xattr, &real)))
263 return err;
264
265 if (buf && *size >= real) {
266 if ((err = sqfs_xattr_value(&xattr, buf)))
267 return err;
268 }
269
270 *size = real;
271 return err;
272 }
273
274