Path: blob/master/Utilities/cmlibarchive/libarchive/archive_entry.c
5021 views
/*-1* Copyright (c) 2003-2007 Tim Kientzle2* Copyright (c) 2016 Martin Matuska3* All rights reserved.4*5* Redistribution and use in source and binary forms, with or without6* modification, are permitted provided that the following conditions7* are met:8* 1. Redistributions of source code must retain the above copyright9* notice, this list of conditions and the following disclaimer.10* 2. Redistributions in binary form must reproduce the above copyright11* notice, this list of conditions and the following disclaimer in the12* documentation and/or other materials provided with the distribution.13*14* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR15* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES16* 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, BUT19* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,20* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY21* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT22* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF23* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.24*/2526#include "archive_platform.h"2728#ifdef HAVE_SYS_STAT_H29#include <sys/stat.h>30#endif31#ifdef HAVE_SYS_TYPES_H32#include <sys/types.h>33#endif34#if MAJOR_IN_MKDEV35#include <sys/mkdev.h>36#define HAVE_MAJOR37#elif MAJOR_IN_SYSMACROS38#include <sys/sysmacros.h>39#define HAVE_MAJOR40#endif41#ifdef HAVE_ERRNO_H42#include <errno.h>43#endif44#ifdef HAVE_LIMITS_H45#include <limits.h>46#endif47#ifdef HAVE_LINUX_FS_H48#include <linux/fs.h> /* for Linux file flags */49#endif50/*51* Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h.52* As the include guards don't agree, the order of include is important.53*/54#ifdef HAVE_LINUX_EXT2_FS_H55#include <linux/ext2_fs.h> /* for Linux file flags */56#endif57#if defined(HAVE_EXT2FS_EXT2_FS_H) && !defined(__CYGWIN__)58#include <ext2fs/ext2_fs.h> /* for Linux file flags */59#endif60#include <stddef.h>61#include <stdio.h>62#ifdef HAVE_STDLIB_H63#include <stdlib.h>64#endif65#ifdef HAVE_STRING_H66#include <string.h>67#endif68#ifdef HAVE_WCHAR_H69#include <wchar.h>70#endif7172#include "archive.h"73#include "archive_acl_private.h"74#include "archive_entry.h"75#include "archive_entry_locale.h"76#include "archive_private.h"77#include "archive_entry_private.h"7879#if !defined(HAVE_MAJOR) && !defined(major)80/* Replacement for major/minor/makedev. */81#define major(x) ((int)(0x00ff & ((x) >> 8)))82#define minor(x) ((int)(0xffff00ff & (x)))83#define makedev(maj,min) ((0xff00 & ((maj)<<8)) | (0xffff00ff & (min)))84#endif8586/* Play games to come up with a suitable makedev() definition. */87#ifdef __QNXNTO__88/* QNX. <sigh> */89#include <sys/netmgr.h>90#define ae_makedev(maj, min) makedev(ND_LOCAL_NODE, (maj), (min))91#elif defined makedev92/* There's a "makedev" macro. */93#define ae_makedev(maj, min) makedev((maj), (min))94#elif defined mkdev || ((defined _WIN32 || defined __WIN32__) && !defined(__CYGWIN__))95/* Windows. <sigh> */96#define ae_makedev(maj, min) mkdev((maj), (min))97#else98/* There's a "makedev" function. */99#define ae_makedev(maj, min) makedev((maj), (min))100#endif101102/*103* This adjustment is needed to support the following idiom for adding104* 1000ns to the stored time:105* archive_entry_set_atime(archive_entry_atime(),106* archive_entry_atime_nsec() + 1000)107* The additional if() here compensates for ambiguity in the C standard,108* which permits two possible interpretations of a % b when a is negative.109*/110#define FIX_NS(t,ns) \111do { \112t += ns / 1000000000; \113ns %= 1000000000; \114if (ns < 0) { --t; ns += 1000000000; } \115} while (0)116117static char * ae_fflagstostr(unsigned long bitset, unsigned long bitclear);118static const wchar_t *ae_wcstofflags(const wchar_t *stringp,119unsigned long *setp, unsigned long *clrp);120static const char *ae_strtofflags(const char *stringp, size_t length,121unsigned long *setp, unsigned long *clrp);122123#ifndef HAVE_WCSCPY124static wchar_t * wcscpy(wchar_t *s1, const wchar_t *s2)125{126wchar_t *dest = s1;127while ((*s1 = *s2) != L'\0')128++s1, ++s2;129return dest;130}131#endif132#ifndef HAVE_WCSLEN133static size_t wcslen(const wchar_t *s)134{135const wchar_t *p = s;136while (*p != L'\0')137++p;138return p - s;139}140#endif141#ifndef HAVE_WMEMCMP142/* Good enough for simple equality testing, but not for sorting. */143#define wmemcmp(a,b,i) memcmp((a), (b), (i) * sizeof(wchar_t))144#endif145146/****************************************************************************147*148* Public Interface149*150****************************************************************************/151152struct archive_entry *153archive_entry_clear(struct archive_entry *entry)154{155if (entry == NULL)156return (NULL);157archive_mstring_clean(&entry->ae_fflags_text);158archive_mstring_clean(&entry->ae_gname);159archive_mstring_clean(&entry->ae_linkname);160archive_mstring_clean(&entry->ae_pathname);161archive_mstring_clean(&entry->ae_sourcepath);162archive_mstring_clean(&entry->ae_uname);163archive_entry_copy_mac_metadata(entry, NULL, 0);164archive_acl_clear(&entry->acl);165archive_entry_xattr_clear(entry);166archive_entry_sparse_clear(entry);167free(entry->stat);168entry->ae_symlink_type = AE_SYMLINK_TYPE_UNDEFINED;169memset(entry, 0, sizeof(*entry));170return entry;171}172173struct archive_entry *174archive_entry_clone(struct archive_entry *entry)175{176struct archive_entry *entry2;177struct ae_xattr *xp;178struct ae_sparse *sp;179size_t s;180const void *p;181182/* Allocate new structure and copy over all of the fields. */183/* TODO: Should we copy the archive over? Or require a new archive184* as an argument? */185entry2 = archive_entry_new2(entry->archive);186if (entry2 == NULL)187return (NULL);188entry2->ae_stat = entry->ae_stat;189entry2->ae_fflags_set = entry->ae_fflags_set;190entry2->ae_fflags_clear = entry->ae_fflags_clear;191192/* TODO: XXX If clone can have a different archive, what do we do here if193* character sets are different? XXX */194archive_mstring_copy(&entry2->ae_fflags_text, &entry->ae_fflags_text);195archive_mstring_copy(&entry2->ae_gname, &entry->ae_gname);196archive_mstring_copy(&entry2->ae_linkname, &entry->ae_linkname);197archive_mstring_copy(&entry2->ae_pathname, &entry->ae_pathname);198archive_mstring_copy(&entry2->ae_sourcepath, &entry->ae_sourcepath);199entry2->ae_set = entry->ae_set;200archive_mstring_copy(&entry2->ae_uname, &entry->ae_uname);201202/* Copy symlink type */203entry2->ae_symlink_type = entry->ae_symlink_type;204205/* Copy encryption status */206entry2->encryption = entry->encryption;207208/* Copy digests */209#define copy_digest(_e2, _e, _t) \210memcpy(_e2->digest._t, _e->digest._t, sizeof(_e2->digest._t))211212copy_digest(entry2, entry, md5);213copy_digest(entry2, entry, rmd160);214copy_digest(entry2, entry, sha1);215copy_digest(entry2, entry, sha256);216copy_digest(entry2, entry, sha384);217copy_digest(entry2, entry, sha512);218219#undef copy_digest220221/* Copy ACL data over. */222archive_acl_copy(&entry2->acl, &entry->acl);223224/* Copy Mac OS metadata. */225p = archive_entry_mac_metadata(entry, &s);226archive_entry_copy_mac_metadata(entry2, p, s);227228/* Copy xattr data over. */229xp = entry->xattr_head;230while (xp != NULL) {231archive_entry_xattr_add_entry(entry2,232xp->name, xp->value, xp->size);233xp = xp->next;234}235236/* Copy sparse data over. */237sp = entry->sparse_head;238while (sp != NULL) {239archive_entry_sparse_add_entry(entry2,240sp->offset, sp->length);241sp = sp->next;242}243244return (entry2);245}246247void248archive_entry_free(struct archive_entry *entry)249{250archive_entry_clear(entry);251free(entry);252}253254struct archive_entry *255archive_entry_new(void)256{257return archive_entry_new2(NULL);258}259260struct archive_entry *261archive_entry_new2(struct archive *a)262{263struct archive_entry *entry;264265entry = calloc(1, sizeof(*entry));266if (entry == NULL)267return (NULL);268entry->archive = a;269entry->ae_symlink_type = AE_SYMLINK_TYPE_UNDEFINED;270return (entry);271}272273/*274* Functions for reading fields from an archive_entry.275*/276277__LA_TIME_T278archive_entry_atime(struct archive_entry *entry)279{280return (entry->ae_stat.aest_atime);281}282283long284archive_entry_atime_nsec(struct archive_entry *entry)285{286return (entry->ae_stat.aest_atime_nsec);287}288289int290archive_entry_atime_is_set(struct archive_entry *entry)291{292return (entry->ae_set & AE_SET_ATIME);293}294295__LA_TIME_T296archive_entry_birthtime(struct archive_entry *entry)297{298return (entry->ae_stat.aest_birthtime);299}300301long302archive_entry_birthtime_nsec(struct archive_entry *entry)303{304return (entry->ae_stat.aest_birthtime_nsec);305}306307int308archive_entry_birthtime_is_set(struct archive_entry *entry)309{310return (entry->ae_set & AE_SET_BIRTHTIME);311}312313__LA_TIME_T314archive_entry_ctime(struct archive_entry *entry)315{316return (entry->ae_stat.aest_ctime);317}318319int320archive_entry_ctime_is_set(struct archive_entry *entry)321{322return (entry->ae_set & AE_SET_CTIME);323}324325long326archive_entry_ctime_nsec(struct archive_entry *entry)327{328return (entry->ae_stat.aest_ctime_nsec);329}330331__LA_DEV_T332archive_entry_dev(struct archive_entry *entry)333{334if (entry->ae_stat.aest_dev_is_broken_down)335return ae_makedev(entry->ae_stat.aest_devmajor,336entry->ae_stat.aest_devminor);337else338return (entry->ae_stat.aest_dev);339}340341int342archive_entry_dev_is_set(struct archive_entry *entry)343{344return (entry->ae_set & AE_SET_DEV);345}346347__LA_DEV_T348archive_entry_devmajor(struct archive_entry *entry)349{350if (entry->ae_stat.aest_dev_is_broken_down)351return (entry->ae_stat.aest_devmajor);352else353return major(entry->ae_stat.aest_dev);354}355356__LA_DEV_T357archive_entry_devminor(struct archive_entry *entry)358{359if (entry->ae_stat.aest_dev_is_broken_down)360return (entry->ae_stat.aest_devminor);361else362return minor(entry->ae_stat.aest_dev);363}364365__LA_MODE_T366archive_entry_filetype(struct archive_entry *entry)367{368return (AE_IFMT & entry->acl.mode);369}370371int372archive_entry_filetype_is_set(struct archive_entry *entry)373{374return (entry->ae_set & AE_SET_FILETYPE);375}376377void378archive_entry_fflags(struct archive_entry *entry,379unsigned long *set, unsigned long *clear)380{381*set = entry->ae_fflags_set;382*clear = entry->ae_fflags_clear;383}384385/*386* Note: if text was provided, this just returns that text. If you387* really need the text to be rebuilt in a canonical form, set the388* text, ask for the bitmaps, then set the bitmaps. (Setting the389* bitmaps clears any stored text.) This design is deliberate: if390* we're editing archives, we don't want to discard flags just because391* they aren't supported on the current system. The bitmap<->text392* conversions are platform-specific (see below).393*/394const char *395archive_entry_fflags_text(struct archive_entry *entry)396{397const char *f;398char *p;399400if (archive_mstring_get_mbs(entry->archive,401&entry->ae_fflags_text, &f) == 0) {402if (f != NULL)403return (f);404} else if (errno == ENOMEM)405__archive_errx(1, "No memory");406407if (entry->ae_fflags_set == 0 && entry->ae_fflags_clear == 0)408return (NULL);409410p = ae_fflagstostr(entry->ae_fflags_set, entry->ae_fflags_clear);411if (p == NULL)412return (NULL);413414archive_mstring_copy_mbs(&entry->ae_fflags_text, p);415free(p);416if (archive_mstring_get_mbs(entry->archive,417&entry->ae_fflags_text, &f) == 0)418return (f);419if (errno == ENOMEM)420__archive_errx(1, "No memory");421return (NULL);422}423424la_int64_t425archive_entry_gid(struct archive_entry *entry)426{427return (entry->ae_stat.aest_gid);428}429430int431archive_entry_gid_is_set(struct archive_entry *entry)432{433return (entry->ae_set & AE_SET_GID);434}435436const char *437archive_entry_gname(struct archive_entry *entry)438{439const char *p;440if (archive_mstring_get_mbs(entry->archive, &entry->ae_gname, &p) == 0)441return (p);442if (errno == ENOMEM)443__archive_errx(1, "No memory");444return (NULL);445}446447const char *448archive_entry_gname_utf8(struct archive_entry *entry)449{450const char *p;451if (archive_mstring_get_utf8(entry->archive, &entry->ae_gname, &p) == 0)452return (p);453if (errno == ENOMEM)454__archive_errx(1, "No memory");455return (NULL);456}457458459const wchar_t *460archive_entry_gname_w(struct archive_entry *entry)461{462const wchar_t *p;463if (archive_mstring_get_wcs(entry->archive, &entry->ae_gname, &p) == 0)464return (p);465if (errno == ENOMEM)466__archive_errx(1, "No memory");467return (NULL);468}469470int471_archive_entry_gname_l(struct archive_entry *entry,472const char **p, size_t *len, struct archive_string_conv *sc)473{474return (archive_mstring_get_mbs_l(entry->archive, &entry->ae_gname, p, len, sc));475}476477void478archive_entry_set_link_to_hardlink(struct archive_entry *entry)479{480if ((entry->ae_set & AE_SET_SYMLINK) != 0) {481entry->ae_set &= ~AE_SET_SYMLINK;482}483entry->ae_set |= AE_SET_HARDLINK;484}485486const char *487archive_entry_hardlink(struct archive_entry *entry)488{489const char *p;490if ((entry->ae_set & AE_SET_HARDLINK) == 0)491return (NULL);492if (archive_mstring_get_mbs(493entry->archive, &entry->ae_linkname, &p) == 0)494return (p);495if (errno == ENOMEM)496__archive_errx(1, "No memory");497return (NULL);498}499500const char *501archive_entry_hardlink_utf8(struct archive_entry *entry)502{503const char *p;504if ((entry->ae_set & AE_SET_HARDLINK) == 0)505return (NULL);506if (archive_mstring_get_utf8(507entry->archive, &entry->ae_linkname, &p) == 0)508return (p);509if (errno == ENOMEM)510__archive_errx(1, "No memory");511return (NULL);512}513514const wchar_t *515archive_entry_hardlink_w(struct archive_entry *entry)516{517const wchar_t *p;518if ((entry->ae_set & AE_SET_HARDLINK) == 0)519return (NULL);520if (archive_mstring_get_wcs(521entry->archive, &entry->ae_linkname, &p) == 0)522return (p);523if (errno == ENOMEM)524__archive_errx(1, "No memory");525return (NULL);526}527528int529archive_entry_hardlink_is_set(struct archive_entry *entry)530{531return (entry->ae_set & AE_SET_HARDLINK) != 0;532}533534int535_archive_entry_hardlink_l(struct archive_entry *entry,536const char **p, size_t *len, struct archive_string_conv *sc)537{538if ((entry->ae_set & AE_SET_HARDLINK) == 0) {539*p = NULL;540*len = 0;541return (0);542}543return (archive_mstring_get_mbs_l(entry->archive, &entry->ae_linkname, p, len, sc));544}545546la_int64_t547archive_entry_ino(struct archive_entry *entry)548{549return (entry->ae_stat.aest_ino);550}551552int553archive_entry_ino_is_set(struct archive_entry *entry)554{555return (entry->ae_set & AE_SET_INO);556}557558la_int64_t559archive_entry_ino64(struct archive_entry *entry)560{561return (entry->ae_stat.aest_ino);562}563564__LA_MODE_T565archive_entry_mode(struct archive_entry *entry)566{567return (entry->acl.mode);568}569570__LA_TIME_T571archive_entry_mtime(struct archive_entry *entry)572{573return (entry->ae_stat.aest_mtime);574}575576long577archive_entry_mtime_nsec(struct archive_entry *entry)578{579return (entry->ae_stat.aest_mtime_nsec);580}581582int583archive_entry_mtime_is_set(struct archive_entry *entry)584{585return (entry->ae_set & AE_SET_MTIME);586}587588unsigned int589archive_entry_nlink(struct archive_entry *entry)590{591return (entry->ae_stat.aest_nlink);592}593594/* Instead, our caller could have chosen a specific encoding595* (archive_mstring_get_mbs, archive_mstring_get_utf8,596* archive_mstring_get_wcs). So we should try multiple597* encodings. Try mbs first because of history, even though598* utf8 might be better for pathname portability.599* Also omit wcs because of type mismatch (char * versus wchar *)600*/601const char *602archive_entry_pathname(struct archive_entry *entry)603{604const char *p;605if (archive_mstring_get_mbs(606entry->archive, &entry->ae_pathname, &p) == 0)607return (p);608#if HAVE_EILSEQ /*{*/609if (errno == EILSEQ) {610if (archive_mstring_get_utf8(611entry->archive, &entry->ae_pathname, &p) == 0)612return (p);613}614#endif /*}*/615if (errno == ENOMEM)616__archive_errx(1, "No memory");617return (NULL);618}619620const char *621archive_entry_pathname_utf8(struct archive_entry *entry)622{623const char *p;624if (archive_mstring_get_utf8(625entry->archive, &entry->ae_pathname, &p) == 0)626return (p);627if (errno == ENOMEM)628__archive_errx(1, "No memory");629return (NULL);630}631632const wchar_t *633archive_entry_pathname_w(struct archive_entry *entry)634{635const wchar_t *p;636if (archive_mstring_get_wcs(637entry->archive, &entry->ae_pathname, &p) == 0)638return (p);639if (errno == ENOMEM)640__archive_errx(1, "No memory");641return (NULL);642}643644int645_archive_entry_pathname_l(struct archive_entry *entry,646const char **p, size_t *len, struct archive_string_conv *sc)647{648return (archive_mstring_get_mbs_l(entry->archive, &entry->ae_pathname, p, len, sc));649}650651__LA_MODE_T652archive_entry_perm(struct archive_entry *entry)653{654return (~AE_IFMT & entry->acl.mode);655}656657int658archive_entry_perm_is_set(struct archive_entry *entry)659{660return (entry->ae_set & AE_SET_PERM);661}662663int664archive_entry_rdev_is_set(struct archive_entry *entry)665{666return (entry->ae_set & AE_SET_RDEV);667}668669__LA_DEV_T670archive_entry_rdev(struct archive_entry *entry)671{672if (archive_entry_rdev_is_set(entry)) {673if (entry->ae_stat.aest_rdev_is_broken_down)674return ae_makedev(entry->ae_stat.aest_rdevmajor,675entry->ae_stat.aest_rdevminor);676else677return (entry->ae_stat.aest_rdev);678} else {679return 0;680}681}682683__LA_DEV_T684archive_entry_rdevmajor(struct archive_entry *entry)685{686if (archive_entry_rdev_is_set(entry)) {687if (entry->ae_stat.aest_rdev_is_broken_down)688return (entry->ae_stat.aest_rdevmajor);689else690return major(entry->ae_stat.aest_rdev);691} else {692return 0;693}694}695696__LA_DEV_T697archive_entry_rdevminor(struct archive_entry *entry)698{699if (archive_entry_rdev_is_set(entry)) {700if (entry->ae_stat.aest_rdev_is_broken_down)701return (entry->ae_stat.aest_rdevminor);702else703return minor(entry->ae_stat.aest_rdev);704} else {705return 0;706}707}708709la_int64_t710archive_entry_size(struct archive_entry *entry)711{712return (entry->ae_stat.aest_size);713}714715int716archive_entry_size_is_set(struct archive_entry *entry)717{718return (entry->ae_set & AE_SET_SIZE);719}720721const char *722archive_entry_sourcepath(struct archive_entry *entry)723{724const char *p;725if (archive_mstring_get_mbs(726entry->archive, &entry->ae_sourcepath, &p) == 0)727return (p);728if (errno == ENOMEM)729__archive_errx(1, "No memory");730return (NULL);731}732733const wchar_t *734archive_entry_sourcepath_w(struct archive_entry *entry)735{736const wchar_t *p;737if (archive_mstring_get_wcs(738entry->archive, &entry->ae_sourcepath, &p) == 0)739return (p);740return (NULL);741}742743const char *744archive_entry_symlink(struct archive_entry *entry)745{746const char *p;747if ((entry->ae_set & AE_SET_SYMLINK) == 0)748return (NULL);749if (archive_mstring_get_mbs(750entry->archive, &entry->ae_linkname, &p) == 0)751return (p);752if (errno == ENOMEM)753__archive_errx(1, "No memory");754return (NULL);755}756757void758archive_entry_set_link_to_symlink(struct archive_entry *entry)759{760if ((entry->ae_set & AE_SET_HARDLINK) != 0) {761entry->ae_set &= ~AE_SET_HARDLINK;762}763entry->ae_set |= AE_SET_SYMLINK;764}765766int767archive_entry_symlink_type(struct archive_entry *entry)768{769return (entry->ae_symlink_type);770}771772const char *773archive_entry_symlink_utf8(struct archive_entry *entry)774{775const char *p;776if ((entry->ae_set & AE_SET_SYMLINK) == 0)777return (NULL);778if (archive_mstring_get_utf8(779entry->archive, &entry->ae_linkname, &p) == 0)780return (p);781if (errno == ENOMEM)782__archive_errx(1, "No memory");783return (NULL);784}785786const wchar_t *787archive_entry_symlink_w(struct archive_entry *entry)788{789const wchar_t *p;790if ((entry->ae_set & AE_SET_SYMLINK) == 0)791return (NULL);792if (archive_mstring_get_wcs(793entry->archive, &entry->ae_linkname, &p) == 0)794return (p);795if (errno == ENOMEM)796__archive_errx(1, "No memory");797return (NULL);798}799800int801_archive_entry_symlink_l(struct archive_entry *entry,802const char **p, size_t *len, struct archive_string_conv *sc)803{804if ((entry->ae_set & AE_SET_SYMLINK) == 0) {805*p = NULL;806*len = 0;807return (0);808}809return (archive_mstring_get_mbs_l(entry->archive, &entry->ae_linkname, p, len, sc));810}811812la_int64_t813archive_entry_uid(struct archive_entry *entry)814{815return (entry->ae_stat.aest_uid);816}817818int819archive_entry_uid_is_set(struct archive_entry *entry)820{821return (entry->ae_set & AE_SET_UID);822}823824const char *825archive_entry_uname(struct archive_entry *entry)826{827const char *p;828if (archive_mstring_get_mbs(entry->archive, &entry->ae_uname, &p) == 0)829return (p);830if (errno == ENOMEM)831__archive_errx(1, "No memory");832return (NULL);833}834835const char *836archive_entry_uname_utf8(struct archive_entry *entry)837{838const char *p;839if (archive_mstring_get_utf8(entry->archive, &entry->ae_uname, &p) == 0)840return (p);841if (errno == ENOMEM)842__archive_errx(1, "No memory");843return (NULL);844}845846const wchar_t *847archive_entry_uname_w(struct archive_entry *entry)848{849const wchar_t *p;850if (archive_mstring_get_wcs(entry->archive, &entry->ae_uname, &p) == 0)851return (p);852if (errno == ENOMEM)853__archive_errx(1, "No memory");854return (NULL);855}856857int858_archive_entry_uname_l(struct archive_entry *entry,859const char **p, size_t *len, struct archive_string_conv *sc)860{861return (archive_mstring_get_mbs_l(entry->archive, &entry->ae_uname, p, len, sc));862}863864int865archive_entry_is_data_encrypted(struct archive_entry *entry)866{867return ((entry->encryption & AE_ENCRYPTION_DATA) == AE_ENCRYPTION_DATA);868}869870int871archive_entry_is_metadata_encrypted(struct archive_entry *entry)872{873return ((entry->encryption & AE_ENCRYPTION_METADATA) == AE_ENCRYPTION_METADATA);874}875876int877archive_entry_is_encrypted(struct archive_entry *entry)878{879return (entry->encryption & (AE_ENCRYPTION_DATA|AE_ENCRYPTION_METADATA));880}881882/*883* Functions to set archive_entry properties.884*/885886void887archive_entry_set_filetype(struct archive_entry *entry, unsigned int type)888{889entry->stat_valid = 0;890entry->acl.mode &= ~AE_IFMT;891entry->acl.mode |= AE_IFMT & type;892entry->ae_set |= AE_SET_FILETYPE;893}894895void896archive_entry_set_fflags(struct archive_entry *entry,897unsigned long set, unsigned long clear)898{899archive_mstring_clean(&entry->ae_fflags_text);900entry->ae_fflags_set = set;901entry->ae_fflags_clear = clear;902}903904const char *905archive_entry_copy_fflags_text(struct archive_entry *entry,906const char *flags)907{908return archive_entry_copy_fflags_text_len(entry, flags, strlen(flags));909}910911const char *912archive_entry_copy_fflags_text_len(struct archive_entry *entry,913const char *flags, size_t flags_length)914{915archive_mstring_copy_mbs_len(&entry->ae_fflags_text, flags, flags_length);916return (ae_strtofflags(flags, flags_length,917&entry->ae_fflags_set, &entry->ae_fflags_clear));918}919920const wchar_t *921archive_entry_copy_fflags_text_w(struct archive_entry *entry,922const wchar_t *flags)923{924archive_mstring_copy_wcs(&entry->ae_fflags_text, flags);925return (ae_wcstofflags(flags,926&entry->ae_fflags_set, &entry->ae_fflags_clear));927}928929void930archive_entry_set_gid(struct archive_entry *entry, la_int64_t g)931{932if (g < 0) {933g = 0;934}935entry->stat_valid = 0;936entry->ae_stat.aest_gid = g;937entry->ae_set |= AE_SET_GID;938}939940void941archive_entry_set_gname(struct archive_entry *entry, const char *name)942{943archive_mstring_copy_mbs(&entry->ae_gname, name);944}945946void947archive_entry_set_gname_utf8(struct archive_entry *entry, const char *name)948{949archive_mstring_copy_utf8(&entry->ae_gname, name);950}951952void953archive_entry_copy_gname(struct archive_entry *entry, const char *name)954{955archive_mstring_copy_mbs(&entry->ae_gname, name);956}957958void959archive_entry_copy_gname_w(struct archive_entry *entry, const wchar_t *name)960{961archive_mstring_copy_wcs(&entry->ae_gname, name);962}963964int965archive_entry_update_gname_utf8(struct archive_entry *entry, const char *name)966{967if (archive_mstring_update_utf8(entry->archive,968&entry->ae_gname, name) == 0)969return (1);970if (errno == ENOMEM)971__archive_errx(1, "No memory");972return (0);973}974975int976_archive_entry_copy_gname_l(struct archive_entry *entry,977const char *name, size_t len, struct archive_string_conv *sc)978{979return (archive_mstring_copy_mbs_len_l(&entry->ae_gname, name, len, sc));980}981982void983archive_entry_set_ino(struct archive_entry *entry, la_int64_t ino)984{985if (ino < 0) {986entry->stat_valid = 0;987entry->ae_set &= ~AE_SET_INO;988return;989}990entry->stat_valid = 0;991entry->ae_set |= AE_SET_INO;992entry->ae_stat.aest_ino = ino;993}994995void996archive_entry_set_ino64(struct archive_entry *entry, la_int64_t ino)997{998if (ino < 0) {999entry->stat_valid = 0;1000entry->ae_set &= ~AE_SET_INO;1001return;1002}1003entry->stat_valid = 0;1004entry->ae_set |= AE_SET_INO;1005entry->ae_stat.aest_ino = ino;1006}10071008void1009archive_entry_set_hardlink(struct archive_entry *entry, const char *target)1010{1011if (target == NULL) {1012entry->ae_set &= ~AE_SET_HARDLINK;1013if (entry->ae_set & AE_SET_SYMLINK) {1014return;1015}1016} else {1017entry->ae_set |= AE_SET_HARDLINK;1018}1019entry->ae_set &= ~AE_SET_SYMLINK;1020archive_mstring_copy_mbs(&entry->ae_linkname, target);1021}10221023void1024archive_entry_set_hardlink_utf8(struct archive_entry *entry, const char *target)1025{1026if (target == NULL && (entry->ae_set & AE_SET_SYMLINK))1027return;1028archive_mstring_copy_utf8(&entry->ae_linkname, target);1029if (target != NULL)1030entry->ae_set |= AE_SET_HARDLINK;1031else1032entry->ae_set &= ~AE_SET_HARDLINK;1033}10341035void1036archive_entry_copy_hardlink(struct archive_entry *entry, const char *target)1037{1038if (target == NULL && (entry->ae_set & AE_SET_SYMLINK))1039return;1040archive_mstring_copy_mbs(&entry->ae_linkname, target);1041if (target != NULL)1042entry->ae_set |= AE_SET_HARDLINK;1043else1044entry->ae_set &= ~AE_SET_HARDLINK;1045}10461047void1048archive_entry_copy_hardlink_w(struct archive_entry *entry, const wchar_t *target)1049{1050if (target == NULL && (entry->ae_set & AE_SET_SYMLINK))1051return;1052archive_mstring_copy_wcs(&entry->ae_linkname, target);1053if (target != NULL)1054entry->ae_set |= AE_SET_HARDLINK;1055else1056entry->ae_set &= ~AE_SET_HARDLINK;1057}10581059int1060archive_entry_update_hardlink_utf8(struct archive_entry *entry, const char *target)1061{1062if (target == NULL && (entry->ae_set & AE_SET_SYMLINK))1063return (0);1064if (target != NULL)1065entry->ae_set |= AE_SET_HARDLINK;1066else1067entry->ae_set &= ~AE_SET_HARDLINK;1068if (archive_mstring_update_utf8(entry->archive,1069&entry->ae_linkname, target) == 0)1070return (1);1071if (errno == ENOMEM)1072__archive_errx(1, "No memory");1073return (0);1074}10751076int1077_archive_entry_copy_hardlink_l(struct archive_entry *entry,1078const char *target, size_t len, struct archive_string_conv *sc)1079{1080int r;10811082if (target == NULL && (entry->ae_set & AE_SET_SYMLINK))1083return (0);1084r = archive_mstring_copy_mbs_len_l(&entry->ae_linkname,1085target, len, sc);1086if (target != NULL && r == 0)1087entry->ae_set |= AE_SET_HARDLINK;1088else1089entry->ae_set &= ~AE_SET_HARDLINK;1090return (r);1091}10921093void1094archive_entry_set_atime(struct archive_entry *entry, __LA_TIME_T t, long ns)1095{1096FIX_NS(t, ns);1097entry->stat_valid = 0;1098entry->ae_set |= AE_SET_ATIME;1099entry->ae_stat.aest_atime = t;1100entry->ae_stat.aest_atime_nsec = ns;1101}11021103void1104archive_entry_unset_atime(struct archive_entry *entry)1105{1106archive_entry_set_atime(entry, 0, 0);1107entry->ae_set &= ~AE_SET_ATIME;1108}11091110void1111archive_entry_set_birthtime(struct archive_entry *entry, __LA_TIME_T t, long ns)1112{1113FIX_NS(t, ns);1114entry->stat_valid = 0;1115entry->ae_set |= AE_SET_BIRTHTIME;1116entry->ae_stat.aest_birthtime = t;1117entry->ae_stat.aest_birthtime_nsec = ns;1118}11191120void1121archive_entry_unset_birthtime(struct archive_entry *entry)1122{1123archive_entry_set_birthtime(entry, 0, 0);1124entry->ae_set &= ~AE_SET_BIRTHTIME;1125}11261127void1128archive_entry_set_ctime(struct archive_entry *entry, __LA_TIME_T t, long ns)1129{1130FIX_NS(t, ns);1131entry->stat_valid = 0;1132entry->ae_set |= AE_SET_CTIME;1133entry->ae_stat.aest_ctime = t;1134entry->ae_stat.aest_ctime_nsec = ns;1135}11361137void1138archive_entry_unset_ctime(struct archive_entry *entry)1139{1140archive_entry_set_ctime(entry, 0, 0);1141entry->ae_set &= ~AE_SET_CTIME;1142}11431144void1145archive_entry_set_dev(struct archive_entry *entry, __LA_DEV_T d)1146{1147entry->stat_valid = 0;1148entry->ae_set |= AE_SET_DEV;1149entry->ae_stat.aest_dev_is_broken_down = 0;1150entry->ae_stat.aest_dev = d;1151}11521153void1154archive_entry_set_devmajor(struct archive_entry *entry, __LA_DEV_T m)1155{1156entry->stat_valid = 0;1157entry->ae_set |= AE_SET_DEV;1158entry->ae_stat.aest_dev_is_broken_down = 1;1159entry->ae_stat.aest_devmajor = m;1160}11611162void1163archive_entry_set_devminor(struct archive_entry *entry, __LA_DEV_T m)1164{1165entry->stat_valid = 0;1166entry->ae_set |= AE_SET_DEV;1167entry->ae_stat.aest_dev_is_broken_down = 1;1168entry->ae_stat.aest_devminor = m;1169}11701171/* Set symlink if symlink is already set, else set hardlink. */1172void1173archive_entry_set_link(struct archive_entry *entry, const char *target)1174{1175archive_mstring_copy_mbs(&entry->ae_linkname, target);1176if ((entry->ae_set & AE_SET_SYMLINK) == 0) {1177entry->ae_set |= AE_SET_HARDLINK;1178}1179}11801181void1182archive_entry_set_link_utf8(struct archive_entry *entry, const char *target)1183{1184archive_mstring_copy_utf8(&entry->ae_linkname, target);1185if ((entry->ae_set & AE_SET_SYMLINK) == 0) {1186entry->ae_set |= AE_SET_HARDLINK;1187}1188}11891190/* Set symlink if symlink is already set, else set hardlink. */1191void1192archive_entry_copy_link(struct archive_entry *entry, const char *target)1193{1194archive_mstring_copy_mbs(&entry->ae_linkname, target);1195if ((entry->ae_set & AE_SET_SYMLINK) == 0) {1196entry->ae_set |= AE_SET_HARDLINK;1197}1198}11991200/* Set symlink if symlink is already set, else set hardlink. */1201void1202archive_entry_copy_link_w(struct archive_entry *entry, const wchar_t *target)1203{1204archive_mstring_copy_wcs(&entry->ae_linkname, target);1205if ((entry->ae_set & AE_SET_SYMLINK) == 0) {1206entry->ae_set |= AE_SET_HARDLINK;1207}1208}12091210int1211archive_entry_update_link_utf8(struct archive_entry *entry, const char *target)1212{1213int r;1214r = archive_mstring_update_utf8(entry->archive,1215&entry->ae_linkname, target);1216if ((entry->ae_set & AE_SET_SYMLINK) == 0) {1217entry->ae_set |= AE_SET_HARDLINK;1218}1219if (r == 0)1220return (1);1221if (errno == ENOMEM)1222__archive_errx(1, "No memory");1223return (0);1224}12251226int1227_archive_entry_copy_link_l(struct archive_entry *entry,1228const char *target, size_t len, struct archive_string_conv *sc)1229{1230int r;12311232r = archive_mstring_copy_mbs_len_l(&entry->ae_linkname,1233target, len, sc);1234if ((entry->ae_set & AE_SET_SYMLINK) == 0) {1235entry->ae_set |= AE_SET_HARDLINK;1236}1237return (r);1238}12391240void1241archive_entry_set_mode(struct archive_entry *entry, mode_t m)1242{1243entry->stat_valid = 0;1244entry->acl.mode = m;1245entry->ae_set |= AE_SET_PERM | AE_SET_FILETYPE;1246}12471248void1249archive_entry_set_mtime(struct archive_entry *entry, __LA_TIME_T t, long ns)1250{1251FIX_NS(t, ns);1252entry->stat_valid = 0;1253entry->ae_set |= AE_SET_MTIME;1254entry->ae_stat.aest_mtime = t;1255entry->ae_stat.aest_mtime_nsec = ns;1256}12571258void1259archive_entry_unset_mtime(struct archive_entry *entry)1260{1261archive_entry_set_mtime(entry, 0, 0);1262entry->ae_set &= ~AE_SET_MTIME;1263}12641265void1266archive_entry_set_nlink(struct archive_entry *entry, unsigned int nlink)1267{1268entry->stat_valid = 0;1269entry->ae_stat.aest_nlink = nlink;1270}12711272void1273archive_entry_set_pathname(struct archive_entry *entry, const char *name)1274{1275archive_mstring_copy_mbs(&entry->ae_pathname, name);1276}12771278void1279archive_entry_set_pathname_utf8(struct archive_entry *entry, const char *name)1280{1281archive_mstring_copy_utf8(&entry->ae_pathname, name);1282}12831284void1285archive_entry_copy_pathname(struct archive_entry *entry, const char *name)1286{1287archive_mstring_copy_mbs(&entry->ae_pathname, name);1288}12891290void1291archive_entry_copy_pathname_w(struct archive_entry *entry, const wchar_t *name)1292{1293archive_mstring_copy_wcs(&entry->ae_pathname, name);1294}12951296int1297archive_entry_update_pathname_utf8(struct archive_entry *entry, const char *name)1298{1299if (archive_mstring_update_utf8(entry->archive,1300&entry->ae_pathname, name) == 0)1301return (1);1302if (errno == ENOMEM)1303__archive_errx(1, "No memory");1304return (0);1305}13061307int1308_archive_entry_copy_pathname_l(struct archive_entry *entry,1309const char *name, size_t len, struct archive_string_conv *sc)1310{1311return (archive_mstring_copy_mbs_len_l(&entry->ae_pathname,1312name, len, sc));1313}13141315void1316archive_entry_set_perm(struct archive_entry *entry, mode_t p)1317{1318entry->stat_valid = 0;1319entry->acl.mode &= AE_IFMT;1320entry->acl.mode |= ~AE_IFMT & p;1321entry->ae_set |= AE_SET_PERM;1322}13231324void1325archive_entry_set_rdev(struct archive_entry *entry, __LA_DEV_T m)1326{1327entry->stat_valid = 0;1328entry->ae_stat.aest_rdev = m;1329entry->ae_stat.aest_rdev_is_broken_down = 0;1330entry->ae_stat.aest_rdevmajor = 0;1331entry->ae_stat.aest_rdevminor = 0;1332entry->ae_set |= AE_SET_RDEV;1333}13341335void1336archive_entry_set_rdevmajor(struct archive_entry *entry, __LA_DEV_T m)1337{1338entry->stat_valid = 0;1339entry->ae_stat.aest_rdev_is_broken_down = 1;1340entry->ae_stat.aest_rdev = 0;1341entry->ae_stat.aest_rdevmajor = m;1342entry->ae_set |= AE_SET_RDEV;1343}13441345void1346archive_entry_set_rdevminor(struct archive_entry *entry, __LA_DEV_T m)1347{1348entry->stat_valid = 0;1349entry->ae_stat.aest_rdev_is_broken_down = 1;1350entry->ae_stat.aest_rdev = 0;1351entry->ae_stat.aest_rdevminor = m;1352entry->ae_set |= AE_SET_RDEV;1353}13541355void1356archive_entry_set_size(struct archive_entry *entry, la_int64_t s)1357{1358if (s < 0) {1359s = 0;1360}1361entry->stat_valid = 0;1362entry->ae_stat.aest_size = s;1363entry->ae_set |= AE_SET_SIZE;1364}13651366void1367archive_entry_unset_size(struct archive_entry *entry)1368{1369archive_entry_set_size(entry, 0);1370entry->ae_set &= ~AE_SET_SIZE;1371}13721373void1374archive_entry_copy_sourcepath(struct archive_entry *entry, const char *path)1375{1376archive_mstring_copy_mbs(&entry->ae_sourcepath, path);1377}13781379void1380archive_entry_copy_sourcepath_w(struct archive_entry *entry, const wchar_t *path)1381{1382archive_mstring_copy_wcs(&entry->ae_sourcepath, path);1383}13841385void1386archive_entry_set_symlink(struct archive_entry *entry, const char *linkname)1387{1388if (linkname == NULL && (entry->ae_set & AE_SET_HARDLINK))1389return;1390archive_mstring_copy_mbs(&entry->ae_linkname, linkname);1391entry->ae_set &= ~AE_SET_HARDLINK;1392if (linkname == NULL)1393entry->ae_set &= ~AE_SET_SYMLINK;1394else1395entry->ae_set |= AE_SET_SYMLINK;1396}13971398void1399archive_entry_set_symlink_type(struct archive_entry *entry, int type)1400{1401entry->ae_symlink_type = type;1402}14031404void1405archive_entry_set_symlink_utf8(struct archive_entry *entry, const char *linkname)1406{1407if (linkname == NULL && (entry->ae_set & AE_SET_HARDLINK))1408return;1409archive_mstring_copy_utf8(&entry->ae_linkname, linkname);1410entry->ae_set &= ~AE_SET_HARDLINK;1411if (linkname == NULL)1412entry->ae_set &= ~AE_SET_SYMLINK;1413else1414entry->ae_set |= AE_SET_SYMLINK;1415}14161417void1418archive_entry_copy_symlink(struct archive_entry *entry, const char *linkname)1419{1420if (linkname == NULL && (entry->ae_set & AE_SET_HARDLINK))1421return;1422archive_mstring_copy_mbs(&entry->ae_linkname, linkname);1423entry->ae_set &= ~AE_SET_HARDLINK;1424if (linkname == NULL)1425entry->ae_set &= ~AE_SET_SYMLINK;1426else1427entry->ae_set |= AE_SET_SYMLINK;1428}14291430void1431archive_entry_copy_symlink_w(struct archive_entry *entry, const wchar_t *linkname)1432{1433if (linkname == NULL && (entry->ae_set & AE_SET_HARDLINK))1434return;1435archive_mstring_copy_wcs(&entry->ae_linkname, linkname);1436entry->ae_set &= ~AE_SET_HARDLINK;1437if (linkname == NULL)1438entry->ae_set &= ~AE_SET_SYMLINK;1439else1440entry->ae_set |= AE_SET_SYMLINK;1441}14421443int1444archive_entry_update_symlink_utf8(struct archive_entry *entry, const char *linkname)1445{1446if (linkname == NULL && (entry->ae_set & AE_SET_HARDLINK))1447return (0);1448entry->ae_set &= ~AE_SET_HARDLINK;1449if (linkname == NULL)1450entry->ae_set &= ~AE_SET_SYMLINK;1451else1452entry->ae_set |= AE_SET_SYMLINK;1453if (archive_mstring_update_utf8(entry->archive,1454&entry->ae_linkname, linkname) == 0)1455return (1);1456if (errno == ENOMEM)1457__archive_errx(1, "No memory");1458return (0);1459}14601461int1462_archive_entry_copy_symlink_l(struct archive_entry *entry,1463const char *linkname, size_t len, struct archive_string_conv *sc)1464{1465int r;14661467if (linkname == NULL && (entry->ae_set & AE_SET_HARDLINK))1468return (0);1469entry->ae_set &= ~AE_SET_HARDLINK;1470r = archive_mstring_copy_mbs_len_l(&entry->ae_linkname,1471linkname, len, sc);1472if (linkname == NULL || r != 0)1473entry->ae_set &= ~AE_SET_SYMLINK;1474else1475entry->ae_set |= AE_SET_SYMLINK;1476return (r);1477}14781479void1480archive_entry_set_uid(struct archive_entry *entry, la_int64_t u)1481{1482if (u < 0) {1483u = 0;1484}1485entry->stat_valid = 0;1486entry->ae_stat.aest_uid = u;1487entry->ae_set |= AE_SET_UID;1488}14891490void1491archive_entry_set_uname(struct archive_entry *entry, const char *name)1492{1493archive_mstring_copy_mbs(&entry->ae_uname, name);1494}14951496void1497archive_entry_set_uname_utf8(struct archive_entry *entry, const char *name)1498{1499archive_mstring_copy_utf8(&entry->ae_uname, name);1500}15011502void1503archive_entry_copy_uname(struct archive_entry *entry, const char *name)1504{1505archive_mstring_copy_mbs(&entry->ae_uname, name);1506}15071508void1509archive_entry_copy_uname_w(struct archive_entry *entry, const wchar_t *name)1510{1511archive_mstring_copy_wcs(&entry->ae_uname, name);1512}15131514int1515archive_entry_update_uname_utf8(struct archive_entry *entry, const char *name)1516{1517if (archive_mstring_update_utf8(entry->archive,1518&entry->ae_uname, name) == 0)1519return (1);1520if (errno == ENOMEM)1521__archive_errx(1, "No memory");1522return (0);1523}15241525void1526archive_entry_set_is_data_encrypted(struct archive_entry *entry, char is_encrypted)1527{1528if (is_encrypted) {1529entry->encryption |= AE_ENCRYPTION_DATA;1530} else {1531entry->encryption &= ~AE_ENCRYPTION_DATA;1532}1533}15341535void1536archive_entry_set_is_metadata_encrypted(struct archive_entry *entry, char is_encrypted)1537{1538if (is_encrypted) {1539entry->encryption |= AE_ENCRYPTION_METADATA;1540} else {1541entry->encryption &= ~AE_ENCRYPTION_METADATA;1542}1543}15441545int1546_archive_entry_copy_uname_l(struct archive_entry *entry,1547const char *name, size_t len, struct archive_string_conv *sc)1548{1549return (archive_mstring_copy_mbs_len_l(&entry->ae_uname,1550name, len, sc));1551}15521553const void *1554archive_entry_mac_metadata(struct archive_entry *entry, size_t *s)1555{1556*s = entry->mac_metadata_size;1557return entry->mac_metadata;1558}15591560void1561archive_entry_copy_mac_metadata(struct archive_entry *entry,1562const void *p, size_t s)1563{1564free(entry->mac_metadata);1565if (p == NULL || s == 0) {1566entry->mac_metadata = NULL;1567entry->mac_metadata_size = 0;1568} else {1569entry->mac_metadata_size = s;1570entry->mac_metadata = malloc(s);1571if (entry->mac_metadata == NULL)1572abort();1573memcpy(entry->mac_metadata, p, s);1574}1575}15761577/* Digest handling */1578const unsigned char *1579archive_entry_digest(struct archive_entry *entry, int type)1580{1581switch (type) {1582case ARCHIVE_ENTRY_DIGEST_MD5:1583return entry->digest.md5;1584case ARCHIVE_ENTRY_DIGEST_RMD160:1585return entry->digest.rmd160;1586case ARCHIVE_ENTRY_DIGEST_SHA1:1587return entry->digest.sha1;1588case ARCHIVE_ENTRY_DIGEST_SHA256:1589return entry->digest.sha256;1590case ARCHIVE_ENTRY_DIGEST_SHA384:1591return entry->digest.sha384;1592case ARCHIVE_ENTRY_DIGEST_SHA512:1593return entry->digest.sha512;1594default:1595return NULL;1596}1597}15981599int1600archive_entry_set_digest(struct archive_entry *entry, int type,1601const unsigned char *digest)1602{1603#define copy_digest(_e, _t, _d)\1604memcpy(_e->digest._t, _d, sizeof(_e->digest._t))16051606switch (type) {1607case ARCHIVE_ENTRY_DIGEST_MD5:1608copy_digest(entry, md5, digest);1609entry->mset_digest |= AE_MSET_DIGEST_MD5;1610break;1611case ARCHIVE_ENTRY_DIGEST_RMD160:1612copy_digest(entry, rmd160, digest);1613entry->mset_digest |= AE_MSET_DIGEST_RMD160;1614break;1615case ARCHIVE_ENTRY_DIGEST_SHA1:1616copy_digest(entry, sha1, digest);1617entry->mset_digest |= AE_MSET_DIGEST_SHA1;1618break;1619case ARCHIVE_ENTRY_DIGEST_SHA256:1620copy_digest(entry, sha256, digest);1621entry->mset_digest |= AE_MSET_DIGEST_SHA256;1622break;1623case ARCHIVE_ENTRY_DIGEST_SHA384:1624copy_digest(entry, sha384, digest);1625entry->mset_digest |= AE_MSET_DIGEST_SHA384;1626break;1627case ARCHIVE_ENTRY_DIGEST_SHA512:1628copy_digest(entry, sha512, digest);1629entry->mset_digest |= AE_MSET_DIGEST_SHA512;1630break;1631default:1632return ARCHIVE_WARN;1633}16341635return ARCHIVE_OK;1636#undef copy_digest1637}16381639/*1640* ACL management. The following would, of course, be a lot simpler1641* if: 1) the last draft of POSIX.1e were a really thorough and1642* complete standard that addressed the needs of ACL archiving and 2)1643* everyone followed it faithfully. Alas, neither is true, so the1644* following is a lot more complex than might seem necessary to the1645* uninitiated.1646*/16471648struct archive_acl *1649archive_entry_acl(struct archive_entry *entry)1650{1651return &entry->acl;1652}16531654void1655archive_entry_acl_clear(struct archive_entry *entry)1656{1657archive_acl_clear(&entry->acl);1658}16591660/*1661* Add a single ACL entry to the internal list of ACL data.1662*/1663int1664archive_entry_acl_add_entry(struct archive_entry *entry,1665int type, int permset, int tag, int id, const char *name)1666{1667return archive_acl_add_entry(&entry->acl, type, permset, tag, id, name);1668}16691670/*1671* As above, but with a wide-character name.1672*/1673int1674archive_entry_acl_add_entry_w(struct archive_entry *entry,1675int type, int permset, int tag, int id, const wchar_t *name)1676{1677return archive_acl_add_entry_w_len(&entry->acl,1678type, permset, tag, id, name, wcslen(name));1679}16801681/*1682* Return a bitmask of ACL types in an archive entry ACL list1683*/1684int1685archive_entry_acl_types(struct archive_entry *entry)1686{1687return (archive_acl_types(&entry->acl));1688}16891690/*1691* Return a count of entries matching "want_type".1692*/1693int1694archive_entry_acl_count(struct archive_entry *entry, int want_type)1695{1696return archive_acl_count(&entry->acl, want_type);1697}16981699/*1700* Prepare for reading entries from the ACL data. Returns a count1701* of entries matching "want_type", or zero if there are no1702* non-extended ACL entries of that type.1703*/1704int1705archive_entry_acl_reset(struct archive_entry *entry, int want_type)1706{1707return archive_acl_reset(&entry->acl, want_type);1708}17091710/*1711* Return the next ACL entry in the list. Fake entries for the1712* standard permissions and include them in the returned list.1713*/1714int1715archive_entry_acl_next(struct archive_entry *entry, int want_type, int *type,1716int *permset, int *tag, int *id, const char **name)1717{1718int r;1719r = archive_acl_next(entry->archive, &entry->acl, want_type, type,1720permset, tag, id, name);1721if (r == ARCHIVE_FATAL && errno == ENOMEM)1722__archive_errx(1, "No memory");1723return (r);1724}17251726/*1727* Generate a text version of the ACL. The flags parameter controls1728* the style of the generated ACL.1729*/1730wchar_t *1731archive_entry_acl_to_text_w(struct archive_entry *entry, la_ssize_t *len,1732int flags)1733{1734return (archive_acl_to_text_w(&entry->acl, len, flags,1735entry->archive));1736}17371738char *1739archive_entry_acl_to_text(struct archive_entry *entry, la_ssize_t *len,1740int flags)1741{1742return (archive_acl_to_text_l(&entry->acl, len, flags, NULL));1743}17441745char *1746_archive_entry_acl_to_text_l(struct archive_entry *entry, ssize_t *len,1747int flags, struct archive_string_conv *sc)1748{1749return (archive_acl_to_text_l(&entry->acl, len, flags, sc));1750}17511752/*1753* ACL text parser.1754*/1755int1756archive_entry_acl_from_text_w(struct archive_entry *entry,1757const wchar_t *wtext, int type)1758{1759return (archive_acl_from_text_w(&entry->acl, wtext, type));1760}17611762int1763archive_entry_acl_from_text(struct archive_entry *entry,1764const char *text, int type)1765{1766return (archive_acl_from_text_l(&entry->acl, text, type, NULL));1767}17681769int1770_archive_entry_acl_from_text_l(struct archive_entry *entry, const char *text,1771int type, struct archive_string_conv *sc)1772{1773return (archive_acl_from_text_l(&entry->acl, text, type, sc));1774}17751776/* Deprecated */1777static int1778archive_entry_acl_text_compat(int *flags)1779{1780if ((*flags & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) == 0)1781return (1);17821783/* ABI compat with old ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID */1784if ((*flags & OLD_ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID) != 0)1785*flags |= ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID;17861787/* ABI compat with old ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT */1788if ((*flags & OLD_ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT) != 0)1789*flags |= ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT;17901791*flags |= ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA;17921793return (0);1794}17951796/* Deprecated */1797const wchar_t *1798archive_entry_acl_text_w(struct archive_entry *entry, int flags)1799{1800free(entry->acl.acl_text_w);1801entry->acl.acl_text_w = NULL;1802if (archive_entry_acl_text_compat(&flags) == 0)1803entry->acl.acl_text_w = archive_acl_to_text_w(&entry->acl,1804NULL, flags, entry->archive);1805return (entry->acl.acl_text_w);1806}18071808/* Deprecated */1809const char *1810archive_entry_acl_text(struct archive_entry *entry, int flags)1811{1812free(entry->acl.acl_text);1813entry->acl.acl_text = NULL;1814if (archive_entry_acl_text_compat(&flags) == 0)1815entry->acl.acl_text = archive_acl_to_text_l(&entry->acl, NULL,1816flags, NULL);18171818return (entry->acl.acl_text);1819}18201821/* Deprecated */1822int1823_archive_entry_acl_text_l(struct archive_entry *entry, int flags,1824const char **acl_text, size_t *len, struct archive_string_conv *sc)1825{1826free(entry->acl.acl_text);1827entry->acl.acl_text = NULL;18281829if (archive_entry_acl_text_compat(&flags) == 0)1830entry->acl.acl_text = archive_acl_to_text_l(&entry->acl,1831(ssize_t *)len, flags, sc);18321833*acl_text = entry->acl.acl_text;18341835return (0);1836}18371838/*1839* Following code is modified from UC Berkeley sources, and1840* is subject to the following copyright notice.1841*/18421843/*-1844* Copyright (c) 19931845* The Regents of the University of California. All rights reserved.1846*1847* Redistribution and use in source and binary forms, with or without1848* modification, are permitted provided that the following conditions1849* are met:1850* 1. Redistributions of source code must retain the above copyright1851* notice, this list of conditions and the following disclaimer.1852* 2. Redistributions in binary form must reproduce the above copyright1853* notice, this list of conditions and the following disclaimer in the1854* documentation and/or other materials provided with the distribution.1855* 4. Neither the name of the University nor the names of its contributors1856* may be used to endorse or promote products derived from this software1857* without specific prior written permission.1858*1859* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND1860* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE1861* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE1862* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE1863* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL1864* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS1865* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)1866* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT1867* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY1868* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF1869* SUCH DAMAGE.1870*/18711872/*1873* Supported file flags on FreeBSD and Mac OS:1874* sappnd,sappend SF_APPEND1875* arch,archived SF_ARCHIVED1876* schg,schange,simmutable SF_IMMUTABLE1877* sunlnk,sunlink SF_NOUNLINK (FreeBSD only)1878* uappnd,uappend UF_APPEND1879* compressed UF_COMPRESSED (Mac OS only)1880* hidden,uhidden UF_HIDDEN1881* uchg,uchange,uimmutable UF_IMMUTABLE1882* nodump UF_NODUMP1883* uunlnk,uunlink UF_NOUNLINK (FreeBSD only)1884* offline,uoffline UF_OFFLINE (FreeBSD only)1885* opaque UF_OPAQUE1886* rdonly,urdonly,readonly UF_READONLY (FreeBSD only)1887* reparse,ureparse UF_REPARSE (FreeBSD only)1888* sparse,usparse UF_SPARSE (FreeBSD only)1889* system,usystem UF_SYSTEM (FreeBSD only)1890*1891* See chflags(2) for more information1892*1893* Supported file attributes on Linux:1894* a append only FS_APPEND_FL sappnd1895* A no atime updates FS_NOATIME_FL atime1896* c compress FS_COMPR_FL compress1897* C no copy on write FS_NOCOW_FL cow1898* d no dump FS_NODUMP_FL dump1899* D synchronous directory updates FS_DIRSYNC_FL dirsync1900* i immutable FS_IMMUTABLE_FL schg1901* j data journalling FS_JOURNAL_DATA_FL journal1902* P project hierarchy FS_PROJINHERIT_FL projinherit1903* s secure deletion FS_SECRM_FL securedeletion1904* S synchronous updates FS_SYNC_FL sync1905* t no tail-merging FS_NOTAIL_FL tail1906* T top of directory hierarchy FS_TOPDIR_FL topdir1907* u undeletable FS_UNRM_FL undel1908*1909* See ioctl_iflags(2) for more information1910*1911* Equivalent file flags supported on FreeBSD / Mac OS and Linux:1912* SF_APPEND FS_APPEND_FL sappnd1913* SF_IMMUTABLE FS_IMMUTABLE_FL schg1914* UF_NODUMP FS_NODUMP_FL nodump1915*/19161917static const struct flag {1918const char *name;1919const wchar_t *wname;1920unsigned long set;1921unsigned long clear;1922} fileflags[] = {1923/* Preferred (shorter) names per flag first, all prefixed by "no" */1924#ifdef SF_APPEND1925{ "nosappnd", L"nosappnd", SF_APPEND, 0},1926{ "nosappend", L"nosappend", SF_APPEND, 0},1927#endif1928#if defined(FS_APPEND_FL) /* 'a' */1929{ "nosappnd", L"nosappnd", FS_APPEND_FL, 0},1930{ "nosappend", L"nosappend", FS_APPEND_FL, 0},1931#elif defined(EXT2_APPEND_FL) /* 'a' */1932{ "nosappnd", L"nosappnd", EXT2_APPEND_FL, 0},1933{ "nosappend", L"nosappend", EXT2_APPEND_FL, 0},1934#endif1935#ifdef SF_ARCHIVED1936{ "noarch", L"noarch", SF_ARCHIVED, 0},1937{ "noarchived", L"noarchived", SF_ARCHIVED, 0},1938#endif1939#ifdef SF_IMMUTABLE1940{ "noschg", L"noschg", SF_IMMUTABLE, 0},1941{ "noschange", L"noschange", SF_IMMUTABLE, 0},1942{ "nosimmutable", L"nosimmutable", SF_IMMUTABLE, 0},1943#endif1944#if defined(FS_IMMUTABLE_FL) /* 'i' */1945{ "noschg", L"noschg", FS_IMMUTABLE_FL, 0},1946{ "noschange", L"noschange", FS_IMMUTABLE_FL, 0},1947{ "nosimmutable", L"nosimmutable", FS_IMMUTABLE_FL, 0},1948#elif defined(EXT2_IMMUTABLE_FL) /* 'i' */1949{ "noschg", L"noschg", EXT2_IMMUTABLE_FL, 0},1950{ "noschange", L"noschange", EXT2_IMMUTABLE_FL, 0},1951{ "nosimmutable", L"nosimmutable", EXT2_IMMUTABLE_FL, 0},1952#endif1953#ifdef SF_NOUNLINK1954{ "nosunlnk", L"nosunlnk", SF_NOUNLINK, 0},1955{ "nosunlink", L"nosunlink", SF_NOUNLINK, 0},1956#endif1957#ifdef UF_APPEND1958{ "nouappnd", L"nouappnd", UF_APPEND, 0},1959{ "nouappend", L"nouappend", UF_APPEND, 0},1960#endif1961#ifdef UF_IMMUTABLE1962{ "nouchg", L"nouchg", UF_IMMUTABLE, 0},1963{ "nouchange", L"nouchange", UF_IMMUTABLE, 0},1964{ "nouimmutable", L"nouimmutable", UF_IMMUTABLE, 0},1965#endif1966#ifdef UF_NODUMP1967{ "nodump", L"nodump", 0, UF_NODUMP},1968#endif1969#if defined(FS_NODUMP_FL) /* 'd' */1970{ "nodump", L"nodump", 0, FS_NODUMP_FL},1971#elif defined(EXT2_NODUMP_FL)1972{ "nodump", L"nodump", 0, EXT2_NODUMP_FL},1973#endif1974#ifdef UF_OPAQUE1975{ "noopaque", L"noopaque", UF_OPAQUE, 0},1976#endif1977#ifdef UF_NOUNLINK1978{ "nouunlnk", L"nouunlnk", UF_NOUNLINK, 0},1979{ "nouunlink", L"nouunlink", UF_NOUNLINK, 0},1980#endif1981#ifdef UF_COMPRESSED1982/* Mac OS */1983{ "nocompressed", L"nocompressed", UF_COMPRESSED, 0},1984#endif1985#ifdef UF_HIDDEN1986{ "nohidden", L"nohidden", UF_HIDDEN, 0},1987{ "nouhidden", L"nouhidden", UF_HIDDEN, 0},1988#endif1989#ifdef FILE_ATTRIBUTE_HIDDEN1990{ "nohidden", L"nohidden", FILE_ATTRIBUTE_HIDDEN, 0},1991{ "nouhidden", L"nouhidden", FILE_ATTRIBUTE_HIDDEN, 0},1992#endif1993#ifdef UF_OFFLINE1994{ "nooffline", L"nooffline", UF_OFFLINE, 0},1995{ "nouoffline", L"nouoffline", UF_OFFLINE, 0},1996#endif1997#ifdef UF_READONLY1998{ "nordonly", L"nordonly", UF_READONLY, 0},1999{ "nourdonly", L"nourdonly", UF_READONLY, 0},2000{ "noreadonly", L"noreadonly", UF_READONLY, 0},2001#endif2002#ifdef FILE_ATTRIBUTE_READONLY2003{ "nordonly", L"nordonly", FILE_ATTRIBUTE_READONLY, 0},2004{ "nourdonly", L"nourdonly", FILE_ATTRIBUTE_READONLY, 0},2005{ "noreadonly", L"noreadonly", FILE_ATTRIBUTE_READONLY, 0},2006#endif2007#ifdef UF_SPARSE2008{ "nosparse", L"nosparse", UF_SPARSE, 0},2009{ "nousparse", L"nousparse", UF_SPARSE, 0},2010#endif2011#ifdef UF_REPARSE2012{ "noreparse", L"noreparse", UF_REPARSE, 0},2013{ "noureparse", L"noureparse", UF_REPARSE, 0},2014#endif2015#ifdef UF_SYSTEM2016{ "nosystem", L"nosystem", UF_SYSTEM, 0},2017{ "nousystem", L"nousystem", UF_SYSTEM, 0},2018#endif2019#ifdef FILE_ATTRIBUTE_SYSTEM2020{ "nosystem", L"nosystem", FILE_ATTRIBUTE_SYSTEM, 0},2021{ "nousystem", L"nousystem", FILE_ATTRIBUTE_SYSTEM, 0},2022#endif2023#if defined(FS_UNRM_FL) /* 'u' */2024{ "noundel", L"noundel", FS_UNRM_FL, 0},2025#elif defined(EXT2_UNRM_FL)2026{ "noundel", L"noundel", EXT2_UNRM_FL, 0},2027#endif20282029#if defined(FS_COMPR_FL) /* 'c' */2030{ "nocompress", L"nocompress", FS_COMPR_FL, 0},2031#elif defined(EXT2_COMPR_FL)2032{ "nocompress", L"nocompress", EXT2_COMPR_FL, 0},2033#endif20342035#if defined(FS_NOATIME_FL) /* 'A' */2036{ "noatime", L"noatime", 0, FS_NOATIME_FL},2037#elif defined(EXT2_NOATIME_FL)2038{ "noatime", L"noatime", 0, EXT2_NOATIME_FL},2039#endif2040#if defined(FS_DIRSYNC_FL) /* 'D' */2041{ "nodirsync", L"nodirsync", FS_DIRSYNC_FL, 0},2042#elif defined(EXT2_DIRSYNC_FL)2043{ "nodirsync", L"nodirsync", EXT2_DIRSYNC_FL, 0},2044#endif2045#if defined(FS_JOURNAL_DATA_FL) /* 'j' */2046{ "nojournal-data",L"nojournal-data", FS_JOURNAL_DATA_FL, 0},2047{ "nojournal", L"nojournal", FS_JOURNAL_DATA_FL, 0},2048#elif defined(EXT3_JOURNAL_DATA_FL)2049{ "nojournal-data",L"nojournal-data", EXT3_JOURNAL_DATA_FL, 0},2050{ "nojournal", L"nojournal", EXT3_JOURNAL_DATA_FL, 0},2051#endif2052#if defined(FS_SECRM_FL) /* 's' */2053{ "nosecdel", L"nosecdel", FS_SECRM_FL, 0},2054{ "nosecuredeletion",L"nosecuredeletion",FS_SECRM_FL, 0},2055#elif defined(EXT2_SECRM_FL)2056{ "nosecdel", L"nosecdel", EXT2_SECRM_FL, 0},2057{ "nosecuredeletion",L"nosecuredeletion",EXT2_SECRM_FL, 0},2058#endif2059#if defined(FS_SYNC_FL) /* 'S' */2060{ "nosync", L"nosync", FS_SYNC_FL, 0},2061#elif defined(EXT2_SYNC_FL)2062{ "nosync", L"nosync", EXT2_SYNC_FL, 0},2063#endif2064#if defined(FS_NOTAIL_FL) /* 't' */2065{ "notail", L"notail", 0, FS_NOTAIL_FL},2066#elif defined(EXT2_NOTAIL_FL)2067{ "notail", L"notail", 0, EXT2_NOTAIL_FL},2068#endif2069#if defined(FS_TOPDIR_FL) /* 'T' */2070{ "notopdir", L"notopdir", FS_TOPDIR_FL, 0},2071#elif defined(EXT2_TOPDIR_FL)2072{ "notopdir", L"notopdir", EXT2_TOPDIR_FL, 0},2073#endif2074#ifdef FS_NOCOW_FL /* 'C' */2075{ "nocow", L"nocow", 0, FS_NOCOW_FL},2076#endif2077#ifdef FS_PROJINHERIT_FL /* 'P' */2078{ "noprojinherit",L"noprojinherit", FS_PROJINHERIT_FL, 0},2079#endif2080{ NULL, NULL, 0, 0}2081};20822083/*2084* fflagstostr --2085* Convert file flags to a comma-separated string. If no flags2086* are set, return the empty string.2087*/2088static char *2089ae_fflagstostr(unsigned long bitset, unsigned long bitclear)2090{2091char *string, *dp;2092const char *sp;2093unsigned long bits;2094const struct flag *flag;2095size_t length;20962097bits = bitset | bitclear;2098length = 0;2099for (flag = fileflags; flag->name != NULL; flag++)2100if (bits & (flag->set | flag->clear)) {2101length += strlen(flag->name) + 1;2102bits &= ~(flag->set | flag->clear);2103}21042105if (length == 0)2106return (NULL);2107string = malloc(length);2108if (string == NULL)2109return (NULL);21102111dp = string;2112for (flag = fileflags; flag->name != NULL; flag++) {2113if (bitset & flag->set || bitclear & flag->clear) {2114sp = flag->name + 2;2115} else if (bitset & flag->clear || bitclear & flag->set) {2116sp = flag->name;2117} else2118continue;2119bitset &= ~(flag->set | flag->clear);2120bitclear &= ~(flag->set | flag->clear);2121if (dp > string)2122*dp++ = ',';2123while ((*dp++ = *sp++) != '\0')2124;2125dp--;2126}21272128*dp = '\0';2129return (string);2130}21312132/*2133* strtofflags --2134* Take string of arguments and return file flags. This2135* version works a little differently than strtofflags(3).2136* In particular, it always tests every token, skipping any2137* unrecognized tokens. It returns a pointer to the first2138* unrecognized token, or NULL if every token was recognized.2139* This version is also const-correct and does not modify the2140* provided string.2141*/2142static const char *2143ae_strtofflags(const char *s, size_t l, unsigned long *setp, unsigned long *clrp)2144{2145const char *start, *end;2146const struct flag *flag;2147unsigned long set, clear;2148const char *failed;21492150set = clear = 0;2151start = s;2152failed = NULL;2153/* Find start of first token. */2154while (l > 0 && (*start == '\t' || *start == ' ' || *start == ',')) {2155start++;2156l--;2157}2158while (l > 0) {2159size_t length;2160/* Locate end of token. */2161end = start;2162while (l > 0 && *end != '\t' &&2163*end != ' ' && *end != ',') {2164end++;2165l--;2166}2167length = end - start;2168for (flag = fileflags; flag->name != NULL; flag++) {2169size_t flag_length = strlen(flag->name);2170if (length == flag_length2171&& memcmp(start, flag->name, length) == 0) {2172/* Matched "noXXXX", so reverse the sense. */2173clear |= flag->set;2174set |= flag->clear;2175break;2176} else if (length == flag_length - 22177&& memcmp(start, flag->name + 2, length) == 0) {2178/* Matched "XXXX", so don't reverse. */2179set |= flag->set;2180clear |= flag->clear;2181break;2182}2183}2184/* Ignore unknown flag names. */2185if (flag->name == NULL && failed == NULL)2186failed = start;21872188/* Find start of next token. */2189start = end;2190while (l > 0 && (*start == '\t' || *start == ' ' || *start == ',')) {2191start++;2192l--;2193}21942195}21962197if (setp)2198*setp = set;2199if (clrp)2200*clrp = clear;22012202/* Return location of first failure. */2203return (failed);2204}22052206/*2207* wcstofflags --2208* Take string of arguments and return file flags. This2209* version works a little differently than strtofflags(3).2210* In particular, it always tests every token, skipping any2211* unrecognized tokens. It returns a pointer to the first2212* unrecognized token, or NULL if every token was recognized.2213* This version is also const-correct and does not modify the2214* provided string.2215*/2216static const wchar_t *2217ae_wcstofflags(const wchar_t *s, unsigned long *setp, unsigned long *clrp)2218{2219const wchar_t *start, *end;2220const struct flag *flag;2221unsigned long set, clear;2222const wchar_t *failed;22232224set = clear = 0;2225start = s;2226failed = NULL;2227/* Find start of first token. */2228while (*start == L'\t' || *start == L' ' || *start == L',')2229start++;2230while (*start != L'\0') {2231size_t length;2232/* Locate end of token. */2233end = start;2234while (*end != L'\0' && *end != L'\t' &&2235*end != L' ' && *end != L',')2236end++;2237length = end - start;2238for (flag = fileflags; flag->wname != NULL; flag++) {2239size_t flag_length = wcslen(flag->wname);2240if (length == flag_length2241&& wmemcmp(start, flag->wname, length) == 0) {2242/* Matched "noXXXX", so reverse the sense. */2243clear |= flag->set;2244set |= flag->clear;2245break;2246} else if (length == flag_length - 22247&& wmemcmp(start, flag->wname + 2, length) == 0) {2248/* Matched "XXXX", so don't reverse. */2249set |= flag->set;2250clear |= flag->clear;2251break;2252}2253}2254/* Ignore unknown flag names. */2255if (flag->wname == NULL && failed == NULL)2256failed = start;22572258/* Find start of next token. */2259start = end;2260while (*start == L'\t' || *start == L' ' || *start == L',')2261start++;22622263}22642265if (setp)2266*setp = set;2267if (clrp)2268*clrp = clear;22692270/* Return location of first failure. */2271return (failed);2272}227322742275#ifdef TEST2276#include <stdio.h>2277int2278main(int argc, char **argv)2279{2280struct archive_entry *entry = archive_entry_new();2281unsigned long set, clear;2282const wchar_t *remainder;22832284remainder = archive_entry_copy_fflags_text_w(entry, L"nosappnd dump archive,,,,,,,");2285archive_entry_fflags(entry, &set, &clear);22862287wprintf(L"set=0x%lX clear=0x%lX remainder='%ls'\n", set, clear, remainder);22882289wprintf(L"new flags='%s'\n", archive_entry_fflags_text(entry));2290return (0);2291}2292#endif229322942295