]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - SQUASHFS/squashfs-tools-4.4/squashfs-tools/xattr.c
keep up with 1.0.67 (#1464)
[Ventoy.git] / SQUASHFS / squashfs-tools-4.4 / squashfs-tools / xattr.c
1 /*
2 * Create a squashfs filesystem. This is a highly compressed read only
3 * filesystem.
4 *
5 * Copyright (c) 2008, 2009, 2010, 2012, 2014, 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 * xattr.c
23 */
24
25 #define TRUE 1
26 #define FALSE 0
27
28 #include <unistd.h>
29 #include <stdio.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <fcntl.h>
33 #include <errno.h>
34 #include <dirent.h>
35 #include <string.h>
36 #include <stdlib.h>
37 #include <sys/xattr.h>
38
39 #include "squashfs_fs.h"
40 #include "squashfs_swap.h"
41 #include "mksquashfs.h"
42 #include "xattr.h"
43 #include "error.h"
44 #include "progressbar.h"
45
46 /* compressed xattr table */
47 static char *xattr_table = NULL;
48 static unsigned int xattr_size = 0;
49
50 /* cached uncompressed xattr data */
51 static char *data_cache = NULL;
52 static int cache_bytes = 0, cache_size = 0;
53
54 /* cached uncompressed xattr id table */
55 static struct squashfs_xattr_id *xattr_id_table = NULL;
56 static int xattr_ids = 0;
57
58 /* saved compressed xattr table */
59 unsigned int sxattr_bytes = 0, stotal_xattr_bytes = 0;
60
61 /* saved cached uncompressed xattr data */
62 static char *sdata_cache = NULL;
63 static int scache_bytes = 0;
64
65 /* saved cached uncompressed xattr id table */
66 static int sxattr_ids = 0;
67
68 /* xattr hash table for value duplicate detection */
69 static struct xattr_list *dupl_value[65536];
70
71 /* xattr hash table for id duplicate detection */
72 static struct dupl_id *dupl_id[65536];
73
74 /* file system globals from mksquashfs.c */
75 extern int no_xattrs, noX;
76 extern long long bytes;
77 extern int fd;
78 extern unsigned int xattr_bytes, total_xattr_bytes;
79
80 /* helper functions from mksquashfs.c */
81 extern unsigned short get_checksum(char *, int, unsigned short);
82 extern void write_destination(int, long long, int, void *);
83 extern long long generic_write_table(int, void *, int, void *, int);
84 extern int mangle(char *, char *, int, int, int, int);
85 extern char *pathname(struct dir_ent *);
86
87 /* helper functions and definitions from read_xattrs.c */
88 extern int read_xattrs_from_disk(int, struct squashfs_super_block *, int, long long *);
89 extern struct xattr_list *get_xattr(int, unsigned int *, int *);
90 extern struct prefix prefix_table[];
91
92
93 static int get_prefix(struct xattr_list *xattr, char *name)
94 {
95 int i;
96
97 xattr->full_name = strdup(name);
98
99 for(i = 0; prefix_table[i].type != -1; i++) {
100 struct prefix *p = &prefix_table[i];
101 if(strncmp(xattr->full_name, p->prefix, strlen(p->prefix)) == 0)
102 break;
103 }
104
105 if(prefix_table[i].type != -1) {
106 xattr->name = xattr->full_name + strlen(prefix_table[i].prefix);
107 xattr->size = strlen(xattr->name);
108 }
109
110 return prefix_table[i].type;
111 }
112
113
114 static int read_xattrs_from_system(char *filename, struct xattr_list **xattrs)
115 {
116 ssize_t size, vsize;
117 char *xattr_names, *p;
118 int i;
119 struct xattr_list *xattr_list = NULL;
120
121 while(1) {
122 size = llistxattr(filename, NULL, 0);
123 if(size <= 0) {
124 if(size < 0 && errno != ENOTSUP) {
125 ERROR_START("llistxattr for %s failed in "
126 "read_attrs, because %s", filename,
127 strerror(errno));
128 ERROR_EXIT(". Ignoring");
129 }
130 return 0;
131 }
132
133 xattr_names = malloc(size);
134 if(xattr_names == NULL)
135 MEM_ERROR();
136
137 size = llistxattr(filename, xattr_names, size);
138 if(size < 0) {
139 free(xattr_names);
140 if(errno == ERANGE)
141 /* xattr list grew? Try again */
142 continue;
143 else {
144 ERROR_START("llistxattr for %s failed in "
145 "read_attrs, because %s", filename,
146 strerror(errno));
147 ERROR_EXIT(". Ignoring");
148 return 0;
149 }
150 }
151
152 break;
153 }
154
155 for(i = 0, p = xattr_names; p < xattr_names + size; i++) {
156 struct xattr_list *x = realloc(xattr_list, (i + 1) *
157 sizeof(struct xattr_list));
158 if(x == NULL)
159 MEM_ERROR();
160 xattr_list = x;
161
162 xattr_list[i].type = get_prefix(&xattr_list[i], p);
163 p += strlen(p) + 1;
164 if(xattr_list[i].type == -1) {
165 ERROR("Unrecognised xattr prefix %s\n",
166 xattr_list[i].full_name);
167 free(xattr_list[i].full_name);
168 i--;
169 continue;
170 }
171
172 while(1) {
173 vsize = lgetxattr(filename, xattr_list[i].full_name,
174 NULL, 0);
175 if(vsize < 0) {
176 ERROR_START("lgetxattr failed for %s in "
177 "read_attrs, because %s", filename,
178 strerror(errno));
179 ERROR_EXIT(". Ignoring");
180 free(xattr_list[i].full_name);
181 goto failed;
182 }
183
184 xattr_list[i].value = malloc(vsize);
185 if(xattr_list[i].value == NULL)
186 MEM_ERROR();
187
188 vsize = lgetxattr(filename, xattr_list[i].full_name,
189 xattr_list[i].value, vsize);
190 if(vsize < 0) {
191 free(xattr_list[i].value);
192 if(errno == ERANGE)
193 /* xattr grew? Try again */
194 continue;
195 else {
196 ERROR_START("lgetxattr failed for %s "
197 "in read_attrs, because %s",
198 filename, strerror(errno));
199 ERROR_EXIT(". Ignoring");
200 free(xattr_list[i].full_name);
201 goto failed;
202 }
203 }
204
205 break;
206 }
207 xattr_list[i].vsize = vsize;
208
209 TRACE("read_xattrs_from_system: filename %s, xattr name %s,"
210 " vsize %d\n", filename, xattr_list[i].full_name,
211 xattr_list[i].vsize);
212 }
213 free(xattr_names);
214 if(i > 0)
215 *xattrs = xattr_list;
216 else
217 free(xattr_list);
218 return i;
219
220 failed:
221 while(--i >= 0) {
222 free(xattr_list[i].full_name);
223 free(xattr_list[i].value);
224 }
225 free(xattr_list);
226 free(xattr_names);
227 return 0;
228 }
229
230
231 static int get_xattr_size(struct xattr_list *xattr)
232 {
233 int size = sizeof(struct squashfs_xattr_entry) +
234 sizeof(struct squashfs_xattr_val) + xattr->size;
235
236 if(xattr->type & XATTR_VALUE_OOL)
237 size += XATTR_VALUE_OOL_SIZE;
238 else
239 size += xattr->vsize;
240
241 return size;
242 }
243
244
245 static void *get_xattr_space(unsigned int req_size, long long *disk)
246 {
247 int data_space;
248 unsigned short c_byte;
249
250 /*
251 * Move and compress cached uncompressed data into xattr table.
252 */
253 while(cache_bytes >= SQUASHFS_METADATA_SIZE) {
254 if((xattr_size - xattr_bytes) <
255 ((SQUASHFS_METADATA_SIZE << 1)) + 2) {
256 xattr_table = realloc(xattr_table, xattr_size +
257 (SQUASHFS_METADATA_SIZE << 1) + 2);
258 if(xattr_table == NULL)
259 MEM_ERROR();
260 xattr_size += (SQUASHFS_METADATA_SIZE << 1) + 2;
261 }
262
263 c_byte = mangle(xattr_table + xattr_bytes + BLOCK_OFFSET,
264 data_cache, SQUASHFS_METADATA_SIZE,
265 SQUASHFS_METADATA_SIZE, noX, 0);
266 TRACE("Xattr block @ 0x%x, size %d\n", xattr_bytes, c_byte);
267 SQUASHFS_SWAP_SHORTS(&c_byte, xattr_table + xattr_bytes, 1);
268 xattr_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + BLOCK_OFFSET;
269 memmove(data_cache, data_cache + SQUASHFS_METADATA_SIZE,
270 cache_bytes - SQUASHFS_METADATA_SIZE);
271 cache_bytes -= SQUASHFS_METADATA_SIZE;
272 }
273
274 /*
275 * Ensure there's enough space in the uncompressed data cache
276 */
277 data_space = cache_size - cache_bytes;
278 if(data_space < req_size) {
279 int realloc_size = req_size - data_space;
280 data_cache = realloc(data_cache, cache_size +
281 realloc_size);
282 if(data_cache == NULL)
283 MEM_ERROR();
284 cache_size += realloc_size;
285 }
286
287 if(disk)
288 *disk = ((long long) xattr_bytes << 16) | cache_bytes;
289 cache_bytes += req_size;
290 return data_cache + cache_bytes - req_size;
291 }
292
293
294 static struct dupl_id *check_id_dupl(struct xattr_list *xattr_list, int xattrs)
295 {
296 struct dupl_id *entry;
297 int i;
298 unsigned short checksum = 0;
299
300 /* compute checksum over all xattrs */
301 for(i = 0; i < xattrs; i++) {
302 struct xattr_list *xattr = &xattr_list[i];
303
304 checksum = get_checksum(xattr->full_name,
305 strlen(xattr->full_name), checksum);
306 checksum = get_checksum(xattr->value,
307 xattr->vsize, checksum);
308 }
309
310 for(entry = dupl_id[checksum]; entry; entry = entry->next) {
311 if (entry->xattrs != xattrs)
312 continue;
313
314 for(i = 0; i < xattrs; i++) {
315 struct xattr_list *xattr = &xattr_list[i];
316 struct xattr_list *dup_xattr = &entry->xattr_list[i];
317
318 if(strcmp(xattr->full_name, dup_xattr->full_name))
319 break;
320
321 if(xattr->vsize != dup_xattr->vsize)
322 break;
323
324 if(memcmp(xattr->value, dup_xattr->value, xattr->vsize))
325 break;
326 }
327
328 if(i == xattrs)
329 break;
330 }
331
332 if(entry == NULL) {
333 /* no duplicate exists */
334 entry = malloc(sizeof(*entry));
335 if(entry == NULL)
336 MEM_ERROR();
337 entry->xattrs = xattrs;
338 entry->xattr_list = xattr_list;
339 entry->xattr_id = SQUASHFS_INVALID_XATTR;
340 entry->next = dupl_id[checksum];
341 dupl_id[checksum] = entry;
342 }
343
344 return entry;
345 }
346
347
348 static void check_value_dupl(struct xattr_list *xattr)
349 {
350 struct xattr_list *entry;
351
352 if(xattr->vsize < XATTR_VALUE_OOL_SIZE)
353 return;
354
355 /* Check if this is a duplicate of an existing value */
356 xattr->vchecksum = get_checksum(xattr->value, xattr->vsize, 0);
357 for(entry = dupl_value[xattr->vchecksum]; entry; entry = entry->vnext) {
358 if(entry->vsize != xattr->vsize)
359 continue;
360
361 if(memcmp(entry->value, xattr->value, xattr->vsize) == 0)
362 break;
363 }
364
365 if(entry == NULL) {
366 /*
367 * No duplicate exists, add to hash table, and mark as
368 * requiring writing
369 */
370 xattr->vnext = dupl_value[xattr->vchecksum];
371 dupl_value[xattr->vchecksum] = xattr;
372 xattr->ool_value = SQUASHFS_INVALID_BLK;
373 } else {
374 /*
375 * Duplicate exists, make type XATTR_VALUE_OOL, and
376 * remember where the duplicate is
377 */
378 xattr->type |= XATTR_VALUE_OOL;
379 xattr->ool_value = entry->ool_value;
380 /* on appending don't free duplicate values because the
381 * duplicate value already points to the non-duplicate value */
382 if(xattr->value != entry->value) {
383 free(xattr->value);
384 xattr->value = entry->value;
385 }
386 }
387 }
388
389
390 static int get_xattr_id(int xattrs, struct xattr_list *xattr_list,
391 long long xattr_disk, struct dupl_id *xattr_dupl)
392 {
393 int i, size = 0;
394 struct squashfs_xattr_id *xattr_id;
395
396 xattr_id_table = realloc(xattr_id_table, (xattr_ids + 1) *
397 sizeof(struct squashfs_xattr_id));
398 if(xattr_id_table == NULL)
399 MEM_ERROR();
400
401 /* get total uncompressed size of xattr data, needed for stat */
402 for(i = 0; i < xattrs; i++)
403 size += strlen(xattr_list[i].full_name) + 1 +
404 xattr_list[i].vsize;
405
406 xattr_id = &xattr_id_table[xattr_ids];
407 xattr_id->xattr = xattr_disk;
408 xattr_id->count = xattrs;
409 xattr_id->size = size;
410
411 /*
412 * keep track of total uncompressed xattr data, needed for mksquashfs
413 * file system summary
414 */
415 total_xattr_bytes += size;
416
417 xattr_dupl->xattr_id = xattr_ids ++;
418 return xattr_dupl->xattr_id;
419 }
420
421
422 long long write_xattrs()
423 {
424 unsigned short c_byte;
425 int i, avail_bytes;
426 char *datap = data_cache;
427 long long start_bytes = bytes;
428 struct squashfs_xattr_table header;
429
430 if(xattr_ids == 0)
431 return SQUASHFS_INVALID_BLK;
432
433 /*
434 * Move and compress cached uncompressed data into xattr table.
435 */
436 while(cache_bytes) {
437 if((xattr_size - xattr_bytes) <
438 ((SQUASHFS_METADATA_SIZE << 1)) + 2) {
439 xattr_table = realloc(xattr_table, xattr_size +
440 (SQUASHFS_METADATA_SIZE << 1) + 2);
441 if(xattr_table == NULL)
442 MEM_ERROR();
443 xattr_size += (SQUASHFS_METADATA_SIZE << 1) + 2;
444 }
445
446 avail_bytes = cache_bytes > SQUASHFS_METADATA_SIZE ?
447 SQUASHFS_METADATA_SIZE : cache_bytes;
448 c_byte = mangle(xattr_table + xattr_bytes + BLOCK_OFFSET, datap,
449 avail_bytes, SQUASHFS_METADATA_SIZE, noX, 0);
450 TRACE("Xattr block @ 0x%x, size %d\n", xattr_bytes, c_byte);
451 SQUASHFS_SWAP_SHORTS(&c_byte, xattr_table + xattr_bytes, 1);
452 xattr_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + BLOCK_OFFSET;
453 datap += avail_bytes;
454 cache_bytes -= avail_bytes;
455 }
456
457 /*
458 * Write compressed xattr table to file system
459 */
460 write_destination(fd, bytes, xattr_bytes, xattr_table);
461 bytes += xattr_bytes;
462
463 /*
464 * Swap if necessary the xattr id table
465 */
466 for(i = 0; i < xattr_ids; i++)
467 SQUASHFS_INSWAP_XATTR_ID(&xattr_id_table[i]);
468
469 header.xattr_ids = xattr_ids;
470 header.xattr_table_start = start_bytes;
471 SQUASHFS_INSWAP_XATTR_TABLE(&header);
472
473 return generic_write_table(xattr_ids * sizeof(struct squashfs_xattr_id),
474 xattr_id_table, sizeof(header), &header, noX);
475 }
476
477
478 int generate_xattrs(int xattrs, struct xattr_list *xattr_list)
479 {
480 int total_size, i;
481 int xattr_value_max;
482 void *xp;
483 long long xattr_disk;
484 struct dupl_id *xattr_dupl;
485
486 /*
487 * check if the file xattrs are a complete duplicate of a pre-existing
488 * id
489 */
490 xattr_dupl = check_id_dupl(xattr_list, xattrs);
491 if(xattr_dupl->xattr_id != SQUASHFS_INVALID_XATTR)
492 return xattr_dupl->xattr_id;
493
494 /*
495 * Scan the xattr_list deciding which type to assign to each
496 * xattr. The choice is fairly straightforward, and depends on the
497 * size of each xattr name/value and the overall size of the
498 * resultant xattr list stored in the xattr metadata table.
499 *
500 * Choices are whether to store data inline or out of line.
501 *
502 * The overall goal is to optimise xattr scanning and lookup, and
503 * to enable the file system layout to scale from a couple of
504 * small xattr name/values to a large number of large xattr
505 * names/values without affecting performance. While hopefully
506 * enabling the common case of a couple of small xattr name/values
507 * to be stored efficiently
508 *
509 * Code repeatedly scans, doing the following
510 * move xattr data out of line if it exceeds
511 * xattr_value_max. Where xattr_value_max is
512 * initially XATTR_INLINE_MAX. If the final uncompressed
513 * xattr list is larger than XATTR_TARGET_MAX then more
514 * aggressively move xattr data out of line by repeatedly
515 * setting inline threshold to 1/2, then 1/4, 1/8 of
516 * XATTR_INLINE_MAX until target achieved or there's
517 * nothing left to move out of line
518 */
519 xattr_value_max = XATTR_INLINE_MAX;
520 while(1) {
521 for(total_size = 0, i = 0; i < xattrs; i++) {
522 struct xattr_list *xattr = &xattr_list[i];
523 xattr->type &= XATTR_PREFIX_MASK; /* all inline */
524 if (xattr->vsize > xattr_value_max)
525 xattr->type |= XATTR_VALUE_OOL;
526
527 total_size += get_xattr_size(xattr);
528 }
529
530 /*
531 * If the total size of the uncompressed xattr list is <=
532 * XATTR_TARGET_MAX we're done
533 */
534 if(total_size <= XATTR_TARGET_MAX)
535 break;
536
537 if(xattr_value_max == XATTR_VALUE_OOL_SIZE)
538 break;
539
540 /*
541 * Inline target not yet at minimum and so reduce it, and
542 * try again
543 */
544 xattr_value_max /= 2;
545 if(xattr_value_max < XATTR_VALUE_OOL_SIZE)
546 xattr_value_max = XATTR_VALUE_OOL_SIZE;
547 }
548
549 /*
550 * Check xattr values for duplicates
551 */
552 for(i = 0; i < xattrs; i++) {
553 check_value_dupl(&xattr_list[i]);
554 }
555
556 /*
557 * Add each out of line value to the file system xattr table
558 * if it doesn't already exist as a duplicate
559 */
560 for(i = 0; i < xattrs; i++) {
561 struct xattr_list *xattr = &xattr_list[i];
562
563 if((xattr->type & XATTR_VALUE_OOL) &&
564 (xattr->ool_value == SQUASHFS_INVALID_BLK)) {
565 struct squashfs_xattr_val val;
566 int size = sizeof(val) + xattr->vsize;
567 xp = get_xattr_space(size, &xattr->ool_value);
568 val.vsize = xattr->vsize;
569 SQUASHFS_SWAP_XATTR_VAL(&val, xp);
570 memcpy(xp + sizeof(val), xattr->value, xattr->vsize);
571 }
572 }
573
574 /*
575 * Create xattr list and add to file system xattr table
576 */
577 get_xattr_space(0, &xattr_disk);
578 for(i = 0; i < xattrs; i++) {
579 struct xattr_list *xattr = &xattr_list[i];
580 struct squashfs_xattr_entry entry;
581 struct squashfs_xattr_val val;
582
583 xp = get_xattr_space(sizeof(entry) + xattr->size, NULL);
584 entry.type = xattr->type;
585 entry.size = xattr->size;
586 SQUASHFS_SWAP_XATTR_ENTRY(&entry, xp);
587 memcpy(xp + sizeof(entry), xattr->name, xattr->size);
588
589 if(xattr->type & XATTR_VALUE_OOL) {
590 int size = sizeof(val) + XATTR_VALUE_OOL_SIZE;
591 xp = get_xattr_space(size, NULL);
592 val.vsize = XATTR_VALUE_OOL_SIZE;
593 SQUASHFS_SWAP_XATTR_VAL(&val, xp);
594 SQUASHFS_SWAP_LONG_LONGS(&xattr->ool_value, xp +
595 sizeof(val), 1);
596 } else {
597 int size = sizeof(val) + xattr->vsize;
598 xp = get_xattr_space(size, &xattr->ool_value);
599 val.vsize = xattr->vsize;
600 SQUASHFS_SWAP_XATTR_VAL(&val, xp);
601 memcpy(xp + sizeof(val), xattr->value, xattr->vsize);
602 }
603 }
604
605 /*
606 * Add to xattr id lookup table
607 */
608 return get_xattr_id(xattrs, xattr_list, xattr_disk, xattr_dupl);
609 }
610
611
612 int read_xattrs(void *d)
613 {
614 struct dir_ent *dir_ent = d;
615 struct inode_info *inode = dir_ent->inode;
616 char *filename = pathname(dir_ent);
617 struct xattr_list *xattr_list;
618 int xattrs;
619
620 if(no_xattrs || IS_PSEUDO(inode) || inode->root_entry)
621 return SQUASHFS_INVALID_XATTR;
622
623 xattrs = read_xattrs_from_system(filename, &xattr_list);
624 if(xattrs == 0)
625 return SQUASHFS_INVALID_XATTR;
626
627 return generate_xattrs(xattrs, xattr_list);
628 }
629
630
631 /*
632 * Add the existing xattr ids and xattr metadata in the file system being
633 * appended to, to the in-memory xattr cache. This allows duplicate checking to
634 * take place against the xattrs already in the file system being appended to,
635 * and ensures the pre-existing xattrs are written out along with any new xattrs
636 */
637 int get_xattrs(int fd, struct squashfs_super_block *sBlk)
638 {
639 int ids, res, i, id;
640 unsigned int count;
641
642 TRACE("get_xattrs\n");
643
644 res = read_xattrs_from_disk(fd, sBlk, FALSE, NULL);
645 if(res == SQUASHFS_INVALID_BLK || res == 0)
646 goto done;
647 ids = res;
648
649 /*
650 * for each xattr id read and construct its list of xattr
651 * name:value pairs, and add them to the in-memory xattr cache
652 */
653 for(i = 0; i < ids; i++) {
654 struct xattr_list *xattr_list = get_xattr(i, &count, &res);
655 if(res) {
656 free_xattr(xattr_list, count);
657 return FALSE;
658 }
659 id = generate_xattrs(count, xattr_list);
660
661 /*
662 * Sanity check, the new xattr id should be the same as the
663 * xattr id in the original file system
664 */
665 if(id != i) {
666 ERROR("BUG, different xattr_id in get_xattrs\n");
667 res = 0;
668 goto done;
669 }
670 }
671
672 done:
673 return res;
674 }
675
676
677 /*
678 * Save current state of xattrs, needed for restoring state in the event of an
679 * abort in appending
680 */
681 void save_xattrs()
682 {
683 /* save the current state of the compressed xattr data */
684 sxattr_bytes = xattr_bytes;
685 stotal_xattr_bytes = total_xattr_bytes;
686
687 /*
688 * save the current state of the cached uncompressed xattr data.
689 * Note we have to save the contents of the data cache because future
690 * operations will delete the current contents
691 */
692 sdata_cache = malloc(cache_bytes);
693 if(sdata_cache == NULL)
694 MEM_ERROR();
695
696 memcpy(sdata_cache, data_cache, cache_bytes);
697 scache_bytes = cache_bytes;
698
699 /* save the current state of the xattr id table */
700 sxattr_ids = xattr_ids;
701 }
702
703
704 /*
705 * Restore xattrs in the event of an abort in appending
706 */
707 void restore_xattrs()
708 {
709 /* restore the state of the compressed xattr data */
710 xattr_bytes = sxattr_bytes;
711 total_xattr_bytes = stotal_xattr_bytes;
712
713 /* restore the state of the uncomoressed xattr data */
714 memcpy(data_cache, sdata_cache, scache_bytes);
715 cache_bytes = scache_bytes;
716
717 /* restore the state of the xattr id table */
718 xattr_ids = sxattr_ids;
719 }