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