1 /*- 2 * Copyright (c) 2003-2007 Tim Kientzle 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 26 #include "archive_platform.h" 27 __FBSDID("$FreeBSD: head/lib/libarchive/archive_entry.c 201096 2009-12-28 02:41:27Z kientzle $"); 28 29 #ifdef HAVE_SYS_STAT_H 30 #include <sys/stat.h> 31 #endif 32 #ifdef HAVE_SYS_TYPES_H 33 #include <sys/types.h> 34 #endif 35 #if MAJOR_IN_MKDEV 36 #include <sys/mkdev.h> 37 #define HAVE_MAJOR 38 #elif MAJOR_IN_SYSMACROS 39 #include <sys/sysmacros.h> 40 #define HAVE_MAJOR 41 #endif 42 #ifdef HAVE_ERRNO_H 43 #include <errno.h> 44 #endif 45 #ifdef HAVE_LIMITS_H 46 #include <limits.h> 47 #endif 48 #ifdef HAVE_LINUX_FS_H 49 #include <linux/fs.h> /* for Linux file flags */ 50 #endif 51 /* 52 * Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h. 53 * As the include guards don't agree, the order of include is important. 54 */ 55 #ifdef HAVE_LINUX_EXT2_FS_H 56 #include <linux/ext2_fs.h> /* for Linux file flags */ 57 #endif 58 #if defined(HAVE_EXT2FS_EXT2_FS_H) && !defined(__CYGWIN__) 59 #include <ext2fs/ext2_fs.h> /* for Linux file flags */ 60 #endif 61 #include <stddef.h> 62 #include <stdio.h> 63 #ifdef HAVE_STDLIB_H 64 #include <stdlib.h> 65 #endif 66 #ifdef HAVE_STRING_H 67 #include <string.h> 68 #endif 69 #ifdef HAVE_WCHAR_H 70 #include <wchar.h> 71 #endif 72 73 #include "archive.h" 74 #include "archive_acl_private.h" 75 #include "archive_entry.h" 76 #include "archive_entry_locale.h" 77 #include "archive_private.h" 78 #include "archive_entry_private.h" 79 80 #if !defined(HAVE_MAJOR) && !defined(major) 81 /* Replacement for major/minor/makedev. */ 82 #define major(x) ((int)(0x00ff & ((x) >> 8))) 83 #define minor(x) ((int)(0xffff00ff & (x))) 84 #define makedev(maj,min) ((0xff00 & ((maj)<<8)) | (0xffff00ff & (min))) 85 #endif 86 87 /* Play games to come up with a suitable makedev() definition. */ 88 #ifdef __QNXNTO__ 89 /* QNX. <sigh> */ 90 #include <sys/netmgr.h> 91 #define ae_makedev(maj, min) makedev(ND_LOCAL_NODE, (maj), (min)) 92 #elif defined makedev 93 /* There's a "makedev" macro. */ 94 #define ae_makedev(maj, min) makedev((maj), (min)) 95 #elif defined mkdev || ((defined _WIN32 || defined __WIN32__) && !defined(__CYGWIN__)) 96 /* Windows. <sigh> */ 97 #define ae_makedev(maj, min) mkdev((maj), (min)) 98 #else 99 /* There's a "makedev" function. */ 100 #define ae_makedev(maj, min) makedev((maj), (min)) 101 #endif 102 103 /* 104 * This adjustment is needed to support the following idiom for adding 105 * 1000ns to the stored time: 106 * archive_entry_set_atime(archive_entry_atime(), 107 * archive_entry_atime_nsec() + 1000) 108 * The additional if() here compensates for ambiguity in the C standard, 109 * which permits two possible interpretations of a % b when a is negative. 110 */ 111 #define FIX_NS(t,ns) \ 112 do { \ 113 t += ns / 1000000000; \ 114 ns %= 1000000000; \ 115 if (ns < 0) { --t; ns += 1000000000; } \ 116 } while (0) 117 118 static char * ae_fflagstostr(unsigned long bitset, unsigned long bitclear); 119 static const wchar_t *ae_wcstofflags(const wchar_t *stringp, 120 unsigned long *setp, unsigned long *clrp); 121 static const char *ae_strtofflags(const char *stringp, 122 unsigned long *setp, unsigned long *clrp); 123 124 #ifndef HAVE_WCSCPY 125 static wchar_t * wcscpy(wchar_t *s1, const wchar_t *s2) 126 { 127 wchar_t *dest = s1; 128 while ((*s1 = *s2) != L'\0') 129 ++s1, ++s2; 130 return dest; 131 } 132 #endif 133 #ifndef HAVE_WCSLEN 134 static size_t wcslen(const wchar_t *s) 135 { 136 const wchar_t *p = s; 137 while (*p != L'\0') 138 ++p; 139 return p - s; 140 } 141 #endif 142 #ifndef HAVE_WMEMCMP 143 /* Good enough for simple equality testing, but not for sorting. */ 144 #define wmemcmp(a,b,i) memcmp((a), (b), (i) * sizeof(wchar_t)) 145 #endif 146 147 /**************************************************************************** 148 * 149 * Public Interface 150 * 151 ****************************************************************************/ 152 153 struct archive_entry * 154 archive_entry_clear(struct archive_entry *entry) 155 { 156 if (entry == NULL) 157 return (NULL); 158 archive_mstring_clean(&entry->ae_fflags_text); 159 archive_mstring_clean(&entry->ae_gname); 160 archive_mstring_clean(&entry->ae_hardlink); 161 archive_mstring_clean(&entry->ae_pathname); 162 archive_mstring_clean(&entry->ae_sourcepath); 163 archive_mstring_clean(&entry->ae_symlink); 164 archive_mstring_clean(&entry->ae_uname); 165 archive_entry_copy_mac_metadata(entry, NULL, 0); 166 archive_acl_clear(&entry->acl); 167 archive_entry_xattr_clear(entry); 168 archive_entry_sparse_clear(entry); 169 free(entry->stat); 170 memset(entry, 0, sizeof(*entry)); 171 return entry; 172 } 173 174 struct archive_entry * 175 archive_entry_clone(struct archive_entry *entry) 176 { 177 struct archive_entry *entry2; 178 struct ae_xattr *xp; 179 struct ae_sparse *sp; 180 size_t s; 181 const void *p; 182 183 /* Allocate new structure and copy over all of the fields. */ 184 /* TODO: Should we copy the archive over? Or require a new archive 185 * as an argument? */ 186 entry2 = archive_entry_new2(entry->archive); 187 if (entry2 == NULL) 188 return (NULL); 189 entry2->ae_stat = entry->ae_stat; 190 entry2->ae_fflags_set = entry->ae_fflags_set; 191 entry2->ae_fflags_clear = entry->ae_fflags_clear; 192 193 /* TODO: XXX If clone can have a different archive, what do we do here if 194 * character sets are different? XXX */ 195 archive_mstring_copy(&entry2->ae_fflags_text, &entry->ae_fflags_text); 196 archive_mstring_copy(&entry2->ae_gname, &entry->ae_gname); 197 archive_mstring_copy(&entry2->ae_hardlink, &entry->ae_hardlink); 198 archive_mstring_copy(&entry2->ae_pathname, &entry->ae_pathname); 199 archive_mstring_copy(&entry2->ae_sourcepath, &entry->ae_sourcepath); 200 archive_mstring_copy(&entry2->ae_symlink, &entry->ae_symlink); 201 entry2->ae_set = entry->ae_set; 202 archive_mstring_copy(&entry2->ae_uname, &entry->ae_uname); 203 204 /* Copy ACL data over. */ 205 archive_acl_copy(&entry2->acl, &entry->acl); 206 207 /* Copy Mac OS metadata. */ 208 p = archive_entry_mac_metadata(entry, &s); 209 archive_entry_copy_mac_metadata(entry2, p, s); 210 211 /* Copy xattr data over. */ 212 xp = entry->xattr_head; 213 while (xp != NULL) { 214 archive_entry_xattr_add_entry(entry2, 215 xp->name, xp->value, xp->size); 216 xp = xp->next; 217 } 218 219 /* Copy sparse data over. */ 220 sp = entry->sparse_head; 221 while (sp != NULL) { 222 archive_entry_sparse_add_entry(entry2, 223 sp->offset, sp->length); 224 sp = sp->next; 225 } 226 227 return (entry2); 228 } 229 230 void 231 archive_entry_free(struct archive_entry *entry) 232 { 233 archive_entry_clear(entry); 234 free(entry); 235 } 236 237 struct archive_entry * 238 archive_entry_new(void) 239 { 240 return archive_entry_new2(NULL); 241 } 242 243 struct archive_entry * 244 archive_entry_new2(struct archive *a) 245 { 246 struct archive_entry *entry; 247 248 entry = (struct archive_entry *)malloc(sizeof(*entry)); 249 if (entry == NULL) 250 return (NULL); 251 memset(entry, 0, sizeof(*entry)); 252 entry->archive = a; 253 return (entry); 254 } 255 256 /* 257 * Functions for reading fields from an archive_entry. 258 */ 259 260 time_t 261 archive_entry_atime(struct archive_entry *entry) 262 { 263 return (entry->ae_stat.aest_atime); 264 } 265 266 long 267 archive_entry_atime_nsec(struct archive_entry *entry) 268 { 269 return (entry->ae_stat.aest_atime_nsec); 270 } 271 272 int 273 archive_entry_atime_is_set(struct archive_entry *entry) 274 { 275 return (entry->ae_set & AE_SET_ATIME); 276 } 277 278 time_t 279 archive_entry_birthtime(struct archive_entry *entry) 280 { 281 return (entry->ae_stat.aest_birthtime); 282 } 283 284 long 285 archive_entry_birthtime_nsec(struct archive_entry *entry) 286 { 287 return (entry->ae_stat.aest_birthtime_nsec); 288 } 289 290 int 291 archive_entry_birthtime_is_set(struct archive_entry *entry) 292 { 293 return (entry->ae_set & AE_SET_BIRTHTIME); 294 } 295 296 time_t 297 archive_entry_ctime(struct archive_entry *entry) 298 { 299 return (entry->ae_stat.aest_ctime); 300 } 301 302 int 303 archive_entry_ctime_is_set(struct archive_entry *entry) 304 { 305 return (entry->ae_set & AE_SET_CTIME); 306 } 307 308 long 309 archive_entry_ctime_nsec(struct archive_entry *entry) 310 { 311 return (entry->ae_stat.aest_ctime_nsec); 312 } 313 314 dev_t 315 archive_entry_dev(struct archive_entry *entry) 316 { 317 if (entry->ae_stat.aest_dev_is_broken_down) 318 return ae_makedev(entry->ae_stat.aest_devmajor, 319 entry->ae_stat.aest_devminor); 320 else 321 return (entry->ae_stat.aest_dev); 322 } 323 324 int 325 archive_entry_dev_is_set(struct archive_entry *entry) 326 { 327 return (entry->ae_set & AE_SET_DEV); 328 } 329 330 dev_t 331 archive_entry_devmajor(struct archive_entry *entry) 332 { 333 if (entry->ae_stat.aest_dev_is_broken_down) 334 return (entry->ae_stat.aest_devmajor); 335 else 336 return major(entry->ae_stat.aest_dev); 337 } 338 339 dev_t 340 archive_entry_devminor(struct archive_entry *entry) 341 { 342 if (entry->ae_stat.aest_dev_is_broken_down) 343 return (entry->ae_stat.aest_devminor); 344 else 345 return minor(entry->ae_stat.aest_dev); 346 } 347 348 mode_t 349 archive_entry_filetype(struct archive_entry *entry) 350 { 351 return (AE_IFMT & entry->acl.mode); 352 } 353 354 void 355 archive_entry_fflags(struct archive_entry *entry, 356 unsigned long *set, unsigned long *clear) 357 { 358 *set = entry->ae_fflags_set; 359 *clear = entry->ae_fflags_clear; 360 } 361 362 /* 363 * Note: if text was provided, this just returns that text. If you 364 * really need the text to be rebuilt in a canonical form, set the 365 * text, ask for the bitmaps, then set the bitmaps. (Setting the 366 * bitmaps clears any stored text.) This design is deliberate: if 367 * we're editing archives, we don't want to discard flags just because 368 * they aren't supported on the current system. The bitmap<->text 369 * conversions are platform-specific (see below). 370 */ 371 const char * 372 archive_entry_fflags_text(struct archive_entry *entry) 373 { 374 const char *f; 375 char *p; 376 377 if (archive_mstring_get_mbs(entry->archive, 378 &entry->ae_fflags_text, &f) == 0) { 379 if (f != NULL) 380 return (f); 381 } else if (errno == ENOMEM) 382 __archive_errx(1, "No memory"); 383 384 if (entry->ae_fflags_set == 0 && entry->ae_fflags_clear == 0) 385 return (NULL); 386 387 p = ae_fflagstostr(entry->ae_fflags_set, entry->ae_fflags_clear); 388 if (p == NULL) 389 return (NULL); 390 391 archive_mstring_copy_mbs(&entry->ae_fflags_text, p); 392 free(p); 393 if (archive_mstring_get_mbs(entry->archive, 394 &entry->ae_fflags_text, &f) == 0) 395 return (f); 396 if (errno == ENOMEM) 397 __archive_errx(1, "No memory"); 398 return (NULL); 399 } 400 401 int64_t 402 archive_entry_gid(struct archive_entry *entry) 403 { 404 return (entry->ae_stat.aest_gid); 405 } 406 407 const char * 408 archive_entry_gname(struct archive_entry *entry) 409 { 410 const char *p; 411 if (archive_mstring_get_mbs(entry->archive, &entry->ae_gname, &p) == 0) 412 return (p); 413 if (errno == ENOMEM) 414 __archive_errx(1, "No memory"); 415 return (NULL); 416 } 417 418 const wchar_t * 419 archive_entry_gname_w(struct archive_entry *entry) 420 { 421 const wchar_t *p; 422 if (archive_mstring_get_wcs(entry->archive, &entry->ae_gname, &p) == 0) 423 return (p); 424 if (errno == ENOMEM) 425 __archive_errx(1, "No memory"); 426 return (NULL); 427 } 428 429 int 430 _archive_entry_gname_l(struct archive_entry *entry, 431 const char **p, size_t *len, struct archive_string_conv *sc) 432 { 433 return (archive_mstring_get_mbs_l(&entry->ae_gname, p, len, sc)); 434 } 435 436 const char * 437 archive_entry_hardlink(struct archive_entry *entry) 438 { 439 const char *p; 440 if ((entry->ae_set & AE_SET_HARDLINK) == 0) 441 return (NULL); 442 if (archive_mstring_get_mbs( 443 entry->archive, &entry->ae_hardlink, &p) == 0) 444 return (p); 445 if (errno == ENOMEM) 446 __archive_errx(1, "No memory"); 447 return (NULL); 448 } 449 450 const wchar_t * 451 archive_entry_hardlink_w(struct archive_entry *entry) 452 { 453 const wchar_t *p; 454 if ((entry->ae_set & AE_SET_HARDLINK) == 0) 455 return (NULL); 456 if (archive_mstring_get_wcs( 457 entry->archive, &entry->ae_hardlink, &p) == 0) 458 return (p); 459 if (errno == ENOMEM) 460 __archive_errx(1, "No memory"); 461 return (NULL); 462 } 463 464 int 465 _archive_entry_hardlink_l(struct archive_entry *entry, 466 const char **p, size_t *len, struct archive_string_conv *sc) 467 { 468 if ((entry->ae_set & AE_SET_HARDLINK) == 0) { 469 *p = NULL; 470 *len = 0; 471 return (0); 472 } 473 return (archive_mstring_get_mbs_l(&entry->ae_hardlink, p, len, sc)); 474 } 475 476 int64_t 477 archive_entry_ino(struct archive_entry *entry) 478 { 479 return (entry->ae_stat.aest_ino); 480 } 481 482 int 483 archive_entry_ino_is_set(struct archive_entry *entry) 484 { 485 return (entry->ae_set & AE_SET_INO); 486 } 487 488 int64_t 489 archive_entry_ino64(struct archive_entry *entry) 490 { 491 return (entry->ae_stat.aest_ino); 492 } 493 494 mode_t 495 archive_entry_mode(struct archive_entry *entry) 496 { 497 return (entry->acl.mode); 498 } 499 500 time_t 501 archive_entry_mtime(struct archive_entry *entry) 502 { 503 return (entry->ae_stat.aest_mtime); 504 } 505 506 long 507 archive_entry_mtime_nsec(struct archive_entry *entry) 508 { 509 return (entry->ae_stat.aest_mtime_nsec); 510 } 511 512 int 513 archive_entry_mtime_is_set(struct archive_entry *entry) 514 { 515 return (entry->ae_set & AE_SET_MTIME); 516 } 517 518 unsigned int 519 archive_entry_nlink(struct archive_entry *entry) 520 { 521 return (entry->ae_stat.aest_nlink); 522 } 523 524 const char * 525 archive_entry_pathname(struct archive_entry *entry) 526 { 527 const char *p; 528 if (archive_mstring_get_mbs( 529 entry->archive, &entry->ae_pathname, &p) == 0) 530 return (p); 531 if (errno == ENOMEM) 532 __archive_errx(1, "No memory"); 533 return (NULL); 534 } 535 536 const wchar_t * 537 archive_entry_pathname_w(struct archive_entry *entry) 538 { 539 const wchar_t *p; 540 if (archive_mstring_get_wcs( 541 entry->archive, &entry->ae_pathname, &p) == 0) 542 return (p); 543 if (errno == ENOMEM) 544 __archive_errx(1, "No memory"); 545 return (NULL); 546 } 547 548 int 549 _archive_entry_pathname_l(struct archive_entry *entry, 550 const char **p, size_t *len, struct archive_string_conv *sc) 551 { 552 return (archive_mstring_get_mbs_l(&entry->ae_pathname, p, len, sc)); 553 } 554 555 mode_t 556 archive_entry_perm(struct archive_entry *entry) 557 { 558 return (~AE_IFMT & entry->acl.mode); 559 } 560 561 dev_t 562 archive_entry_rdev(struct archive_entry *entry) 563 { 564 if (entry->ae_stat.aest_rdev_is_broken_down) 565 return ae_makedev(entry->ae_stat.aest_rdevmajor, 566 entry->ae_stat.aest_rdevminor); 567 else 568 return (entry->ae_stat.aest_rdev); 569 } 570 571 dev_t 572 archive_entry_rdevmajor(struct archive_entry *entry) 573 { 574 if (entry->ae_stat.aest_rdev_is_broken_down) 575 return (entry->ae_stat.aest_rdevmajor); 576 else 577 return major(entry->ae_stat.aest_rdev); 578 } 579 580 dev_t 581 archive_entry_rdevminor(struct archive_entry *entry) 582 { 583 if (entry->ae_stat.aest_rdev_is_broken_down) 584 return (entry->ae_stat.aest_rdevminor); 585 else 586 return minor(entry->ae_stat.aest_rdev); 587 } 588 589 int64_t 590 archive_entry_size(struct archive_entry *entry) 591 { 592 return (entry->ae_stat.aest_size); 593 } 594 595 int 596 archive_entry_size_is_set(struct archive_entry *entry) 597 { 598 return (entry->ae_set & AE_SET_SIZE); 599 } 600 601 const char * 602 archive_entry_sourcepath(struct archive_entry *entry) 603 { 604 const char *p; 605 if (archive_mstring_get_mbs( 606 entry->archive, &entry->ae_sourcepath, &p) == 0) 607 return (p); 608 if (errno == ENOMEM) 609 __archive_errx(1, "No memory"); 610 return (NULL); 611 } 612 613 const wchar_t * 614 archive_entry_sourcepath_w(struct archive_entry *entry) 615 { 616 const wchar_t *p; 617 if (archive_mstring_get_wcs( 618 entry->archive, &entry->ae_sourcepath, &p) == 0) 619 return (p); 620 return (NULL); 621 } 622 623 const char * 624 archive_entry_symlink(struct archive_entry *entry) 625 { 626 const char *p; 627 if ((entry->ae_set & AE_SET_SYMLINK) == 0) 628 return (NULL); 629 if (archive_mstring_get_mbs( 630 entry->archive, &entry->ae_symlink, &p) == 0) 631 return (p); 632 if (errno == ENOMEM) 633 __archive_errx(1, "No memory"); 634 return (NULL); 635 } 636 637 const wchar_t * 638 archive_entry_symlink_w(struct archive_entry *entry) 639 { 640 const wchar_t *p; 641 if ((entry->ae_set & AE_SET_SYMLINK) == 0) 642 return (NULL); 643 if (archive_mstring_get_wcs( 644 entry->archive, &entry->ae_symlink, &p) == 0) 645 return (p); 646 if (errno == ENOMEM) 647 __archive_errx(1, "No memory"); 648 return (NULL); 649 } 650 651 int 652 _archive_entry_symlink_l(struct archive_entry *entry, 653 const char **p, size_t *len, struct archive_string_conv *sc) 654 { 655 if ((entry->ae_set & AE_SET_SYMLINK) == 0) { 656 *p = NULL; 657 *len = 0; 658 return (0); 659 } 660 return (archive_mstring_get_mbs_l( &entry->ae_symlink, p, len, sc)); 661 } 662 663 int64_t 664 archive_entry_uid(struct archive_entry *entry) 665 { 666 return (entry->ae_stat.aest_uid); 667 } 668 669 const char * 670 archive_entry_uname(struct archive_entry *entry) 671 { 672 const char *p; 673 if (archive_mstring_get_mbs(entry->archive, &entry->ae_uname, &p) == 0) 674 return (p); 675 if (errno == ENOMEM) 676 __archive_errx(1, "No memory"); 677 return (NULL); 678 } 679 680 const wchar_t * 681 archive_entry_uname_w(struct archive_entry *entry) 682 { 683 const wchar_t *p; 684 if (archive_mstring_get_wcs(entry->archive, &entry->ae_uname, &p) == 0) 685 return (p); 686 if (errno == ENOMEM) 687 __archive_errx(1, "No memory"); 688 return (NULL); 689 } 690 691 int 692 _archive_entry_uname_l(struct archive_entry *entry, 693 const char **p, size_t *len, struct archive_string_conv *sc) 694 { 695 return (archive_mstring_get_mbs_l(&entry->ae_uname, p, len, sc)); 696 } 697 698 /* 699 * Functions to set archive_entry properties. 700 */ 701 702 void 703 archive_entry_set_filetype(struct archive_entry *entry, unsigned int type) 704 { 705 entry->stat_valid = 0; 706 entry->acl.mode &= ~AE_IFMT; 707 entry->acl.mode |= AE_IFMT & type; 708 } 709 710 void 711 archive_entry_set_fflags(struct archive_entry *entry, 712 unsigned long set, unsigned long clear) 713 { 714 archive_mstring_clean(&entry->ae_fflags_text); 715 entry->ae_fflags_set = set; 716 entry->ae_fflags_clear = clear; 717 } 718 719 const char * 720 archive_entry_copy_fflags_text(struct archive_entry *entry, 721 const char *flags) 722 { 723 archive_mstring_copy_mbs(&entry->ae_fflags_text, flags); 724 return (ae_strtofflags(flags, 725 &entry->ae_fflags_set, &entry->ae_fflags_clear)); 726 } 727 728 const wchar_t * 729 archive_entry_copy_fflags_text_w(struct archive_entry *entry, 730 const wchar_t *flags) 731 { 732 archive_mstring_copy_wcs(&entry->ae_fflags_text, flags); 733 return (ae_wcstofflags(flags, 734 &entry->ae_fflags_set, &entry->ae_fflags_clear)); 735 } 736 737 void 738 archive_entry_set_gid(struct archive_entry *entry, int64_t g) 739 { 740 entry->stat_valid = 0; 741 entry->ae_stat.aest_gid = g; 742 } 743 744 void 745 archive_entry_set_gname(struct archive_entry *entry, const char *name) 746 { 747 archive_mstring_copy_mbs(&entry->ae_gname, name); 748 } 749 750 void 751 archive_entry_copy_gname(struct archive_entry *entry, const char *name) 752 { 753 archive_mstring_copy_mbs(&entry->ae_gname, name); 754 } 755 756 void 757 archive_entry_copy_gname_w(struct archive_entry *entry, const wchar_t *name) 758 { 759 archive_mstring_copy_wcs(&entry->ae_gname, name); 760 } 761 762 int 763 archive_entry_update_gname_utf8(struct archive_entry *entry, const char *name) 764 { 765 if (archive_mstring_update_utf8(entry->archive, 766 &entry->ae_gname, name) == 0) 767 return (1); 768 if (errno == ENOMEM) 769 __archive_errx(1, "No memory"); 770 return (0); 771 } 772 773 int 774 _archive_entry_copy_gname_l(struct archive_entry *entry, 775 const char *name, size_t len, struct archive_string_conv *sc) 776 { 777 return (archive_mstring_copy_mbs_len_l(&entry->ae_gname, name, len, sc)); 778 } 779 780 void 781 archive_entry_set_ino(struct archive_entry *entry, int64_t ino) 782 { 783 entry->stat_valid = 0; 784 entry->ae_set |= AE_SET_INO; 785 entry->ae_stat.aest_ino = ino; 786 } 787 788 void 789 archive_entry_set_ino64(struct archive_entry *entry, int64_t ino) 790 { 791 entry->stat_valid = 0; 792 entry->ae_set |= AE_SET_INO; 793 entry->ae_stat.aest_ino = ino; 794 } 795 796 void 797 archive_entry_set_hardlink(struct archive_entry *entry, const char *target) 798 { 799 archive_mstring_copy_mbs(&entry->ae_hardlink, target); 800 if (target != NULL) 801 entry->ae_set |= AE_SET_HARDLINK; 802 else 803 entry->ae_set &= ~AE_SET_HARDLINK; 804 } 805 806 void 807 archive_entry_copy_hardlink(struct archive_entry *entry, const char *target) 808 { 809 archive_mstring_copy_mbs(&entry->ae_hardlink, target); 810 if (target != NULL) 811 entry->ae_set |= AE_SET_HARDLINK; 812 else 813 entry->ae_set &= ~AE_SET_HARDLINK; 814 } 815 816 void 817 archive_entry_copy_hardlink_w(struct archive_entry *entry, const wchar_t *target) 818 { 819 archive_mstring_copy_wcs(&entry->ae_hardlink, target); 820 if (target != NULL) 821 entry->ae_set |= AE_SET_HARDLINK; 822 else 823 entry->ae_set &= ~AE_SET_HARDLINK; 824 } 825 826 int 827 archive_entry_update_hardlink_utf8(struct archive_entry *entry, const char *target) 828 { 829 if (target != NULL) 830 entry->ae_set |= AE_SET_HARDLINK; 831 else 832 entry->ae_set &= ~AE_SET_HARDLINK; 833 if (archive_mstring_update_utf8(entry->archive, 834 &entry->ae_hardlink, target) == 0) 835 return (1); 836 if (errno == ENOMEM) 837 __archive_errx(1, "No memory"); 838 return (0); 839 } 840 841 int 842 _archive_entry_copy_hardlink_l(struct archive_entry *entry, 843 const char *target, size_t len, struct archive_string_conv *sc) 844 { 845 int r; 846 847 r = archive_mstring_copy_mbs_len_l(&entry->ae_hardlink, 848 target, len, sc); 849 if (target != NULL && r == 0) 850 entry->ae_set |= AE_SET_HARDLINK; 851 else 852 entry->ae_set &= ~AE_SET_HARDLINK; 853 return (r); 854 } 855 856 void 857 archive_entry_set_atime(struct archive_entry *entry, time_t t, long ns) 858 { 859 FIX_NS(t, ns); 860 entry->stat_valid = 0; 861 entry->ae_set |= AE_SET_ATIME; 862 entry->ae_stat.aest_atime = t; 863 entry->ae_stat.aest_atime_nsec = ns; 864 } 865 866 void 867 archive_entry_unset_atime(struct archive_entry *entry) 868 { 869 archive_entry_set_atime(entry, 0, 0); 870 entry->ae_set &= ~AE_SET_ATIME; 871 } 872 873 void 874 archive_entry_set_birthtime(struct archive_entry *entry, time_t t, long ns) 875 { 876 FIX_NS(t, ns); 877 entry->stat_valid = 0; 878 entry->ae_set |= AE_SET_BIRTHTIME; 879 entry->ae_stat.aest_birthtime = t; 880 entry->ae_stat.aest_birthtime_nsec = ns; 881 } 882 883 void 884 archive_entry_unset_birthtime(struct archive_entry *entry) 885 { 886 archive_entry_set_birthtime(entry, 0, 0); 887 entry->ae_set &= ~AE_SET_BIRTHTIME; 888 } 889 890 void 891 archive_entry_set_ctime(struct archive_entry *entry, time_t t, long ns) 892 { 893 FIX_NS(t, ns); 894 entry->stat_valid = 0; 895 entry->ae_set |= AE_SET_CTIME; 896 entry->ae_stat.aest_ctime = t; 897 entry->ae_stat.aest_ctime_nsec = ns; 898 } 899 900 void 901 archive_entry_unset_ctime(struct archive_entry *entry) 902 { 903 archive_entry_set_ctime(entry, 0, 0); 904 entry->ae_set &= ~AE_SET_CTIME; 905 } 906 907 void 908 archive_entry_set_dev(struct archive_entry *entry, dev_t d) 909 { 910 entry->stat_valid = 0; 911 entry->ae_set |= AE_SET_DEV; 912 entry->ae_stat.aest_dev_is_broken_down = 0; 913 entry->ae_stat.aest_dev = d; 914 } 915 916 void 917 archive_entry_set_devmajor(struct archive_entry *entry, dev_t m) 918 { 919 entry->stat_valid = 0; 920 entry->ae_set |= AE_SET_DEV; 921 entry->ae_stat.aest_dev_is_broken_down = 1; 922 entry->ae_stat.aest_devmajor = m; 923 } 924 925 void 926 archive_entry_set_devminor(struct archive_entry *entry, dev_t m) 927 { 928 entry->stat_valid = 0; 929 entry->ae_set |= AE_SET_DEV; 930 entry->ae_stat.aest_dev_is_broken_down = 1; 931 entry->ae_stat.aest_devminor = m; 932 } 933 934 /* Set symlink if symlink is already set, else set hardlink. */ 935 void 936 archive_entry_set_link(struct archive_entry *entry, const char *target) 937 { 938 if (entry->ae_set & AE_SET_SYMLINK) 939 archive_mstring_copy_mbs(&entry->ae_symlink, target); 940 else 941 archive_mstring_copy_mbs(&entry->ae_hardlink, target); 942 } 943 944 /* Set symlink if symlink is already set, else set hardlink. */ 945 void 946 archive_entry_copy_link(struct archive_entry *entry, const char *target) 947 { 948 if (entry->ae_set & AE_SET_SYMLINK) 949 archive_mstring_copy_mbs(&entry->ae_symlink, target); 950 else 951 archive_mstring_copy_mbs(&entry->ae_hardlink, target); 952 } 953 954 /* Set symlink if symlink is already set, else set hardlink. */ 955 void 956 archive_entry_copy_link_w(struct archive_entry *entry, const wchar_t *target) 957 { 958 if (entry->ae_set & AE_SET_SYMLINK) 959 archive_mstring_copy_wcs(&entry->ae_symlink, target); 960 else 961 archive_mstring_copy_wcs(&entry->ae_hardlink, target); 962 } 963 964 int 965 archive_entry_update_link_utf8(struct archive_entry *entry, const char *target) 966 { 967 int r; 968 if (entry->ae_set & AE_SET_SYMLINK) 969 r = archive_mstring_update_utf8(entry->archive, 970 &entry->ae_symlink, target); 971 else 972 r = archive_mstring_update_utf8(entry->archive, 973 &entry->ae_hardlink, target); 974 if (r == 0) 975 return (1); 976 if (errno == ENOMEM) 977 __archive_errx(1, "No memory"); 978 return (0); 979 } 980 981 int 982 _archive_entry_copy_link_l(struct archive_entry *entry, 983 const char *target, size_t len, struct archive_string_conv *sc) 984 { 985 int r; 986 987 if (entry->ae_set & AE_SET_SYMLINK) 988 r = archive_mstring_copy_mbs_len_l(&entry->ae_symlink, 989 target, len, sc); 990 else 991 r = archive_mstring_copy_mbs_len_l(&entry->ae_hardlink, 992 target, len, sc); 993 return (r); 994 } 995 996 void 997 archive_entry_set_mode(struct archive_entry *entry, mode_t m) 998 { 999 entry->stat_valid = 0; 1000 entry->acl.mode = m; 1001 } 1002 1003 void 1004 archive_entry_set_mtime(struct archive_entry *entry, time_t t, long ns) 1005 { 1006 FIX_NS(t, ns); 1007 entry->stat_valid = 0; 1008 entry->ae_set |= AE_SET_MTIME; 1009 entry->ae_stat.aest_mtime = t; 1010 entry->ae_stat.aest_mtime_nsec = ns; 1011 } 1012 1013 void 1014 archive_entry_unset_mtime(struct archive_entry *entry) 1015 { 1016 archive_entry_set_mtime(entry, 0, 0); 1017 entry->ae_set &= ~AE_SET_MTIME; 1018 } 1019 1020 void 1021 archive_entry_set_nlink(struct archive_entry *entry, unsigned int nlink) 1022 { 1023 entry->stat_valid = 0; 1024 entry->ae_stat.aest_nlink = nlink; 1025 } 1026 1027 void 1028 archive_entry_set_pathname(struct archive_entry *entry, const char *name) 1029 { 1030 archive_mstring_copy_mbs(&entry->ae_pathname, name); 1031 } 1032 1033 void 1034 archive_entry_copy_pathname(struct archive_entry *entry, const char *name) 1035 { 1036 archive_mstring_copy_mbs(&entry->ae_pathname, name); 1037 } 1038 1039 void 1040 archive_entry_copy_pathname_w(struct archive_entry *entry, const wchar_t *name) 1041 { 1042 archive_mstring_copy_wcs(&entry->ae_pathname, name); 1043 } 1044 1045 int 1046 archive_entry_update_pathname_utf8(struct archive_entry *entry, const char *name) 1047 { 1048 if (archive_mstring_update_utf8(entry->archive, 1049 &entry->ae_pathname, name) == 0) 1050 return (1); 1051 if (errno == ENOMEM) 1052 __archive_errx(1, "No memory"); 1053 return (0); 1054 } 1055 1056 int 1057 _archive_entry_copy_pathname_l(struct archive_entry *entry, 1058 const char *name, size_t len, struct archive_string_conv *sc) 1059 { 1060 return (archive_mstring_copy_mbs_len_l(&entry->ae_pathname, 1061 name, len, sc)); 1062 } 1063 1064 void 1065 archive_entry_set_perm(struct archive_entry *entry, mode_t p) 1066 { 1067 entry->stat_valid = 0; 1068 entry->acl.mode &= AE_IFMT; 1069 entry->acl.mode |= ~AE_IFMT & p; 1070 } 1071 1072 void 1073 archive_entry_set_rdev(struct archive_entry *entry, dev_t m) 1074 { 1075 entry->stat_valid = 0; 1076 entry->ae_stat.aest_rdev = m; 1077 entry->ae_stat.aest_rdev_is_broken_down = 0; 1078 } 1079 1080 void 1081 archive_entry_set_rdevmajor(struct archive_entry *entry, dev_t m) 1082 { 1083 entry->stat_valid = 0; 1084 entry->ae_stat.aest_rdev_is_broken_down = 1; 1085 entry->ae_stat.aest_rdevmajor = m; 1086 } 1087 1088 void 1089 archive_entry_set_rdevminor(struct archive_entry *entry, dev_t m) 1090 { 1091 entry->stat_valid = 0; 1092 entry->ae_stat.aest_rdev_is_broken_down = 1; 1093 entry->ae_stat.aest_rdevminor = m; 1094 } 1095 1096 void 1097 archive_entry_set_size(struct archive_entry *entry, int64_t s) 1098 { 1099 entry->stat_valid = 0; 1100 entry->ae_stat.aest_size = s; 1101 entry->ae_set |= AE_SET_SIZE; 1102 } 1103 1104 void 1105 archive_entry_unset_size(struct archive_entry *entry) 1106 { 1107 archive_entry_set_size(entry, 0); 1108 entry->ae_set &= ~AE_SET_SIZE; 1109 } 1110 1111 void 1112 archive_entry_copy_sourcepath(struct archive_entry *entry, const char *path) 1113 { 1114 archive_mstring_copy_mbs(&entry->ae_sourcepath, path); 1115 } 1116 1117 void 1118 archive_entry_copy_sourcepath_w(struct archive_entry *entry, const wchar_t *path) 1119 { 1120 archive_mstring_copy_wcs(&entry->ae_sourcepath, path); 1121 } 1122 1123 void 1124 archive_entry_set_symlink(struct archive_entry *entry, const char *linkname) 1125 { 1126 archive_mstring_copy_mbs(&entry->ae_symlink, linkname); 1127 if (linkname != NULL) 1128 entry->ae_set |= AE_SET_SYMLINK; 1129 else 1130 entry->ae_set &= ~AE_SET_SYMLINK; 1131 } 1132 1133 void 1134 archive_entry_copy_symlink(struct archive_entry *entry, const char *linkname) 1135 { 1136 archive_mstring_copy_mbs(&entry->ae_symlink, linkname); 1137 if (linkname != NULL) 1138 entry->ae_set |= AE_SET_SYMLINK; 1139 else 1140 entry->ae_set &= ~AE_SET_SYMLINK; 1141 } 1142 1143 void 1144 archive_entry_copy_symlink_w(struct archive_entry *entry, const wchar_t *linkname) 1145 { 1146 archive_mstring_copy_wcs(&entry->ae_symlink, linkname); 1147 if (linkname != NULL) 1148 entry->ae_set |= AE_SET_SYMLINK; 1149 else 1150 entry->ae_set &= ~AE_SET_SYMLINK; 1151 } 1152 1153 int 1154 archive_entry_update_symlink_utf8(struct archive_entry *entry, const char *linkname) 1155 { 1156 if (linkname != NULL) 1157 entry->ae_set |= AE_SET_SYMLINK; 1158 else 1159 entry->ae_set &= ~AE_SET_SYMLINK; 1160 if (archive_mstring_update_utf8(entry->archive, 1161 &entry->ae_symlink, linkname) == 0) 1162 return (1); 1163 if (errno == ENOMEM) 1164 __archive_errx(1, "No memory"); 1165 return (0); 1166 } 1167 1168 int 1169 _archive_entry_copy_symlink_l(struct archive_entry *entry, 1170 const char *linkname, size_t len, struct archive_string_conv *sc) 1171 { 1172 int r; 1173 1174 r = archive_mstring_copy_mbs_len_l(&entry->ae_symlink, 1175 linkname, len, sc); 1176 if (linkname != NULL && r == 0) 1177 entry->ae_set |= AE_SET_SYMLINK; 1178 else 1179 entry->ae_set &= ~AE_SET_SYMLINK; 1180 return (r); 1181 } 1182 1183 void 1184 archive_entry_set_uid(struct archive_entry *entry, int64_t u) 1185 { 1186 entry->stat_valid = 0; 1187 entry->ae_stat.aest_uid = u; 1188 } 1189 1190 void 1191 archive_entry_set_uname(struct archive_entry *entry, const char *name) 1192 { 1193 archive_mstring_copy_mbs(&entry->ae_uname, name); 1194 } 1195 1196 void 1197 archive_entry_copy_uname(struct archive_entry *entry, const char *name) 1198 { 1199 archive_mstring_copy_mbs(&entry->ae_uname, name); 1200 } 1201 1202 void 1203 archive_entry_copy_uname_w(struct archive_entry *entry, const wchar_t *name) 1204 { 1205 archive_mstring_copy_wcs(&entry->ae_uname, name); 1206 } 1207 1208 int 1209 archive_entry_update_uname_utf8(struct archive_entry *entry, const char *name) 1210 { 1211 if (archive_mstring_update_utf8(entry->archive, 1212 &entry->ae_uname, name) == 0) 1213 return (1); 1214 if (errno == ENOMEM) 1215 __archive_errx(1, "No memory"); 1216 return (0); 1217 } 1218 1219 int 1220 _archive_entry_copy_uname_l(struct archive_entry *entry, 1221 const char *name, size_t len, struct archive_string_conv *sc) 1222 { 1223 return (archive_mstring_copy_mbs_len_l(&entry->ae_uname, 1224 name, len, sc)); 1225 } 1226 1227 const void * 1228 archive_entry_mac_metadata(struct archive_entry *entry, size_t *s) 1229 { 1230 *s = entry->mac_metadata_size; 1231 return entry->mac_metadata; 1232 } 1233 1234 void 1235 archive_entry_copy_mac_metadata(struct archive_entry *entry, 1236 const void *p, size_t s) 1237 { 1238 free(entry->mac_metadata); 1239 if (p == NULL || s == 0) { 1240 entry->mac_metadata = NULL; 1241 entry->mac_metadata_size = 0; 1242 } else { 1243 entry->mac_metadata_size = s; 1244 entry->mac_metadata = malloc(s); 1245 if (entry->mac_metadata == NULL) 1246 abort(); 1247 memcpy(entry->mac_metadata, p, s); 1248 } 1249 } 1250 1251 /* 1252 * ACL management. The following would, of course, be a lot simpler 1253 * if: 1) the last draft of POSIX.1e were a really thorough and 1254 * complete standard that addressed the needs of ACL archiving and 2) 1255 * everyone followed it faithfully. Alas, neither is true, so the 1256 * following is a lot more complex than might seem necessary to the 1257 * uninitiated. 1258 */ 1259 1260 struct archive_acl * 1261 archive_entry_acl(struct archive_entry *entry) 1262 { 1263 return &entry->acl; 1264 } 1265 1266 void 1267 archive_entry_acl_clear(struct archive_entry *entry) 1268 { 1269 archive_acl_clear(&entry->acl); 1270 } 1271 1272 /* 1273 * Add a single ACL entry to the internal list of ACL data. 1274 */ 1275 int 1276 archive_entry_acl_add_entry(struct archive_entry *entry, 1277 int type, int permset, int tag, int id, const char *name) 1278 { 1279 return archive_acl_add_entry(&entry->acl, type, permset, tag, id, name); 1280 } 1281 1282 /* 1283 * As above, but with a wide-character name. 1284 */ 1285 int 1286 archive_entry_acl_add_entry_w(struct archive_entry *entry, 1287 int type, int permset, int tag, int id, const wchar_t *name) 1288 { 1289 return archive_acl_add_entry_w_len(&entry->acl, 1290 type, permset, tag, id, name, wcslen(name)); 1291 } 1292 1293 /* 1294 * Return a count of entries matching "want_type". 1295 */ 1296 int 1297 archive_entry_acl_count(struct archive_entry *entry, int want_type) 1298 { 1299 return archive_acl_count(&entry->acl, want_type); 1300 } 1301 1302 /* 1303 * Prepare for reading entries from the ACL data. Returns a count 1304 * of entries matching "want_type", or zero if there are no 1305 * non-extended ACL entries of that type. 1306 */ 1307 int 1308 archive_entry_acl_reset(struct archive_entry *entry, int want_type) 1309 { 1310 return archive_acl_reset(&entry->acl, want_type); 1311 } 1312 1313 /* 1314 * Return the next ACL entry in the list. Fake entries for the 1315 * standard permissions and include them in the returned list. 1316 */ 1317 int 1318 archive_entry_acl_next(struct archive_entry *entry, int want_type, int *type, 1319 int *permset, int *tag, int *id, const char **name) 1320 { 1321 int r; 1322 r = archive_acl_next(entry->archive, &entry->acl, want_type, type, 1323 permset, tag, id, name); 1324 if (r == ARCHIVE_FATAL && errno == ENOMEM) 1325 __archive_errx(1, "No memory"); 1326 return (r); 1327 } 1328 1329 /* 1330 * Generate a text version of the ACL. The flags parameter controls 1331 * the style of the generated ACL. 1332 */ 1333 const wchar_t * 1334 archive_entry_acl_text_w(struct archive_entry *entry, int flags) 1335 { 1336 const wchar_t *r; 1337 r = archive_acl_text_w(entry->archive, &entry->acl, flags); 1338 if (r == NULL && errno == ENOMEM) 1339 __archive_errx(1, "No memory"); 1340 return (r); 1341 } 1342 1343 const char * 1344 archive_entry_acl_text(struct archive_entry *entry, int flags) 1345 { 1346 const char *p; 1347 if (archive_acl_text_l(&entry->acl, flags, &p, NULL, NULL) != 0 1348 && errno == ENOMEM) 1349 __archive_errx(1, "No memory"); 1350 return (p); 1351 } 1352 1353 int 1354 _archive_entry_acl_text_l(struct archive_entry *entry, int flags, 1355 const char **acl_text, size_t *len, struct archive_string_conv *sc) 1356 { 1357 return (archive_acl_text_l(&entry->acl, flags, acl_text, len, sc)); 1358 } 1359 1360 /* 1361 * Following code is modified from UC Berkeley sources, and 1362 * is subject to the following copyright notice. 1363 */ 1364 1365 /*- 1366 * Copyright (c) 1993 1367 * The Regents of the University of California. All rights reserved. 1368 * 1369 * Redistribution and use in source and binary forms, with or without 1370 * modification, are permitted provided that the following conditions 1371 * are met: 1372 * 1. Redistributions of source code must retain the above copyright 1373 * notice, this list of conditions and the following disclaimer. 1374 * 2. Redistributions in binary form must reproduce the above copyright 1375 * notice, this list of conditions and the following disclaimer in the 1376 * documentation and/or other materials provided with the distribution. 1377 * 4. Neither the name of the University nor the names of its contributors 1378 * may be used to endorse or promote products derived from this software 1379 * without specific prior written permission. 1380 * 1381 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 1382 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1383 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1384 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 1385 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1386 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 1387 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 1388 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 1389 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 1390 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 1391 * SUCH DAMAGE. 1392 */ 1393 1394 static struct flag { 1395 const char *name; 1396 const wchar_t *wname; 1397 unsigned long set; 1398 unsigned long clear; 1399 } flags[] = { 1400 /* Preferred (shorter) names per flag first, all prefixed by "no" */ 1401 #ifdef SF_APPEND 1402 { "nosappnd", L"nosappnd", SF_APPEND, 0 }, 1403 { "nosappend", L"nosappend", SF_APPEND, 0 }, 1404 #endif 1405 #ifdef EXT2_APPEND_FL /* 'a' */ 1406 { "nosappnd", L"nosappnd", EXT2_APPEND_FL, 0 }, 1407 { "nosappend", L"nosappend", EXT2_APPEND_FL, 0 }, 1408 #endif 1409 #ifdef SF_ARCHIVED 1410 { "noarch", L"noarch", SF_ARCHIVED, 0 }, 1411 { "noarchived", L"noarchived", SF_ARCHIVED, 0 }, 1412 #endif 1413 #ifdef SF_IMMUTABLE 1414 { "noschg", L"noschg", SF_IMMUTABLE, 0 }, 1415 { "noschange", L"noschange", SF_IMMUTABLE, 0 }, 1416 { "nosimmutable", L"nosimmutable", SF_IMMUTABLE, 0 }, 1417 #endif 1418 #ifdef EXT2_IMMUTABLE_FL /* 'i' */ 1419 { "noschg", L"noschg", EXT2_IMMUTABLE_FL, 0 }, 1420 { "noschange", L"noschange", EXT2_IMMUTABLE_FL, 0 }, 1421 { "nosimmutable", L"nosimmutable", EXT2_IMMUTABLE_FL, 0 }, 1422 #endif 1423 #ifdef SF_NOUNLINK 1424 { "nosunlnk", L"nosunlnk", SF_NOUNLINK, 0 }, 1425 { "nosunlink", L"nosunlink", SF_NOUNLINK, 0 }, 1426 #endif 1427 #ifdef SF_SNAPSHOT 1428 { "nosnapshot", L"nosnapshot", SF_SNAPSHOT, 0 }, 1429 #endif 1430 #ifdef UF_APPEND 1431 { "nouappnd", L"nouappnd", UF_APPEND, 0 }, 1432 { "nouappend", L"nouappend", UF_APPEND, 0 }, 1433 #endif 1434 #ifdef UF_IMMUTABLE 1435 { "nouchg", L"nouchg", UF_IMMUTABLE, 0 }, 1436 { "nouchange", L"nouchange", UF_IMMUTABLE, 0 }, 1437 { "nouimmutable", L"nouimmutable", UF_IMMUTABLE, 0 }, 1438 #endif 1439 #ifdef UF_NODUMP 1440 { "nodump", L"nodump", 0, UF_NODUMP}, 1441 #endif 1442 #ifdef EXT2_NODUMP_FL /* 'd' */ 1443 { "nodump", L"nodump", 0, EXT2_NODUMP_FL}, 1444 #endif 1445 #ifdef UF_OPAQUE 1446 { "noopaque", L"noopaque", UF_OPAQUE, 0 }, 1447 #endif 1448 #ifdef UF_NOUNLINK 1449 { "nouunlnk", L"nouunlnk", UF_NOUNLINK, 0 }, 1450 { "nouunlink", L"nouunlink", UF_NOUNLINK, 0 }, 1451 #endif 1452 #ifdef UF_COMPRESSED 1453 { "nocompressed",L"nocompressed", UF_COMPRESSED, 0 }, 1454 #endif 1455 #ifdef EXT2_UNRM_FL 1456 { "nouunlink", L"nouunlink", EXT2_UNRM_FL, 0}, 1457 #endif 1458 1459 #ifdef EXT2_BTREE_FL 1460 { "nobtree", L"nobtree", EXT2_BTREE_FL, 0 }, 1461 #endif 1462 1463 #ifdef EXT2_ECOMPR_FL 1464 { "nocomperr", L"nocomperr", EXT2_ECOMPR_FL, 0 }, 1465 #endif 1466 1467 #ifdef EXT2_COMPR_FL /* 'c' */ 1468 { "nocompress", L"nocompress", EXT2_COMPR_FL, 0 }, 1469 #endif 1470 1471 #ifdef EXT2_NOATIME_FL /* 'A' */ 1472 { "noatime", L"noatime", 0, EXT2_NOATIME_FL}, 1473 #endif 1474 1475 #ifdef EXT2_DIRTY_FL 1476 { "nocompdirty",L"nocompdirty", EXT2_DIRTY_FL, 0}, 1477 #endif 1478 1479 #ifdef EXT2_COMPRBLK_FL 1480 #ifdef EXT2_NOCOMPR_FL 1481 { "nocomprblk", L"nocomprblk", EXT2_COMPRBLK_FL, EXT2_NOCOMPR_FL}, 1482 #else 1483 { "nocomprblk", L"nocomprblk", EXT2_COMPRBLK_FL, 0}, 1484 #endif 1485 #endif 1486 #ifdef EXT2_DIRSYNC_FL 1487 { "nodirsync", L"nodirsync", EXT2_DIRSYNC_FL, 0}, 1488 #endif 1489 #ifdef EXT2_INDEX_FL 1490 { "nohashidx", L"nohashidx", EXT2_INDEX_FL, 0}, 1491 #endif 1492 #ifdef EXT2_IMAGIC_FL 1493 { "noimagic", L"noimagic", EXT2_IMAGIC_FL, 0}, 1494 #endif 1495 #ifdef EXT3_JOURNAL_DATA_FL 1496 { "nojournal", L"nojournal", EXT3_JOURNAL_DATA_FL, 0}, 1497 #endif 1498 #ifdef EXT2_SECRM_FL 1499 { "nosecuredeletion",L"nosecuredeletion",EXT2_SECRM_FL, 0}, 1500 #endif 1501 #ifdef EXT2_SYNC_FL 1502 { "nosync", L"nosync", EXT2_SYNC_FL, 0}, 1503 #endif 1504 #ifdef EXT2_NOTAIL_FL 1505 { "notail", L"notail", 0, EXT2_NOTAIL_FL}, 1506 #endif 1507 #ifdef EXT2_TOPDIR_FL 1508 { "notopdir", L"notopdir", EXT2_TOPDIR_FL, 0}, 1509 #endif 1510 #ifdef EXT2_RESERVED_FL 1511 { "noreserved", L"noreserved", EXT2_RESERVED_FL, 0}, 1512 #endif 1513 1514 { NULL, NULL, 0, 0 } 1515 }; 1516 1517 /* 1518 * fflagstostr -- 1519 * Convert file flags to a comma-separated string. If no flags 1520 * are set, return the empty string. 1521 */ 1522 static char * 1523 ae_fflagstostr(unsigned long bitset, unsigned long bitclear) 1524 { 1525 char *string, *dp; 1526 const char *sp; 1527 unsigned long bits; 1528 struct flag *flag; 1529 size_t length; 1530 1531 bits = bitset | bitclear; 1532 length = 0; 1533 for (flag = flags; flag->name != NULL; flag++) 1534 if (bits & (flag->set | flag->clear)) { 1535 length += strlen(flag->name) + 1; 1536 bits &= ~(flag->set | flag->clear); 1537 } 1538 1539 if (length == 0) 1540 return (NULL); 1541 string = (char *)malloc(length); 1542 if (string == NULL) 1543 return (NULL); 1544 1545 dp = string; 1546 for (flag = flags; flag->name != NULL; flag++) { 1547 if (bitset & flag->set || bitclear & flag->clear) { 1548 sp = flag->name + 2; 1549 } else if (bitset & flag->clear || bitclear & flag->set) { 1550 sp = flag->name; 1551 } else 1552 continue; 1553 bitset &= ~(flag->set | flag->clear); 1554 bitclear &= ~(flag->set | flag->clear); 1555 if (dp > string) 1556 *dp++ = ','; 1557 while ((*dp++ = *sp++) != '\0') 1558 ; 1559 dp--; 1560 } 1561 1562 *dp = '\0'; 1563 return (string); 1564 } 1565 1566 /* 1567 * strtofflags -- 1568 * Take string of arguments and return file flags. This 1569 * version works a little differently than strtofflags(3). 1570 * In particular, it always tests every token, skipping any 1571 * unrecognized tokens. It returns a pointer to the first 1572 * unrecognized token, or NULL if every token was recognized. 1573 * This version is also const-correct and does not modify the 1574 * provided string. 1575 */ 1576 static const char * 1577 ae_strtofflags(const char *s, unsigned long *setp, unsigned long *clrp) 1578 { 1579 const char *start, *end; 1580 struct flag *flag; 1581 unsigned long set, clear; 1582 const char *failed; 1583 1584 set = clear = 0; 1585 start = s; 1586 failed = NULL; 1587 /* Find start of first token. */ 1588 while (*start == '\t' || *start == ' ' || *start == ',') 1589 start++; 1590 while (*start != '\0') { 1591 /* Locate end of token. */ 1592 end = start; 1593 while (*end != '\0' && *end != '\t' && 1594 *end != ' ' && *end != ',') 1595 end++; 1596 for (flag = flags; flag->name != NULL; flag++) { 1597 if (memcmp(start, flag->name, end - start) == 0) { 1598 /* Matched "noXXXX", so reverse the sense. */ 1599 clear |= flag->set; 1600 set |= flag->clear; 1601 break; 1602 } else if (memcmp(start, flag->name + 2, end - start) 1603 == 0) { 1604 /* Matched "XXXX", so don't reverse. */ 1605 set |= flag->set; 1606 clear |= flag->clear; 1607 break; 1608 } 1609 } 1610 /* Ignore unknown flag names. */ 1611 if (flag->name == NULL && failed == NULL) 1612 failed = start; 1613 1614 /* Find start of next token. */ 1615 start = end; 1616 while (*start == '\t' || *start == ' ' || *start == ',') 1617 start++; 1618 1619 } 1620 1621 if (setp) 1622 *setp = set; 1623 if (clrp) 1624 *clrp = clear; 1625 1626 /* Return location of first failure. */ 1627 return (failed); 1628 } 1629 1630 /* 1631 * wcstofflags -- 1632 * Take string of arguments and return file flags. This 1633 * version works a little differently than strtofflags(3). 1634 * In particular, it always tests every token, skipping any 1635 * unrecognized tokens. It returns a pointer to the first 1636 * unrecognized token, or NULL if every token was recognized. 1637 * This version is also const-correct and does not modify the 1638 * provided string. 1639 */ 1640 static const wchar_t * 1641 ae_wcstofflags(const wchar_t *s, unsigned long *setp, unsigned long *clrp) 1642 { 1643 const wchar_t *start, *end; 1644 struct flag *flag; 1645 unsigned long set, clear; 1646 const wchar_t *failed; 1647 1648 set = clear = 0; 1649 start = s; 1650 failed = NULL; 1651 /* Find start of first token. */ 1652 while (*start == L'\t' || *start == L' ' || *start == L',') 1653 start++; 1654 while (*start != L'\0') { 1655 /* Locate end of token. */ 1656 end = start; 1657 while (*end != L'\0' && *end != L'\t' && 1658 *end != L' ' && *end != L',') 1659 end++; 1660 for (flag = flags; flag->wname != NULL; flag++) { 1661 if (wmemcmp(start, flag->wname, end - start) == 0) { 1662 /* Matched "noXXXX", so reverse the sense. */ 1663 clear |= flag->set; 1664 set |= flag->clear; 1665 break; 1666 } else if (wmemcmp(start, flag->wname + 2, end - start) 1667 == 0) { 1668 /* Matched "XXXX", so don't reverse. */ 1669 set |= flag->set; 1670 clear |= flag->clear; 1671 break; 1672 } 1673 } 1674 /* Ignore unknown flag names. */ 1675 if (flag->wname == NULL && failed == NULL) 1676 failed = start; 1677 1678 /* Find start of next token. */ 1679 start = end; 1680 while (*start == L'\t' || *start == L' ' || *start == L',') 1681 start++; 1682 1683 } 1684 1685 if (setp) 1686 *setp = set; 1687 if (clrp) 1688 *clrp = clear; 1689 1690 /* Return location of first failure. */ 1691 return (failed); 1692 } 1693 1694 1695 #ifdef TEST 1696 #include <stdio.h> 1697 int 1698 main(int argc, char **argv) 1699 { 1700 struct archive_entry *entry = archive_entry_new(); 1701 unsigned long set, clear; 1702 const wchar_t *remainder; 1703 1704 remainder = archive_entry_copy_fflags_text_w(entry, L"nosappnd dump archive,,,,,,,"); 1705 archive_entry_fflags(entry, &set, &clear); 1706 1707 wprintf(L"set=0x%lX clear=0x%lX remainder='%ls'\n", set, clear, remainder); 1708 1709 wprintf(L"new flags='%s'\n", archive_entry_fflags_text(entry)); 1710 return (0); 1711 } 1712 #endif 1713