1228753Smm/*- 2228753Smm * Copyright (c) 2003-2007 Tim Kientzle 3228753Smm * All rights reserved. 4228753Smm * 5228753Smm * Redistribution and use in source and binary forms, with or without 6228753Smm * modification, are permitted provided that the following conditions 7228753Smm * are met: 8228753Smm * 1. Redistributions of source code must retain the above copyright 9228753Smm * notice, this list of conditions and the following disclaimer. 10228753Smm * 2. Redistributions in binary form must reproduce the above copyright 11228753Smm * notice, this list of conditions and the following disclaimer in the 12228753Smm * documentation and/or other materials provided with the distribution. 13228753Smm * 14228753Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 15228753Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16228753Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17228753Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 18228753Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19228753Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20228753Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21228753Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22228753Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23228753Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24228753Smm */ 25228753Smm 26228753Smm#include "archive_platform.h" 27229592Smm__FBSDID("$FreeBSD$"); 28228753Smm 29228753Smm#ifdef HAVE_SYS_STAT_H 30228753Smm#include <sys/stat.h> 31228753Smm#endif 32228753Smm#ifdef HAVE_SYS_TYPES_H 33228753Smm#include <sys/types.h> 34228753Smm#endif 35228753Smm#if MAJOR_IN_MKDEV 36228753Smm#include <sys/mkdev.h> 37228753Smm#define HAVE_MAJOR 38228753Smm#elif MAJOR_IN_SYSMACROS 39228753Smm#include <sys/sysmacros.h> 40228753Smm#define HAVE_MAJOR 41228753Smm#endif 42228753Smm#ifdef HAVE_LIMITS_H 43228753Smm#include <limits.h> 44228753Smm#endif 45228753Smm#ifdef HAVE_LINUX_FS_H 46228753Smm#include <linux/fs.h> /* for Linux file flags */ 47228753Smm#endif 48228753Smm/* 49228753Smm * Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h. 50228753Smm * As the include guards don't agree, the order of include is important. 51228753Smm */ 52228753Smm#ifdef HAVE_LINUX_EXT2_FS_H 53228753Smm#include <linux/ext2_fs.h> /* for Linux file flags */ 54228753Smm#endif 55228753Smm#if defined(HAVE_EXT2FS_EXT2_FS_H) && !defined(__CYGWIN__) 56228753Smm#include <ext2fs/ext2_fs.h> /* for Linux file flags */ 57228753Smm#endif 58228753Smm#include <stddef.h> 59228753Smm#include <stdio.h> 60228753Smm#ifdef HAVE_STDLIB_H 61228753Smm#include <stdlib.h> 62228753Smm#endif 63228753Smm#ifdef HAVE_STRING_H 64228753Smm#include <string.h> 65228753Smm#endif 66228753Smm#ifdef HAVE_WCHAR_H 67228753Smm#include <wchar.h> 68228753Smm#endif 69228753Smm 70228753Smm#include "archive.h" 71228753Smm#include "archive_entry.h" 72228753Smm#include "archive_private.h" 73228753Smm#include "archive_entry_private.h" 74228753Smm 75228753Smm#undef max 76228753Smm#define max(a, b) ((a)>(b)?(a):(b)) 77228753Smm 78228753Smm#if !defined(HAVE_MAJOR) && !defined(major) 79228753Smm/* Replacement for major/minor/makedev. */ 80228753Smm#define major(x) ((int)(0x00ff & ((x) >> 8))) 81228753Smm#define minor(x) ((int)(0xffff00ff & (x))) 82228753Smm#define makedev(maj,min) ((0xff00 & ((maj)<<8)) | (0xffff00ff & (min))) 83228753Smm#endif 84228753Smm 85228753Smm/* Play games to come up with a suitable makedev() definition. */ 86228753Smm#ifdef __QNXNTO__ 87228753Smm/* QNX. <sigh> */ 88228753Smm#include <sys/netmgr.h> 89228753Smm#define ae_makedev(maj, min) makedev(ND_LOCAL_NODE, (maj), (min)) 90228753Smm#elif defined makedev 91228753Smm/* There's a "makedev" macro. */ 92228753Smm#define ae_makedev(maj, min) makedev((maj), (min)) 93228753Smm#elif defined mkdev || ((defined _WIN32 || defined __WIN32__) && !defined(__CYGWIN__)) 94228753Smm/* Windows. <sigh> */ 95228753Smm#define ae_makedev(maj, min) mkdev((maj), (min)) 96228753Smm#else 97228753Smm/* There's a "makedev" function. */ 98228753Smm#define ae_makedev(maj, min) makedev((maj), (min)) 99228753Smm#endif 100228753Smm 101228753Smmstatic void aes_clean(struct aes *); 102228753Smmstatic void aes_copy(struct aes *dest, struct aes *src); 103228753Smmstatic const char * aes_get_mbs(struct aes *); 104228753Smmstatic const wchar_t * aes_get_wcs(struct aes *); 105228753Smmstatic int aes_set_mbs(struct aes *, const char *mbs); 106228753Smmstatic int aes_copy_mbs(struct aes *, const char *mbs); 107228753Smm/* static void aes_set_wcs(struct aes *, const wchar_t *wcs); */ 108228753Smmstatic int aes_copy_wcs(struct aes *, const wchar_t *wcs); 109228753Smmstatic int aes_copy_wcs_len(struct aes *, const wchar_t *wcs, size_t); 110228753Smm 111228753Smmstatic char * ae_fflagstostr(unsigned long bitset, unsigned long bitclear); 112228753Smmstatic const wchar_t *ae_wcstofflags(const wchar_t *stringp, 113228753Smm unsigned long *setp, unsigned long *clrp); 114228753Smmstatic const char *ae_strtofflags(const char *stringp, 115228753Smm unsigned long *setp, unsigned long *clrp); 116228753Smmstatic void append_entry_w(wchar_t **wp, const wchar_t *prefix, int tag, 117228753Smm const wchar_t *wname, int perm, int id); 118228753Smmstatic void append_id_w(wchar_t **wp, int id); 119228753Smm 120228753Smmstatic int acl_special(struct archive_entry *entry, 121228753Smm int type, int permset, int tag); 122228753Smmstatic struct ae_acl *acl_new_entry(struct archive_entry *entry, 123228753Smm int type, int permset, int tag, int id); 124228753Smmstatic int isint_w(const wchar_t *start, const wchar_t *end, int *result); 125228753Smmstatic int ismode_w(const wchar_t *start, const wchar_t *end, int *result); 126228753Smmstatic void next_field_w(const wchar_t **wp, const wchar_t **start, 127228753Smm const wchar_t **end, wchar_t *sep); 128228753Smmstatic int prefix_w(const wchar_t *start, const wchar_t *end, 129228753Smm const wchar_t *test); 130228753Smmstatic void 131228753Smmarchive_entry_acl_add_entry_w_len(struct archive_entry *entry, int type, 132228753Smm int permset, int tag, int id, const wchar_t *name, size_t); 133228753Smm 134228753Smm 135228753Smm#ifndef HAVE_WCSCPY 136228753Smmstatic wchar_t * wcscpy(wchar_t *s1, const wchar_t *s2) 137228753Smm{ 138228753Smm wchar_t *dest = s1; 139228753Smm while ((*s1 = *s2) != L'\0') 140228753Smm ++s1, ++s2; 141228753Smm return dest; 142228753Smm} 143228753Smm#endif 144228753Smm#ifndef HAVE_WCSLEN 145228753Smmstatic size_t wcslen(const wchar_t *s) 146228753Smm{ 147228753Smm const wchar_t *p = s; 148228753Smm while (*p != L'\0') 149228753Smm ++p; 150228753Smm return p - s; 151228753Smm} 152228753Smm#endif 153228753Smm#ifndef HAVE_WMEMCMP 154228753Smm/* Good enough for simple equality testing, but not for sorting. */ 155228753Smm#define wmemcmp(a,b,i) memcmp((a), (b), (i) * sizeof(wchar_t)) 156228753Smm#endif 157228753Smm#ifndef HAVE_WMEMCPY 158228753Smm#define wmemcpy(a,b,i) (wchar_t *)memcpy((a), (b), (i) * sizeof(wchar_t)) 159228753Smm#endif 160228753Smm 161228753Smmstatic void 162228753Smmaes_clean(struct aes *aes) 163228753Smm{ 164228753Smm if (aes->aes_wcs) { 165228753Smm free((wchar_t *)(uintptr_t)aes->aes_wcs); 166228753Smm aes->aes_wcs = NULL; 167228753Smm } 168228753Smm archive_string_free(&(aes->aes_mbs)); 169228753Smm archive_string_free(&(aes->aes_utf8)); 170228753Smm aes->aes_set = 0; 171228753Smm} 172228753Smm 173228753Smmstatic void 174228753Smmaes_copy(struct aes *dest, struct aes *src) 175228753Smm{ 176228753Smm wchar_t *wp; 177228753Smm 178228753Smm dest->aes_set = src->aes_set; 179228753Smm archive_string_copy(&(dest->aes_mbs), &(src->aes_mbs)); 180228753Smm archive_string_copy(&(dest->aes_utf8), &(src->aes_utf8)); 181228753Smm 182228753Smm if (src->aes_wcs != NULL) { 183228753Smm wp = (wchar_t *)malloc((wcslen(src->aes_wcs) + 1) 184228753Smm * sizeof(wchar_t)); 185228753Smm if (wp == NULL) 186228753Smm __archive_errx(1, "No memory for aes_copy()"); 187228753Smm wcscpy(wp, src->aes_wcs); 188228753Smm dest->aes_wcs = wp; 189228753Smm } 190228753Smm} 191228753Smm 192228753Smmstatic const char * 193228753Smmaes_get_utf8(struct aes *aes) 194228753Smm{ 195228753Smm if (aes->aes_set & AES_SET_UTF8) 196228753Smm return (aes->aes_utf8.s); 197228753Smm if ((aes->aes_set & AES_SET_WCS) 198228753Smm && archive_strappend_w_utf8(&(aes->aes_utf8), aes->aes_wcs) != NULL) { 199228753Smm aes->aes_set |= AES_SET_UTF8; 200228753Smm return (aes->aes_utf8.s); 201228753Smm } 202228753Smm return (NULL); 203228753Smm} 204228753Smm 205228753Smmstatic const char * 206228753Smmaes_get_mbs(struct aes *aes) 207228753Smm{ 208228753Smm /* If we already have an MBS form, return that immediately. */ 209228753Smm if (aes->aes_set & AES_SET_MBS) 210228753Smm return (aes->aes_mbs.s); 211228753Smm /* If there's a WCS form, try converting with the native locale. */ 212228753Smm if ((aes->aes_set & AES_SET_WCS) 213228753Smm && archive_strappend_w_mbs(&(aes->aes_mbs), aes->aes_wcs) != NULL) { 214228753Smm aes->aes_set |= AES_SET_MBS; 215228753Smm return (aes->aes_mbs.s); 216228753Smm } 217228753Smm /* We'll use UTF-8 for MBS if all else fails. */ 218228753Smm return (aes_get_utf8(aes)); 219228753Smm} 220228753Smm 221228753Smmstatic const wchar_t * 222228753Smmaes_get_wcs(struct aes *aes) 223228753Smm{ 224228753Smm wchar_t *w; 225228753Smm size_t r; 226228753Smm 227228753Smm /* Return WCS form if we already have it. */ 228228753Smm if (aes->aes_set & AES_SET_WCS) 229228753Smm return (aes->aes_wcs); 230228753Smm 231228753Smm if (aes->aes_set & AES_SET_MBS) { 232228753Smm /* Try converting MBS to WCS using native locale. */ 233228753Smm /* 234228753Smm * No single byte will be more than one wide character, 235228753Smm * so this length estimate will always be big enough. 236228753Smm */ 237228753Smm size_t wcs_length = aes->aes_mbs.length; 238228753Smm 239228753Smm w = (wchar_t *)malloc((wcs_length + 1) * sizeof(wchar_t)); 240228753Smm if (w == NULL) 241228753Smm __archive_errx(1, "No memory for aes_get_wcs()"); 242228753Smm r = mbstowcs(w, aes->aes_mbs.s, wcs_length); 243228753Smm if (r != (size_t)-1 && r != 0) { 244228753Smm w[r] = 0; 245228753Smm aes->aes_set |= AES_SET_WCS; 246228753Smm return (aes->aes_wcs = w); 247228753Smm } 248228753Smm free(w); 249228753Smm } 250228753Smm 251228753Smm if (aes->aes_set & AES_SET_UTF8) { 252228753Smm /* Try converting UTF8 to WCS. */ 253228753Smm aes->aes_wcs = __archive_string_utf8_w(&(aes->aes_utf8)); 254228753Smm if (aes->aes_wcs != NULL) 255228753Smm aes->aes_set |= AES_SET_WCS; 256228753Smm return (aes->aes_wcs); 257228753Smm } 258228753Smm return (NULL); 259228753Smm} 260228753Smm 261228753Smmstatic int 262228753Smmaes_set_mbs(struct aes *aes, const char *mbs) 263228753Smm{ 264228753Smm return (aes_copy_mbs(aes, mbs)); 265228753Smm} 266228753Smm 267228753Smmstatic int 268228753Smmaes_copy_mbs(struct aes *aes, const char *mbs) 269228753Smm{ 270228753Smm if (mbs == NULL) { 271228753Smm aes->aes_set = 0; 272228753Smm return (0); 273228753Smm } 274228753Smm aes->aes_set = AES_SET_MBS; /* Only MBS form is set now. */ 275228753Smm archive_strcpy(&(aes->aes_mbs), mbs); 276228753Smm archive_string_empty(&(aes->aes_utf8)); 277228753Smm if (aes->aes_wcs) { 278228753Smm free((wchar_t *)(uintptr_t)aes->aes_wcs); 279228753Smm aes->aes_wcs = NULL; 280228753Smm } 281228753Smm return (0); 282228753Smm} 283228753Smm 284228753Smm/* 285228753Smm * The 'update' form tries to proactively update all forms of 286228753Smm * this string (WCS and MBS) and returns an error if any of 287228753Smm * them fail. This is used by the 'pax' handler, for instance, 288228753Smm * to detect and report character-conversion failures early while 289228753Smm * still allowing clients to get potentially useful values from 290228753Smm * the more tolerant lazy conversions. (get_mbs and get_wcs will 291228753Smm * strive to give the user something useful, so you can get hopefully 292228753Smm * usable values even if some of the character conversions are failing.) 293228753Smm */ 294228753Smmstatic int 295228753Smmaes_update_utf8(struct aes *aes, const char *utf8) 296228753Smm{ 297228753Smm if (utf8 == NULL) { 298228753Smm aes->aes_set = 0; 299228753Smm return (1); /* Succeeded in clearing everything. */ 300228753Smm } 301228753Smm 302228753Smm /* Save the UTF8 string. */ 303228753Smm archive_strcpy(&(aes->aes_utf8), utf8); 304228753Smm 305228753Smm /* Empty the mbs and wcs strings. */ 306228753Smm archive_string_empty(&(aes->aes_mbs)); 307228753Smm if (aes->aes_wcs) { 308228753Smm free((wchar_t *)(uintptr_t)aes->aes_wcs); 309228753Smm aes->aes_wcs = NULL; 310228753Smm } 311228753Smm 312228753Smm aes->aes_set = AES_SET_UTF8; /* Only UTF8 is set now. */ 313228753Smm 314228753Smm /* TODO: We should just do a direct UTF-8 to MBS conversion 315228753Smm * here. That would be faster, use less space, and give the 316228753Smm * same information. (If a UTF-8 to MBS conversion succeeds, 317228753Smm * then UTF-8->WCS and Unicode->MBS conversions will both 318228753Smm * succeed.) */ 319228753Smm 320228753Smm /* Try converting UTF8 to WCS, return false on failure. */ 321228753Smm aes->aes_wcs = __archive_string_utf8_w(&(aes->aes_utf8)); 322228753Smm if (aes->aes_wcs == NULL) 323228753Smm return (0); 324228753Smm aes->aes_set = AES_SET_UTF8 | AES_SET_WCS; /* Both UTF8 and WCS set. */ 325228753Smm 326228753Smm /* Try converting WCS to MBS, return false on failure. */ 327228753Smm if (archive_strappend_w_mbs(&(aes->aes_mbs), aes->aes_wcs) == NULL) 328228753Smm return (0); 329228753Smm aes->aes_set = AES_SET_UTF8 | AES_SET_WCS | AES_SET_MBS; 330228753Smm 331228753Smm /* All conversions succeeded. */ 332228753Smm return (1); 333228753Smm} 334228753Smm 335228753Smmstatic int 336228753Smmaes_copy_wcs(struct aes *aes, const wchar_t *wcs) 337228753Smm{ 338228753Smm return aes_copy_wcs_len(aes, wcs, wcs == NULL ? 0 : wcslen(wcs)); 339228753Smm} 340228753Smm 341228753Smmstatic int 342228753Smmaes_copy_wcs_len(struct aes *aes, const wchar_t *wcs, size_t len) 343228753Smm{ 344228753Smm wchar_t *w; 345228753Smm 346228753Smm if (wcs == NULL) { 347228753Smm aes->aes_set = 0; 348228753Smm return (0); 349228753Smm } 350228753Smm aes->aes_set = AES_SET_WCS; /* Only WCS form set. */ 351228753Smm archive_string_empty(&(aes->aes_mbs)); 352228753Smm archive_string_empty(&(aes->aes_utf8)); 353228753Smm if (aes->aes_wcs) { 354228753Smm free((wchar_t *)(uintptr_t)aes->aes_wcs); 355228753Smm aes->aes_wcs = NULL; 356228753Smm } 357228753Smm w = (wchar_t *)malloc((len + 1) * sizeof(wchar_t)); 358228753Smm if (w == NULL) 359228753Smm __archive_errx(1, "No memory for aes_copy_wcs()"); 360228753Smm wmemcpy(w, wcs, len); 361228753Smm w[len] = L'\0'; 362228753Smm aes->aes_wcs = w; 363228753Smm return (0); 364228753Smm} 365228753Smm 366228753Smm/**************************************************************************** 367228753Smm * 368228753Smm * Public Interface 369228753Smm * 370228753Smm ****************************************************************************/ 371228753Smm 372228753Smmstruct archive_entry * 373228753Smmarchive_entry_clear(struct archive_entry *entry) 374228753Smm{ 375228753Smm if (entry == NULL) 376228753Smm return (NULL); 377228753Smm aes_clean(&entry->ae_fflags_text); 378228753Smm aes_clean(&entry->ae_gname); 379228753Smm aes_clean(&entry->ae_hardlink); 380228753Smm aes_clean(&entry->ae_pathname); 381228753Smm aes_clean(&entry->ae_sourcepath); 382228753Smm aes_clean(&entry->ae_symlink); 383228753Smm aes_clean(&entry->ae_uname); 384228753Smm archive_entry_acl_clear(entry); 385228753Smm archive_entry_xattr_clear(entry); 386228753Smm free(entry->stat); 387228753Smm memset(entry, 0, sizeof(*entry)); 388228753Smm return entry; 389228753Smm} 390228753Smm 391228753Smmstruct archive_entry * 392228753Smmarchive_entry_clone(struct archive_entry *entry) 393228753Smm{ 394228753Smm struct archive_entry *entry2; 395228753Smm struct ae_acl *ap, *ap2; 396228753Smm struct ae_xattr *xp; 397228753Smm 398228753Smm /* Allocate new structure and copy over all of the fields. */ 399228753Smm entry2 = (struct archive_entry *)malloc(sizeof(*entry2)); 400228753Smm if (entry2 == NULL) 401228753Smm return (NULL); 402228753Smm memset(entry2, 0, sizeof(*entry2)); 403228753Smm entry2->ae_stat = entry->ae_stat; 404228753Smm entry2->ae_fflags_set = entry->ae_fflags_set; 405228753Smm entry2->ae_fflags_clear = entry->ae_fflags_clear; 406228753Smm 407228753Smm aes_copy(&entry2->ae_fflags_text, &entry->ae_fflags_text); 408228753Smm aes_copy(&entry2->ae_gname, &entry->ae_gname); 409228753Smm aes_copy(&entry2->ae_hardlink, &entry->ae_hardlink); 410228753Smm aes_copy(&entry2->ae_pathname, &entry->ae_pathname); 411228753Smm aes_copy(&entry2->ae_sourcepath, &entry->ae_sourcepath); 412228753Smm aes_copy(&entry2->ae_symlink, &entry->ae_symlink); 413228753Smm entry2->ae_set = entry->ae_set; 414228753Smm aes_copy(&entry2->ae_uname, &entry->ae_uname); 415228753Smm 416228753Smm /* Copy ACL data over. */ 417228753Smm ap = entry->acl_head; 418228753Smm while (ap != NULL) { 419228753Smm ap2 = acl_new_entry(entry2, 420228753Smm ap->type, ap->permset, ap->tag, ap->id); 421228753Smm if (ap2 != NULL) 422228753Smm aes_copy(&ap2->name, &ap->name); 423228753Smm ap = ap->next; 424228753Smm } 425228753Smm 426228753Smm /* Copy xattr data over. */ 427228753Smm xp = entry->xattr_head; 428228753Smm while (xp != NULL) { 429228753Smm archive_entry_xattr_add_entry(entry2, 430228753Smm xp->name, xp->value, xp->size); 431228753Smm xp = xp->next; 432228753Smm } 433228753Smm 434228753Smm return (entry2); 435228753Smm} 436228753Smm 437228753Smmvoid 438228753Smmarchive_entry_free(struct archive_entry *entry) 439228753Smm{ 440228753Smm archive_entry_clear(entry); 441228753Smm free(entry); 442228753Smm} 443228753Smm 444228753Smmstruct archive_entry * 445228753Smmarchive_entry_new(void) 446228753Smm{ 447228753Smm struct archive_entry *entry; 448228753Smm 449228753Smm entry = (struct archive_entry *)malloc(sizeof(*entry)); 450228753Smm if (entry == NULL) 451228753Smm return (NULL); 452228753Smm memset(entry, 0, sizeof(*entry)); 453228753Smm return (entry); 454228753Smm} 455228753Smm 456228753Smm/* 457228753Smm * Functions for reading fields from an archive_entry. 458228753Smm */ 459228753Smm 460228753Smmtime_t 461228753Smmarchive_entry_atime(struct archive_entry *entry) 462228753Smm{ 463228753Smm return (entry->ae_stat.aest_atime); 464228753Smm} 465228753Smm 466228753Smmlong 467228753Smmarchive_entry_atime_nsec(struct archive_entry *entry) 468228753Smm{ 469228753Smm return (entry->ae_stat.aest_atime_nsec); 470228753Smm} 471228753Smm 472228753Smmint 473228753Smmarchive_entry_atime_is_set(struct archive_entry *entry) 474228753Smm{ 475228753Smm return (entry->ae_set & AE_SET_ATIME); 476228753Smm} 477228753Smm 478228753Smmtime_t 479228753Smmarchive_entry_birthtime(struct archive_entry *entry) 480228753Smm{ 481228753Smm return (entry->ae_stat.aest_birthtime); 482228753Smm} 483228753Smm 484228753Smmlong 485228753Smmarchive_entry_birthtime_nsec(struct archive_entry *entry) 486228753Smm{ 487228753Smm return (entry->ae_stat.aest_birthtime_nsec); 488228753Smm} 489228753Smm 490228753Smmint 491228753Smmarchive_entry_birthtime_is_set(struct archive_entry *entry) 492228753Smm{ 493228753Smm return (entry->ae_set & AE_SET_BIRTHTIME); 494228753Smm} 495228753Smm 496228753Smmtime_t 497228753Smmarchive_entry_ctime(struct archive_entry *entry) 498228753Smm{ 499228753Smm return (entry->ae_stat.aest_ctime); 500228753Smm} 501228753Smm 502228753Smmint 503228753Smmarchive_entry_ctime_is_set(struct archive_entry *entry) 504228753Smm{ 505228753Smm return (entry->ae_set & AE_SET_CTIME); 506228753Smm} 507228753Smm 508228753Smmlong 509228753Smmarchive_entry_ctime_nsec(struct archive_entry *entry) 510228753Smm{ 511228753Smm return (entry->ae_stat.aest_ctime_nsec); 512228753Smm} 513228753Smm 514228753Smmdev_t 515228753Smmarchive_entry_dev(struct archive_entry *entry) 516228753Smm{ 517228753Smm if (entry->ae_stat.aest_dev_is_broken_down) 518228753Smm return ae_makedev(entry->ae_stat.aest_devmajor, 519228753Smm entry->ae_stat.aest_devminor); 520228753Smm else 521228753Smm return (entry->ae_stat.aest_dev); 522228753Smm} 523228753Smm 524228753Smmdev_t 525228753Smmarchive_entry_devmajor(struct archive_entry *entry) 526228753Smm{ 527228753Smm if (entry->ae_stat.aest_dev_is_broken_down) 528228753Smm return (entry->ae_stat.aest_devmajor); 529228753Smm else 530228753Smm return major(entry->ae_stat.aest_dev); 531228753Smm} 532228753Smm 533228753Smmdev_t 534228753Smmarchive_entry_devminor(struct archive_entry *entry) 535228753Smm{ 536228753Smm if (entry->ae_stat.aest_dev_is_broken_down) 537228753Smm return (entry->ae_stat.aest_devminor); 538228753Smm else 539228753Smm return minor(entry->ae_stat.aest_dev); 540228753Smm} 541228753Smm 542228753Smmmode_t 543228753Smmarchive_entry_filetype(struct archive_entry *entry) 544228753Smm{ 545228753Smm return (AE_IFMT & entry->ae_stat.aest_mode); 546228753Smm} 547228753Smm 548228753Smmvoid 549228753Smmarchive_entry_fflags(struct archive_entry *entry, 550228753Smm unsigned long *set, unsigned long *clear) 551228753Smm{ 552228753Smm *set = entry->ae_fflags_set; 553228753Smm *clear = entry->ae_fflags_clear; 554228753Smm} 555228753Smm 556228753Smm/* 557228753Smm * Note: if text was provided, this just returns that text. If you 558228753Smm * really need the text to be rebuilt in a canonical form, set the 559228753Smm * text, ask for the bitmaps, then set the bitmaps. (Setting the 560228753Smm * bitmaps clears any stored text.) This design is deliberate: if 561228753Smm * we're editing archives, we don't want to discard flags just because 562228753Smm * they aren't supported on the current system. The bitmap<->text 563228753Smm * conversions are platform-specific (see below). 564228753Smm */ 565228753Smmconst char * 566228753Smmarchive_entry_fflags_text(struct archive_entry *entry) 567228753Smm{ 568228753Smm const char *f; 569228753Smm char *p; 570228753Smm 571228753Smm f = aes_get_mbs(&entry->ae_fflags_text); 572228753Smm if (f != NULL) 573228753Smm return (f); 574228753Smm 575228753Smm if (entry->ae_fflags_set == 0 && entry->ae_fflags_clear == 0) 576228753Smm return (NULL); 577228753Smm 578228753Smm p = ae_fflagstostr(entry->ae_fflags_set, entry->ae_fflags_clear); 579228753Smm if (p == NULL) 580228753Smm return (NULL); 581228753Smm 582228753Smm aes_copy_mbs(&entry->ae_fflags_text, p); 583228753Smm free(p); 584228753Smm f = aes_get_mbs(&entry->ae_fflags_text); 585228753Smm return (f); 586228753Smm} 587228753Smm 588228753Smmgid_t 589228753Smmarchive_entry_gid(struct archive_entry *entry) 590228753Smm{ 591228753Smm return (entry->ae_stat.aest_gid); 592228753Smm} 593228753Smm 594228753Smmconst char * 595228753Smmarchive_entry_gname(struct archive_entry *entry) 596228753Smm{ 597228753Smm return (aes_get_mbs(&entry->ae_gname)); 598228753Smm} 599228753Smm 600228753Smmconst wchar_t * 601228753Smmarchive_entry_gname_w(struct archive_entry *entry) 602228753Smm{ 603228753Smm return (aes_get_wcs(&entry->ae_gname)); 604228753Smm} 605228753Smm 606228753Smmconst char * 607228753Smmarchive_entry_hardlink(struct archive_entry *entry) 608228753Smm{ 609228753Smm if (entry->ae_set & AE_SET_HARDLINK) 610228753Smm return (aes_get_mbs(&entry->ae_hardlink)); 611228753Smm return (NULL); 612228753Smm} 613228753Smm 614228753Smmconst wchar_t * 615228753Smmarchive_entry_hardlink_w(struct archive_entry *entry) 616228753Smm{ 617228753Smm if (entry->ae_set & AE_SET_HARDLINK) 618228753Smm return (aes_get_wcs(&entry->ae_hardlink)); 619228753Smm return (NULL); 620228753Smm} 621228753Smm 622228753Smmino_t 623228753Smmarchive_entry_ino(struct archive_entry *entry) 624228753Smm{ 625228753Smm return (entry->ae_stat.aest_ino); 626228753Smm} 627228753Smm 628228753Smmint64_t 629228753Smmarchive_entry_ino64(struct archive_entry *entry) 630228753Smm{ 631228753Smm return (entry->ae_stat.aest_ino); 632228753Smm} 633228753Smm 634228753Smmmode_t 635228753Smmarchive_entry_mode(struct archive_entry *entry) 636228753Smm{ 637228753Smm return (entry->ae_stat.aest_mode); 638228753Smm} 639228753Smm 640228753Smmtime_t 641228753Smmarchive_entry_mtime(struct archive_entry *entry) 642228753Smm{ 643228753Smm return (entry->ae_stat.aest_mtime); 644228753Smm} 645228753Smm 646228753Smmlong 647228753Smmarchive_entry_mtime_nsec(struct archive_entry *entry) 648228753Smm{ 649228753Smm return (entry->ae_stat.aest_mtime_nsec); 650228753Smm} 651228753Smm 652228753Smmint 653228753Smmarchive_entry_mtime_is_set(struct archive_entry *entry) 654228753Smm{ 655228753Smm return (entry->ae_set & AE_SET_MTIME); 656228753Smm} 657228753Smm 658228753Smmunsigned int 659228753Smmarchive_entry_nlink(struct archive_entry *entry) 660228753Smm{ 661228753Smm return (entry->ae_stat.aest_nlink); 662228753Smm} 663228753Smm 664228753Smmconst char * 665228753Smmarchive_entry_pathname(struct archive_entry *entry) 666228753Smm{ 667228753Smm return (aes_get_mbs(&entry->ae_pathname)); 668228753Smm} 669228753Smm 670228753Smmconst wchar_t * 671228753Smmarchive_entry_pathname_w(struct archive_entry *entry) 672228753Smm{ 673228753Smm return (aes_get_wcs(&entry->ae_pathname)); 674228753Smm} 675228753Smm 676228753Smmdev_t 677228753Smmarchive_entry_rdev(struct archive_entry *entry) 678228753Smm{ 679228753Smm if (entry->ae_stat.aest_rdev_is_broken_down) 680228753Smm return ae_makedev(entry->ae_stat.aest_rdevmajor, 681228753Smm entry->ae_stat.aest_rdevminor); 682228753Smm else 683228753Smm return (entry->ae_stat.aest_rdev); 684228753Smm} 685228753Smm 686228753Smmdev_t 687228753Smmarchive_entry_rdevmajor(struct archive_entry *entry) 688228753Smm{ 689228753Smm if (entry->ae_stat.aest_rdev_is_broken_down) 690228753Smm return (entry->ae_stat.aest_rdevmajor); 691228753Smm else 692228753Smm return major(entry->ae_stat.aest_rdev); 693228753Smm} 694228753Smm 695228753Smmdev_t 696228753Smmarchive_entry_rdevminor(struct archive_entry *entry) 697228753Smm{ 698228753Smm if (entry->ae_stat.aest_rdev_is_broken_down) 699228753Smm return (entry->ae_stat.aest_rdevminor); 700228753Smm else 701228753Smm return minor(entry->ae_stat.aest_rdev); 702228753Smm} 703228753Smm 704228753Smmint64_t 705228753Smmarchive_entry_size(struct archive_entry *entry) 706228753Smm{ 707228753Smm return (entry->ae_stat.aest_size); 708228753Smm} 709228753Smm 710228753Smmint 711228753Smmarchive_entry_size_is_set(struct archive_entry *entry) 712228753Smm{ 713228753Smm return (entry->ae_set & AE_SET_SIZE); 714228753Smm} 715228753Smm 716228753Smmconst char * 717228753Smmarchive_entry_sourcepath(struct archive_entry *entry) 718228753Smm{ 719228753Smm return (aes_get_mbs(&entry->ae_sourcepath)); 720228753Smm} 721228753Smm 722228753Smmconst char * 723228753Smmarchive_entry_symlink(struct archive_entry *entry) 724228753Smm{ 725228753Smm if (entry->ae_set & AE_SET_SYMLINK) 726228753Smm return (aes_get_mbs(&entry->ae_symlink)); 727228753Smm return (NULL); 728228753Smm} 729228753Smm 730228753Smmconst wchar_t * 731228753Smmarchive_entry_symlink_w(struct archive_entry *entry) 732228753Smm{ 733228753Smm if (entry->ae_set & AE_SET_SYMLINK) 734228753Smm return (aes_get_wcs(&entry->ae_symlink)); 735228753Smm return (NULL); 736228753Smm} 737228753Smm 738228753Smmuid_t 739228753Smmarchive_entry_uid(struct archive_entry *entry) 740228753Smm{ 741228753Smm return (entry->ae_stat.aest_uid); 742228753Smm} 743228753Smm 744228753Smmconst char * 745228753Smmarchive_entry_uname(struct archive_entry *entry) 746228753Smm{ 747228753Smm return (aes_get_mbs(&entry->ae_uname)); 748228753Smm} 749228753Smm 750228753Smmconst wchar_t * 751228753Smmarchive_entry_uname_w(struct archive_entry *entry) 752228753Smm{ 753228753Smm return (aes_get_wcs(&entry->ae_uname)); 754228753Smm} 755228753Smm 756228753Smm/* 757228753Smm * Functions to set archive_entry properties. 758228753Smm */ 759228753Smm 760228753Smmvoid 761228753Smmarchive_entry_set_filetype(struct archive_entry *entry, unsigned int type) 762228753Smm{ 763228753Smm entry->stat_valid = 0; 764228753Smm entry->ae_stat.aest_mode &= ~AE_IFMT; 765228753Smm entry->ae_stat.aest_mode |= AE_IFMT & type; 766228753Smm} 767228753Smm 768228753Smmvoid 769228753Smmarchive_entry_set_fflags(struct archive_entry *entry, 770228753Smm unsigned long set, unsigned long clear) 771228753Smm{ 772228753Smm aes_clean(&entry->ae_fflags_text); 773228753Smm entry->ae_fflags_set = set; 774228753Smm entry->ae_fflags_clear = clear; 775228753Smm} 776228753Smm 777228753Smmconst char * 778228753Smmarchive_entry_copy_fflags_text(struct archive_entry *entry, 779228753Smm const char *flags) 780228753Smm{ 781228753Smm aes_copy_mbs(&entry->ae_fflags_text, flags); 782228753Smm return (ae_strtofflags(flags, 783228753Smm &entry->ae_fflags_set, &entry->ae_fflags_clear)); 784228753Smm} 785228753Smm 786228753Smmconst wchar_t * 787228753Smmarchive_entry_copy_fflags_text_w(struct archive_entry *entry, 788228753Smm const wchar_t *flags) 789228753Smm{ 790228753Smm aes_copy_wcs(&entry->ae_fflags_text, flags); 791228753Smm return (ae_wcstofflags(flags, 792228753Smm &entry->ae_fflags_set, &entry->ae_fflags_clear)); 793228753Smm} 794228753Smm 795228753Smmvoid 796228753Smmarchive_entry_set_gid(struct archive_entry *entry, gid_t g) 797228753Smm{ 798228753Smm entry->stat_valid = 0; 799228753Smm entry->ae_stat.aest_gid = g; 800228753Smm} 801228753Smm 802228753Smmvoid 803228753Smmarchive_entry_set_gname(struct archive_entry *entry, const char *name) 804228753Smm{ 805228753Smm aes_set_mbs(&entry->ae_gname, name); 806228753Smm} 807228753Smm 808228753Smmvoid 809228753Smmarchive_entry_copy_gname(struct archive_entry *entry, const char *name) 810228753Smm{ 811228753Smm aes_copy_mbs(&entry->ae_gname, name); 812228753Smm} 813228753Smm 814228753Smmvoid 815228753Smmarchive_entry_copy_gname_w(struct archive_entry *entry, const wchar_t *name) 816228753Smm{ 817228753Smm aes_copy_wcs(&entry->ae_gname, name); 818228753Smm} 819228753Smm 820228753Smmint 821228753Smmarchive_entry_update_gname_utf8(struct archive_entry *entry, const char *name) 822228753Smm{ 823228753Smm return (aes_update_utf8(&entry->ae_gname, name)); 824228753Smm} 825228753Smm 826228753Smmvoid 827228753Smmarchive_entry_set_ino(struct archive_entry *entry, unsigned long ino) 828228753Smm{ 829228753Smm entry->stat_valid = 0; 830228753Smm entry->ae_stat.aest_ino = ino; 831228753Smm} 832228753Smm 833228753Smmvoid 834228753Smmarchive_entry_set_ino64(struct archive_entry *entry, int64_t ino) 835228753Smm{ 836228753Smm entry->stat_valid = 0; 837228753Smm entry->ae_stat.aest_ino = ino; 838228753Smm} 839228753Smm 840228753Smmvoid 841228753Smmarchive_entry_set_hardlink(struct archive_entry *entry, const char *target) 842228753Smm{ 843228753Smm aes_set_mbs(&entry->ae_hardlink, target); 844228753Smm if (target != NULL) 845228753Smm entry->ae_set |= AE_SET_HARDLINK; 846228753Smm else 847228753Smm entry->ae_set &= ~AE_SET_HARDLINK; 848228753Smm} 849228753Smm 850228753Smmvoid 851228753Smmarchive_entry_copy_hardlink(struct archive_entry *entry, const char *target) 852228753Smm{ 853228753Smm aes_copy_mbs(&entry->ae_hardlink, target); 854228753Smm if (target != NULL) 855228753Smm entry->ae_set |= AE_SET_HARDLINK; 856228753Smm else 857228753Smm entry->ae_set &= ~AE_SET_HARDLINK; 858228753Smm} 859228753Smm 860228753Smmvoid 861228753Smmarchive_entry_copy_hardlink_w(struct archive_entry *entry, const wchar_t *target) 862228753Smm{ 863228753Smm aes_copy_wcs(&entry->ae_hardlink, target); 864228753Smm if (target != NULL) 865228753Smm entry->ae_set |= AE_SET_HARDLINK; 866228753Smm else 867228753Smm entry->ae_set &= ~AE_SET_HARDLINK; 868228753Smm} 869228753Smm 870228753Smmint 871228753Smmarchive_entry_update_hardlink_utf8(struct archive_entry *entry, const char *target) 872228753Smm{ 873228753Smm if (target != NULL) 874228753Smm entry->ae_set |= AE_SET_HARDLINK; 875228753Smm else 876228753Smm entry->ae_set &= ~AE_SET_HARDLINK; 877228753Smm return (aes_update_utf8(&entry->ae_hardlink, target)); 878228753Smm} 879228753Smm 880228753Smmvoid 881228753Smmarchive_entry_set_atime(struct archive_entry *entry, time_t t, long ns) 882228753Smm{ 883228753Smm entry->stat_valid = 0; 884228753Smm entry->ae_set |= AE_SET_ATIME; 885228753Smm entry->ae_stat.aest_atime = t; 886228753Smm entry->ae_stat.aest_atime_nsec = ns; 887228753Smm} 888228753Smm 889228753Smmvoid 890228753Smmarchive_entry_unset_atime(struct archive_entry *entry) 891228753Smm{ 892228753Smm archive_entry_set_atime(entry, 0, 0); 893228753Smm entry->ae_set &= ~AE_SET_ATIME; 894228753Smm} 895228753Smm 896228753Smmvoid 897228753Smmarchive_entry_set_birthtime(struct archive_entry *entry, time_t m, long ns) 898228753Smm{ 899228753Smm entry->stat_valid = 0; 900228753Smm entry->ae_set |= AE_SET_BIRTHTIME; 901228753Smm entry->ae_stat.aest_birthtime = m; 902228753Smm entry->ae_stat.aest_birthtime_nsec = ns; 903228753Smm} 904228753Smm 905228753Smmvoid 906228753Smmarchive_entry_unset_birthtime(struct archive_entry *entry) 907228753Smm{ 908228753Smm archive_entry_set_birthtime(entry, 0, 0); 909228753Smm entry->ae_set &= ~AE_SET_BIRTHTIME; 910228753Smm} 911228753Smm 912228753Smmvoid 913228753Smmarchive_entry_set_ctime(struct archive_entry *entry, time_t t, long ns) 914228753Smm{ 915228753Smm entry->stat_valid = 0; 916228753Smm entry->ae_set |= AE_SET_CTIME; 917228753Smm entry->ae_stat.aest_ctime = t; 918228753Smm entry->ae_stat.aest_ctime_nsec = ns; 919228753Smm} 920228753Smm 921228753Smmvoid 922228753Smmarchive_entry_unset_ctime(struct archive_entry *entry) 923228753Smm{ 924228753Smm archive_entry_set_ctime(entry, 0, 0); 925228753Smm entry->ae_set &= ~AE_SET_CTIME; 926228753Smm} 927228753Smm 928228753Smmvoid 929228753Smmarchive_entry_set_dev(struct archive_entry *entry, dev_t d) 930228753Smm{ 931228753Smm entry->stat_valid = 0; 932228753Smm entry->ae_stat.aest_dev_is_broken_down = 0; 933228753Smm entry->ae_stat.aest_dev = d; 934228753Smm} 935228753Smm 936228753Smmvoid 937228753Smmarchive_entry_set_devmajor(struct archive_entry *entry, dev_t m) 938228753Smm{ 939228753Smm entry->stat_valid = 0; 940228753Smm entry->ae_stat.aest_dev_is_broken_down = 1; 941228753Smm entry->ae_stat.aest_devmajor = m; 942228753Smm} 943228753Smm 944228753Smmvoid 945228753Smmarchive_entry_set_devminor(struct archive_entry *entry, dev_t m) 946228753Smm{ 947228753Smm entry->stat_valid = 0; 948228753Smm entry->ae_stat.aest_dev_is_broken_down = 1; 949228753Smm entry->ae_stat.aest_devminor = m; 950228753Smm} 951228753Smm 952228753Smm/* Set symlink if symlink is already set, else set hardlink. */ 953228753Smmvoid 954228753Smmarchive_entry_set_link(struct archive_entry *entry, const char *target) 955228753Smm{ 956228753Smm if (entry->ae_set & AE_SET_SYMLINK) 957228753Smm aes_set_mbs(&entry->ae_symlink, target); 958228753Smm else 959228753Smm aes_set_mbs(&entry->ae_hardlink, target); 960228753Smm} 961228753Smm 962228753Smm/* Set symlink if symlink is already set, else set hardlink. */ 963228753Smmvoid 964228753Smmarchive_entry_copy_link(struct archive_entry *entry, const char *target) 965228753Smm{ 966228753Smm if (entry->ae_set & AE_SET_SYMLINK) 967228753Smm aes_copy_mbs(&entry->ae_symlink, target); 968228753Smm else 969228753Smm aes_copy_mbs(&entry->ae_hardlink, target); 970228753Smm} 971228753Smm 972228753Smm/* Set symlink if symlink is already set, else set hardlink. */ 973228753Smmvoid 974228753Smmarchive_entry_copy_link_w(struct archive_entry *entry, const wchar_t *target) 975228753Smm{ 976228753Smm if (entry->ae_set & AE_SET_SYMLINK) 977228753Smm aes_copy_wcs(&entry->ae_symlink, target); 978228753Smm else 979228753Smm aes_copy_wcs(&entry->ae_hardlink, target); 980228753Smm} 981228753Smm 982228753Smmint 983228753Smmarchive_entry_update_link_utf8(struct archive_entry *entry, const char *target) 984228753Smm{ 985228753Smm if (entry->ae_set & AE_SET_SYMLINK) 986228753Smm return (aes_update_utf8(&entry->ae_symlink, target)); 987228753Smm else 988228753Smm return (aes_update_utf8(&entry->ae_hardlink, target)); 989228753Smm} 990228753Smm 991228753Smmvoid 992228753Smmarchive_entry_set_mode(struct archive_entry *entry, mode_t m) 993228753Smm{ 994228753Smm entry->stat_valid = 0; 995228753Smm entry->ae_stat.aest_mode = m; 996228753Smm} 997228753Smm 998228753Smmvoid 999228753Smmarchive_entry_set_mtime(struct archive_entry *entry, time_t m, long ns) 1000228753Smm{ 1001228753Smm entry->stat_valid = 0; 1002228753Smm entry->ae_set |= AE_SET_MTIME; 1003228753Smm entry->ae_stat.aest_mtime = m; 1004228753Smm entry->ae_stat.aest_mtime_nsec = ns; 1005228753Smm} 1006228753Smm 1007228753Smmvoid 1008228753Smmarchive_entry_unset_mtime(struct archive_entry *entry) 1009228753Smm{ 1010228753Smm archive_entry_set_mtime(entry, 0, 0); 1011228753Smm entry->ae_set &= ~AE_SET_MTIME; 1012228753Smm} 1013228753Smm 1014228753Smmvoid 1015228753Smmarchive_entry_set_nlink(struct archive_entry *entry, unsigned int nlink) 1016228753Smm{ 1017228753Smm entry->stat_valid = 0; 1018228753Smm entry->ae_stat.aest_nlink = nlink; 1019228753Smm} 1020228753Smm 1021228753Smmvoid 1022228753Smmarchive_entry_set_pathname(struct archive_entry *entry, const char *name) 1023228753Smm{ 1024228753Smm aes_set_mbs(&entry->ae_pathname, name); 1025228753Smm} 1026228753Smm 1027228753Smmvoid 1028228753Smmarchive_entry_copy_pathname(struct archive_entry *entry, const char *name) 1029228753Smm{ 1030228753Smm aes_copy_mbs(&entry->ae_pathname, name); 1031228753Smm} 1032228753Smm 1033228753Smmvoid 1034228753Smmarchive_entry_copy_pathname_w(struct archive_entry *entry, const wchar_t *name) 1035228753Smm{ 1036228753Smm aes_copy_wcs(&entry->ae_pathname, name); 1037228753Smm} 1038228753Smm 1039228753Smmint 1040228753Smmarchive_entry_update_pathname_utf8(struct archive_entry *entry, const char *name) 1041228753Smm{ 1042228753Smm return (aes_update_utf8(&entry->ae_pathname, name)); 1043228753Smm} 1044228753Smm 1045228753Smmvoid 1046228753Smmarchive_entry_set_perm(struct archive_entry *entry, mode_t p) 1047228753Smm{ 1048228753Smm entry->stat_valid = 0; 1049228753Smm entry->ae_stat.aest_mode &= AE_IFMT; 1050228753Smm entry->ae_stat.aest_mode |= ~AE_IFMT & p; 1051228753Smm} 1052228753Smm 1053228753Smmvoid 1054228753Smmarchive_entry_set_rdev(struct archive_entry *entry, dev_t m) 1055228753Smm{ 1056228753Smm entry->stat_valid = 0; 1057228753Smm entry->ae_stat.aest_rdev = m; 1058228753Smm entry->ae_stat.aest_rdev_is_broken_down = 0; 1059228753Smm} 1060228753Smm 1061228753Smmvoid 1062228753Smmarchive_entry_set_rdevmajor(struct archive_entry *entry, dev_t m) 1063228753Smm{ 1064228753Smm entry->stat_valid = 0; 1065228753Smm entry->ae_stat.aest_rdev_is_broken_down = 1; 1066228753Smm entry->ae_stat.aest_rdevmajor = m; 1067228753Smm} 1068228753Smm 1069228753Smmvoid 1070228753Smmarchive_entry_set_rdevminor(struct archive_entry *entry, dev_t m) 1071228753Smm{ 1072228753Smm entry->stat_valid = 0; 1073228753Smm entry->ae_stat.aest_rdev_is_broken_down = 1; 1074228753Smm entry->ae_stat.aest_rdevminor = m; 1075228753Smm} 1076228753Smm 1077228753Smmvoid 1078228753Smmarchive_entry_set_size(struct archive_entry *entry, int64_t s) 1079228753Smm{ 1080228753Smm entry->stat_valid = 0; 1081228753Smm entry->ae_stat.aest_size = s; 1082228753Smm entry->ae_set |= AE_SET_SIZE; 1083228753Smm} 1084228753Smm 1085228753Smmvoid 1086228753Smmarchive_entry_unset_size(struct archive_entry *entry) 1087228753Smm{ 1088228753Smm archive_entry_set_size(entry, 0); 1089228753Smm entry->ae_set &= ~AE_SET_SIZE; 1090228753Smm} 1091228753Smm 1092228753Smmvoid 1093228753Smmarchive_entry_copy_sourcepath(struct archive_entry *entry, const char *path) 1094228753Smm{ 1095228753Smm aes_set_mbs(&entry->ae_sourcepath, path); 1096228753Smm} 1097228753Smm 1098228753Smmvoid 1099228753Smmarchive_entry_set_symlink(struct archive_entry *entry, const char *linkname) 1100228753Smm{ 1101228753Smm aes_set_mbs(&entry->ae_symlink, linkname); 1102228753Smm if (linkname != NULL) 1103228753Smm entry->ae_set |= AE_SET_SYMLINK; 1104228753Smm else 1105228753Smm entry->ae_set &= ~AE_SET_SYMLINK; 1106228753Smm} 1107228753Smm 1108228753Smmvoid 1109228753Smmarchive_entry_copy_symlink(struct archive_entry *entry, const char *linkname) 1110228753Smm{ 1111228753Smm aes_copy_mbs(&entry->ae_symlink, linkname); 1112228753Smm if (linkname != NULL) 1113228753Smm entry->ae_set |= AE_SET_SYMLINK; 1114228753Smm else 1115228753Smm entry->ae_set &= ~AE_SET_SYMLINK; 1116228753Smm} 1117228753Smm 1118228753Smmvoid 1119228753Smmarchive_entry_copy_symlink_w(struct archive_entry *entry, const wchar_t *linkname) 1120228753Smm{ 1121228753Smm aes_copy_wcs(&entry->ae_symlink, linkname); 1122228753Smm if (linkname != NULL) 1123228753Smm entry->ae_set |= AE_SET_SYMLINK; 1124228753Smm else 1125228753Smm entry->ae_set &= ~AE_SET_SYMLINK; 1126228753Smm} 1127228753Smm 1128228753Smmint 1129228753Smmarchive_entry_update_symlink_utf8(struct archive_entry *entry, const char *linkname) 1130228753Smm{ 1131228753Smm if (linkname != NULL) 1132228753Smm entry->ae_set |= AE_SET_SYMLINK; 1133228753Smm else 1134228753Smm entry->ae_set &= ~AE_SET_SYMLINK; 1135228753Smm return (aes_update_utf8(&entry->ae_symlink, linkname)); 1136228753Smm} 1137228753Smm 1138228753Smmvoid 1139228753Smmarchive_entry_set_uid(struct archive_entry *entry, uid_t u) 1140228753Smm{ 1141228753Smm entry->stat_valid = 0; 1142228753Smm entry->ae_stat.aest_uid = u; 1143228753Smm} 1144228753Smm 1145228753Smmvoid 1146228753Smmarchive_entry_set_uname(struct archive_entry *entry, const char *name) 1147228753Smm{ 1148228753Smm aes_set_mbs(&entry->ae_uname, name); 1149228753Smm} 1150228753Smm 1151228753Smmvoid 1152228753Smmarchive_entry_copy_uname(struct archive_entry *entry, const char *name) 1153228753Smm{ 1154228753Smm aes_copy_mbs(&entry->ae_uname, name); 1155228753Smm} 1156228753Smm 1157228753Smmvoid 1158228753Smmarchive_entry_copy_uname_w(struct archive_entry *entry, const wchar_t *name) 1159228753Smm{ 1160228753Smm aes_copy_wcs(&entry->ae_uname, name); 1161228753Smm} 1162228753Smm 1163228753Smmint 1164228753Smmarchive_entry_update_uname_utf8(struct archive_entry *entry, const char *name) 1165228753Smm{ 1166228753Smm return (aes_update_utf8(&entry->ae_uname, name)); 1167228753Smm} 1168228753Smm 1169228753Smm/* 1170228753Smm * ACL management. The following would, of course, be a lot simpler 1171228753Smm * if: 1) the last draft of POSIX.1e were a really thorough and 1172228753Smm * complete standard that addressed the needs of ACL archiving and 2) 1173228753Smm * everyone followed it faithfully. Alas, neither is true, so the 1174228753Smm * following is a lot more complex than might seem necessary to the 1175228753Smm * uninitiated. 1176228753Smm */ 1177228753Smm 1178228753Smmvoid 1179228753Smmarchive_entry_acl_clear(struct archive_entry *entry) 1180228753Smm{ 1181228753Smm struct ae_acl *ap; 1182228753Smm 1183228753Smm while (entry->acl_head != NULL) { 1184228753Smm ap = entry->acl_head->next; 1185228753Smm aes_clean(&entry->acl_head->name); 1186228753Smm free(entry->acl_head); 1187228753Smm entry->acl_head = ap; 1188228753Smm } 1189228753Smm if (entry->acl_text_w != NULL) { 1190228753Smm free(entry->acl_text_w); 1191228753Smm entry->acl_text_w = NULL; 1192228753Smm } 1193228753Smm entry->acl_p = NULL; 1194228753Smm entry->acl_state = 0; /* Not counting. */ 1195228753Smm} 1196228753Smm 1197228753Smm/* 1198228753Smm * Add a single ACL entry to the internal list of ACL data. 1199228753Smm */ 1200228753Smmvoid 1201228753Smmarchive_entry_acl_add_entry(struct archive_entry *entry, 1202228753Smm int type, int permset, int tag, int id, const char *name) 1203228753Smm{ 1204228753Smm struct ae_acl *ap; 1205228753Smm 1206228753Smm if (acl_special(entry, type, permset, tag) == 0) 1207228753Smm return; 1208228753Smm ap = acl_new_entry(entry, type, permset, tag, id); 1209228753Smm if (ap == NULL) { 1210228753Smm /* XXX Error XXX */ 1211228753Smm return; 1212228753Smm } 1213228753Smm if (name != NULL && *name != '\0') 1214228753Smm aes_copy_mbs(&ap->name, name); 1215228753Smm else 1216228753Smm aes_clean(&ap->name); 1217228753Smm} 1218228753Smm 1219228753Smm/* 1220228753Smm * As above, but with a wide-character name. 1221228753Smm */ 1222228753Smmvoid 1223228753Smmarchive_entry_acl_add_entry_w(struct archive_entry *entry, 1224228753Smm int type, int permset, int tag, int id, const wchar_t *name) 1225228753Smm{ 1226228753Smm archive_entry_acl_add_entry_w_len(entry, type, permset, tag, id, name, wcslen(name)); 1227228753Smm} 1228228753Smm 1229228753Smmstatic void 1230228753Smmarchive_entry_acl_add_entry_w_len(struct archive_entry *entry, 1231228753Smm int type, int permset, int tag, int id, const wchar_t *name, size_t len) 1232228753Smm{ 1233228753Smm struct ae_acl *ap; 1234228753Smm 1235228753Smm if (acl_special(entry, type, permset, tag) == 0) 1236228753Smm return; 1237228753Smm ap = acl_new_entry(entry, type, permset, tag, id); 1238228753Smm if (ap == NULL) { 1239228753Smm /* XXX Error XXX */ 1240228753Smm return; 1241228753Smm } 1242228753Smm if (name != NULL && *name != L'\0' && len > 0) 1243228753Smm aes_copy_wcs_len(&ap->name, name, len); 1244228753Smm else 1245228753Smm aes_clean(&ap->name); 1246228753Smm} 1247228753Smm 1248228753Smm/* 1249228753Smm * If this ACL entry is part of the standard POSIX permissions set, 1250228753Smm * store the permissions in the stat structure and return zero. 1251228753Smm */ 1252228753Smmstatic int 1253228753Smmacl_special(struct archive_entry *entry, int type, int permset, int tag) 1254228753Smm{ 1255228753Smm if (type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS) { 1256228753Smm switch (tag) { 1257228753Smm case ARCHIVE_ENTRY_ACL_USER_OBJ: 1258228753Smm entry->ae_stat.aest_mode &= ~0700; 1259228753Smm entry->ae_stat.aest_mode |= (permset & 7) << 6; 1260228753Smm return (0); 1261228753Smm case ARCHIVE_ENTRY_ACL_GROUP_OBJ: 1262228753Smm entry->ae_stat.aest_mode &= ~0070; 1263228753Smm entry->ae_stat.aest_mode |= (permset & 7) << 3; 1264228753Smm return (0); 1265228753Smm case ARCHIVE_ENTRY_ACL_OTHER: 1266228753Smm entry->ae_stat.aest_mode &= ~0007; 1267228753Smm entry->ae_stat.aest_mode |= permset & 7; 1268228753Smm return (0); 1269228753Smm } 1270228753Smm } 1271228753Smm return (1); 1272228753Smm} 1273228753Smm 1274228753Smm/* 1275228753Smm * Allocate and populate a new ACL entry with everything but the 1276228753Smm * name. 1277228753Smm */ 1278228753Smmstatic struct ae_acl * 1279228753Smmacl_new_entry(struct archive_entry *entry, 1280228753Smm int type, int permset, int tag, int id) 1281228753Smm{ 1282228753Smm struct ae_acl *ap, *aq; 1283228753Smm 1284228753Smm if (type != ARCHIVE_ENTRY_ACL_TYPE_ACCESS && 1285228753Smm type != ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) 1286228753Smm return (NULL); 1287228753Smm if (entry->acl_text_w != NULL) { 1288228753Smm free(entry->acl_text_w); 1289228753Smm entry->acl_text_w = NULL; 1290228753Smm } 1291228753Smm 1292228753Smm /* XXX TODO: More sanity-checks on the arguments XXX */ 1293228753Smm 1294228753Smm /* If there's a matching entry already in the list, overwrite it. */ 1295228753Smm ap = entry->acl_head; 1296228753Smm aq = NULL; 1297228753Smm while (ap != NULL) { 1298228753Smm if (ap->type == type && ap->tag == tag && ap->id == id) { 1299228753Smm ap->permset = permset; 1300228753Smm return (ap); 1301228753Smm } 1302228753Smm aq = ap; 1303228753Smm ap = ap->next; 1304228753Smm } 1305228753Smm 1306228753Smm /* Add a new entry to the end of the list. */ 1307228753Smm ap = (struct ae_acl *)malloc(sizeof(*ap)); 1308228753Smm if (ap == NULL) 1309228753Smm return (NULL); 1310228753Smm memset(ap, 0, sizeof(*ap)); 1311228753Smm if (aq == NULL) 1312228753Smm entry->acl_head = ap; 1313228753Smm else 1314228753Smm aq->next = ap; 1315228753Smm ap->type = type; 1316228753Smm ap->tag = tag; 1317228753Smm ap->id = id; 1318228753Smm ap->permset = permset; 1319228753Smm return (ap); 1320228753Smm} 1321228753Smm 1322228753Smm/* 1323228753Smm * Return a count of entries matching "want_type". 1324228753Smm */ 1325228753Smmint 1326228753Smmarchive_entry_acl_count(struct archive_entry *entry, int want_type) 1327228753Smm{ 1328228753Smm int count; 1329228753Smm struct ae_acl *ap; 1330228753Smm 1331228753Smm count = 0; 1332228753Smm ap = entry->acl_head; 1333228753Smm while (ap != NULL) { 1334228753Smm if ((ap->type & want_type) != 0) 1335228753Smm count++; 1336228753Smm ap = ap->next; 1337228753Smm } 1338228753Smm 1339228753Smm if (count > 0 && ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0)) 1340228753Smm count += 3; 1341228753Smm return (count); 1342228753Smm} 1343228753Smm 1344228753Smm/* 1345228753Smm * Prepare for reading entries from the ACL data. Returns a count 1346228753Smm * of entries matching "want_type", or zero if there are no 1347228753Smm * non-extended ACL entries of that type. 1348228753Smm */ 1349228753Smmint 1350228753Smmarchive_entry_acl_reset(struct archive_entry *entry, int want_type) 1351228753Smm{ 1352228753Smm int count, cutoff; 1353228753Smm 1354228753Smm count = archive_entry_acl_count(entry, want_type); 1355228753Smm 1356228753Smm /* 1357228753Smm * If the only entries are the three standard ones, 1358228753Smm * then don't return any ACL data. (In this case, 1359228753Smm * client can just use chmod(2) to set permissions.) 1360228753Smm */ 1361228753Smm if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) 1362228753Smm cutoff = 3; 1363228753Smm else 1364228753Smm cutoff = 0; 1365228753Smm 1366228753Smm if (count > cutoff) 1367228753Smm entry->acl_state = ARCHIVE_ENTRY_ACL_USER_OBJ; 1368228753Smm else 1369228753Smm entry->acl_state = 0; 1370228753Smm entry->acl_p = entry->acl_head; 1371228753Smm return (count); 1372228753Smm} 1373228753Smm 1374228753Smm/* 1375228753Smm * Return the next ACL entry in the list. Fake entries for the 1376228753Smm * standard permissions and include them in the returned list. 1377228753Smm */ 1378228753Smm 1379228753Smmint 1380228753Smmarchive_entry_acl_next(struct archive_entry *entry, int want_type, int *type, 1381228753Smm int *permset, int *tag, int *id, const char **name) 1382228753Smm{ 1383228753Smm *name = NULL; 1384228753Smm *id = -1; 1385228753Smm 1386228753Smm /* 1387228753Smm * The acl_state is either zero (no entries available), -1 1388228753Smm * (reading from list), or an entry type (retrieve that type 1389228753Smm * from ae_stat.aest_mode). 1390228753Smm */ 1391228753Smm if (entry->acl_state == 0) 1392228753Smm return (ARCHIVE_WARN); 1393228753Smm 1394228753Smm /* The first three access entries are special. */ 1395228753Smm if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) { 1396228753Smm switch (entry->acl_state) { 1397228753Smm case ARCHIVE_ENTRY_ACL_USER_OBJ: 1398228753Smm *permset = (entry->ae_stat.aest_mode >> 6) & 7; 1399228753Smm *type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS; 1400228753Smm *tag = ARCHIVE_ENTRY_ACL_USER_OBJ; 1401228753Smm entry->acl_state = ARCHIVE_ENTRY_ACL_GROUP_OBJ; 1402228753Smm return (ARCHIVE_OK); 1403228753Smm case ARCHIVE_ENTRY_ACL_GROUP_OBJ: 1404228753Smm *permset = (entry->ae_stat.aest_mode >> 3) & 7; 1405228753Smm *type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS; 1406228753Smm *tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ; 1407228753Smm entry->acl_state = ARCHIVE_ENTRY_ACL_OTHER; 1408228753Smm return (ARCHIVE_OK); 1409228753Smm case ARCHIVE_ENTRY_ACL_OTHER: 1410228753Smm *permset = entry->ae_stat.aest_mode & 7; 1411228753Smm *type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS; 1412228753Smm *tag = ARCHIVE_ENTRY_ACL_OTHER; 1413228753Smm entry->acl_state = -1; 1414228753Smm entry->acl_p = entry->acl_head; 1415228753Smm return (ARCHIVE_OK); 1416228753Smm default: 1417228753Smm break; 1418228753Smm } 1419228753Smm } 1420228753Smm 1421228753Smm while (entry->acl_p != NULL && (entry->acl_p->type & want_type) == 0) 1422228753Smm entry->acl_p = entry->acl_p->next; 1423228753Smm if (entry->acl_p == NULL) { 1424228753Smm entry->acl_state = 0; 1425228753Smm *type = 0; 1426228753Smm *permset = 0; 1427228753Smm *tag = 0; 1428228753Smm *id = -1; 1429228753Smm *name = NULL; 1430228753Smm return (ARCHIVE_EOF); /* End of ACL entries. */ 1431228753Smm } 1432228753Smm *type = entry->acl_p->type; 1433228753Smm *permset = entry->acl_p->permset; 1434228753Smm *tag = entry->acl_p->tag; 1435228753Smm *id = entry->acl_p->id; 1436228753Smm *name = aes_get_mbs(&entry->acl_p->name); 1437228753Smm entry->acl_p = entry->acl_p->next; 1438228753Smm return (ARCHIVE_OK); 1439228753Smm} 1440228753Smm 1441228753Smm/* 1442228753Smm * Generate a text version of the ACL. The flags parameter controls 1443228753Smm * the style of the generated ACL. 1444228753Smm */ 1445228753Smmconst wchar_t * 1446228753Smmarchive_entry_acl_text_w(struct archive_entry *entry, int flags) 1447228753Smm{ 1448228753Smm int count; 1449228753Smm size_t length; 1450228753Smm const wchar_t *wname; 1451228753Smm const wchar_t *prefix; 1452228753Smm wchar_t separator; 1453228753Smm struct ae_acl *ap; 1454228753Smm int id; 1455228753Smm wchar_t *wp; 1456228753Smm 1457228753Smm if (entry->acl_text_w != NULL) { 1458228753Smm free (entry->acl_text_w); 1459228753Smm entry->acl_text_w = NULL; 1460228753Smm } 1461228753Smm 1462228753Smm separator = L','; 1463228753Smm count = 0; 1464228753Smm length = 0; 1465228753Smm ap = entry->acl_head; 1466228753Smm while (ap != NULL) { 1467228753Smm if ((ap->type & flags) != 0) { 1468228753Smm count++; 1469228753Smm if ((flags & ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT) && 1470228753Smm (ap->type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT)) 1471228753Smm length += 8; /* "default:" */ 1472228753Smm length += 5; /* tag name */ 1473228753Smm length += 1; /* colon */ 1474228753Smm wname = aes_get_wcs(&ap->name); 1475228753Smm if (wname != NULL) 1476228753Smm length += wcslen(wname); 1477228753Smm else 1478228753Smm length += sizeof(uid_t) * 3 + 1; 1479228753Smm length ++; /* colon */ 1480228753Smm length += 3; /* rwx */ 1481228753Smm length += 1; /* colon */ 1482228753Smm length += max(sizeof(uid_t), sizeof(gid_t)) * 3 + 1; 1483228753Smm length ++; /* newline */ 1484228753Smm } 1485228753Smm ap = ap->next; 1486228753Smm } 1487228753Smm 1488228753Smm if (count > 0 && ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0)) { 1489228753Smm length += 10; /* "user::rwx\n" */ 1490228753Smm length += 11; /* "group::rwx\n" */ 1491228753Smm length += 11; /* "other::rwx\n" */ 1492228753Smm } 1493228753Smm 1494228753Smm if (count == 0) 1495228753Smm return (NULL); 1496228753Smm 1497228753Smm /* Now, allocate the string and actually populate it. */ 1498228753Smm wp = entry->acl_text_w = (wchar_t *)malloc(length * sizeof(wchar_t)); 1499228753Smm if (wp == NULL) 1500228753Smm __archive_errx(1, "No memory to generate the text version of the ACL"); 1501228753Smm count = 0; 1502228753Smm if ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) { 1503228753Smm append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_USER_OBJ, NULL, 1504228753Smm entry->ae_stat.aest_mode & 0700, -1); 1505228753Smm *wp++ = ','; 1506228753Smm append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_GROUP_OBJ, NULL, 1507228753Smm entry->ae_stat.aest_mode & 0070, -1); 1508228753Smm *wp++ = ','; 1509228753Smm append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_OTHER, NULL, 1510228753Smm entry->ae_stat.aest_mode & 0007, -1); 1511228753Smm count += 3; 1512228753Smm 1513228753Smm ap = entry->acl_head; 1514228753Smm while (ap != NULL) { 1515228753Smm if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) { 1516228753Smm wname = aes_get_wcs(&ap->name); 1517228753Smm *wp++ = separator; 1518228753Smm if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID) 1519228753Smm id = ap->id; 1520228753Smm else 1521228753Smm id = -1; 1522228753Smm append_entry_w(&wp, NULL, ap->tag, wname, 1523228753Smm ap->permset, id); 1524228753Smm count++; 1525228753Smm } 1526228753Smm ap = ap->next; 1527228753Smm } 1528228753Smm } 1529228753Smm 1530228753Smm 1531228753Smm if ((flags & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) { 1532228753Smm if (flags & ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT) 1533228753Smm prefix = L"default:"; 1534228753Smm else 1535228753Smm prefix = NULL; 1536228753Smm ap = entry->acl_head; 1537228753Smm count = 0; 1538228753Smm while (ap != NULL) { 1539228753Smm if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) { 1540228753Smm wname = aes_get_wcs(&ap->name); 1541228753Smm if (count > 0) 1542228753Smm *wp++ = separator; 1543228753Smm if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID) 1544228753Smm id = ap->id; 1545228753Smm else 1546228753Smm id = -1; 1547228753Smm append_entry_w(&wp, prefix, ap->tag, 1548228753Smm wname, ap->permset, id); 1549228753Smm count ++; 1550228753Smm } 1551228753Smm ap = ap->next; 1552228753Smm } 1553228753Smm } 1554228753Smm 1555228753Smm return (entry->acl_text_w); 1556228753Smm} 1557228753Smm 1558228753Smmstatic void 1559228753Smmappend_id_w(wchar_t **wp, int id) 1560228753Smm{ 1561228753Smm if (id < 0) 1562228753Smm id = 0; 1563228753Smm if (id > 9) 1564228753Smm append_id_w(wp, id / 10); 1565228753Smm *(*wp)++ = L"0123456789"[id % 10]; 1566228753Smm} 1567228753Smm 1568228753Smmstatic void 1569228753Smmappend_entry_w(wchar_t **wp, const wchar_t *prefix, int tag, 1570228753Smm const wchar_t *wname, int perm, int id) 1571228753Smm{ 1572228753Smm if (prefix != NULL) { 1573228753Smm wcscpy(*wp, prefix); 1574228753Smm *wp += wcslen(*wp); 1575228753Smm } 1576228753Smm switch (tag) { 1577228753Smm case ARCHIVE_ENTRY_ACL_USER_OBJ: 1578228753Smm wname = NULL; 1579228753Smm id = -1; 1580228753Smm /* FALLTHROUGH */ 1581228753Smm case ARCHIVE_ENTRY_ACL_USER: 1582228753Smm wcscpy(*wp, L"user"); 1583228753Smm break; 1584228753Smm case ARCHIVE_ENTRY_ACL_GROUP_OBJ: 1585228753Smm wname = NULL; 1586228753Smm id = -1; 1587228753Smm /* FALLTHROUGH */ 1588228753Smm case ARCHIVE_ENTRY_ACL_GROUP: 1589228753Smm wcscpy(*wp, L"group"); 1590228753Smm break; 1591228753Smm case ARCHIVE_ENTRY_ACL_MASK: 1592228753Smm wcscpy(*wp, L"mask"); 1593228753Smm wname = NULL; 1594228753Smm id = -1; 1595228753Smm break; 1596228753Smm case ARCHIVE_ENTRY_ACL_OTHER: 1597228753Smm wcscpy(*wp, L"other"); 1598228753Smm wname = NULL; 1599228753Smm id = -1; 1600228753Smm break; 1601228753Smm } 1602228753Smm *wp += wcslen(*wp); 1603228753Smm *(*wp)++ = L':'; 1604228753Smm if (wname != NULL) { 1605228753Smm wcscpy(*wp, wname); 1606228753Smm *wp += wcslen(*wp); 1607228753Smm } else if (tag == ARCHIVE_ENTRY_ACL_USER 1608228753Smm || tag == ARCHIVE_ENTRY_ACL_GROUP) { 1609228753Smm append_id_w(wp, id); 1610228753Smm id = -1; 1611228753Smm } 1612228753Smm *(*wp)++ = L':'; 1613228753Smm *(*wp)++ = (perm & 0444) ? L'r' : L'-'; 1614228753Smm *(*wp)++ = (perm & 0222) ? L'w' : L'-'; 1615228753Smm *(*wp)++ = (perm & 0111) ? L'x' : L'-'; 1616228753Smm if (id != -1) { 1617228753Smm *(*wp)++ = L':'; 1618228753Smm append_id_w(wp, id); 1619228753Smm } 1620228753Smm **wp = L'\0'; 1621228753Smm} 1622228753Smm 1623228753Smm/* 1624228753Smm * Parse a textual ACL. This automatically recognizes and supports 1625228753Smm * extensions described above. The 'type' argument is used to 1626228753Smm * indicate the type that should be used for any entries not 1627228753Smm * explicitly marked as "default:". 1628228753Smm */ 1629228753Smmint 1630228753Smm__archive_entry_acl_parse_w(struct archive_entry *entry, 1631228753Smm const wchar_t *text, int default_type) 1632228753Smm{ 1633228753Smm struct { 1634228753Smm const wchar_t *start; 1635228753Smm const wchar_t *end; 1636228753Smm } field[4], name; 1637228753Smm 1638228753Smm int fields, n; 1639228753Smm int type, tag, permset, id; 1640228753Smm wchar_t sep; 1641228753Smm 1642228753Smm while (text != NULL && *text != L'\0') { 1643228753Smm /* 1644228753Smm * Parse the fields out of the next entry, 1645228753Smm * advance 'text' to start of next entry. 1646228753Smm */ 1647228753Smm fields = 0; 1648228753Smm do { 1649228753Smm const wchar_t *start, *end; 1650228753Smm next_field_w(&text, &start, &end, &sep); 1651228753Smm if (fields < 4) { 1652228753Smm field[fields].start = start; 1653228753Smm field[fields].end = end; 1654228753Smm } 1655228753Smm ++fields; 1656228753Smm } while (sep == L':'); 1657228753Smm 1658228753Smm /* Set remaining fields to blank. */ 1659228753Smm for (n = fields; n < 4; ++n) 1660228753Smm field[n].start = field[n].end = NULL; 1661228753Smm 1662228753Smm /* Check for a numeric ID in field 1 or 3. */ 1663228753Smm id = -1; 1664228753Smm isint_w(field[1].start, field[1].end, &id); 1665228753Smm /* Field 3 is optional. */ 1666228753Smm if (id == -1 && fields > 3) 1667228753Smm isint_w(field[3].start, field[3].end, &id); 1668228753Smm 1669228753Smm /* 1670228753Smm * Solaris extension: "defaultuser::rwx" is the 1671228753Smm * default ACL corresponding to "user::rwx", etc. 1672228753Smm */ 1673228753Smm if (field[0].end - field[0].start > 7 1674228753Smm && wmemcmp(field[0].start, L"default", 7) == 0) { 1675228753Smm type = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT; 1676228753Smm field[0].start += 7; 1677228753Smm } else 1678228753Smm type = default_type; 1679228753Smm 1680228753Smm name.start = name.end = NULL; 1681228753Smm if (prefix_w(field[0].start, field[0].end, L"user")) { 1682228753Smm if (!ismode_w(field[2].start, field[2].end, &permset)) 1683228753Smm return (ARCHIVE_WARN); 1684228753Smm if (id != -1 || field[1].start < field[1].end) { 1685228753Smm tag = ARCHIVE_ENTRY_ACL_USER; 1686228753Smm name = field[1]; 1687228753Smm } else 1688228753Smm tag = ARCHIVE_ENTRY_ACL_USER_OBJ; 1689228753Smm } else if (prefix_w(field[0].start, field[0].end, L"group")) { 1690228753Smm if (!ismode_w(field[2].start, field[2].end, &permset)) 1691228753Smm return (ARCHIVE_WARN); 1692228753Smm if (id != -1 || field[1].start < field[1].end) { 1693228753Smm tag = ARCHIVE_ENTRY_ACL_GROUP; 1694228753Smm name = field[1]; 1695228753Smm } else 1696228753Smm tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ; 1697228753Smm } else if (prefix_w(field[0].start, field[0].end, L"other")) { 1698228753Smm if (fields == 2 1699228753Smm && field[1].start < field[1].end 1700228753Smm && ismode_w(field[1].start, field[1].end, &permset)) { 1701228753Smm /* This is Solaris-style "other:rwx" */ 1702228753Smm } else if (fields == 3 1703228753Smm && field[1].start == field[1].end 1704228753Smm && field[2].start < field[2].end 1705228753Smm && ismode_w(field[2].start, field[2].end, &permset)) { 1706228753Smm /* This is FreeBSD-style "other::rwx" */ 1707228753Smm } else 1708228753Smm return (ARCHIVE_WARN); 1709228753Smm tag = ARCHIVE_ENTRY_ACL_OTHER; 1710228753Smm } else if (prefix_w(field[0].start, field[0].end, L"mask")) { 1711228753Smm if (fields == 2 1712228753Smm && field[1].start < field[1].end 1713228753Smm && ismode_w(field[1].start, field[1].end, &permset)) { 1714228753Smm /* This is Solaris-style "mask:rwx" */ 1715228753Smm } else if (fields == 3 1716228753Smm && field[1].start == field[1].end 1717228753Smm && field[2].start < field[2].end 1718228753Smm && ismode_w(field[2].start, field[2].end, &permset)) { 1719228753Smm /* This is FreeBSD-style "mask::rwx" */ 1720228753Smm } else 1721228753Smm return (ARCHIVE_WARN); 1722228753Smm tag = ARCHIVE_ENTRY_ACL_MASK; 1723228753Smm } else 1724228753Smm return (ARCHIVE_WARN); 1725228753Smm 1726228753Smm /* Add entry to the internal list. */ 1727228753Smm archive_entry_acl_add_entry_w_len(entry, type, permset, 1728228753Smm tag, id, name.start, name.end - name.start); 1729228753Smm } 1730228753Smm return (ARCHIVE_OK); 1731228753Smm} 1732228753Smm 1733228753Smm/* 1734228753Smm * Parse a string to a positive decimal integer. Returns true if 1735228753Smm * the string is non-empty and consists only of decimal digits, 1736228753Smm * false otherwise. 1737228753Smm */ 1738228753Smmstatic int 1739228753Smmisint_w(const wchar_t *start, const wchar_t *end, int *result) 1740228753Smm{ 1741228753Smm int n = 0; 1742228753Smm if (start >= end) 1743228753Smm return (0); 1744228753Smm while (start < end) { 1745228753Smm if (*start < '0' || *start > '9') 1746228753Smm return (0); 1747228753Smm if (n > (INT_MAX / 10)) 1748228753Smm n = INT_MAX; 1749228753Smm else { 1750228753Smm n *= 10; 1751228753Smm n += *start - '0'; 1752228753Smm } 1753228753Smm start++; 1754228753Smm } 1755228753Smm *result = n; 1756228753Smm return (1); 1757228753Smm} 1758228753Smm 1759228753Smm/* 1760228753Smm * Parse a string as a mode field. Returns true if 1761228753Smm * the string is non-empty and consists only of mode characters, 1762228753Smm * false otherwise. 1763228753Smm */ 1764228753Smmstatic int 1765228753Smmismode_w(const wchar_t *start, const wchar_t *end, int *permset) 1766228753Smm{ 1767228753Smm const wchar_t *p; 1768228753Smm 1769228753Smm if (start >= end) 1770228753Smm return (0); 1771228753Smm p = start; 1772228753Smm *permset = 0; 1773228753Smm while (p < end) { 1774228753Smm switch (*p++) { 1775228753Smm case 'r': case 'R': 1776228753Smm *permset |= ARCHIVE_ENTRY_ACL_READ; 1777228753Smm break; 1778228753Smm case 'w': case 'W': 1779228753Smm *permset |= ARCHIVE_ENTRY_ACL_WRITE; 1780228753Smm break; 1781228753Smm case 'x': case 'X': 1782228753Smm *permset |= ARCHIVE_ENTRY_ACL_EXECUTE; 1783228753Smm break; 1784228753Smm case '-': 1785228753Smm break; 1786228753Smm default: 1787228753Smm return (0); 1788228753Smm } 1789228753Smm } 1790228753Smm return (1); 1791228753Smm} 1792228753Smm 1793228753Smm/* 1794228753Smm * Match "[:whitespace:]*(.*)[:whitespace:]*[:,\n]". *wp is updated 1795228753Smm * to point to just after the separator. *start points to the first 1796228753Smm * character of the matched text and *end just after the last 1797228753Smm * character of the matched identifier. In particular *end - *start 1798228753Smm * is the length of the field body, not including leading or trailing 1799228753Smm * whitespace. 1800228753Smm */ 1801228753Smmstatic void 1802228753Smmnext_field_w(const wchar_t **wp, const wchar_t **start, 1803228753Smm const wchar_t **end, wchar_t *sep) 1804228753Smm{ 1805228753Smm /* Skip leading whitespace to find start of field. */ 1806228753Smm while (**wp == L' ' || **wp == L'\t' || **wp == L'\n') { 1807228753Smm (*wp)++; 1808228753Smm } 1809228753Smm *start = *wp; 1810228753Smm 1811228753Smm /* Scan for the separator. */ 1812228753Smm while (**wp != L'\0' && **wp != L',' && **wp != L':' && 1813228753Smm **wp != L'\n') { 1814228753Smm (*wp)++; 1815228753Smm } 1816228753Smm *sep = **wp; 1817228753Smm 1818228753Smm /* Trim trailing whitespace to locate end of field. */ 1819228753Smm *end = *wp - 1; 1820228753Smm while (**end == L' ' || **end == L'\t' || **end == L'\n') { 1821228753Smm (*end)--; 1822228753Smm } 1823228753Smm (*end)++; 1824228753Smm 1825228753Smm /* Adjust scanner location. */ 1826228753Smm if (**wp != L'\0') 1827228753Smm (*wp)++; 1828228753Smm} 1829228753Smm 1830228753Smm/* 1831228753Smm * Return true if the characters [start...end) are a prefix of 'test'. 1832228753Smm * This makes it easy to handle the obvious abbreviations: 'u' for 'user', etc. 1833228753Smm */ 1834228753Smmstatic int 1835228753Smmprefix_w(const wchar_t *start, const wchar_t *end, const wchar_t *test) 1836228753Smm{ 1837228753Smm if (start == end) 1838228753Smm return (0); 1839228753Smm 1840228753Smm if (*start++ != *test++) 1841228753Smm return (0); 1842228753Smm 1843228753Smm while (start < end && *start++ == *test++) 1844228753Smm ; 1845228753Smm 1846228753Smm if (start < end) 1847228753Smm return (0); 1848228753Smm 1849228753Smm return (1); 1850228753Smm} 1851228753Smm 1852228753Smm 1853228753Smm/* 1854228753Smm * Following code is modified from UC Berkeley sources, and 1855228753Smm * is subject to the following copyright notice. 1856228753Smm */ 1857228753Smm 1858228753Smm/*- 1859228753Smm * Copyright (c) 1993 1860228753Smm * The Regents of the University of California. All rights reserved. 1861228753Smm * 1862228753Smm * Redistribution and use in source and binary forms, with or without 1863228753Smm * modification, are permitted provided that the following conditions 1864228753Smm * are met: 1865228753Smm * 1. Redistributions of source code must retain the above copyright 1866228753Smm * notice, this list of conditions and the following disclaimer. 1867228753Smm * 2. Redistributions in binary form must reproduce the above copyright 1868228753Smm * notice, this list of conditions and the following disclaimer in the 1869228753Smm * documentation and/or other materials provided with the distribution. 1870228753Smm * 4. Neither the name of the University nor the names of its contributors 1871228753Smm * may be used to endorse or promote products derived from this software 1872228753Smm * without specific prior written permission. 1873228753Smm * 1874228753Smm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 1875228753Smm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1876228753Smm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1877228753Smm * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 1878228753Smm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1879228753Smm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 1880228753Smm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 1881228753Smm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 1882228753Smm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 1883228753Smm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 1884228753Smm * SUCH DAMAGE. 1885228753Smm */ 1886228753Smm 1887228753Smmstatic struct flag { 1888228753Smm const char *name; 1889228753Smm const wchar_t *wname; 1890228753Smm unsigned long set; 1891228753Smm unsigned long clear; 1892228753Smm} flags[] = { 1893228753Smm /* Preferred (shorter) names per flag first, all prefixed by "no" */ 1894228753Smm#ifdef SF_APPEND 1895228753Smm { "nosappnd", L"nosappnd", SF_APPEND, 0 }, 1896228753Smm { "nosappend", L"nosappend", SF_APPEND, 0 }, 1897228753Smm#endif 1898228753Smm#ifdef EXT2_APPEND_FL /* 'a' */ 1899228753Smm { "nosappnd", L"nosappnd", EXT2_APPEND_FL, 0 }, 1900228753Smm { "nosappend", L"nosappend", EXT2_APPEND_FL, 0 }, 1901228753Smm#endif 1902228753Smm#ifdef SF_ARCHIVED 1903228753Smm { "noarch", L"noarch", SF_ARCHIVED, 0 }, 1904228753Smm { "noarchived", L"noarchived", SF_ARCHIVED, 0 }, 1905228753Smm#endif 1906228753Smm#ifdef SF_IMMUTABLE 1907228753Smm { "noschg", L"noschg", SF_IMMUTABLE, 0 }, 1908228753Smm { "noschange", L"noschange", SF_IMMUTABLE, 0 }, 1909228753Smm { "nosimmutable", L"nosimmutable", SF_IMMUTABLE, 0 }, 1910228753Smm#endif 1911228753Smm#ifdef EXT2_IMMUTABLE_FL /* 'i' */ 1912228753Smm { "noschg", L"noschg", EXT2_IMMUTABLE_FL, 0 }, 1913228753Smm { "noschange", L"noschange", EXT2_IMMUTABLE_FL, 0 }, 1914228753Smm { "nosimmutable", L"nosimmutable", EXT2_IMMUTABLE_FL, 0 }, 1915228753Smm#endif 1916228753Smm#ifdef SF_NOUNLINK 1917228753Smm { "nosunlnk", L"nosunlnk", SF_NOUNLINK, 0 }, 1918228753Smm { "nosunlink", L"nosunlink", SF_NOUNLINK, 0 }, 1919228753Smm#endif 1920228753Smm#ifdef SF_SNAPSHOT 1921228753Smm { "nosnapshot", L"nosnapshot", SF_SNAPSHOT, 0 }, 1922228753Smm#endif 1923228753Smm#ifdef UF_APPEND 1924228753Smm { "nouappnd", L"nouappnd", UF_APPEND, 0 }, 1925228753Smm { "nouappend", L"nouappend", UF_APPEND, 0 }, 1926228753Smm#endif 1927228753Smm#ifdef UF_IMMUTABLE 1928228753Smm { "nouchg", L"nouchg", UF_IMMUTABLE, 0 }, 1929228753Smm { "nouchange", L"nouchange", UF_IMMUTABLE, 0 }, 1930228753Smm { "nouimmutable", L"nouimmutable", UF_IMMUTABLE, 0 }, 1931228753Smm#endif 1932228753Smm#ifdef UF_NODUMP 1933228753Smm { "nodump", L"nodump", 0, UF_NODUMP}, 1934228753Smm#endif 1935228753Smm#ifdef EXT2_NODUMP_FL /* 'd' */ 1936228753Smm { "nodump", L"nodump", 0, EXT2_NODUMP_FL}, 1937228753Smm#endif 1938228753Smm#ifdef UF_OPAQUE 1939228753Smm { "noopaque", L"noopaque", UF_OPAQUE, 0 }, 1940228753Smm#endif 1941228753Smm#ifdef UF_NOUNLINK 1942228753Smm { "nouunlnk", L"nouunlnk", UF_NOUNLINK, 0 }, 1943228753Smm { "nouunlink", L"nouunlink", UF_NOUNLINK, 0 }, 1944228753Smm#endif 1945228753Smm#ifdef EXT2_UNRM_FL 1946228753Smm { "nouunlink", L"nouunlink", EXT2_UNRM_FL, 0}, 1947228753Smm#endif 1948228753Smm 1949228753Smm#ifdef EXT2_BTREE_FL 1950228753Smm { "nobtree", L"nobtree", EXT2_BTREE_FL, 0 }, 1951228753Smm#endif 1952228753Smm 1953228753Smm#ifdef EXT2_ECOMPR_FL 1954228753Smm { "nocomperr", L"nocomperr", EXT2_ECOMPR_FL, 0 }, 1955228753Smm#endif 1956228753Smm 1957228753Smm#ifdef EXT2_COMPR_FL /* 'c' */ 1958228753Smm { "nocompress", L"nocompress", EXT2_COMPR_FL, 0 }, 1959228753Smm#endif 1960228753Smm 1961228753Smm#ifdef EXT2_NOATIME_FL /* 'A' */ 1962228753Smm { "noatime", L"noatime", 0, EXT2_NOATIME_FL}, 1963228753Smm#endif 1964228753Smm 1965228753Smm#ifdef EXT2_DIRTY_FL 1966228753Smm { "nocompdirty",L"nocompdirty", EXT2_DIRTY_FL, 0}, 1967228753Smm#endif 1968228753Smm 1969228753Smm#ifdef EXT2_COMPRBLK_FL 1970228753Smm#ifdef EXT2_NOCOMPR_FL 1971228753Smm { "nocomprblk", L"nocomprblk", EXT2_COMPRBLK_FL, EXT2_NOCOMPR_FL}, 1972228753Smm#else 1973228753Smm { "nocomprblk", L"nocomprblk", EXT2_COMPRBLK_FL, 0}, 1974228753Smm#endif 1975228753Smm#endif 1976228753Smm#ifdef EXT2_DIRSYNC_FL 1977228753Smm { "nodirsync", L"nodirsync", EXT2_DIRSYNC_FL, 0}, 1978228753Smm#endif 1979228753Smm#ifdef EXT2_INDEX_FL 1980228753Smm { "nohashidx", L"nohashidx", EXT2_INDEX_FL, 0}, 1981228753Smm#endif 1982228753Smm#ifdef EXT2_IMAGIC_FL 1983228753Smm { "noimagic", L"noimagic", EXT2_IMAGIC_FL, 0}, 1984228753Smm#endif 1985228753Smm#ifdef EXT3_JOURNAL_DATA_FL 1986228753Smm { "nojournal", L"nojournal", EXT3_JOURNAL_DATA_FL, 0}, 1987228753Smm#endif 1988228753Smm#ifdef EXT2_SECRM_FL 1989228753Smm { "nosecuredeletion",L"nosecuredeletion",EXT2_SECRM_FL, 0}, 1990228753Smm#endif 1991228753Smm#ifdef EXT2_SYNC_FL 1992228753Smm { "nosync", L"nosync", EXT2_SYNC_FL, 0}, 1993228753Smm#endif 1994228753Smm#ifdef EXT2_NOTAIL_FL 1995228753Smm { "notail", L"notail", 0, EXT2_NOTAIL_FL}, 1996228753Smm#endif 1997228753Smm#ifdef EXT2_TOPDIR_FL 1998228753Smm { "notopdir", L"notopdir", EXT2_TOPDIR_FL, 0}, 1999228753Smm#endif 2000228753Smm#ifdef EXT2_RESERVED_FL 2001228753Smm { "noreserved", L"noreserved", EXT2_RESERVED_FL, 0}, 2002228753Smm#endif 2003228753Smm 2004228753Smm { NULL, NULL, 0, 0 } 2005228753Smm}; 2006228753Smm 2007228753Smm/* 2008228753Smm * fflagstostr -- 2009228753Smm * Convert file flags to a comma-separated string. If no flags 2010228753Smm * are set, return the empty string. 2011228753Smm */ 2012228753Smmstatic char * 2013228753Smmae_fflagstostr(unsigned long bitset, unsigned long bitclear) 2014228753Smm{ 2015228753Smm char *string, *dp; 2016228753Smm const char *sp; 2017228753Smm unsigned long bits; 2018228753Smm struct flag *flag; 2019228753Smm size_t length; 2020228753Smm 2021228753Smm bits = bitset | bitclear; 2022228753Smm length = 0; 2023228753Smm for (flag = flags; flag->name != NULL; flag++) 2024228753Smm if (bits & (flag->set | flag->clear)) { 2025228753Smm length += strlen(flag->name) + 1; 2026228753Smm bits &= ~(flag->set | flag->clear); 2027228753Smm } 2028228753Smm 2029228753Smm if (length == 0) 2030228753Smm return (NULL); 2031228753Smm string = (char *)malloc(length); 2032228753Smm if (string == NULL) 2033228753Smm return (NULL); 2034228753Smm 2035228753Smm dp = string; 2036228753Smm for (flag = flags; flag->name != NULL; flag++) { 2037228753Smm if (bitset & flag->set || bitclear & flag->clear) { 2038228753Smm sp = flag->name + 2; 2039228753Smm } else if (bitset & flag->clear || bitclear & flag->set) { 2040228753Smm sp = flag->name; 2041228753Smm } else 2042228753Smm continue; 2043228753Smm bitset &= ~(flag->set | flag->clear); 2044228753Smm bitclear &= ~(flag->set | flag->clear); 2045228753Smm if (dp > string) 2046228753Smm *dp++ = ','; 2047228753Smm while ((*dp++ = *sp++) != '\0') 2048228753Smm ; 2049228753Smm dp--; 2050228753Smm } 2051228753Smm 2052228753Smm *dp = '\0'; 2053228753Smm return (string); 2054228753Smm} 2055228753Smm 2056228753Smm/* 2057228753Smm * strtofflags -- 2058228753Smm * Take string of arguments and return file flags. This 2059228753Smm * version works a little differently than strtofflags(3). 2060228753Smm * In particular, it always tests every token, skipping any 2061228753Smm * unrecognized tokens. It returns a pointer to the first 2062228753Smm * unrecognized token, or NULL if every token was recognized. 2063228753Smm * This version is also const-correct and does not modify the 2064228753Smm * provided string. 2065228753Smm */ 2066228753Smmstatic const char * 2067228753Smmae_strtofflags(const char *s, unsigned long *setp, unsigned long *clrp) 2068228753Smm{ 2069228753Smm const char *start, *end; 2070228753Smm struct flag *flag; 2071228753Smm unsigned long set, clear; 2072228753Smm const char *failed; 2073228753Smm 2074228753Smm set = clear = 0; 2075228753Smm start = s; 2076228753Smm failed = NULL; 2077228753Smm /* Find start of first token. */ 2078228753Smm while (*start == '\t' || *start == ' ' || *start == ',') 2079228753Smm start++; 2080228753Smm while (*start != '\0') { 2081228753Smm /* Locate end of token. */ 2082228753Smm end = start; 2083228753Smm while (*end != '\0' && *end != '\t' && 2084228753Smm *end != ' ' && *end != ',') 2085228753Smm end++; 2086228753Smm for (flag = flags; flag->name != NULL; flag++) { 2087228753Smm if (memcmp(start, flag->name, end - start) == 0) { 2088228753Smm /* Matched "noXXXX", so reverse the sense. */ 2089228753Smm clear |= flag->set; 2090228753Smm set |= flag->clear; 2091228753Smm break; 2092228753Smm } else if (memcmp(start, flag->name + 2, end - start) 2093228753Smm == 0) { 2094228753Smm /* Matched "XXXX", so don't reverse. */ 2095228753Smm set |= flag->set; 2096228753Smm clear |= flag->clear; 2097228753Smm break; 2098228753Smm } 2099228753Smm } 2100228753Smm /* Ignore unknown flag names. */ 2101228753Smm if (flag->name == NULL && failed == NULL) 2102228753Smm failed = start; 2103228753Smm 2104228753Smm /* Find start of next token. */ 2105228753Smm start = end; 2106228753Smm while (*start == '\t' || *start == ' ' || *start == ',') 2107228753Smm start++; 2108228753Smm 2109228753Smm } 2110228753Smm 2111228753Smm if (setp) 2112228753Smm *setp = set; 2113228753Smm if (clrp) 2114228753Smm *clrp = clear; 2115228753Smm 2116228753Smm /* Return location of first failure. */ 2117228753Smm return (failed); 2118228753Smm} 2119228753Smm 2120228753Smm/* 2121228753Smm * wcstofflags -- 2122228753Smm * Take string of arguments and return file flags. This 2123228753Smm * version works a little differently than strtofflags(3). 2124228753Smm * In particular, it always tests every token, skipping any 2125228753Smm * unrecognized tokens. It returns a pointer to the first 2126228753Smm * unrecognized token, or NULL if every token was recognized. 2127228753Smm * This version is also const-correct and does not modify the 2128228753Smm * provided string. 2129228753Smm */ 2130228753Smmstatic const wchar_t * 2131228753Smmae_wcstofflags(const wchar_t *s, unsigned long *setp, unsigned long *clrp) 2132228753Smm{ 2133228753Smm const wchar_t *start, *end; 2134228753Smm struct flag *flag; 2135228753Smm unsigned long set, clear; 2136228753Smm const wchar_t *failed; 2137228753Smm 2138228753Smm set = clear = 0; 2139228753Smm start = s; 2140228753Smm failed = NULL; 2141228753Smm /* Find start of first token. */ 2142228753Smm while (*start == L'\t' || *start == L' ' || *start == L',') 2143228753Smm start++; 2144228753Smm while (*start != L'\0') { 2145228753Smm /* Locate end of token. */ 2146228753Smm end = start; 2147228753Smm while (*end != L'\0' && *end != L'\t' && 2148228753Smm *end != L' ' && *end != L',') 2149228753Smm end++; 2150228753Smm for (flag = flags; flag->wname != NULL; flag++) { 2151228753Smm if (wmemcmp(start, flag->wname, end - start) == 0) { 2152228753Smm /* Matched "noXXXX", so reverse the sense. */ 2153228753Smm clear |= flag->set; 2154228753Smm set |= flag->clear; 2155228753Smm break; 2156228753Smm } else if (wmemcmp(start, flag->wname + 2, end - start) 2157228753Smm == 0) { 2158228753Smm /* Matched "XXXX", so don't reverse. */ 2159228753Smm set |= flag->set; 2160228753Smm clear |= flag->clear; 2161228753Smm break; 2162228753Smm } 2163228753Smm } 2164228753Smm /* Ignore unknown flag names. */ 2165228753Smm if (flag->wname == NULL && failed == NULL) 2166228753Smm failed = start; 2167228753Smm 2168228753Smm /* Find start of next token. */ 2169228753Smm start = end; 2170228753Smm while (*start == L'\t' || *start == L' ' || *start == L',') 2171228753Smm start++; 2172228753Smm 2173228753Smm } 2174228753Smm 2175228753Smm if (setp) 2176228753Smm *setp = set; 2177228753Smm if (clrp) 2178228753Smm *clrp = clear; 2179228753Smm 2180228753Smm /* Return location of first failure. */ 2181228753Smm return (failed); 2182228753Smm} 2183228753Smm 2184228753Smm 2185228753Smm#ifdef TEST 2186228753Smm#include <stdio.h> 2187228753Smmint 2188228753Smmmain(int argc, char **argv) 2189228753Smm{ 2190228753Smm struct archive_entry *entry = archive_entry_new(); 2191228753Smm unsigned long set, clear; 2192228753Smm const wchar_t *remainder; 2193228753Smm 2194228753Smm remainder = archive_entry_copy_fflags_text_w(entry, L"nosappnd dump archive,,,,,,,"); 2195228753Smm archive_entry_fflags(entry, &set, &clear); 2196228753Smm 2197228753Smm wprintf(L"set=0x%lX clear=0x%lX remainder='%ls'\n", set, clear, remainder); 2198228753Smm 2199228753Smm wprintf(L"new flags='%s'\n", archive_entry_fflags_text(entry)); 2200228753Smm return (0); 2201228753Smm} 2202228753Smm#endif 2203