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