]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - SQUASHFS/squashfs-tools-4.4/squashfs-tools/read_xattrs.c
1.1.07 release
[Ventoy.git] / SQUASHFS / squashfs-tools-4.4 / squashfs-tools / read_xattrs.c
1 /*
2 * Read a squashfs filesystem. This is a highly compressed read only
3 * filesystem.
4 *
5 * Copyright (c) 2010, 2012, 2013, 2019
6 * Phillip Lougher <phillip@squashfs.org.uk>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2,
11 * or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 *
22 * read_xattrs.c
23 */
24
25 /*
26 * Common xattr read code shared between mksquashfs and unsquashfs
27 */
28
29 #define TRUE 1
30 #define FALSE 0
31 #include <stdio.h>
32 #include <string.h>
33
34 #ifndef linux
35 #define __BYTE_ORDER BYTE_ORDER
36 #define __BIG_ENDIAN BIG_ENDIAN
37 #define __LITTLE_ENDIAN LITTLE_ENDIAN
38 #else
39 #include <endian.h>
40 #endif
41
42 #include "squashfs_fs.h"
43 #include "squashfs_swap.h"
44 #include "xattr.h"
45 #include "error.h"
46
47 #include <stdlib.h>
48
49 extern int read_fs_bytes(int, long long, int, void *);
50 extern int read_block(int, long long, long long *, int, void *);
51
52 static struct hash_entry {
53 long long start;
54 unsigned int offset;
55 struct hash_entry *next;
56 } *hash_table[65536];
57
58 static struct squashfs_xattr_id *xattr_ids;
59 static void *xattrs = NULL;
60 static long long xattr_table_start;
61
62 /*
63 * Prefix lookup table, storing mapping to/from prefix string and prefix id
64 */
65 struct prefix prefix_table[] = {
66 { "user.", SQUASHFS_XATTR_USER },
67 { "trusted.", SQUASHFS_XATTR_TRUSTED },
68 { "security.", SQUASHFS_XATTR_SECURITY },
69 { "", -1 }
70 };
71
72 /*
73 * store mapping from location of compressed block in fs ->
74 * location of uncompressed block in memory
75 */
76 static void save_xattr_block(long long start, int offset)
77 {
78 struct hash_entry *hash_entry = malloc(sizeof(*hash_entry));
79 int hash = start & 0xffff;
80
81 TRACE("save_xattr_block: start %lld, offset %d\n", start, offset);
82
83 if(hash_entry == NULL)
84 MEM_ERROR();
85
86 hash_entry->start = start;
87 hash_entry->offset = offset;
88 hash_entry->next = hash_table[hash];
89 hash_table[hash] = hash_entry;
90 }
91
92
93 /*
94 * map from location of compressed block in fs ->
95 * location of uncompressed block in memory
96 */
97 static int get_xattr_block(long long start)
98 {
99 int hash = start & 0xffff;
100 struct hash_entry *hash_entry = hash_table[hash];
101
102 for(; hash_entry; hash_entry = hash_entry->next)
103 if(hash_entry->start == start)
104 break;
105
106 TRACE("get_xattr_block: start %lld, offset %d\n", start,
107 hash_entry ? hash_entry->offset : -1);
108
109 return hash_entry ? hash_entry->offset : -1;
110 }
111
112
113 /*
114 * construct the xattr_list entry from the fs xattr, including
115 * mapping name and prefix into a full name
116 */
117 static int read_xattr_entry(struct xattr_list *xattr,
118 struct squashfs_xattr_entry *entry, void *name)
119 {
120 int i, len, type = entry->type & XATTR_PREFIX_MASK;
121
122 for(i = 0; prefix_table[i].type != -1; i++)
123 if(prefix_table[i].type == type)
124 break;
125
126 if(prefix_table[i].type == -1) {
127 ERROR("read_xattr_entry: Unrecognised xattr type %d\n", type);
128 return 0;
129 }
130
131 len = strlen(prefix_table[i].prefix);
132 xattr->full_name = malloc(len + entry->size + 1);
133 if(xattr->full_name == NULL)
134 MEM_ERROR();
135
136 memcpy(xattr->full_name, prefix_table[i].prefix, len);
137 memcpy(xattr->full_name + len, name, entry->size);
138 xattr->full_name[len + entry->size] = '\0';
139 xattr->name = xattr->full_name + len;
140 xattr->size = entry->size;
141 xattr->type = type;
142
143 return 1;
144 }
145
146
147 /*
148 * Read and decompress the xattr id table and the xattr metadata.
149 * This is cached in memory for later use by get_xattr()
150 */
151 int read_xattrs_from_disk(int fd, struct squashfs_super_block *sBlk, int flag, long long *table_start)
152 {
153 /*
154 * Note on overflow limits:
155 * Size of ids (id_table.xattr_ids) is 2^32 (unsigned int)
156 * Max size of bytes is 2^32*16 or 2^36
157 * Max indexes is (2^32*16)/8K or 2^23
158 * Max index_bytes is ((2^32*16)/8K)*8 or 2^26 or 64M
159 */
160 int res, i, indexes, index_bytes;
161 unsigned int ids;
162 long long bytes;
163 long long *index, start, end;
164 struct squashfs_xattr_table id_table;
165
166 TRACE("read_xattrs_from_disk\n");
167
168 if(sBlk->xattr_id_table_start == SQUASHFS_INVALID_BLK)
169 return SQUASHFS_INVALID_BLK;
170
171 /*
172 * Read xattr id table, containing start of xattr metadata and the
173 * number of xattrs in the file system
174 */
175 res = read_fs_bytes(fd, sBlk->xattr_id_table_start, sizeof(id_table),
176 &id_table);
177 if(res == 0)
178 return 0;
179
180 SQUASHFS_INSWAP_XATTR_TABLE(&id_table);
181
182 /*
183 * Compute index table values
184 */
185 ids = id_table.xattr_ids;
186 xattr_table_start = id_table.xattr_table_start;
187 index_bytes = SQUASHFS_XATTR_BLOCK_BYTES((long long) ids);
188 indexes = SQUASHFS_XATTR_BLOCKS((long long) ids);
189
190 /*
191 * The size of the index table (index_bytes) should match the
192 * table start and end points
193 */
194 if(index_bytes != (sBlk->bytes_used - (sBlk->xattr_id_table_start + sizeof(id_table)))) {
195 ERROR("read_xattrs_from_disk: Bad xattr_ids count in super block\n");
196 return 0;
197 }
198
199 /*
200 * id_table.xattr_table_start stores the start of the compressed xattr
201 * metadata blocks. This by definition is also the end of the previous
202 * filesystem table - the id lookup table.
203 */
204 if(table_start != NULL)
205 *table_start = id_table.xattr_table_start;
206
207 /*
208 * If flag is set then return once we've read the above
209 * table_start. That value is necessary for sanity checking,
210 * but we don't actually want to extract the xattrs, and so
211 * stop here.
212 */
213 if(flag)
214 return id_table.xattr_ids;
215
216 /*
217 * Allocate and read the index to the xattr id table metadata
218 * blocks
219 */
220 index = malloc(index_bytes);
221 if(index == NULL)
222 MEM_ERROR();
223
224 res = read_fs_bytes(fd, sBlk->xattr_id_table_start + sizeof(id_table),
225 index_bytes, index);
226 if(res ==0)
227 goto failed1;
228
229 SQUASHFS_INSWAP_LONG_LONGS(index, indexes);
230
231 /*
232 * Allocate enough space for the uncompressed xattr id table, and
233 * read and decompress it
234 */
235 bytes = SQUASHFS_XATTR_BYTES((long long) ids);
236 xattr_ids = malloc(bytes);
237 if(xattr_ids == NULL)
238 MEM_ERROR();
239
240 for(i = 0; i < indexes; i++) {
241 int expected = (i + 1) != indexes ? SQUASHFS_METADATA_SIZE :
242 bytes & (SQUASHFS_METADATA_SIZE - 1);
243 int length = read_block(fd, index[i], NULL, expected,
244 ((unsigned char *) xattr_ids) +
245 ((long long) i * SQUASHFS_METADATA_SIZE));
246 TRACE("Read xattr id table block %d, from 0x%llx, length "
247 "%d\n", i, index[i], length);
248 if(length == 0) {
249 ERROR("Failed to read xattr id table block %d, "
250 "from 0x%llx, length %d\n", i, index[i],
251 length);
252 goto failed2;
253 }
254 }
255
256 /*
257 * Read and decompress the xattr metadata
258 *
259 * Note the first xattr id table metadata block is immediately after
260 * the last xattr metadata block, so we can use index[0] to work out
261 * the end of the xattr metadata
262 */
263 start = xattr_table_start;
264 end = index[0];
265 for(i = 0; start < end; i++) {
266 int length;
267 xattrs = realloc(xattrs, (i + 1) * SQUASHFS_METADATA_SIZE);
268 if(xattrs == NULL)
269 MEM_ERROR();
270
271 /* store mapping from location of compressed block in fs ->
272 * location of uncompressed block in memory */
273 save_xattr_block(start, i * SQUASHFS_METADATA_SIZE);
274
275 length = read_block(fd, start, &start, 0,
276 ((unsigned char *) xattrs) +
277 (i * SQUASHFS_METADATA_SIZE));
278 TRACE("Read xattr block %d, length %d\n", i, length);
279 if(length == 0) {
280 ERROR("Failed to read xattr block %d\n", i);
281 goto failed3;
282 }
283
284 /*
285 * If this is not the last metadata block in the xattr metadata
286 * then it should be SQUASHFS_METADATA_SIZE in size.
287 * Note, we can't use expected in read_block() above for this
288 * because we don't know if this is the last block until
289 * after reading.
290 */
291 if(start != end && length != SQUASHFS_METADATA_SIZE) {
292 ERROR("Xattr block %d should be %d bytes in length, "
293 "it is %d bytes\n", i, SQUASHFS_METADATA_SIZE,
294 length);
295 goto failed3;
296 }
297 }
298
299 /* swap if necessary the xattr id entries */
300 for(i = 0; i < ids; i++)
301 SQUASHFS_INSWAP_XATTR_ID(&xattr_ids[i]);
302
303 free(index);
304
305 return ids;
306
307 failed3:
308 free(xattrs);
309 failed2:
310 free(xattr_ids);
311 failed1:
312 free(index);
313
314 return 0;
315 }
316
317
318 void free_xattr(struct xattr_list *xattr_list, int count)
319 {
320 int i;
321
322 for(i = 0; i < count; i++)
323 free(xattr_list[i].full_name);
324
325 free(xattr_list);
326 }
327
328
329 /*
330 * Construct and return the list of xattr name:value pairs for the passed xattr
331 * id
332 *
333 * There are two users for get_xattr(), Mksquashfs uses it to read the
334 * xattrs from the filesystem on appending, and Unsquashfs uses it
335 * to retrieve the xattrs for writing to disk.
336 *
337 * Unfortunately, the two users disagree on what to do with unknown
338 * xattr prefixes, Mksquashfs wants to treat this as fatal otherwise
339 * this will cause xattrs to be be lost on appending. Unsquashfs
340 * on the otherhand wants to retrieve the xattrs which are known and
341 * to ignore the rest, this allows Unsquashfs to cope more gracefully
342 * with future versions which may have unknown xattrs, as long as the
343 * general xattr structure is adhered to, Unsquashfs should be able
344 * to safely ignore unknown xattrs, and to write the ones it knows about,
345 * this is better than completely refusing to retrieve all the xattrs.
346 *
347 * So return an error flag if any unrecognised types were found.
348 */
349 struct xattr_list *get_xattr(int i, unsigned int *count, int *failed)
350 {
351 long long start;
352 struct xattr_list *xattr_list = NULL;
353 unsigned int offset;
354 void *xptr;
355 int j, n, res = 1;
356
357 TRACE("get_xattr\n");
358
359 if(xattr_ids[i].count == 0) {
360 ERROR("get_xattr: xattr count unexpectedly 0 - corrupt fs?\n");
361 *failed = TRUE;
362 *count = 0;
363 return NULL;
364 } else
365 *failed = FALSE;
366
367 start = SQUASHFS_XATTR_BLK(xattr_ids[i].xattr) + xattr_table_start;
368 offset = SQUASHFS_XATTR_OFFSET(xattr_ids[i].xattr);
369 xptr = xattrs + get_xattr_block(start) + offset;
370
371 TRACE("get_xattr: xattr_id %d, count %d, start %lld, offset %d\n", i,
372 xattr_ids[i].count, start, offset);
373
374 for(j = 0, n = 0; n < xattr_ids[i].count; n++) {
375 struct squashfs_xattr_entry entry;
376 struct squashfs_xattr_val val;
377
378 if(res != 0) {
379 xattr_list = realloc(xattr_list, (j + 1) *
380 sizeof(struct xattr_list));
381 if(xattr_list == NULL)
382 MEM_ERROR();
383 }
384
385 SQUASHFS_SWAP_XATTR_ENTRY(xptr, &entry);
386 xptr += sizeof(entry);
387
388 res = read_xattr_entry(&xattr_list[j], &entry, xptr);
389 if(res == 0) {
390 /* unknown type, skip, and set error flag */
391 xptr += entry.size;
392 SQUASHFS_SWAP_XATTR_VAL(xptr, &val);
393 xptr += sizeof(val) + val.vsize;
394 *failed = TRUE;
395 continue;
396 }
397
398 xptr += entry.size;
399
400 TRACE("get_xattr: xattr %d, type %d, size %d, name %s\n", j,
401 entry.type, entry.size, xattr_list[j].full_name);
402
403 if(entry.type & SQUASHFS_XATTR_VALUE_OOL) {
404 long long xattr;
405 void *ool_xptr;
406
407 xptr += sizeof(val);
408 SQUASHFS_SWAP_LONG_LONGS(xptr, &xattr, 1);
409 xptr += sizeof(xattr);
410 start = SQUASHFS_XATTR_BLK(xattr) + xattr_table_start;
411 offset = SQUASHFS_XATTR_OFFSET(xattr);
412 ool_xptr = xattrs + get_xattr_block(start) + offset;
413 SQUASHFS_SWAP_XATTR_VAL(ool_xptr, &val);
414 xattr_list[j].value = ool_xptr + sizeof(val);
415 } else {
416 SQUASHFS_SWAP_XATTR_VAL(xptr, &val);
417 xattr_list[j].value = xptr + sizeof(val);
418 xptr += sizeof(val) + val.vsize;
419 }
420
421 TRACE("get_xattr: xattr %d, vsize %d\n", j, val.vsize);
422
423 xattr_list[j++].vsize = val.vsize;
424 }
425
426 *count = j;
427 return xattr_list;
428 }