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_LIMITS_H 43 #include <limits.h> 44 #endif 45 #ifdef HAVE_LINUX_FS_H 46 #include <linux/fs.h> /* for Linux file flags */ 47 #endif 48 /* 49 * Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h. 50 * As the include guards don't agree, the order of include is important. 51 */ 52 #ifdef HAVE_LINUX_EXT2_FS_H 53 #include <linux/ext2_fs.h> /* for Linux file flags */ 54 #endif 55 #if defined(HAVE_EXT2FS_EXT2_FS_H) && !defined(__CYGWIN__) 56 #include <ext2fs/ext2_fs.h> /* for Linux file flags */ 57 #endif 58 #include <stddef.h> 59 #include <stdio.h> 60 #ifdef HAVE_STDLIB_H 61 #include <stdlib.h> 62 #endif 63 #ifdef HAVE_STRING_H 64 #include <string.h> 65 #endif 66 #ifdef HAVE_WCHAR_H 67 #include <wchar.h> 68 #endif 69 70 #include "archive.h" 71 #include "archive_entry.h" 72 #include "archive_private.h" 73 #include "archive_entry_private.h" 74 75 #undef max 76 #define max(a, b) ((a)>(b)?(a):(b)) 77 78 #if !defined(HAVE_MAJOR) && !defined(major) 79 /* Replacement for major/minor/makedev. */ 80 #define major(x) ((int)(0x00ff & ((x) >> 8))) 81 #define minor(x) ((int)(0xffff00ff & (x))) 82 #define makedev(maj,min) ((0xff00 & ((maj)<<8)) | (0xffff00ff & (min))) 83 #endif 84 85 /* Play games to come up with a suitable makedev() definition. */ 86 #ifdef __QNXNTO__ 87 /* QNX. <sigh> */ 88 #include <sys/netmgr.h> 89 #define ae_makedev(maj, min) makedev(ND_LOCAL_NODE, (maj), (min)) 90 #elif defined makedev 91 /* There's a "makedev" macro. */ 92 #define ae_makedev(maj, min) makedev((maj), (min)) 93 #elif defined mkdev || ((defined _WIN32 || defined __WIN32__) && !defined(__CYGWIN__)) 94 /* Windows. <sigh> */ 95 #define ae_makedev(maj, min) mkdev((maj), (min)) 96 #else 97 /* There's a "makedev" function. */ 98 #define ae_makedev(maj, min) makedev((maj), (min)) 99 #endif 100 101 static void aes_clean(struct aes *); 102 static void aes_copy(struct aes *dest, struct aes *src); 103 static const char * aes_get_mbs(struct aes *); 104 static const wchar_t * aes_get_wcs(struct aes *); 105 static int aes_set_mbs(struct aes *, const char *mbs); 106 static int aes_copy_mbs(struct aes *, const char *mbs); 107 /* static void aes_set_wcs(struct aes *, const wchar_t *wcs); */ 108 static int aes_copy_wcs(struct aes *, const wchar_t *wcs); 109 static int aes_copy_wcs_len(struct aes *, const wchar_t *wcs, size_t); 110 111 static char * ae_fflagstostr(unsigned long bitset, unsigned long bitclear); 112 static const wchar_t *ae_wcstofflags(const wchar_t *stringp, 113 unsigned long *setp, unsigned long *clrp); 114 static const char *ae_strtofflags(const char *stringp, 115 unsigned long *setp, unsigned long *clrp); 116 static void append_entry_w(wchar_t **wp, const wchar_t *prefix, int tag, 117 const wchar_t *wname, int perm, int id); 118 static void append_id_w(wchar_t **wp, int id); 119 120 static int acl_special(struct archive_entry *entry, 121 int type, int permset, int tag); 122 static struct ae_acl *acl_new_entry(struct archive_entry *entry, 123 int type, int permset, int tag, int id); 124 static int isint_w(const wchar_t *start, const wchar_t *end, int *result); 125 static int ismode_w(const wchar_t *start, const wchar_t *end, int *result); 126 static void next_field_w(const wchar_t **wp, const wchar_t **start, 127 const wchar_t **end, wchar_t *sep); 128 static int prefix_w(const wchar_t *start, const wchar_t *end, 129 const wchar_t *test); 130 static void 131 archive_entry_acl_add_entry_w_len(struct archive_entry *entry, int type, 132 int permset, int tag, int id, const wchar_t *name, size_t); 133 134 135 #ifndef HAVE_WCSCPY 136 static wchar_t * wcscpy(wchar_t *s1, const wchar_t *s2) 137 { 138 wchar_t *dest = s1; 139 while ((*s1 = *s2) != L'\0') 140 ++s1, ++s2; 141 return dest; 142 } 143 #endif 144 #ifndef HAVE_WCSLEN 145 static size_t wcslen(const wchar_t *s) 146 { 147 const wchar_t *p = s; 148 while (*p != L'\0') 149 ++p; 150 return p - s; 151 } 152 #endif 153 #ifndef HAVE_WMEMCMP 154 /* Good enough for simple equality testing, but not for sorting. */ 155 #define wmemcmp(a,b,i) memcmp((a), (b), (i) * sizeof(wchar_t)) 156 #endif 157 #ifndef HAVE_WMEMCPY 158 #define wmemcpy(a,b,i) (wchar_t *)memcpy((a), (b), (i) * sizeof(wchar_t)) 159 #endif 160 161 static void 162 aes_clean(struct aes *aes) 163 { 164 if (aes->aes_wcs) { 165 free((wchar_t *)(uintptr_t)aes->aes_wcs); 166 aes->aes_wcs = NULL; 167 } 168 archive_string_free(&(aes->aes_mbs)); 169 archive_string_free(&(aes->aes_utf8)); 170 aes->aes_set = 0; 171 } 172 173 static void 174 aes_copy(struct aes *dest, struct aes *src) 175 { 176 wchar_t *wp; 177 178 dest->aes_set = src->aes_set; 179 archive_string_copy(&(dest->aes_mbs), &(src->aes_mbs)); 180 archive_string_copy(&(dest->aes_utf8), &(src->aes_utf8)); 181 182 if (src->aes_wcs != NULL) { 183 wp = (wchar_t *)malloc((wcslen(src->aes_wcs) + 1) 184 * sizeof(wchar_t)); 185 if (wp == NULL) 186 __archive_errx(1, "No memory for aes_copy()"); 187 wcscpy(wp, src->aes_wcs); 188 dest->aes_wcs = wp; 189 } 190 } 191 192 static const char * 193 aes_get_utf8(struct aes *aes) 194 { 195 if (aes->aes_set & AES_SET_UTF8) 196 return (aes->aes_utf8.s); 197 if ((aes->aes_set & AES_SET_WCS) 198 && archive_strappend_w_utf8(&(aes->aes_utf8), aes->aes_wcs) != NULL) { 199 aes->aes_set |= AES_SET_UTF8; 200 return (aes->aes_utf8.s); 201 } 202 return (NULL); 203 } 204 205 static const char * 206 aes_get_mbs(struct aes *aes) 207 { 208 /* If we already have an MBS form, return that immediately. */ 209 if (aes->aes_set & AES_SET_MBS) 210 return (aes->aes_mbs.s); 211 /* If there's a WCS form, try converting with the native locale. */ 212 if ((aes->aes_set & AES_SET_WCS) 213 && archive_strappend_w_mbs(&(aes->aes_mbs), aes->aes_wcs) != NULL) { 214 aes->aes_set |= AES_SET_MBS; 215 return (aes->aes_mbs.s); 216 } 217 /* We'll use UTF-8 for MBS if all else fails. */ 218 return (aes_get_utf8(aes)); 219 } 220 221 static const wchar_t * 222 aes_get_wcs(struct aes *aes) 223 { 224 wchar_t *w; 225 size_t r; 226 227 /* Return WCS form if we already have it. */ 228 if (aes->aes_set & AES_SET_WCS) 229 return (aes->aes_wcs); 230 231 if (aes->aes_set & AES_SET_MBS) { 232 /* Try converting MBS to WCS using native locale. */ 233 /* 234 * No single byte will be more than one wide character, 235 * so this length estimate will always be big enough. 236 */ 237 size_t wcs_length = aes->aes_mbs.length; 238 239 w = (wchar_t *)malloc((wcs_length + 1) * sizeof(wchar_t)); 240 if (w == NULL) 241 __archive_errx(1, "No memory for aes_get_wcs()"); 242 r = mbstowcs(w, aes->aes_mbs.s, wcs_length); 243 if (r != (size_t)-1 && r != 0) { 244 w[r] = 0; 245 aes->aes_set |= AES_SET_WCS; 246 return (aes->aes_wcs = w); 247 } 248 free(w); 249 } 250 251 if (aes->aes_set & AES_SET_UTF8) { 252 /* Try converting UTF8 to WCS. */ 253 aes->aes_wcs = __archive_string_utf8_w(&(aes->aes_utf8)); 254 if (aes->aes_wcs != NULL) 255 aes->aes_set |= AES_SET_WCS; 256 return (aes->aes_wcs); 257 } 258 return (NULL); 259 } 260 261 static int 262 aes_set_mbs(struct aes *aes, const char *mbs) 263 { 264 return (aes_copy_mbs(aes, mbs)); 265 } 266 267 static int 268 aes_copy_mbs(struct aes *aes, const char *mbs) 269 { 270 if (mbs == NULL) { 271 aes->aes_set = 0; 272 return (0); 273 } 274 aes->aes_set = AES_SET_MBS; /* Only MBS form is set now. */ 275 archive_strcpy(&(aes->aes_mbs), mbs); 276 archive_string_empty(&(aes->aes_utf8)); 277 if (aes->aes_wcs) { 278 free((wchar_t *)(uintptr_t)aes->aes_wcs); 279 aes->aes_wcs = NULL; 280 } 281 return (0); 282 } 283 284 /* 285 * The 'update' form tries to proactively update all forms of 286 * this string (WCS and MBS) and returns an error if any of 287 * them fail. This is used by the 'pax' handler, for instance, 288 * to detect and report character-conversion failures early while 289 * still allowing clients to get potentially useful values from 290 * the more tolerant lazy conversions. (get_mbs and get_wcs will 291 * strive to give the user something useful, so you can get hopefully 292 * usable values even if some of the character conversions are failing.) 293 */ 294 static int 295 aes_update_utf8(struct aes *aes, const char *utf8) 296 { 297 if (utf8 == NULL) { 298 aes->aes_set = 0; 299 return (1); /* Succeeded in clearing everything. */ 300 } 301 302 /* Save the UTF8 string. */ 303 archive_strcpy(&(aes->aes_utf8), utf8); 304 305 /* Empty the mbs and wcs strings. */ 306 archive_string_empty(&(aes->aes_mbs)); 307 if (aes->aes_wcs) { 308 free((wchar_t *)(uintptr_t)aes->aes_wcs); 309 aes->aes_wcs = NULL; 310 } 311 312 aes->aes_set = AES_SET_UTF8; /* Only UTF8 is set now. */ 313 314 /* TODO: We should just do a direct UTF-8 to MBS conversion 315 * here. That would be faster, use less space, and give the 316 * same information. (If a UTF-8 to MBS conversion succeeds, 317 * then UTF-8->WCS and Unicode->MBS conversions will both 318 * succeed.) */ 319 320 /* Try converting UTF8 to WCS, return false on failure. */ 321 aes->aes_wcs = __archive_string_utf8_w(&(aes->aes_utf8)); 322 if (aes->aes_wcs == NULL) 323 return (0); 324 aes->aes_set = AES_SET_UTF8 | AES_SET_WCS; /* Both UTF8 and WCS set. */ 325 326 /* Try converting WCS to MBS, return false on failure. */ 327 if (archive_strappend_w_mbs(&(aes->aes_mbs), aes->aes_wcs) == NULL) 328 return (0); 329 aes->aes_set = AES_SET_UTF8 | AES_SET_WCS | AES_SET_MBS; 330 331 /* All conversions succeeded. */ 332 return (1); 333 } 334 335 static int 336 aes_copy_wcs(struct aes *aes, const wchar_t *wcs) 337 { 338 return aes_copy_wcs_len(aes, wcs, wcs == NULL ? 0 : wcslen(wcs)); 339 } 340 341 static int 342 aes_copy_wcs_len(struct aes *aes, const wchar_t *wcs, size_t len) 343 { 344 wchar_t *w; 345 346 if (wcs == NULL) { 347 aes->aes_set = 0; 348 return (0); 349 } 350 aes->aes_set = AES_SET_WCS; /* Only WCS form set. */ 351 archive_string_empty(&(aes->aes_mbs)); 352 archive_string_empty(&(aes->aes_utf8)); 353 if (aes->aes_wcs) { 354 free((wchar_t *)(uintptr_t)aes->aes_wcs); 355 aes->aes_wcs = NULL; 356 } 357 w = (wchar_t *)malloc((len + 1) * sizeof(wchar_t)); 358 if (w == NULL) 359 __archive_errx(1, "No memory for aes_copy_wcs()"); 360 wmemcpy(w, wcs, len); 361 w[len] = L'\0'; 362 aes->aes_wcs = w; 363 return (0); 364 } 365 366 /**************************************************************************** 367 * 368 * Public Interface 369 * 370 ****************************************************************************/ 371 372 struct archive_entry * 373 archive_entry_clear(struct archive_entry *entry) 374 { 375 if (entry == NULL) 376 return (NULL); 377 aes_clean(&entry->ae_fflags_text); 378 aes_clean(&entry->ae_gname); 379 aes_clean(&entry->ae_hardlink); 380 aes_clean(&entry->ae_pathname); 381 aes_clean(&entry->ae_sourcepath); 382 aes_clean(&entry->ae_symlink); 383 aes_clean(&entry->ae_uname); 384 archive_entry_acl_clear(entry); 385 archive_entry_xattr_clear(entry); 386 free(entry->stat); 387 memset(entry, 0, sizeof(*entry)); 388 return entry; 389 } 390 391 struct archive_entry * 392 archive_entry_clone(struct archive_entry *entry) 393 { 394 struct archive_entry *entry2; 395 struct ae_acl *ap, *ap2; 396 struct ae_xattr *xp; 397 398 /* Allocate new structure and copy over all of the fields. */ 399 entry2 = (struct archive_entry *)malloc(sizeof(*entry2)); 400 if (entry2 == NULL) 401 return (NULL); 402 memset(entry2, 0, sizeof(*entry2)); 403 entry2->ae_stat = entry->ae_stat; 404 entry2->ae_fflags_set = entry->ae_fflags_set; 405 entry2->ae_fflags_clear = entry->ae_fflags_clear; 406 407 aes_copy(&entry2->ae_fflags_text, &entry->ae_fflags_text); 408 aes_copy(&entry2->ae_gname, &entry->ae_gname); 409 aes_copy(&entry2->ae_hardlink, &entry->ae_hardlink); 410 aes_copy(&entry2->ae_pathname, &entry->ae_pathname); 411 aes_copy(&entry2->ae_sourcepath, &entry->ae_sourcepath); 412 aes_copy(&entry2->ae_symlink, &entry->ae_symlink); 413 entry2->ae_set = entry->ae_set; 414 aes_copy(&entry2->ae_uname, &entry->ae_uname); 415 416 /* Copy ACL data over. */ 417 ap = entry->acl_head; 418 while (ap != NULL) { 419 ap2 = acl_new_entry(entry2, 420 ap->type, ap->permset, ap->tag, ap->id); 421 if (ap2 != NULL) 422 aes_copy(&ap2->name, &ap->name); 423 ap = ap->next; 424 } 425 426 /* Copy xattr data over. */ 427 xp = entry->xattr_head; 428 while (xp != NULL) { 429 archive_entry_xattr_add_entry(entry2, 430 xp->name, xp->value, xp->size); 431 xp = xp->next; 432 } 433 434 return (entry2); 435 } 436 437 void 438 archive_entry_free(struct archive_entry *entry) 439 { 440 archive_entry_clear(entry); 441 free(entry); 442 } 443 444 struct archive_entry * 445 archive_entry_new(void) 446 { 447 struct archive_entry *entry; 448 449 entry = (struct archive_entry *)malloc(sizeof(*entry)); 450 if (entry == NULL) 451 return (NULL); 452 memset(entry, 0, sizeof(*entry)); 453 return (entry); 454 } 455 456 /* 457 * Functions for reading fields from an archive_entry. 458 */ 459 460 time_t 461 archive_entry_atime(struct archive_entry *entry) 462 { 463 return (entry->ae_stat.aest_atime); 464 } 465 466 long 467 archive_entry_atime_nsec(struct archive_entry *entry) 468 { 469 return (entry->ae_stat.aest_atime_nsec); 470 } 471 472 int 473 archive_entry_atime_is_set(struct archive_entry *entry) 474 { 475 return (entry->ae_set & AE_SET_ATIME); 476 } 477 478 time_t 479 archive_entry_birthtime(struct archive_entry *entry) 480 { 481 return (entry->ae_stat.aest_birthtime); 482 } 483 484 long 485 archive_entry_birthtime_nsec(struct archive_entry *entry) 486 { 487 return (entry->ae_stat.aest_birthtime_nsec); 488 } 489 490 int 491 archive_entry_birthtime_is_set(struct archive_entry *entry) 492 { 493 return (entry->ae_set & AE_SET_BIRTHTIME); 494 } 495 496 time_t 497 archive_entry_ctime(struct archive_entry *entry) 498 { 499 return (entry->ae_stat.aest_ctime); 500 } 501 502 int 503 archive_entry_ctime_is_set(struct archive_entry *entry) 504 { 505 return (entry->ae_set & AE_SET_CTIME); 506 } 507 508 long 509 archive_entry_ctime_nsec(struct archive_entry *entry) 510 { 511 return (entry->ae_stat.aest_ctime_nsec); 512 } 513 514 dev_t 515 archive_entry_dev(struct archive_entry *entry) 516 { 517 if (entry->ae_stat.aest_dev_is_broken_down) 518 return ae_makedev(entry->ae_stat.aest_devmajor, 519 entry->ae_stat.aest_devminor); 520 else 521 return (entry->ae_stat.aest_dev); 522 } 523 524 dev_t 525 archive_entry_devmajor(struct archive_entry *entry) 526 { 527 if (entry->ae_stat.aest_dev_is_broken_down) 528 return (entry->ae_stat.aest_devmajor); 529 else 530 return major(entry->ae_stat.aest_dev); 531 } 532 533 dev_t 534 archive_entry_devminor(struct archive_entry *entry) 535 { 536 if (entry->ae_stat.aest_dev_is_broken_down) 537 return (entry->ae_stat.aest_devminor); 538 else 539 return minor(entry->ae_stat.aest_dev); 540 } 541 542 mode_t 543 archive_entry_filetype(struct archive_entry *entry) 544 { 545 return (AE_IFMT & entry->ae_stat.aest_mode); 546 } 547 548 void 549 archive_entry_fflags(struct archive_entry *entry, 550 unsigned long *set, unsigned long *clear) 551 { 552 *set = entry->ae_fflags_set; 553 *clear = entry->ae_fflags_clear; 554 } 555 556 /* 557 * Note: if text was provided, this just returns that text. If you 558 * really need the text to be rebuilt in a canonical form, set the 559 * text, ask for the bitmaps, then set the bitmaps. (Setting the 560 * bitmaps clears any stored text.) This design is deliberate: if 561 * we're editing archives, we don't want to discard flags just because 562 * they aren't supported on the current system. The bitmap<->text 563 * conversions are platform-specific (see below). 564 */ 565 const char * 566 archive_entry_fflags_text(struct archive_entry *entry) 567 { 568 const char *f; 569 char *p; 570 571 f = aes_get_mbs(&entry->ae_fflags_text); 572 if (f != NULL) 573 return (f); 574 575 if (entry->ae_fflags_set == 0 && entry->ae_fflags_clear == 0) 576 return (NULL); 577 578 p = ae_fflagstostr(entry->ae_fflags_set, entry->ae_fflags_clear); 579 if (p == NULL) 580 return (NULL); 581 582 aes_copy_mbs(&entry->ae_fflags_text, p); 583 free(p); 584 f = aes_get_mbs(&entry->ae_fflags_text); 585 return (f); 586 } 587 588 gid_t 589 archive_entry_gid(struct archive_entry *entry) 590 { 591 return (entry->ae_stat.aest_gid); 592 } 593 594 const char * 595 archive_entry_gname(struct archive_entry *entry) 596 { 597 return (aes_get_mbs(&entry->ae_gname)); 598 } 599 600 const wchar_t * 601 archive_entry_gname_w(struct archive_entry *entry) 602 { 603 return (aes_get_wcs(&entry->ae_gname)); 604 } 605 606 const char * 607 archive_entry_hardlink(struct archive_entry *entry) 608 { 609 if (entry->ae_set & AE_SET_HARDLINK) 610 return (aes_get_mbs(&entry->ae_hardlink)); 611 return (NULL); 612 } 613 614 const wchar_t * 615 archive_entry_hardlink_w(struct archive_entry *entry) 616 { 617 if (entry->ae_set & AE_SET_HARDLINK) 618 return (aes_get_wcs(&entry->ae_hardlink)); 619 return (NULL); 620 } 621 622 ino_t 623 archive_entry_ino(struct archive_entry *entry) 624 { 625 return (entry->ae_stat.aest_ino); 626 } 627 628 int64_t 629 archive_entry_ino64(struct archive_entry *entry) 630 { 631 return (entry->ae_stat.aest_ino); 632 } 633 634 mode_t 635 archive_entry_mode(struct archive_entry *entry) 636 { 637 return (entry->ae_stat.aest_mode); 638 } 639 640 time_t 641 archive_entry_mtime(struct archive_entry *entry) 642 { 643 return (entry->ae_stat.aest_mtime); 644 } 645 646 long 647 archive_entry_mtime_nsec(struct archive_entry *entry) 648 { 649 return (entry->ae_stat.aest_mtime_nsec); 650 } 651 652 int 653 archive_entry_mtime_is_set(struct archive_entry *entry) 654 { 655 return (entry->ae_set & AE_SET_MTIME); 656 } 657 658 unsigned int 659 archive_entry_nlink(struct archive_entry *entry) 660 { 661 return (entry->ae_stat.aest_nlink); 662 } 663 664 const char * 665 archive_entry_pathname(struct archive_entry *entry) 666 { 667 return (aes_get_mbs(&entry->ae_pathname)); 668 } 669 670 const wchar_t * 671 archive_entry_pathname_w(struct archive_entry *entry) 672 { 673 return (aes_get_wcs(&entry->ae_pathname)); 674 } 675 676 dev_t 677 archive_entry_rdev(struct archive_entry *entry) 678 { 679 if (entry->ae_stat.aest_rdev_is_broken_down) 680 return ae_makedev(entry->ae_stat.aest_rdevmajor, 681 entry->ae_stat.aest_rdevminor); 682 else 683 return (entry->ae_stat.aest_rdev); 684 } 685 686 dev_t 687 archive_entry_rdevmajor(struct archive_entry *entry) 688 { 689 if (entry->ae_stat.aest_rdev_is_broken_down) 690 return (entry->ae_stat.aest_rdevmajor); 691 else 692 return major(entry->ae_stat.aest_rdev); 693 } 694 695 dev_t 696 archive_entry_rdevminor(struct archive_entry *entry) 697 { 698 if (entry->ae_stat.aest_rdev_is_broken_down) 699 return (entry->ae_stat.aest_rdevminor); 700 else 701 return minor(entry->ae_stat.aest_rdev); 702 } 703 704 int64_t 705 archive_entry_size(struct archive_entry *entry) 706 { 707 return (entry->ae_stat.aest_size); 708 } 709 710 int 711 archive_entry_size_is_set(struct archive_entry *entry) 712 { 713 return (entry->ae_set & AE_SET_SIZE); 714 } 715 716 const char * 717 archive_entry_sourcepath(struct archive_entry *entry) 718 { 719 return (aes_get_mbs(&entry->ae_sourcepath)); 720 } 721 722 const char * 723 archive_entry_symlink(struct archive_entry *entry) 724 { 725 if (entry->ae_set & AE_SET_SYMLINK) 726 return (aes_get_mbs(&entry->ae_symlink)); 727 return (NULL); 728 } 729 730 const wchar_t * 731 archive_entry_symlink_w(struct archive_entry *entry) 732 { 733 if (entry->ae_set & AE_SET_SYMLINK) 734 return (aes_get_wcs(&entry->ae_symlink)); 735 return (NULL); 736 } 737 738 uid_t 739 archive_entry_uid(struct archive_entry *entry) 740 { 741 return (entry->ae_stat.aest_uid); 742 } 743 744 const char * 745 archive_entry_uname(struct archive_entry *entry) 746 { 747 return (aes_get_mbs(&entry->ae_uname)); 748 } 749 750 const wchar_t * 751 archive_entry_uname_w(struct archive_entry *entry) 752 { 753 return (aes_get_wcs(&entry->ae_uname)); 754 } 755 756 /* 757 * Functions to set archive_entry properties. 758 */ 759 760 void 761 archive_entry_set_filetype(struct archive_entry *entry, unsigned int type) 762 { 763 entry->stat_valid = 0; 764 entry->ae_stat.aest_mode &= ~AE_IFMT; 765 entry->ae_stat.aest_mode |= AE_IFMT & type; 766 } 767 768 void 769 archive_entry_set_fflags(struct archive_entry *entry, 770 unsigned long set, unsigned long clear) 771 { 772 aes_clean(&entry->ae_fflags_text); 773 entry->ae_fflags_set = set; 774 entry->ae_fflags_clear = clear; 775 } 776 777 const char * 778 archive_entry_copy_fflags_text(struct archive_entry *entry, 779 const char *flags) 780 { 781 aes_copy_mbs(&entry->ae_fflags_text, flags); 782 return (ae_strtofflags(flags, 783 &entry->ae_fflags_set, &entry->ae_fflags_clear)); 784 } 785 786 const wchar_t * 787 archive_entry_copy_fflags_text_w(struct archive_entry *entry, 788 const wchar_t *flags) 789 { 790 aes_copy_wcs(&entry->ae_fflags_text, flags); 791 return (ae_wcstofflags(flags, 792 &entry->ae_fflags_set, &entry->ae_fflags_clear)); 793 } 794 795 void 796 archive_entry_set_gid(struct archive_entry *entry, gid_t g) 797 { 798 entry->stat_valid = 0; 799 entry->ae_stat.aest_gid = g; 800 } 801 802 void 803 archive_entry_set_gname(struct archive_entry *entry, const char *name) 804 { 805 aes_set_mbs(&entry->ae_gname, name); 806 } 807 808 void 809 archive_entry_copy_gname(struct archive_entry *entry, const char *name) 810 { 811 aes_copy_mbs(&entry->ae_gname, name); 812 } 813 814 void 815 archive_entry_copy_gname_w(struct archive_entry *entry, const wchar_t *name) 816 { 817 aes_copy_wcs(&entry->ae_gname, name); 818 } 819 820 int 821 archive_entry_update_gname_utf8(struct archive_entry *entry, const char *name) 822 { 823 return (aes_update_utf8(&entry->ae_gname, name)); 824 } 825 826 void 827 archive_entry_set_ino(struct archive_entry *entry, unsigned long ino) 828 { 829 entry->stat_valid = 0; 830 entry->ae_stat.aest_ino = ino; 831 } 832 833 void 834 archive_entry_set_ino64(struct archive_entry *entry, int64_t ino) 835 { 836 entry->stat_valid = 0; 837 entry->ae_stat.aest_ino = ino; 838 } 839 840 void 841 archive_entry_set_hardlink(struct archive_entry *entry, const char *target) 842 { 843 aes_set_mbs(&entry->ae_hardlink, target); 844 if (target != NULL) 845 entry->ae_set |= AE_SET_HARDLINK; 846 else 847 entry->ae_set &= ~AE_SET_HARDLINK; 848 } 849 850 void 851 archive_entry_copy_hardlink(struct archive_entry *entry, const char *target) 852 { 853 aes_copy_mbs(&entry->ae_hardlink, target); 854 if (target != NULL) 855 entry->ae_set |= AE_SET_HARDLINK; 856 else 857 entry->ae_set &= ~AE_SET_HARDLINK; 858 } 859 860 void 861 archive_entry_copy_hardlink_w(struct archive_entry *entry, const wchar_t *target) 862 { 863 aes_copy_wcs(&entry->ae_hardlink, target); 864 if (target != NULL) 865 entry->ae_set |= AE_SET_HARDLINK; 866 else 867 entry->ae_set &= ~AE_SET_HARDLINK; 868 } 869 870 int 871 archive_entry_update_hardlink_utf8(struct archive_entry *entry, const char *target) 872 { 873 if (target != NULL) 874 entry->ae_set |= AE_SET_HARDLINK; 875 else 876 entry->ae_set &= ~AE_SET_HARDLINK; 877 return (aes_update_utf8(&entry->ae_hardlink, target)); 878 } 879 880 void 881 archive_entry_set_atime(struct archive_entry *entry, time_t t, long ns) 882 { 883 entry->stat_valid = 0; 884 entry->ae_set |= AE_SET_ATIME; 885 entry->ae_stat.aest_atime = t; 886 entry->ae_stat.aest_atime_nsec = ns; 887 } 888 889 void 890 archive_entry_unset_atime(struct archive_entry *entry) 891 { 892 archive_entry_set_atime(entry, 0, 0); 893 entry->ae_set &= ~AE_SET_ATIME; 894 } 895 896 void 897 archive_entry_set_birthtime(struct archive_entry *entry, time_t m, long ns) 898 { 899 entry->stat_valid = 0; 900 entry->ae_set |= AE_SET_BIRTHTIME; 901 entry->ae_stat.aest_birthtime = m; 902 entry->ae_stat.aest_birthtime_nsec = ns; 903 } 904 905 void 906 archive_entry_unset_birthtime(struct archive_entry *entry) 907 { 908 archive_entry_set_birthtime(entry, 0, 0); 909 entry->ae_set &= ~AE_SET_BIRTHTIME; 910 } 911 912 void 913 archive_entry_set_ctime(struct archive_entry *entry, time_t t, long ns) 914 { 915 entry->stat_valid = 0; 916 entry->ae_set |= AE_SET_CTIME; 917 entry->ae_stat.aest_ctime = t; 918 entry->ae_stat.aest_ctime_nsec = ns; 919 } 920 921 void 922 archive_entry_unset_ctime(struct archive_entry *entry) 923 { 924 archive_entry_set_ctime(entry, 0, 0); 925 entry->ae_set &= ~AE_SET_CTIME; 926 } 927 928 void 929 archive_entry_set_dev(struct archive_entry *entry, dev_t d) 930 { 931 entry->stat_valid = 0; 932 entry->ae_stat.aest_dev_is_broken_down = 0; 933 entry->ae_stat.aest_dev = d; 934 } 935 936 void 937 archive_entry_set_devmajor(struct archive_entry *entry, dev_t m) 938 { 939 entry->stat_valid = 0; 940 entry->ae_stat.aest_dev_is_broken_down = 1; 941 entry->ae_stat.aest_devmajor = m; 942 } 943 944 void 945 archive_entry_set_devminor(struct archive_entry *entry, dev_t m) 946 { 947 entry->stat_valid = 0; 948 entry->ae_stat.aest_dev_is_broken_down = 1; 949 entry->ae_stat.aest_devminor = m; 950 } 951 952 /* Set symlink if symlink is already set, else set hardlink. */ 953 void 954 archive_entry_set_link(struct archive_entry *entry, const char *target) 955 { 956 if (entry->ae_set & AE_SET_SYMLINK) 957 aes_set_mbs(&entry->ae_symlink, target); 958 else 959 aes_set_mbs(&entry->ae_hardlink, target); 960 } 961 962 /* Set symlink if symlink is already set, else set hardlink. */ 963 void 964 archive_entry_copy_link(struct archive_entry *entry, const char *target) 965 { 966 if (entry->ae_set & AE_SET_SYMLINK) 967 aes_copy_mbs(&entry->ae_symlink, target); 968 else 969 aes_copy_mbs(&entry->ae_hardlink, target); 970 } 971 972 /* Set symlink if symlink is already set, else set hardlink. */ 973 void 974 archive_entry_copy_link_w(struct archive_entry *entry, const wchar_t *target) 975 { 976 if (entry->ae_set & AE_SET_SYMLINK) 977 aes_copy_wcs(&entry->ae_symlink, target); 978 else 979 aes_copy_wcs(&entry->ae_hardlink, target); 980 } 981 982 int 983 archive_entry_update_link_utf8(struct archive_entry *entry, const char *target) 984 { 985 if (entry->ae_set & AE_SET_SYMLINK) 986 return (aes_update_utf8(&entry->ae_symlink, target)); 987 else 988 return (aes_update_utf8(&entry->ae_hardlink, target)); 989 } 990 991 void 992 archive_entry_set_mode(struct archive_entry *entry, mode_t m) 993 { 994 entry->stat_valid = 0; 995 entry->ae_stat.aest_mode = m; 996 } 997 998 void 999 archive_entry_set_mtime(struct archive_entry *entry, time_t m, long ns) 1000 { 1001 entry->stat_valid = 0; 1002 entry->ae_set |= AE_SET_MTIME; 1003 entry->ae_stat.aest_mtime = m; 1004 entry->ae_stat.aest_mtime_nsec = ns; 1005 } 1006 1007 void 1008 archive_entry_unset_mtime(struct archive_entry *entry) 1009 { 1010 archive_entry_set_mtime(entry, 0, 0); 1011 entry->ae_set &= ~AE_SET_MTIME; 1012 } 1013 1014 void 1015 archive_entry_set_nlink(struct archive_entry *entry, unsigned int nlink) 1016 { 1017 entry->stat_valid = 0; 1018 entry->ae_stat.aest_nlink = nlink; 1019 } 1020 1021 void 1022 archive_entry_set_pathname(struct archive_entry *entry, const char *name) 1023 { 1024 aes_set_mbs(&entry->ae_pathname, name); 1025 } 1026 1027 void 1028 archive_entry_copy_pathname(struct archive_entry *entry, const char *name) 1029 { 1030 aes_copy_mbs(&entry->ae_pathname, name); 1031 } 1032 1033 void 1034 archive_entry_copy_pathname_w(struct archive_entry *entry, const wchar_t *name) 1035 { 1036 aes_copy_wcs(&entry->ae_pathname, name); 1037 } 1038 1039 int 1040 archive_entry_update_pathname_utf8(struct archive_entry *entry, const char *name) 1041 { 1042 return (aes_update_utf8(&entry->ae_pathname, name)); 1043 } 1044 1045 void 1046 archive_entry_set_perm(struct archive_entry *entry, mode_t p) 1047 { 1048 entry->stat_valid = 0; 1049 entry->ae_stat.aest_mode &= AE_IFMT; 1050 entry->ae_stat.aest_mode |= ~AE_IFMT & p; 1051 } 1052 1053 void 1054 archive_entry_set_rdev(struct archive_entry *entry, dev_t m) 1055 { 1056 entry->stat_valid = 0; 1057 entry->ae_stat.aest_rdev = m; 1058 entry->ae_stat.aest_rdev_is_broken_down = 0; 1059 } 1060 1061 void 1062 archive_entry_set_rdevmajor(struct archive_entry *entry, dev_t m) 1063 { 1064 entry->stat_valid = 0; 1065 entry->ae_stat.aest_rdev_is_broken_down = 1; 1066 entry->ae_stat.aest_rdevmajor = m; 1067 } 1068 1069 void 1070 archive_entry_set_rdevminor(struct archive_entry *entry, dev_t m) 1071 { 1072 entry->stat_valid = 0; 1073 entry->ae_stat.aest_rdev_is_broken_down = 1; 1074 entry->ae_stat.aest_rdevminor = m; 1075 } 1076 1077 void 1078 archive_entry_set_size(struct archive_entry *entry, int64_t s) 1079 { 1080 entry->stat_valid = 0; 1081 entry->ae_stat.aest_size = s; 1082 entry->ae_set |= AE_SET_SIZE; 1083 } 1084 1085 void 1086 archive_entry_unset_size(struct archive_entry *entry) 1087 { 1088 archive_entry_set_size(entry, 0); 1089 entry->ae_set &= ~AE_SET_SIZE; 1090 } 1091 1092 void 1093 archive_entry_copy_sourcepath(struct archive_entry *entry, const char *path) 1094 { 1095 aes_set_mbs(&entry->ae_sourcepath, path); 1096 } 1097 1098 void 1099 archive_entry_set_symlink(struct archive_entry *entry, const char *linkname) 1100 { 1101 aes_set_mbs(&entry->ae_symlink, linkname); 1102 if (linkname != NULL) 1103 entry->ae_set |= AE_SET_SYMLINK; 1104 else 1105 entry->ae_set &= ~AE_SET_SYMLINK; 1106 } 1107 1108 void 1109 archive_entry_copy_symlink(struct archive_entry *entry, const char *linkname) 1110 { 1111 aes_copy_mbs(&entry->ae_symlink, linkname); 1112 if (linkname != NULL) 1113 entry->ae_set |= AE_SET_SYMLINK; 1114 else 1115 entry->ae_set &= ~AE_SET_SYMLINK; 1116 } 1117 1118 void 1119 archive_entry_copy_symlink_w(struct archive_entry *entry, const wchar_t *linkname) 1120 { 1121 aes_copy_wcs(&entry->ae_symlink, linkname); 1122 if (linkname != NULL) 1123 entry->ae_set |= AE_SET_SYMLINK; 1124 else 1125 entry->ae_set &= ~AE_SET_SYMLINK; 1126 } 1127 1128 int 1129 archive_entry_update_symlink_utf8(struct archive_entry *entry, const char *linkname) 1130 { 1131 if (linkname != NULL) 1132 entry->ae_set |= AE_SET_SYMLINK; 1133 else 1134 entry->ae_set &= ~AE_SET_SYMLINK; 1135 return (aes_update_utf8(&entry->ae_symlink, linkname)); 1136 } 1137 1138 void 1139 archive_entry_set_uid(struct archive_entry *entry, uid_t u) 1140 { 1141 entry->stat_valid = 0; 1142 entry->ae_stat.aest_uid = u; 1143 } 1144 1145 void 1146 archive_entry_set_uname(struct archive_entry *entry, const char *name) 1147 { 1148 aes_set_mbs(&entry->ae_uname, name); 1149 } 1150 1151 void 1152 archive_entry_copy_uname(struct archive_entry *entry, const char *name) 1153 { 1154 aes_copy_mbs(&entry->ae_uname, name); 1155 } 1156 1157 void 1158 archive_entry_copy_uname_w(struct archive_entry *entry, const wchar_t *name) 1159 { 1160 aes_copy_wcs(&entry->ae_uname, name); 1161 } 1162 1163 int 1164 archive_entry_update_uname_utf8(struct archive_entry *entry, const char *name) 1165 { 1166 return (aes_update_utf8(&entry->ae_uname, name)); 1167 } 1168 1169 /* 1170 * ACL management. The following would, of course, be a lot simpler 1171 * if: 1) the last draft of POSIX.1e were a really thorough and 1172 * complete standard that addressed the needs of ACL archiving and 2) 1173 * everyone followed it faithfully. Alas, neither is true, so the 1174 * following is a lot more complex than might seem necessary to the 1175 * uninitiated. 1176 */ 1177 1178 void 1179 archive_entry_acl_clear(struct archive_entry *entry) 1180 { 1181 struct ae_acl *ap; 1182 1183 while (entry->acl_head != NULL) { 1184 ap = entry->acl_head->next; 1185 aes_clean(&entry->acl_head->name); 1186 free(entry->acl_head); 1187 entry->acl_head = ap; 1188 } 1189 if (entry->acl_text_w != NULL) { 1190 free(entry->acl_text_w); 1191 entry->acl_text_w = NULL; 1192 } 1193 entry->acl_p = NULL; 1194 entry->acl_state = 0; /* Not counting. */ 1195 } 1196 1197 /* 1198 * Add a single ACL entry to the internal list of ACL data. 1199 */ 1200 void 1201 archive_entry_acl_add_entry(struct archive_entry *entry, 1202 int type, int permset, int tag, int id, const char *name) 1203 { 1204 struct ae_acl *ap; 1205 1206 if (acl_special(entry, type, permset, tag) == 0) 1207 return; 1208 ap = acl_new_entry(entry, type, permset, tag, id); 1209 if (ap == NULL) { 1210 /* XXX Error XXX */ 1211 return; 1212 } 1213 if (name != NULL && *name != '\0') 1214 aes_copy_mbs(&ap->name, name); 1215 else 1216 aes_clean(&ap->name); 1217 } 1218 1219 /* 1220 * As above, but with a wide-character name. 1221 */ 1222 void 1223 archive_entry_acl_add_entry_w(struct archive_entry *entry, 1224 int type, int permset, int tag, int id, const wchar_t *name) 1225 { 1226 archive_entry_acl_add_entry_w_len(entry, type, permset, tag, id, name, wcslen(name)); 1227 } 1228 1229 static void 1230 archive_entry_acl_add_entry_w_len(struct archive_entry *entry, 1231 int type, int permset, int tag, int id, const wchar_t *name, size_t len) 1232 { 1233 struct ae_acl *ap; 1234 1235 if (acl_special(entry, type, permset, tag) == 0) 1236 return; 1237 ap = acl_new_entry(entry, type, permset, tag, id); 1238 if (ap == NULL) { 1239 /* XXX Error XXX */ 1240 return; 1241 } 1242 if (name != NULL && *name != L'\0' && len > 0) 1243 aes_copy_wcs_len(&ap->name, name, len); 1244 else 1245 aes_clean(&ap->name); 1246 } 1247 1248 /* 1249 * If this ACL entry is part of the standard POSIX permissions set, 1250 * store the permissions in the stat structure and return zero. 1251 */ 1252 static int 1253 acl_special(struct archive_entry *entry, int type, int permset, int tag) 1254 { 1255 if (type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS) { 1256 switch (tag) { 1257 case ARCHIVE_ENTRY_ACL_USER_OBJ: 1258 entry->ae_stat.aest_mode &= ~0700; 1259 entry->ae_stat.aest_mode |= (permset & 7) << 6; 1260 return (0); 1261 case ARCHIVE_ENTRY_ACL_GROUP_OBJ: 1262 entry->ae_stat.aest_mode &= ~0070; 1263 entry->ae_stat.aest_mode |= (permset & 7) << 3; 1264 return (0); 1265 case ARCHIVE_ENTRY_ACL_OTHER: 1266 entry->ae_stat.aest_mode &= ~0007; 1267 entry->ae_stat.aest_mode |= permset & 7; 1268 return (0); 1269 } 1270 } 1271 return (1); 1272 } 1273 1274 /* 1275 * Allocate and populate a new ACL entry with everything but the 1276 * name. 1277 */ 1278 static struct ae_acl * 1279 acl_new_entry(struct archive_entry *entry, 1280 int type, int permset, int tag, int id) 1281 { 1282 struct ae_acl *ap, *aq; 1283 1284 if (type != ARCHIVE_ENTRY_ACL_TYPE_ACCESS && 1285 type != ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) 1286 return (NULL); 1287 if (entry->acl_text_w != NULL) { 1288 free(entry->acl_text_w); 1289 entry->acl_text_w = NULL; 1290 } 1291 1292 /* XXX TODO: More sanity-checks on the arguments XXX */ 1293 1294 /* If there's a matching entry already in the list, overwrite it. */ 1295 ap = entry->acl_head; 1296 aq = NULL; 1297 while (ap != NULL) { 1298 if (ap->type == type && ap->tag == tag && ap->id == id) { 1299 ap->permset = permset; 1300 return (ap); 1301 } 1302 aq = ap; 1303 ap = ap->next; 1304 } 1305 1306 /* Add a new entry to the end of the list. */ 1307 ap = (struct ae_acl *)malloc(sizeof(*ap)); 1308 if (ap == NULL) 1309 return (NULL); 1310 memset(ap, 0, sizeof(*ap)); 1311 if (aq == NULL) 1312 entry->acl_head = ap; 1313 else 1314 aq->next = ap; 1315 ap->type = type; 1316 ap->tag = tag; 1317 ap->id = id; 1318 ap->permset = permset; 1319 return (ap); 1320 } 1321 1322 /* 1323 * Return a count of entries matching "want_type". 1324 */ 1325 int 1326 archive_entry_acl_count(struct archive_entry *entry, int want_type) 1327 { 1328 int count; 1329 struct ae_acl *ap; 1330 1331 count = 0; 1332 ap = entry->acl_head; 1333 while (ap != NULL) { 1334 if ((ap->type & want_type) != 0) 1335 count++; 1336 ap = ap->next; 1337 } 1338 1339 if (count > 0 && ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0)) 1340 count += 3; 1341 return (count); 1342 } 1343 1344 /* 1345 * Prepare for reading entries from the ACL data. Returns a count 1346 * of entries matching "want_type", or zero if there are no 1347 * non-extended ACL entries of that type. 1348 */ 1349 int 1350 archive_entry_acl_reset(struct archive_entry *entry, int want_type) 1351 { 1352 int count, cutoff; 1353 1354 count = archive_entry_acl_count(entry, want_type); 1355 1356 /* 1357 * If the only entries are the three standard ones, 1358 * then don't return any ACL data. (In this case, 1359 * client can just use chmod(2) to set permissions.) 1360 */ 1361 if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) 1362 cutoff = 3; 1363 else 1364 cutoff = 0; 1365 1366 if (count > cutoff) 1367 entry->acl_state = ARCHIVE_ENTRY_ACL_USER_OBJ; 1368 else 1369 entry->acl_state = 0; 1370 entry->acl_p = entry->acl_head; 1371 return (count); 1372 } 1373 1374 /* 1375 * Return the next ACL entry in the list. Fake entries for the 1376 * standard permissions and include them in the returned list. 1377 */ 1378 1379 int 1380 archive_entry_acl_next(struct archive_entry *entry, int want_type, int *type, 1381 int *permset, int *tag, int *id, const char **name) 1382 { 1383 *name = NULL; 1384 *id = -1; 1385 1386 /* 1387 * The acl_state is either zero (no entries available), -1 1388 * (reading from list), or an entry type (retrieve that type 1389 * from ae_stat.aest_mode). 1390 */ 1391 if (entry->acl_state == 0) 1392 return (ARCHIVE_WARN); 1393 1394 /* The first three access entries are special. */ 1395 if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) { 1396 switch (entry->acl_state) { 1397 case ARCHIVE_ENTRY_ACL_USER_OBJ: 1398 *permset = (entry->ae_stat.aest_mode >> 6) & 7; 1399 *type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS; 1400 *tag = ARCHIVE_ENTRY_ACL_USER_OBJ; 1401 entry->acl_state = ARCHIVE_ENTRY_ACL_GROUP_OBJ; 1402 return (ARCHIVE_OK); 1403 case ARCHIVE_ENTRY_ACL_GROUP_OBJ: 1404 *permset = (entry->ae_stat.aest_mode >> 3) & 7; 1405 *type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS; 1406 *tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ; 1407 entry->acl_state = ARCHIVE_ENTRY_ACL_OTHER; 1408 return (ARCHIVE_OK); 1409 case ARCHIVE_ENTRY_ACL_OTHER: 1410 *permset = entry->ae_stat.aest_mode & 7; 1411 *type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS; 1412 *tag = ARCHIVE_ENTRY_ACL_OTHER; 1413 entry->acl_state = -1; 1414 entry->acl_p = entry->acl_head; 1415 return (ARCHIVE_OK); 1416 default: 1417 break; 1418 } 1419 } 1420 1421 while (entry->acl_p != NULL && (entry->acl_p->type & want_type) == 0) 1422 entry->acl_p = entry->acl_p->next; 1423 if (entry->acl_p == NULL) { 1424 entry->acl_state = 0; 1425 *type = 0; 1426 *permset = 0; 1427 *tag = 0; 1428 *id = -1; 1429 *name = NULL; 1430 return (ARCHIVE_EOF); /* End of ACL entries. */ 1431 } 1432 *type = entry->acl_p->type; 1433 *permset = entry->acl_p->permset; 1434 *tag = entry->acl_p->tag; 1435 *id = entry->acl_p->id; 1436 *name = aes_get_mbs(&entry->acl_p->name); 1437 entry->acl_p = entry->acl_p->next; 1438 return (ARCHIVE_OK); 1439 } 1440 1441 /* 1442 * Generate a text version of the ACL. The flags parameter controls 1443 * the style of the generated ACL. 1444 */ 1445 const wchar_t * 1446 archive_entry_acl_text_w(struct archive_entry *entry, int flags) 1447 { 1448 int count; 1449 size_t length; 1450 const wchar_t *wname; 1451 const wchar_t *prefix; 1452 wchar_t separator; 1453 struct ae_acl *ap; 1454 int id; 1455 wchar_t *wp; 1456 1457 if (entry->acl_text_w != NULL) { 1458 free (entry->acl_text_w); 1459 entry->acl_text_w = NULL; 1460 } 1461 1462 separator = L','; 1463 count = 0; 1464 length = 0; 1465 ap = entry->acl_head; 1466 while (ap != NULL) { 1467 if ((ap->type & flags) != 0) { 1468 count++; 1469 if ((flags & ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT) && 1470 (ap->type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT)) 1471 length += 8; /* "default:" */ 1472 length += 5; /* tag name */ 1473 length += 1; /* colon */ 1474 wname = aes_get_wcs(&ap->name); 1475 if (wname != NULL) 1476 length += wcslen(wname); 1477 else 1478 length += sizeof(uid_t) * 3 + 1; 1479 length ++; /* colon */ 1480 length += 3; /* rwx */ 1481 length += 1; /* colon */ 1482 length += max(sizeof(uid_t), sizeof(gid_t)) * 3 + 1; 1483 length ++; /* newline */ 1484 } 1485 ap = ap->next; 1486 } 1487 1488 if (count > 0 && ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0)) { 1489 length += 10; /* "user::rwx\n" */ 1490 length += 11; /* "group::rwx\n" */ 1491 length += 11; /* "other::rwx\n" */ 1492 } 1493 1494 if (count == 0) 1495 return (NULL); 1496 1497 /* Now, allocate the string and actually populate it. */ 1498 wp = entry->acl_text_w = (wchar_t *)malloc(length * sizeof(wchar_t)); 1499 if (wp == NULL) 1500 __archive_errx(1, "No memory to generate the text version of the ACL"); 1501 count = 0; 1502 if ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) { 1503 append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_USER_OBJ, NULL, 1504 entry->ae_stat.aest_mode & 0700, -1); 1505 *wp++ = ','; 1506 append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_GROUP_OBJ, NULL, 1507 entry->ae_stat.aest_mode & 0070, -1); 1508 *wp++ = ','; 1509 append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_OTHER, NULL, 1510 entry->ae_stat.aest_mode & 0007, -1); 1511 count += 3; 1512 1513 ap = entry->acl_head; 1514 while (ap != NULL) { 1515 if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) { 1516 wname = aes_get_wcs(&ap->name); 1517 *wp++ = separator; 1518 if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID) 1519 id = ap->id; 1520 else 1521 id = -1; 1522 append_entry_w(&wp, NULL, ap->tag, wname, 1523 ap->permset, id); 1524 count++; 1525 } 1526 ap = ap->next; 1527 } 1528 } 1529 1530 1531 if ((flags & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) { 1532 if (flags & ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT) 1533 prefix = L"default:"; 1534 else 1535 prefix = NULL; 1536 ap = entry->acl_head; 1537 count = 0; 1538 while (ap != NULL) { 1539 if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) { 1540 wname = aes_get_wcs(&ap->name); 1541 if (count > 0) 1542 *wp++ = separator; 1543 if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID) 1544 id = ap->id; 1545 else 1546 id = -1; 1547 append_entry_w(&wp, prefix, ap->tag, 1548 wname, ap->permset, id); 1549 count ++; 1550 } 1551 ap = ap->next; 1552 } 1553 } 1554 1555 return (entry->acl_text_w); 1556 } 1557 1558 static void 1559 append_id_w(wchar_t **wp, int id) 1560 { 1561 if (id < 0) 1562 id = 0; 1563 if (id > 9) 1564 append_id_w(wp, id / 10); 1565 *(*wp)++ = L"0123456789"[id % 10]; 1566 } 1567 1568 static void 1569 append_entry_w(wchar_t **wp, const wchar_t *prefix, int tag, 1570 const wchar_t *wname, int perm, int id) 1571 { 1572 if (prefix != NULL) { 1573 wcscpy(*wp, prefix); 1574 *wp += wcslen(*wp); 1575 } 1576 switch (tag) { 1577 case ARCHIVE_ENTRY_ACL_USER_OBJ: 1578 wname = NULL; 1579 id = -1; 1580 /* FALLTHROUGH */ 1581 case ARCHIVE_ENTRY_ACL_USER: 1582 wcscpy(*wp, L"user"); 1583 break; 1584 case ARCHIVE_ENTRY_ACL_GROUP_OBJ: 1585 wname = NULL; 1586 id = -1; 1587 /* FALLTHROUGH */ 1588 case ARCHIVE_ENTRY_ACL_GROUP: 1589 wcscpy(*wp, L"group"); 1590 break; 1591 case ARCHIVE_ENTRY_ACL_MASK: 1592 wcscpy(*wp, L"mask"); 1593 wname = NULL; 1594 id = -1; 1595 break; 1596 case ARCHIVE_ENTRY_ACL_OTHER: 1597 wcscpy(*wp, L"other"); 1598 wname = NULL; 1599 id = -1; 1600 break; 1601 } 1602 *wp += wcslen(*wp); 1603 *(*wp)++ = L':'; 1604 if (wname != NULL) { 1605 wcscpy(*wp, wname); 1606 *wp += wcslen(*wp); 1607 } else if (tag == ARCHIVE_ENTRY_ACL_USER 1608 || tag == ARCHIVE_ENTRY_ACL_GROUP) { 1609 append_id_w(wp, id); 1610 id = -1; 1611 } 1612 *(*wp)++ = L':'; 1613 *(*wp)++ = (perm & 0444) ? L'r' : L'-'; 1614 *(*wp)++ = (perm & 0222) ? L'w' : L'-'; 1615 *(*wp)++ = (perm & 0111) ? L'x' : L'-'; 1616 if (id != -1) { 1617 *(*wp)++ = L':'; 1618 append_id_w(wp, id); 1619 } 1620 **wp = L'\0'; 1621 } 1622 1623 /* 1624 * Parse a textual ACL. This automatically recognizes and supports 1625 * extensions described above. The 'type' argument is used to 1626 * indicate the type that should be used for any entries not 1627 * explicitly marked as "default:". 1628 */ 1629 int 1630 __archive_entry_acl_parse_w(struct archive_entry *entry, 1631 const wchar_t *text, int default_type) 1632 { 1633 struct { 1634 const wchar_t *start; 1635 const wchar_t *end; 1636 } field[4], name; 1637 1638 int fields, n; 1639 int type, tag, permset, id; 1640 wchar_t sep; 1641 1642 while (text != NULL && *text != L'\0') { 1643 /* 1644 * Parse the fields out of the next entry, 1645 * advance 'text' to start of next entry. 1646 */ 1647 fields = 0; 1648 do { 1649 const wchar_t *start, *end; 1650 next_field_w(&text, &start, &end, &sep); 1651 if (fields < 4) { 1652 field[fields].start = start; 1653 field[fields].end = end; 1654 } 1655 ++fields; 1656 } while (sep == L':'); 1657 1658 /* Set remaining fields to blank. */ 1659 for (n = fields; n < 4; ++n) 1660 field[n].start = field[n].end = NULL; 1661 1662 /* Check for a numeric ID in field 1 or 3. */ 1663 id = -1; 1664 isint_w(field[1].start, field[1].end, &id); 1665 /* Field 3 is optional. */ 1666 if (id == -1 && fields > 3) 1667 isint_w(field[3].start, field[3].end, &id); 1668 1669 /* 1670 * Solaris extension: "defaultuser::rwx" is the 1671 * default ACL corresponding to "user::rwx", etc. 1672 */ 1673 if (field[0].end - field[0].start > 7 1674 && wmemcmp(field[0].start, L"default", 7) == 0) { 1675 type = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT; 1676 field[0].start += 7; 1677 } else 1678 type = default_type; 1679 1680 name.start = name.end = NULL; 1681 if (prefix_w(field[0].start, field[0].end, L"user")) { 1682 if (!ismode_w(field[2].start, field[2].end, &permset)) 1683 return (ARCHIVE_WARN); 1684 if (id != -1 || field[1].start < field[1].end) { 1685 tag = ARCHIVE_ENTRY_ACL_USER; 1686 name = field[1]; 1687 } else 1688 tag = ARCHIVE_ENTRY_ACL_USER_OBJ; 1689 } else if (prefix_w(field[0].start, field[0].end, L"group")) { 1690 if (!ismode_w(field[2].start, field[2].end, &permset)) 1691 return (ARCHIVE_WARN); 1692 if (id != -1 || field[1].start < field[1].end) { 1693 tag = ARCHIVE_ENTRY_ACL_GROUP; 1694 name = field[1]; 1695 } else 1696 tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ; 1697 } else if (prefix_w(field[0].start, field[0].end, L"other")) { 1698 if (fields == 2 1699 && field[1].start < field[1].end 1700 && ismode_w(field[1].start, field[1].end, &permset)) { 1701 /* This is Solaris-style "other:rwx" */ 1702 } else if (fields == 3 1703 && field[1].start == field[1].end 1704 && field[2].start < field[2].end 1705 && ismode_w(field[2].start, field[2].end, &permset)) { 1706 /* This is FreeBSD-style "other::rwx" */ 1707 } else 1708 return (ARCHIVE_WARN); 1709 tag = ARCHIVE_ENTRY_ACL_OTHER; 1710 } else if (prefix_w(field[0].start, field[0].end, L"mask")) { 1711 if (fields == 2 1712 && field[1].start < field[1].end 1713 && ismode_w(field[1].start, field[1].end, &permset)) { 1714 /* This is Solaris-style "mask:rwx" */ 1715 } else if (fields == 3 1716 && field[1].start == field[1].end 1717 && field[2].start < field[2].end 1718 && ismode_w(field[2].start, field[2].end, &permset)) { 1719 /* This is FreeBSD-style "mask::rwx" */ 1720 } else 1721 return (ARCHIVE_WARN); 1722 tag = ARCHIVE_ENTRY_ACL_MASK; 1723 } else 1724 return (ARCHIVE_WARN); 1725 1726 /* Add entry to the internal list. */ 1727 archive_entry_acl_add_entry_w_len(entry, type, permset, 1728 tag, id, name.start, name.end - name.start); 1729 } 1730 return (ARCHIVE_OK); 1731 } 1732 1733 /* 1734 * Parse a string to a positive decimal integer. Returns true if 1735 * the string is non-empty and consists only of decimal digits, 1736 * false otherwise. 1737 */ 1738 static int 1739 isint_w(const wchar_t *start, const wchar_t *end, int *result) 1740 { 1741 int n = 0; 1742 if (start >= end) 1743 return (0); 1744 while (start < end) { 1745 if (*start < '0' || *start > '9') 1746 return (0); 1747 if (n > (INT_MAX / 10)) 1748 n = INT_MAX; 1749 else { 1750 n *= 10; 1751 n += *start - '0'; 1752 } 1753 start++; 1754 } 1755 *result = n; 1756 return (1); 1757 } 1758 1759 /* 1760 * Parse a string as a mode field. Returns true if 1761 * the string is non-empty and consists only of mode characters, 1762 * false otherwise. 1763 */ 1764 static int 1765 ismode_w(const wchar_t *start, const wchar_t *end, int *permset) 1766 { 1767 const wchar_t *p; 1768 1769 if (start >= end) 1770 return (0); 1771 p = start; 1772 *permset = 0; 1773 while (p < end) { 1774 switch (*p++) { 1775 case 'r': case 'R': 1776 *permset |= ARCHIVE_ENTRY_ACL_READ; 1777 break; 1778 case 'w': case 'W': 1779 *permset |= ARCHIVE_ENTRY_ACL_WRITE; 1780 break; 1781 case 'x': case 'X': 1782 *permset |= ARCHIVE_ENTRY_ACL_EXECUTE; 1783 break; 1784 case '-': 1785 break; 1786 default: 1787 return (0); 1788 } 1789 } 1790 return (1); 1791 } 1792 1793 /* 1794 * Match "[:whitespace:]*(.*)[:whitespace:]*[:,\n]". *wp is updated 1795 * to point to just after the separator. *start points to the first 1796 * character of the matched text and *end just after the last 1797 * character of the matched identifier. In particular *end - *start 1798 * is the length of the field body, not including leading or trailing 1799 * whitespace. 1800 */ 1801 static void 1802 next_field_w(const wchar_t **wp, const wchar_t **start, 1803 const wchar_t **end, wchar_t *sep) 1804 { 1805 /* Skip leading whitespace to find start of field. */ 1806 while (**wp == L' ' || **wp == L'\t' || **wp == L'\n') { 1807 (*wp)++; 1808 } 1809 *start = *wp; 1810 1811 /* Scan for the separator. */ 1812 while (**wp != L'\0' && **wp != L',' && **wp != L':' && 1813 **wp != L'\n') { 1814 (*wp)++; 1815 } 1816 *sep = **wp; 1817 1818 /* Trim trailing whitespace to locate end of field. */ 1819 *end = *wp - 1; 1820 while (**end == L' ' || **end == L'\t' || **end == L'\n') { 1821 (*end)--; 1822 } 1823 (*end)++; 1824 1825 /* Adjust scanner location. */ 1826 if (**wp != L'\0') 1827 (*wp)++; 1828 } 1829 1830 /* 1831 * Return true if the characters [start...end) are a prefix of 'test'. 1832 * This makes it easy to handle the obvious abbreviations: 'u' for 'user', etc. 1833 */ 1834 static int 1835 prefix_w(const wchar_t *start, const wchar_t *end, const wchar_t *test) 1836 { 1837 if (start == end) 1838 return (0); 1839 1840 if (*start++ != *test++) 1841 return (0); 1842 1843 while (start < end && *start++ == *test++) 1844 ; 1845 1846 if (start < end) 1847 return (0); 1848 1849 return (1); 1850 } 1851 1852 1853 /* 1854 * Following code is modified from UC Berkeley sources, and 1855 * is subject to the following copyright notice. 1856 */ 1857 1858 /*- 1859 * Copyright (c) 1993 1860 * The Regents of the University of California. All rights reserved. 1861 * 1862 * Redistribution and use in source and binary forms, with or without 1863 * modification, are permitted provided that the following conditions 1864 * are met: 1865 * 1. Redistributions of source code must retain the above copyright 1866 * notice, this list of conditions and the following disclaimer. 1867 * 2. Redistributions in binary form must reproduce the above copyright 1868 * notice, this list of conditions and the following disclaimer in the 1869 * documentation and/or other materials provided with the distribution. 1870 * 4. Neither the name of the University nor the names of its contributors 1871 * may be used to endorse or promote products derived from this software 1872 * without specific prior written permission. 1873 * 1874 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 1875 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1876 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1877 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 1878 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1879 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 1880 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 1881 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 1882 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 1883 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 1884 * SUCH DAMAGE. 1885 */ 1886 1887 static struct flag { 1888 const char *name; 1889 const wchar_t *wname; 1890 unsigned long set; 1891 unsigned long clear; 1892 } flags[] = { 1893 /* Preferred (shorter) names per flag first, all prefixed by "no" */ 1894 #ifdef SF_APPEND 1895 { "nosappnd", L"nosappnd", SF_APPEND, 0 }, 1896 { "nosappend", L"nosappend", SF_APPEND, 0 }, 1897 #endif 1898 #ifdef EXT2_APPEND_FL /* 'a' */ 1899 { "nosappnd", L"nosappnd", EXT2_APPEND_FL, 0 }, 1900 { "nosappend", L"nosappend", EXT2_APPEND_FL, 0 }, 1901 #endif 1902 #ifdef SF_ARCHIVED 1903 { "noarch", L"noarch", SF_ARCHIVED, 0 }, 1904 { "noarchived", L"noarchived", SF_ARCHIVED, 0 }, 1905 #endif 1906 #ifdef SF_IMMUTABLE 1907 { "noschg", L"noschg", SF_IMMUTABLE, 0 }, 1908 { "noschange", L"noschange", SF_IMMUTABLE, 0 }, 1909 { "nosimmutable", L"nosimmutable", SF_IMMUTABLE, 0 }, 1910 #endif 1911 #ifdef EXT2_IMMUTABLE_FL /* 'i' */ 1912 { "noschg", L"noschg", EXT2_IMMUTABLE_FL, 0 }, 1913 { "noschange", L"noschange", EXT2_IMMUTABLE_FL, 0 }, 1914 { "nosimmutable", L"nosimmutable", EXT2_IMMUTABLE_FL, 0 }, 1915 #endif 1916 #ifdef SF_NOUNLINK 1917 { "nosunlnk", L"nosunlnk", SF_NOUNLINK, 0 }, 1918 { "nosunlink", L"nosunlink", SF_NOUNLINK, 0 }, 1919 #endif 1920 #ifdef SF_SNAPSHOT 1921 { "nosnapshot", L"nosnapshot", SF_SNAPSHOT, 0 }, 1922 #endif 1923 #ifdef UF_APPEND 1924 { "nouappnd", L"nouappnd", UF_APPEND, 0 }, 1925 { "nouappend", L"nouappend", UF_APPEND, 0 }, 1926 #endif 1927 #ifdef UF_IMMUTABLE 1928 { "nouchg", L"nouchg", UF_IMMUTABLE, 0 }, 1929 { "nouchange", L"nouchange", UF_IMMUTABLE, 0 }, 1930 { "nouimmutable", L"nouimmutable", UF_IMMUTABLE, 0 }, 1931 #endif 1932 #ifdef UF_NODUMP 1933 { "nodump", L"nodump", 0, UF_NODUMP}, 1934 #endif 1935 #ifdef EXT2_NODUMP_FL /* 'd' */ 1936 { "nodump", L"nodump", 0, EXT2_NODUMP_FL}, 1937 #endif 1938 #ifdef UF_OPAQUE 1939 { "noopaque", L"noopaque", UF_OPAQUE, 0 }, 1940 #endif 1941 #ifdef UF_NOUNLINK 1942 { "nouunlnk", L"nouunlnk", UF_NOUNLINK, 0 }, 1943 { "nouunlink", L"nouunlink", UF_NOUNLINK, 0 }, 1944 #endif 1945 #ifdef EXT2_UNRM_FL 1946 { "nouunlink", L"nouunlink", EXT2_UNRM_FL, 0}, 1947 #endif 1948 1949 #ifdef EXT2_BTREE_FL 1950 { "nobtree", L"nobtree", EXT2_BTREE_FL, 0 }, 1951 #endif 1952 1953 #ifdef EXT2_ECOMPR_FL 1954 { "nocomperr", L"nocomperr", EXT2_ECOMPR_FL, 0 }, 1955 #endif 1956 1957 #ifdef EXT2_COMPR_FL /* 'c' */ 1958 { "nocompress", L"nocompress", EXT2_COMPR_FL, 0 }, 1959 #endif 1960 1961 #ifdef EXT2_NOATIME_FL /* 'A' */ 1962 { "noatime", L"noatime", 0, EXT2_NOATIME_FL}, 1963 #endif 1964 1965 #ifdef EXT2_DIRTY_FL 1966 { "nocompdirty",L"nocompdirty", EXT2_DIRTY_FL, 0}, 1967 #endif 1968 1969 #ifdef EXT2_COMPRBLK_FL 1970 #ifdef EXT2_NOCOMPR_FL 1971 { "nocomprblk", L"nocomprblk", EXT2_COMPRBLK_FL, EXT2_NOCOMPR_FL}, 1972 #else 1973 { "nocomprblk", L"nocomprblk", EXT2_COMPRBLK_FL, 0}, 1974 #endif 1975 #endif 1976 #ifdef EXT2_DIRSYNC_FL 1977 { "nodirsync", L"nodirsync", EXT2_DIRSYNC_FL, 0}, 1978 #endif 1979 #ifdef EXT2_INDEX_FL 1980 { "nohashidx", L"nohashidx", EXT2_INDEX_FL, 0}, 1981 #endif 1982 #ifdef EXT2_IMAGIC_FL 1983 { "noimagic", L"noimagic", EXT2_IMAGIC_FL, 0}, 1984 #endif 1985 #ifdef EXT3_JOURNAL_DATA_FL 1986 { "nojournal", L"nojournal", EXT3_JOURNAL_DATA_FL, 0}, 1987 #endif 1988 #ifdef EXT2_SECRM_FL 1989 { "nosecuredeletion",L"nosecuredeletion",EXT2_SECRM_FL, 0}, 1990 #endif 1991 #ifdef EXT2_SYNC_FL 1992 { "nosync", L"nosync", EXT2_SYNC_FL, 0}, 1993 #endif 1994 #ifdef EXT2_NOTAIL_FL 1995 { "notail", L"notail", 0, EXT2_NOTAIL_FL}, 1996 #endif 1997 #ifdef EXT2_TOPDIR_FL 1998 { "notopdir", L"notopdir", EXT2_TOPDIR_FL, 0}, 1999 #endif 2000 #ifdef EXT2_RESERVED_FL 2001 { "noreserved", L"noreserved", EXT2_RESERVED_FL, 0}, 2002 #endif 2003 2004 { NULL, NULL, 0, 0 } 2005 }; 2006 2007 /* 2008 * fflagstostr -- 2009 * Convert file flags to a comma-separated string. If no flags 2010 * are set, return the empty string. 2011 */ 2012 static char * 2013 ae_fflagstostr(unsigned long bitset, unsigned long bitclear) 2014 { 2015 char *string, *dp; 2016 const char *sp; 2017 unsigned long bits; 2018 struct flag *flag; 2019 size_t length; 2020 2021 bits = bitset | bitclear; 2022 length = 0; 2023 for (flag = flags; flag->name != NULL; flag++) 2024 if (bits & (flag->set | flag->clear)) { 2025 length += strlen(flag->name) + 1; 2026 bits &= ~(flag->set | flag->clear); 2027 } 2028 2029 if (length == 0) 2030 return (NULL); 2031 string = (char *)malloc(length); 2032 if (string == NULL) 2033 return (NULL); 2034 2035 dp = string; 2036 for (flag = flags; flag->name != NULL; flag++) { 2037 if (bitset & flag->set || bitclear & flag->clear) { 2038 sp = flag->name + 2; 2039 } else if (bitset & flag->clear || bitclear & flag->set) { 2040 sp = flag->name; 2041 } else 2042 continue; 2043 bitset &= ~(flag->set | flag->clear); 2044 bitclear &= ~(flag->set | flag->clear); 2045 if (dp > string) 2046 *dp++ = ','; 2047 while ((*dp++ = *sp++) != '\0') 2048 ; 2049 dp--; 2050 } 2051 2052 *dp = '\0'; 2053 return (string); 2054 } 2055 2056 /* 2057 * strtofflags -- 2058 * Take string of arguments and return file flags. This 2059 * version works a little differently than strtofflags(3). 2060 * In particular, it always tests every token, skipping any 2061 * unrecognized tokens. It returns a pointer to the first 2062 * unrecognized token, or NULL if every token was recognized. 2063 * This version is also const-correct and does not modify the 2064 * provided string. 2065 */ 2066 static const char * 2067 ae_strtofflags(const char *s, unsigned long *setp, unsigned long *clrp) 2068 { 2069 const char *start, *end; 2070 struct flag *flag; 2071 unsigned long set, clear; 2072 const char *failed; 2073 2074 set = clear = 0; 2075 start = s; 2076 failed = NULL; 2077 /* Find start of first token. */ 2078 while (*start == '\t' || *start == ' ' || *start == ',') 2079 start++; 2080 while (*start != '\0') { 2081 /* Locate end of token. */ 2082 end = start; 2083 while (*end != '\0' && *end != '\t' && 2084 *end != ' ' && *end != ',') 2085 end++; 2086 for (flag = flags; flag->name != NULL; flag++) { 2087 if (memcmp(start, flag->name, end - start) == 0) { 2088 /* Matched "noXXXX", so reverse the sense. */ 2089 clear |= flag->set; 2090 set |= flag->clear; 2091 break; 2092 } else if (memcmp(start, flag->name + 2, end - start) 2093 == 0) { 2094 /* Matched "XXXX", so don't reverse. */ 2095 set |= flag->set; 2096 clear |= flag->clear; 2097 break; 2098 } 2099 } 2100 /* Ignore unknown flag names. */ 2101 if (flag->name == NULL && failed == NULL) 2102 failed = start; 2103 2104 /* Find start of next token. */ 2105 start = end; 2106 while (*start == '\t' || *start == ' ' || *start == ',') 2107 start++; 2108 2109 } 2110 2111 if (setp) 2112 *setp = set; 2113 if (clrp) 2114 *clrp = clear; 2115 2116 /* Return location of first failure. */ 2117 return (failed); 2118 } 2119 2120 /* 2121 * wcstofflags -- 2122 * Take string of arguments and return file flags. This 2123 * version works a little differently than strtofflags(3). 2124 * In particular, it always tests every token, skipping any 2125 * unrecognized tokens. It returns a pointer to the first 2126 * unrecognized token, or NULL if every token was recognized. 2127 * This version is also const-correct and does not modify the 2128 * provided string. 2129 */ 2130 static const wchar_t * 2131 ae_wcstofflags(const wchar_t *s, unsigned long *setp, unsigned long *clrp) 2132 { 2133 const wchar_t *start, *end; 2134 struct flag *flag; 2135 unsigned long set, clear; 2136 const wchar_t *failed; 2137 2138 set = clear = 0; 2139 start = s; 2140 failed = NULL; 2141 /* Find start of first token. */ 2142 while (*start == L'\t' || *start == L' ' || *start == L',') 2143 start++; 2144 while (*start != L'\0') { 2145 /* Locate end of token. */ 2146 end = start; 2147 while (*end != L'\0' && *end != L'\t' && 2148 *end != L' ' && *end != L',') 2149 end++; 2150 for (flag = flags; flag->wname != NULL; flag++) { 2151 if (wmemcmp(start, flag->wname, end - start) == 0) { 2152 /* Matched "noXXXX", so reverse the sense. */ 2153 clear |= flag->set; 2154 set |= flag->clear; 2155 break; 2156 } else if (wmemcmp(start, flag->wname + 2, end - start) 2157 == 0) { 2158 /* Matched "XXXX", so don't reverse. */ 2159 set |= flag->set; 2160 clear |= flag->clear; 2161 break; 2162 } 2163 } 2164 /* Ignore unknown flag names. */ 2165 if (flag->wname == NULL && failed == NULL) 2166 failed = start; 2167 2168 /* Find start of next token. */ 2169 start = end; 2170 while (*start == L'\t' || *start == L' ' || *start == L',') 2171 start++; 2172 2173 } 2174 2175 if (setp) 2176 *setp = set; 2177 if (clrp) 2178 *clrp = clear; 2179 2180 /* Return location of first failure. */ 2181 return (failed); 2182 } 2183 2184 2185 #ifdef TEST 2186 #include <stdio.h> 2187 int 2188 main(int argc, char **argv) 2189 { 2190 struct archive_entry *entry = archive_entry_new(); 2191 unsigned long set, clear; 2192 const wchar_t *remainder; 2193 2194 remainder = archive_entry_copy_fflags_text_w(entry, L"nosappnd dump archive,,,,,,,"); 2195 archive_entry_fflags(entry, &set, &clear); 2196 2197 wprintf(L"set=0x%lX clear=0x%lX remainder='%ls'\n", set, clear, remainder); 2198 2199 wprintf(L"new flags='%s'\n", archive_entry_fflags_text(entry)); 2200 return (0); 2201 } 2202 #endif 2203