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 101static void aes_clean(struct aes *); 102static void aes_copy(struct aes *dest, struct aes *src); 103static const char * aes_get_mbs(struct aes *); 104static const wchar_t * aes_get_wcs(struct aes *); 105static int aes_set_mbs(struct aes *, const char *mbs); 106static int aes_copy_mbs(struct aes *, const char *mbs); 107/* static void aes_set_wcs(struct aes *, const wchar_t *wcs); */ 108static int aes_copy_wcs(struct aes *, const wchar_t *wcs); 109static int aes_copy_wcs_len(struct aes *, const wchar_t *wcs, size_t); 110 111static char * ae_fflagstostr(unsigned long bitset, unsigned long bitclear); 112static const wchar_t *ae_wcstofflags(const wchar_t *stringp, 113 unsigned long *setp, unsigned long *clrp); 114static const char *ae_strtofflags(const char *stringp, 115 unsigned long *setp, unsigned long *clrp); 116static void append_entry_w(wchar_t **wp, const wchar_t *prefix, int tag, 117 const wchar_t *wname, int perm, int id); 118static void append_id_w(wchar_t **wp, int id); 119 120static int acl_special(struct archive_entry *entry, 121 int type, int permset, int tag); 122static struct ae_acl *acl_new_entry(struct archive_entry *entry, 123 int type, int permset, int tag, int id); 124static int isint_w(const wchar_t *start, const wchar_t *end, int *result); 125static int ismode_w(const wchar_t *start, const wchar_t *end, int *result); 126static void next_field_w(const wchar_t **wp, const wchar_t **start, 127 const wchar_t **end, wchar_t *sep); 128static int prefix_w(const wchar_t *start, const wchar_t *end, 129 const wchar_t *test); 130static void 131archive_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 136static 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 145static 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 161static void 162aes_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 173static void 174aes_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 192static const char * 193aes_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 205static const char * 206aes_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 221static const wchar_t * 222aes_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 261static int 262aes_set_mbs(struct aes *aes, const char *mbs) 263{ 264 return (aes_copy_mbs(aes, mbs)); 265} 266 267static int 268aes_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 */ 294static int 295aes_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 335static int 336aes_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 341static int 342aes_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 372struct archive_entry * 373archive_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 391struct archive_entry * 392archive_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 437void 438archive_entry_free(struct archive_entry *entry) 439{ 440 archive_entry_clear(entry); 441 free(entry); 442} 443 444struct archive_entry * 445archive_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 460time_t 461archive_entry_atime(struct archive_entry *entry) 462{ 463 return (entry->ae_stat.aest_atime); 464} 465 466long 467archive_entry_atime_nsec(struct archive_entry *entry) 468{ 469 return (entry->ae_stat.aest_atime_nsec); 470} 471 472int 473archive_entry_atime_is_set(struct archive_entry *entry) 474{ 475 return (entry->ae_set & AE_SET_ATIME); 476} 477 478time_t 479archive_entry_birthtime(struct archive_entry *entry) 480{ 481 return (entry->ae_stat.aest_birthtime); 482} 483 484long 485archive_entry_birthtime_nsec(struct archive_entry *entry) 486{ 487 return (entry->ae_stat.aest_birthtime_nsec); 488} 489 490int 491archive_entry_birthtime_is_set(struct archive_entry *entry) 492{ 493 return (entry->ae_set & AE_SET_BIRTHTIME); 494} 495 496time_t 497archive_entry_ctime(struct archive_entry *entry) 498{ 499 return (entry->ae_stat.aest_ctime); 500} 501 502int 503archive_entry_ctime_is_set(struct archive_entry *entry) 504{ 505 return (entry->ae_set & AE_SET_CTIME); 506} 507 508long 509archive_entry_ctime_nsec(struct archive_entry *entry) 510{ 511 return (entry->ae_stat.aest_ctime_nsec); 512} 513 514dev_t 515archive_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 524dev_t 525archive_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 533dev_t 534archive_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 542mode_t 543archive_entry_filetype(struct archive_entry *entry) 544{ 545 return (AE_IFMT & entry->ae_stat.aest_mode); 546} 547 548void 549archive_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 */ 565const char * 566archive_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 588gid_t 589archive_entry_gid(struct archive_entry *entry) 590{ 591 return (entry->ae_stat.aest_gid); 592} 593 594const char * 595archive_entry_gname(struct archive_entry *entry) 596{ 597 return (aes_get_mbs(&entry->ae_gname)); 598} 599 600const wchar_t * 601archive_entry_gname_w(struct archive_entry *entry) 602{ 603 return (aes_get_wcs(&entry->ae_gname)); 604} 605 606const char * 607archive_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 614const wchar_t * 615archive_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 622ino_t 623archive_entry_ino(struct archive_entry *entry) 624{ 625 return (entry->ae_stat.aest_ino); 626} 627 628int64_t 629archive_entry_ino64(struct archive_entry *entry) 630{ 631 return (entry->ae_stat.aest_ino); 632} 633 634mode_t 635archive_entry_mode(struct archive_entry *entry) 636{ 637 return (entry->ae_stat.aest_mode); 638} 639 640time_t 641archive_entry_mtime(struct archive_entry *entry) 642{ 643 return (entry->ae_stat.aest_mtime); 644} 645 646long 647archive_entry_mtime_nsec(struct archive_entry *entry) 648{ 649 return (entry->ae_stat.aest_mtime_nsec); 650} 651 652int 653archive_entry_mtime_is_set(struct archive_entry *entry) 654{ 655 return (entry->ae_set & AE_SET_MTIME); 656} 657 658unsigned int 659archive_entry_nlink(struct archive_entry *entry) 660{ 661 return (entry->ae_stat.aest_nlink); 662} 663 664const char * 665archive_entry_pathname(struct archive_entry *entry) 666{ 667 return (aes_get_mbs(&entry->ae_pathname)); 668} 669 670const wchar_t * 671archive_entry_pathname_w(struct archive_entry *entry) 672{ 673 return (aes_get_wcs(&entry->ae_pathname)); 674} 675 676dev_t 677archive_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 686dev_t 687archive_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 695dev_t 696archive_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 704int64_t 705archive_entry_size(struct archive_entry *entry) 706{ 707 return (entry->ae_stat.aest_size); 708} 709 710int 711archive_entry_size_is_set(struct archive_entry *entry) 712{ 713 return (entry->ae_set & AE_SET_SIZE); 714} 715 716const char * 717archive_entry_sourcepath(struct archive_entry *entry) 718{ 719 return (aes_get_mbs(&entry->ae_sourcepath)); 720} 721 722const char * 723archive_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 730const wchar_t * 731archive_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 738uid_t 739archive_entry_uid(struct archive_entry *entry) 740{ 741 return (entry->ae_stat.aest_uid); 742} 743 744const char * 745archive_entry_uname(struct archive_entry *entry) 746{ 747 return (aes_get_mbs(&entry->ae_uname)); 748} 749 750const wchar_t * 751archive_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 760void 761archive_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 768void 769archive_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 777const char * 778archive_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 786const wchar_t * 787archive_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 795void 796archive_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 802void 803archive_entry_set_gname(struct archive_entry *entry, const char *name) 804{ 805 aes_set_mbs(&entry->ae_gname, name); 806} 807 808void 809archive_entry_copy_gname(struct archive_entry *entry, const char *name) 810{ 811 aes_copy_mbs(&entry->ae_gname, name); 812} 813 814void 815archive_entry_copy_gname_w(struct archive_entry *entry, const wchar_t *name) 816{ 817 aes_copy_wcs(&entry->ae_gname, name); 818} 819 820int 821archive_entry_update_gname_utf8(struct archive_entry *entry, const char *name) 822{ 823 return (aes_update_utf8(&entry->ae_gname, name)); 824} 825 826void 827archive_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 833void 834archive_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 840void 841archive_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 850void 851archive_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 860void 861archive_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 870int 871archive_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 880void 881archive_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 889void 890archive_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 896void 897archive_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 905void 906archive_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 912void 913archive_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 921void 922archive_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 928void 929archive_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 936void 937archive_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 944void 945archive_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. */ 953void 954archive_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. */ 963void 964archive_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. */ 973void 974archive_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 982int 983archive_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 991void 992archive_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 998void 999archive_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 1007void 1008archive_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 1014void 1015archive_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 1021void 1022archive_entry_set_pathname(struct archive_entry *entry, const char *name) 1023{ 1024 aes_set_mbs(&entry->ae_pathname, name); 1025} 1026 1027void 1028archive_entry_copy_pathname(struct archive_entry *entry, const char *name) 1029{ 1030 aes_copy_mbs(&entry->ae_pathname, name); 1031} 1032 1033void 1034archive_entry_copy_pathname_w(struct archive_entry *entry, const wchar_t *name) 1035{ 1036 aes_copy_wcs(&entry->ae_pathname, name); 1037} 1038 1039int 1040archive_entry_update_pathname_utf8(struct archive_entry *entry, const char *name) 1041{ 1042 return (aes_update_utf8(&entry->ae_pathname, name)); 1043} 1044 1045void 1046archive_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 1053void 1054archive_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 1061void 1062archive_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 1069void 1070archive_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 1077void 1078archive_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 1085void 1086archive_entry_unset_size(struct archive_entry *entry) 1087{ 1088 archive_entry_set_size(entry, 0); 1089 entry->ae_set &= ~AE_SET_SIZE; 1090} 1091 1092void 1093archive_entry_copy_sourcepath(struct archive_entry *entry, const char *path) 1094{ 1095 aes_set_mbs(&entry->ae_sourcepath, path); 1096} 1097 1098void 1099archive_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 1108void 1109archive_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 1118void 1119archive_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 1128int 1129archive_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 1138void 1139archive_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 1145void 1146archive_entry_set_uname(struct archive_entry *entry, const char *name) 1147{ 1148 aes_set_mbs(&entry->ae_uname, name); 1149} 1150 1151void 1152archive_entry_copy_uname(struct archive_entry *entry, const char *name) 1153{ 1154 aes_copy_mbs(&entry->ae_uname, name); 1155} 1156 1157void 1158archive_entry_copy_uname_w(struct archive_entry *entry, const wchar_t *name) 1159{ 1160 aes_copy_wcs(&entry->ae_uname, name); 1161} 1162 1163int 1164archive_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 1178void 1179archive_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 */ 1200void 1201archive_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 */ 1222void 1223archive_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 1229static void 1230archive_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 */ 1252static int 1253acl_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 */ 1278static struct ae_acl * 1279acl_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 */ 1325int 1326archive_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 */ 1349int 1350archive_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 1379int 1380archive_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 */ 1445const wchar_t * 1446archive_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 1558static void 1559append_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 1568static void 1569append_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 */ 1629int 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 */ 1738static int 1739isint_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 */ 1764static int 1765ismode_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 */ 1801static void 1802next_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 */ 1834static int 1835prefix_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 1887static 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 */ 2012static char * 2013ae_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 */ 2066static const char * 2067ae_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 */ 2130static const wchar_t * 2131ae_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> 2187int 2188main(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