1228753Smm/*-
2228753Smm * Copyright (c) 2003-2007 Tim Kientzle
3313571Smm * Copyright (c) 2016 Martin Matuska
4228753Smm * All rights reserved.
5228753Smm *
6228753Smm * Redistribution and use in source and binary forms, with or without
7228753Smm * modification, are permitted provided that the following conditions
8228753Smm * are met:
9228753Smm * 1. Redistributions of source code must retain the above copyright
10228753Smm *    notice, this list of conditions and the following disclaimer.
11228753Smm * 2. Redistributions in binary form must reproduce the above copyright
12228753Smm *    notice, this list of conditions and the following disclaimer in the
13228753Smm *    documentation and/or other materials provided with the distribution.
14228753Smm *
15228753Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
16228753Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17228753Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18228753Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
19228753Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20228753Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21228753Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22228753Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23228753Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24228753Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25228753Smm */
26228753Smm
27228753Smm#include "archive_platform.h"
28228763Smm__FBSDID("$FreeBSD: stable/10/contrib/libarchive/libarchive/archive_entry.c 368708 2020-12-16 22:25:40Z mm $");
29228753Smm
30228753Smm#ifdef HAVE_SYS_STAT_H
31228753Smm#include <sys/stat.h>
32228753Smm#endif
33228753Smm#ifdef HAVE_SYS_TYPES_H
34228753Smm#include <sys/types.h>
35228753Smm#endif
36228753Smm#if MAJOR_IN_MKDEV
37228753Smm#include <sys/mkdev.h>
38228753Smm#define HAVE_MAJOR
39228753Smm#elif MAJOR_IN_SYSMACROS
40228753Smm#include <sys/sysmacros.h>
41228753Smm#define HAVE_MAJOR
42228753Smm#endif
43232153Smm#ifdef HAVE_ERRNO_H
44232153Smm#include <errno.h>
45232153Smm#endif
46228753Smm#ifdef HAVE_LIMITS_H
47228753Smm#include <limits.h>
48228753Smm#endif
49228753Smm#ifdef HAVE_LINUX_FS_H
50228753Smm#include <linux/fs.h>	/* for Linux file flags */
51228753Smm#endif
52228753Smm/*
53228753Smm * Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h.
54228753Smm * As the include guards don't agree, the order of include is important.
55228753Smm */
56228753Smm#ifdef HAVE_LINUX_EXT2_FS_H
57228753Smm#include <linux/ext2_fs.h>	/* for Linux file flags */
58228753Smm#endif
59228753Smm#if defined(HAVE_EXT2FS_EXT2_FS_H) && !defined(__CYGWIN__)
60228753Smm#include <ext2fs/ext2_fs.h>	/* for Linux file flags */
61228753Smm#endif
62228753Smm#include <stddef.h>
63228753Smm#include <stdio.h>
64228753Smm#ifdef HAVE_STDLIB_H
65228753Smm#include <stdlib.h>
66228753Smm#endif
67228753Smm#ifdef HAVE_STRING_H
68228753Smm#include <string.h>
69228753Smm#endif
70228753Smm#ifdef HAVE_WCHAR_H
71228753Smm#include <wchar.h>
72228753Smm#endif
73228753Smm
74228753Smm#include "archive.h"
75232153Smm#include "archive_acl_private.h"
76228753Smm#include "archive_entry.h"
77232153Smm#include "archive_entry_locale.h"
78228753Smm#include "archive_private.h"
79228753Smm#include "archive_entry_private.h"
80228753Smm
81228753Smm#if !defined(HAVE_MAJOR) && !defined(major)
82228753Smm/* Replacement for major/minor/makedev. */
83228753Smm#define	major(x) ((int)(0x00ff & ((x) >> 8)))
84228753Smm#define	minor(x) ((int)(0xffff00ff & (x)))
85228753Smm#define	makedev(maj,min) ((0xff00 & ((maj)<<8)) | (0xffff00ff & (min)))
86228753Smm#endif
87228753Smm
88228753Smm/* Play games to come up with a suitable makedev() definition. */
89228753Smm#ifdef __QNXNTO__
90228753Smm/* QNX.  <sigh> */
91228753Smm#include <sys/netmgr.h>
92228753Smm#define ae_makedev(maj, min) makedev(ND_LOCAL_NODE, (maj), (min))
93228753Smm#elif defined makedev
94228753Smm/* There's a "makedev" macro. */
95228753Smm#define ae_makedev(maj, min) makedev((maj), (min))
96228753Smm#elif defined mkdev || ((defined _WIN32 || defined __WIN32__) && !defined(__CYGWIN__))
97228753Smm/* Windows. <sigh> */
98228753Smm#define ae_makedev(maj, min) mkdev((maj), (min))
99228753Smm#else
100228753Smm/* There's a "makedev" function. */
101228753Smm#define ae_makedev(maj, min) makedev((maj), (min))
102228753Smm#endif
103228753Smm
104232153Smm/*
105232153Smm * This adjustment is needed to support the following idiom for adding
106232153Smm * 1000ns to the stored time:
107232153Smm * archive_entry_set_atime(archive_entry_atime(),
108232153Smm *                         archive_entry_atime_nsec() + 1000)
109232153Smm * The additional if() here compensates for ambiguity in the C standard,
110232153Smm * which permits two possible interpretations of a % b when a is negative.
111232153Smm */
112232153Smm#define FIX_NS(t,ns) \
113232153Smm	do {	\
114232153Smm		t += ns / 1000000000; \
115232153Smm		ns %= 1000000000; \
116232153Smm		if (ns < 0) { --t; ns += 1000000000; } \
117232153Smm	} while (0)
118228753Smm
119228753Smmstatic char *	 ae_fflagstostr(unsigned long bitset, unsigned long bitclear);
120228753Smmstatic const wchar_t	*ae_wcstofflags(const wchar_t *stringp,
121228753Smm		    unsigned long *setp, unsigned long *clrp);
122228753Smmstatic const char	*ae_strtofflags(const char *stringp,
123228753Smm		    unsigned long *setp, unsigned long *clrp);
124228753Smm
125228753Smm#ifndef HAVE_WCSCPY
126228753Smmstatic wchar_t * wcscpy(wchar_t *s1, const wchar_t *s2)
127228753Smm{
128228753Smm	wchar_t *dest = s1;
129228753Smm	while ((*s1 = *s2) != L'\0')
130228753Smm		++s1, ++s2;
131228753Smm	return dest;
132228753Smm}
133228753Smm#endif
134228753Smm#ifndef HAVE_WCSLEN
135228753Smmstatic size_t wcslen(const wchar_t *s)
136228753Smm{
137228753Smm	const wchar_t *p = s;
138228753Smm	while (*p != L'\0')
139228753Smm		++p;
140228753Smm	return p - s;
141228753Smm}
142228753Smm#endif
143228753Smm#ifndef HAVE_WMEMCMP
144228753Smm/* Good enough for simple equality testing, but not for sorting. */
145228753Smm#define wmemcmp(a,b,i)  memcmp((a), (b), (i) * sizeof(wchar_t))
146228753Smm#endif
147228753Smm
148228753Smm/****************************************************************************
149228753Smm *
150228753Smm * Public Interface
151228753Smm *
152228753Smm ****************************************************************************/
153228753Smm
154228753Smmstruct archive_entry *
155228753Smmarchive_entry_clear(struct archive_entry *entry)
156228753Smm{
157228753Smm	if (entry == NULL)
158228753Smm		return (NULL);
159232153Smm	archive_mstring_clean(&entry->ae_fflags_text);
160232153Smm	archive_mstring_clean(&entry->ae_gname);
161232153Smm	archive_mstring_clean(&entry->ae_hardlink);
162232153Smm	archive_mstring_clean(&entry->ae_pathname);
163232153Smm	archive_mstring_clean(&entry->ae_sourcepath);
164232153Smm	archive_mstring_clean(&entry->ae_symlink);
165232153Smm	archive_mstring_clean(&entry->ae_uname);
166232153Smm	archive_entry_copy_mac_metadata(entry, NULL, 0);
167232153Smm	archive_acl_clear(&entry->acl);
168228753Smm	archive_entry_xattr_clear(entry);
169232153Smm	archive_entry_sparse_clear(entry);
170228753Smm	free(entry->stat);
171348608Smm	entry->ae_symlink_type = AE_SYMLINK_TYPE_UNDEFINED;
172228753Smm	memset(entry, 0, sizeof(*entry));
173228753Smm	return entry;
174228753Smm}
175228753Smm
176228753Smmstruct archive_entry *
177228753Smmarchive_entry_clone(struct archive_entry *entry)
178228753Smm{
179228753Smm	struct archive_entry *entry2;
180228753Smm	struct ae_xattr *xp;
181232153Smm	struct ae_sparse *sp;
182232153Smm	size_t s;
183232153Smm	const void *p;
184228753Smm
185228753Smm	/* Allocate new structure and copy over all of the fields. */
186232153Smm	/* TODO: Should we copy the archive over?  Or require a new archive
187232153Smm	 * as an argument? */
188232153Smm	entry2 = archive_entry_new2(entry->archive);
189228753Smm	if (entry2 == NULL)
190228753Smm		return (NULL);
191228753Smm	entry2->ae_stat = entry->ae_stat;
192228753Smm	entry2->ae_fflags_set = entry->ae_fflags_set;
193228753Smm	entry2->ae_fflags_clear = entry->ae_fflags_clear;
194228753Smm
195232153Smm	/* TODO: XXX If clone can have a different archive, what do we do here if
196232153Smm	 * character sets are different? XXX */
197232153Smm	archive_mstring_copy(&entry2->ae_fflags_text, &entry->ae_fflags_text);
198232153Smm	archive_mstring_copy(&entry2->ae_gname, &entry->ae_gname);
199232153Smm	archive_mstring_copy(&entry2->ae_hardlink, &entry->ae_hardlink);
200232153Smm	archive_mstring_copy(&entry2->ae_pathname, &entry->ae_pathname);
201232153Smm	archive_mstring_copy(&entry2->ae_sourcepath, &entry->ae_sourcepath);
202232153Smm	archive_mstring_copy(&entry2->ae_symlink, &entry->ae_symlink);
203228753Smm	entry2->ae_set = entry->ae_set;
204232153Smm	archive_mstring_copy(&entry2->ae_uname, &entry->ae_uname);
205228753Smm
206348608Smm	/* Copy symlink type */
207348608Smm	entry2->ae_symlink_type = entry->ae_symlink_type;
208348608Smm
209302001Smm	/* Copy encryption status */
210302001Smm	entry2->encryption = entry->encryption;
211368708Smm
212368708Smm	/* Copy digests */
213368708Smm#define copy_digest(_e2, _e, _t) \
214368708Smm	memcpy(_e2->digest._t, _e->digest._t, sizeof(_e2->digest._t))
215368708Smm
216368708Smm	copy_digest(entry2, entry, md5);
217368708Smm	copy_digest(entry2, entry, rmd160);
218368708Smm	copy_digest(entry2, entry, sha1);
219368708Smm	copy_digest(entry2, entry, sha256);
220368708Smm	copy_digest(entry2, entry, sha384);
221368708Smm	copy_digest(entry2, entry, sha512);
222368708Smm
223368708Smm#undef copy_digest
224302001Smm
225228753Smm	/* Copy ACL data over. */
226232153Smm	archive_acl_copy(&entry2->acl, &entry->acl);
227228753Smm
228232153Smm	/* Copy Mac OS metadata. */
229232153Smm	p = archive_entry_mac_metadata(entry, &s);
230232153Smm	archive_entry_copy_mac_metadata(entry2, p, s);
231232153Smm
232228753Smm	/* Copy xattr data over. */
233228753Smm	xp = entry->xattr_head;
234228753Smm	while (xp != NULL) {
235228753Smm		archive_entry_xattr_add_entry(entry2,
236228753Smm		    xp->name, xp->value, xp->size);
237228753Smm		xp = xp->next;
238228753Smm	}
239228753Smm
240232153Smm	/* Copy sparse data over. */
241232153Smm	sp = entry->sparse_head;
242232153Smm	while (sp != NULL) {
243232153Smm		archive_entry_sparse_add_entry(entry2,
244232153Smm		    sp->offset, sp->length);
245232153Smm		sp = sp->next;
246232153Smm	}
247232153Smm
248228753Smm	return (entry2);
249228753Smm}
250228753Smm
251228753Smmvoid
252228753Smmarchive_entry_free(struct archive_entry *entry)
253228753Smm{
254228753Smm	archive_entry_clear(entry);
255228753Smm	free(entry);
256228753Smm}
257228753Smm
258228753Smmstruct archive_entry *
259228753Smmarchive_entry_new(void)
260228753Smm{
261232153Smm	return archive_entry_new2(NULL);
262232153Smm}
263232153Smm
264232153Smmstruct archive_entry *
265232153Smmarchive_entry_new2(struct archive *a)
266232153Smm{
267228753Smm	struct archive_entry *entry;
268228753Smm
269311042Smm	entry = (struct archive_entry *)calloc(1, sizeof(*entry));
270228753Smm	if (entry == NULL)
271228753Smm		return (NULL);
272232153Smm	entry->archive = a;
273348608Smm	entry->ae_symlink_type = AE_SYMLINK_TYPE_UNDEFINED;
274228753Smm	return (entry);
275228753Smm}
276228753Smm
277228753Smm/*
278228753Smm * Functions for reading fields from an archive_entry.
279228753Smm */
280228753Smm
281228753Smmtime_t
282228753Smmarchive_entry_atime(struct archive_entry *entry)
283228753Smm{
284228753Smm	return (entry->ae_stat.aest_atime);
285228753Smm}
286228753Smm
287228753Smmlong
288228753Smmarchive_entry_atime_nsec(struct archive_entry *entry)
289228753Smm{
290228753Smm	return (entry->ae_stat.aest_atime_nsec);
291228753Smm}
292228753Smm
293228753Smmint
294228753Smmarchive_entry_atime_is_set(struct archive_entry *entry)
295228753Smm{
296228753Smm	return (entry->ae_set & AE_SET_ATIME);
297228753Smm}
298228753Smm
299228753Smmtime_t
300228753Smmarchive_entry_birthtime(struct archive_entry *entry)
301228753Smm{
302228753Smm	return (entry->ae_stat.aest_birthtime);
303228753Smm}
304228753Smm
305228753Smmlong
306228753Smmarchive_entry_birthtime_nsec(struct archive_entry *entry)
307228753Smm{
308228753Smm	return (entry->ae_stat.aest_birthtime_nsec);
309228753Smm}
310228753Smm
311228753Smmint
312228753Smmarchive_entry_birthtime_is_set(struct archive_entry *entry)
313228753Smm{
314228753Smm	return (entry->ae_set & AE_SET_BIRTHTIME);
315228753Smm}
316228753Smm
317228753Smmtime_t
318228753Smmarchive_entry_ctime(struct archive_entry *entry)
319228753Smm{
320228753Smm	return (entry->ae_stat.aest_ctime);
321228753Smm}
322228753Smm
323228753Smmint
324228753Smmarchive_entry_ctime_is_set(struct archive_entry *entry)
325228753Smm{
326228753Smm	return (entry->ae_set & AE_SET_CTIME);
327228753Smm}
328228753Smm
329228753Smmlong
330228753Smmarchive_entry_ctime_nsec(struct archive_entry *entry)
331228753Smm{
332228753Smm	return (entry->ae_stat.aest_ctime_nsec);
333228753Smm}
334228753Smm
335228753Smmdev_t
336228753Smmarchive_entry_dev(struct archive_entry *entry)
337228753Smm{
338228753Smm	if (entry->ae_stat.aest_dev_is_broken_down)
339228753Smm		return ae_makedev(entry->ae_stat.aest_devmajor,
340228753Smm		    entry->ae_stat.aest_devminor);
341228753Smm	else
342228753Smm		return (entry->ae_stat.aest_dev);
343228753Smm}
344228753Smm
345232153Smmint
346232153Smmarchive_entry_dev_is_set(struct archive_entry *entry)
347232153Smm{
348232153Smm	return (entry->ae_set & AE_SET_DEV);
349232153Smm}
350232153Smm
351228753Smmdev_t
352228753Smmarchive_entry_devmajor(struct archive_entry *entry)
353228753Smm{
354228753Smm	if (entry->ae_stat.aest_dev_is_broken_down)
355228753Smm		return (entry->ae_stat.aest_devmajor);
356228753Smm	else
357228753Smm		return major(entry->ae_stat.aest_dev);
358228753Smm}
359228753Smm
360228753Smmdev_t
361228753Smmarchive_entry_devminor(struct archive_entry *entry)
362228753Smm{
363228753Smm	if (entry->ae_stat.aest_dev_is_broken_down)
364228753Smm		return (entry->ae_stat.aest_devminor);
365228753Smm	else
366228753Smm		return minor(entry->ae_stat.aest_dev);
367228753Smm}
368228753Smm
369362134Smm__LA_MODE_T
370228753Smmarchive_entry_filetype(struct archive_entry *entry)
371228753Smm{
372232153Smm	return (AE_IFMT & entry->acl.mode);
373228753Smm}
374228753Smm
375228753Smmvoid
376228753Smmarchive_entry_fflags(struct archive_entry *entry,
377228753Smm    unsigned long *set, unsigned long *clear)
378228753Smm{
379228753Smm	*set = entry->ae_fflags_set;
380228753Smm	*clear = entry->ae_fflags_clear;
381228753Smm}
382228753Smm
383228753Smm/*
384228753Smm * Note: if text was provided, this just returns that text.  If you
385228753Smm * really need the text to be rebuilt in a canonical form, set the
386228753Smm * text, ask for the bitmaps, then set the bitmaps.  (Setting the
387228753Smm * bitmaps clears any stored text.)  This design is deliberate: if
388228753Smm * we're editing archives, we don't want to discard flags just because
389228753Smm * they aren't supported on the current system.  The bitmap<->text
390228753Smm * conversions are platform-specific (see below).
391228753Smm */
392228753Smmconst char *
393228753Smmarchive_entry_fflags_text(struct archive_entry *entry)
394228753Smm{
395228753Smm	const char *f;
396228753Smm	char *p;
397228753Smm
398232153Smm	if (archive_mstring_get_mbs(entry->archive,
399238856Smm	    &entry->ae_fflags_text, &f) == 0) {
400238856Smm		if (f != NULL)
401238856Smm			return (f);
402238856Smm	} else if (errno == ENOMEM)
403238856Smm		__archive_errx(1, "No memory");
404228753Smm
405228753Smm	if (entry->ae_fflags_set == 0  &&  entry->ae_fflags_clear == 0)
406228753Smm		return (NULL);
407228753Smm
408228753Smm	p = ae_fflagstostr(entry->ae_fflags_set, entry->ae_fflags_clear);
409228753Smm	if (p == NULL)
410228753Smm		return (NULL);
411228753Smm
412232153Smm	archive_mstring_copy_mbs(&entry->ae_fflags_text, p);
413228753Smm	free(p);
414232153Smm	if (archive_mstring_get_mbs(entry->archive,
415232153Smm	    &entry->ae_fflags_text, &f) == 0)
416232153Smm		return (f);
417238856Smm	if (errno == ENOMEM)
418238856Smm		__archive_errx(1, "No memory");
419232153Smm	return (NULL);
420228753Smm}
421228753Smm
422315433Smmla_int64_t
423228753Smmarchive_entry_gid(struct archive_entry *entry)
424228753Smm{
425228753Smm	return (entry->ae_stat.aest_gid);
426228753Smm}
427228753Smm
428228753Smmconst char *
429228753Smmarchive_entry_gname(struct archive_entry *entry)
430228753Smm{
431232153Smm	const char *p;
432232153Smm	if (archive_mstring_get_mbs(entry->archive, &entry->ae_gname, &p) == 0)
433232153Smm		return (p);
434238856Smm	if (errno == ENOMEM)
435238856Smm		__archive_errx(1, "No memory");
436232153Smm	return (NULL);
437228753Smm}
438228753Smm
439302001Smmconst char *
440302001Smmarchive_entry_gname_utf8(struct archive_entry *entry)
441302001Smm{
442302001Smm	const char *p;
443302001Smm	if (archive_mstring_get_utf8(entry->archive, &entry->ae_gname, &p) == 0)
444302001Smm		return (p);
445302001Smm	if (errno == ENOMEM)
446302001Smm		__archive_errx(1, "No memory");
447302001Smm	return (NULL);
448302001Smm}
449302001Smm
450302001Smm
451228753Smmconst wchar_t *
452228753Smmarchive_entry_gname_w(struct archive_entry *entry)
453228753Smm{
454232153Smm	const wchar_t *p;
455232153Smm	if (archive_mstring_get_wcs(entry->archive, &entry->ae_gname, &p) == 0)
456232153Smm		return (p);
457238856Smm	if (errno == ENOMEM)
458238856Smm		__archive_errx(1, "No memory");
459232153Smm	return (NULL);
460228753Smm}
461228753Smm
462232153Smmint
463232153Smm_archive_entry_gname_l(struct archive_entry *entry,
464232153Smm    const char **p, size_t *len, struct archive_string_conv *sc)
465232153Smm{
466368708Smm	return (archive_mstring_get_mbs_l(entry->archive, &entry->ae_gname, p, len, sc));
467232153Smm}
468232153Smm
469228753Smmconst char *
470228753Smmarchive_entry_hardlink(struct archive_entry *entry)
471228753Smm{
472232153Smm	const char *p;
473238856Smm	if ((entry->ae_set & AE_SET_HARDLINK) == 0)
474238856Smm		return (NULL);
475238856Smm	if (archive_mstring_get_mbs(
476232153Smm	    entry->archive, &entry->ae_hardlink, &p) == 0)
477232153Smm		return (p);
478238856Smm	if (errno == ENOMEM)
479238856Smm		__archive_errx(1, "No memory");
480228753Smm	return (NULL);
481228753Smm}
482228753Smm
483302001Smmconst char *
484302001Smmarchive_entry_hardlink_utf8(struct archive_entry *entry)
485302001Smm{
486302001Smm	const char *p;
487302001Smm	if ((entry->ae_set & AE_SET_HARDLINK) == 0)
488302001Smm		return (NULL);
489302001Smm	if (archive_mstring_get_utf8(
490302001Smm	    entry->archive, &entry->ae_hardlink, &p) == 0)
491302001Smm		return (p);
492302001Smm	if (errno == ENOMEM)
493302001Smm		__archive_errx(1, "No memory");
494302001Smm	return (NULL);
495302001Smm}
496302001Smm
497228753Smmconst wchar_t *
498228753Smmarchive_entry_hardlink_w(struct archive_entry *entry)
499228753Smm{
500232153Smm	const wchar_t *p;
501238856Smm	if ((entry->ae_set & AE_SET_HARDLINK) == 0)
502238856Smm		return (NULL);
503238856Smm	if (archive_mstring_get_wcs(
504232153Smm	    entry->archive, &entry->ae_hardlink, &p) == 0)
505232153Smm		return (p);
506238856Smm	if (errno == ENOMEM)
507238856Smm		__archive_errx(1, "No memory");
508228753Smm	return (NULL);
509228753Smm}
510228753Smm
511232153Smmint
512232153Smm_archive_entry_hardlink_l(struct archive_entry *entry,
513232153Smm    const char **p, size_t *len, struct archive_string_conv *sc)
514232153Smm{
515232153Smm	if ((entry->ae_set & AE_SET_HARDLINK) == 0) {
516232153Smm		*p = NULL;
517232153Smm		*len = 0;
518232153Smm		return (0);
519232153Smm	}
520368708Smm	return (archive_mstring_get_mbs_l(entry->archive, &entry->ae_hardlink, p, len, sc));
521232153Smm}
522232153Smm
523315433Smmla_int64_t
524228753Smmarchive_entry_ino(struct archive_entry *entry)
525228753Smm{
526228753Smm	return (entry->ae_stat.aest_ino);
527228753Smm}
528228753Smm
529232153Smmint
530232153Smmarchive_entry_ino_is_set(struct archive_entry *entry)
531232153Smm{
532232153Smm	return (entry->ae_set & AE_SET_INO);
533232153Smm}
534232153Smm
535315433Smmla_int64_t
536228753Smmarchive_entry_ino64(struct archive_entry *entry)
537228753Smm{
538228753Smm	return (entry->ae_stat.aest_ino);
539228753Smm}
540228753Smm
541362134Smm__LA_MODE_T
542228753Smmarchive_entry_mode(struct archive_entry *entry)
543228753Smm{
544232153Smm	return (entry->acl.mode);
545228753Smm}
546228753Smm
547228753Smmtime_t
548228753Smmarchive_entry_mtime(struct archive_entry *entry)
549228753Smm{
550228753Smm	return (entry->ae_stat.aest_mtime);
551228753Smm}
552228753Smm
553228753Smmlong
554228753Smmarchive_entry_mtime_nsec(struct archive_entry *entry)
555228753Smm{
556228753Smm	return (entry->ae_stat.aest_mtime_nsec);
557228753Smm}
558228753Smm
559228753Smmint
560228753Smmarchive_entry_mtime_is_set(struct archive_entry *entry)
561228753Smm{
562228753Smm	return (entry->ae_set & AE_SET_MTIME);
563228753Smm}
564228753Smm
565228753Smmunsigned int
566228753Smmarchive_entry_nlink(struct archive_entry *entry)
567228753Smm{
568228753Smm	return (entry->ae_stat.aest_nlink);
569228753Smm}
570228753Smm
571228753Smmconst char *
572228753Smmarchive_entry_pathname(struct archive_entry *entry)
573228753Smm{
574232153Smm	const char *p;
575232153Smm	if (archive_mstring_get_mbs(
576232153Smm	    entry->archive, &entry->ae_pathname, &p) == 0)
577232153Smm		return (p);
578238856Smm	if (errno == ENOMEM)
579238856Smm		__archive_errx(1, "No memory");
580232153Smm	return (NULL);
581228753Smm}
582228753Smm
583302001Smmconst char *
584302001Smmarchive_entry_pathname_utf8(struct archive_entry *entry)
585302001Smm{
586302001Smm	const char *p;
587302001Smm	if (archive_mstring_get_utf8(
588302001Smm	    entry->archive, &entry->ae_pathname, &p) == 0)
589302001Smm		return (p);
590302001Smm	if (errno == ENOMEM)
591302001Smm		__archive_errx(1, "No memory");
592302001Smm	return (NULL);
593302001Smm}
594302001Smm
595228753Smmconst wchar_t *
596228753Smmarchive_entry_pathname_w(struct archive_entry *entry)
597228753Smm{
598232153Smm	const wchar_t *p;
599232153Smm	if (archive_mstring_get_wcs(
600232153Smm	    entry->archive, &entry->ae_pathname, &p) == 0)
601232153Smm		return (p);
602238856Smm	if (errno == ENOMEM)
603238856Smm		__archive_errx(1, "No memory");
604232153Smm	return (NULL);
605228753Smm}
606228753Smm
607232153Smmint
608232153Smm_archive_entry_pathname_l(struct archive_entry *entry,
609232153Smm    const char **p, size_t *len, struct archive_string_conv *sc)
610232153Smm{
611368708Smm	return (archive_mstring_get_mbs_l(entry->archive, &entry->ae_pathname, p, len, sc));
612232153Smm}
613232153Smm
614362134Smm__LA_MODE_T
615232153Smmarchive_entry_perm(struct archive_entry *entry)
616232153Smm{
617232153Smm	return (~AE_IFMT & entry->acl.mode);
618232153Smm}
619232153Smm
620228753Smmdev_t
621228753Smmarchive_entry_rdev(struct archive_entry *entry)
622228753Smm{
623228753Smm	if (entry->ae_stat.aest_rdev_is_broken_down)
624228753Smm		return ae_makedev(entry->ae_stat.aest_rdevmajor,
625228753Smm		    entry->ae_stat.aest_rdevminor);
626228753Smm	else
627228753Smm		return (entry->ae_stat.aest_rdev);
628228753Smm}
629228753Smm
630228753Smmdev_t
631228753Smmarchive_entry_rdevmajor(struct archive_entry *entry)
632228753Smm{
633228753Smm	if (entry->ae_stat.aest_rdev_is_broken_down)
634228753Smm		return (entry->ae_stat.aest_rdevmajor);
635228753Smm	else
636228753Smm		return major(entry->ae_stat.aest_rdev);
637228753Smm}
638228753Smm
639228753Smmdev_t
640228753Smmarchive_entry_rdevminor(struct archive_entry *entry)
641228753Smm{
642228753Smm	if (entry->ae_stat.aest_rdev_is_broken_down)
643228753Smm		return (entry->ae_stat.aest_rdevminor);
644228753Smm	else
645228753Smm		return minor(entry->ae_stat.aest_rdev);
646228753Smm}
647228753Smm
648315433Smmla_int64_t
649228753Smmarchive_entry_size(struct archive_entry *entry)
650228753Smm{
651228753Smm	return (entry->ae_stat.aest_size);
652228753Smm}
653228753Smm
654228753Smmint
655228753Smmarchive_entry_size_is_set(struct archive_entry *entry)
656228753Smm{
657228753Smm	return (entry->ae_set & AE_SET_SIZE);
658228753Smm}
659228753Smm
660228753Smmconst char *
661228753Smmarchive_entry_sourcepath(struct archive_entry *entry)
662228753Smm{
663232153Smm	const char *p;
664232153Smm	if (archive_mstring_get_mbs(
665232153Smm	    entry->archive, &entry->ae_sourcepath, &p) == 0)
666232153Smm		return (p);
667238856Smm	if (errno == ENOMEM)
668238856Smm		__archive_errx(1, "No memory");
669232153Smm	return (NULL);
670228753Smm}
671228753Smm
672232153Smmconst wchar_t *
673232153Smmarchive_entry_sourcepath_w(struct archive_entry *entry)
674232153Smm{
675232153Smm	const wchar_t *p;
676232153Smm	if (archive_mstring_get_wcs(
677232153Smm	    entry->archive, &entry->ae_sourcepath, &p) == 0)
678232153Smm		return (p);
679232153Smm	return (NULL);
680232153Smm}
681232153Smm
682228753Smmconst char *
683228753Smmarchive_entry_symlink(struct archive_entry *entry)
684228753Smm{
685232153Smm	const char *p;
686238856Smm	if ((entry->ae_set & AE_SET_SYMLINK) == 0)
687238856Smm		return (NULL);
688238856Smm	if (archive_mstring_get_mbs(
689232153Smm	    entry->archive, &entry->ae_symlink, &p) == 0)
690232153Smm		return (p);
691238856Smm	if (errno == ENOMEM)
692238856Smm		__archive_errx(1, "No memory");
693228753Smm	return (NULL);
694228753Smm}
695228753Smm
696348608Smmint
697348608Smmarchive_entry_symlink_type(struct archive_entry *entry)
698348608Smm{
699348608Smm	return (entry->ae_symlink_type);
700348608Smm}
701348608Smm
702302001Smmconst char *
703302001Smmarchive_entry_symlink_utf8(struct archive_entry *entry)
704302001Smm{
705302001Smm	const char *p;
706302001Smm	if ((entry->ae_set & AE_SET_SYMLINK) == 0)
707302001Smm		return (NULL);
708302001Smm	if (archive_mstring_get_utf8(
709302001Smm	    entry->archive, &entry->ae_symlink, &p) == 0)
710302001Smm		return (p);
711302001Smm	if (errno == ENOMEM)
712302001Smm		__archive_errx(1, "No memory");
713302001Smm	return (NULL);
714302001Smm}
715302001Smm
716228753Smmconst wchar_t *
717228753Smmarchive_entry_symlink_w(struct archive_entry *entry)
718228753Smm{
719232153Smm	const wchar_t *p;
720238856Smm	if ((entry->ae_set & AE_SET_SYMLINK) == 0)
721238856Smm		return (NULL);
722238856Smm	if (archive_mstring_get_wcs(
723232153Smm	    entry->archive, &entry->ae_symlink, &p) == 0)
724232153Smm		return (p);
725238856Smm	if (errno == ENOMEM)
726238856Smm		__archive_errx(1, "No memory");
727228753Smm	return (NULL);
728228753Smm}
729228753Smm
730232153Smmint
731232153Smm_archive_entry_symlink_l(struct archive_entry *entry,
732232153Smm    const char **p, size_t *len, struct archive_string_conv *sc)
733232153Smm{
734232153Smm	if ((entry->ae_set & AE_SET_SYMLINK) == 0) {
735232153Smm		*p = NULL;
736232153Smm		*len = 0;
737232153Smm		return (0);
738232153Smm	}
739368708Smm	return (archive_mstring_get_mbs_l(entry->archive, &entry->ae_symlink, p, len, sc));
740232153Smm}
741232153Smm
742315433Smmla_int64_t
743228753Smmarchive_entry_uid(struct archive_entry *entry)
744228753Smm{
745228753Smm	return (entry->ae_stat.aest_uid);
746228753Smm}
747228753Smm
748228753Smmconst char *
749228753Smmarchive_entry_uname(struct archive_entry *entry)
750228753Smm{
751232153Smm	const char *p;
752232153Smm	if (archive_mstring_get_mbs(entry->archive, &entry->ae_uname, &p) == 0)
753232153Smm		return (p);
754238856Smm	if (errno == ENOMEM)
755238856Smm		__archive_errx(1, "No memory");
756232153Smm	return (NULL);
757228753Smm}
758228753Smm
759302001Smmconst char *
760302001Smmarchive_entry_uname_utf8(struct archive_entry *entry)
761302001Smm{
762302001Smm	const char *p;
763302001Smm	if (archive_mstring_get_utf8(entry->archive, &entry->ae_uname, &p) == 0)
764302001Smm		return (p);
765302001Smm	if (errno == ENOMEM)
766302001Smm		__archive_errx(1, "No memory");
767302001Smm	return (NULL);
768302001Smm}
769302001Smm
770228753Smmconst wchar_t *
771228753Smmarchive_entry_uname_w(struct archive_entry *entry)
772228753Smm{
773232153Smm	const wchar_t *p;
774232153Smm	if (archive_mstring_get_wcs(entry->archive, &entry->ae_uname, &p) == 0)
775232153Smm		return (p);
776238856Smm	if (errno == ENOMEM)
777238856Smm		__archive_errx(1, "No memory");
778232153Smm	return (NULL);
779228753Smm}
780228753Smm
781232153Smmint
782232153Smm_archive_entry_uname_l(struct archive_entry *entry,
783232153Smm    const char **p, size_t *len, struct archive_string_conv *sc)
784232153Smm{
785368708Smm	return (archive_mstring_get_mbs_l(entry->archive, &entry->ae_uname, p, len, sc));
786232153Smm}
787232153Smm
788302001Smmint
789302001Smmarchive_entry_is_data_encrypted(struct archive_entry *entry)
790302001Smm{
791302001Smm	return ((entry->encryption & AE_ENCRYPTION_DATA) == AE_ENCRYPTION_DATA);
792302001Smm}
793302001Smm
794302001Smmint
795302001Smmarchive_entry_is_metadata_encrypted(struct archive_entry *entry)
796302001Smm{
797302001Smm	return ((entry->encryption & AE_ENCRYPTION_METADATA) == AE_ENCRYPTION_METADATA);
798302001Smm}
799302001Smm
800302001Smmint
801302001Smmarchive_entry_is_encrypted(struct archive_entry *entry)
802302001Smm{
803302001Smm	return (entry->encryption & (AE_ENCRYPTION_DATA|AE_ENCRYPTION_METADATA));
804302001Smm}
805302001Smm
806228753Smm/*
807228753Smm * Functions to set archive_entry properties.
808228753Smm */
809228753Smm
810228753Smmvoid
811228753Smmarchive_entry_set_filetype(struct archive_entry *entry, unsigned int type)
812228753Smm{
813228753Smm	entry->stat_valid = 0;
814232153Smm	entry->acl.mode &= ~AE_IFMT;
815232153Smm	entry->acl.mode |= AE_IFMT & type;
816228753Smm}
817228753Smm
818228753Smmvoid
819228753Smmarchive_entry_set_fflags(struct archive_entry *entry,
820228753Smm    unsigned long set, unsigned long clear)
821228753Smm{
822232153Smm	archive_mstring_clean(&entry->ae_fflags_text);
823228753Smm	entry->ae_fflags_set = set;
824228753Smm	entry->ae_fflags_clear = clear;
825228753Smm}
826228753Smm
827228753Smmconst char *
828228753Smmarchive_entry_copy_fflags_text(struct archive_entry *entry,
829228753Smm    const char *flags)
830228753Smm{
831232153Smm	archive_mstring_copy_mbs(&entry->ae_fflags_text, flags);
832228753Smm	return (ae_strtofflags(flags,
833228753Smm		    &entry->ae_fflags_set, &entry->ae_fflags_clear));
834228753Smm}
835228753Smm
836228753Smmconst wchar_t *
837228753Smmarchive_entry_copy_fflags_text_w(struct archive_entry *entry,
838228753Smm    const wchar_t *flags)
839228753Smm{
840232153Smm	archive_mstring_copy_wcs(&entry->ae_fflags_text, flags);
841228753Smm	return (ae_wcstofflags(flags,
842228753Smm		    &entry->ae_fflags_set, &entry->ae_fflags_clear));
843228753Smm}
844228753Smm
845228753Smmvoid
846315433Smmarchive_entry_set_gid(struct archive_entry *entry, la_int64_t g)
847228753Smm{
848228753Smm	entry->stat_valid = 0;
849228753Smm	entry->ae_stat.aest_gid = g;
850228753Smm}
851228753Smm
852228753Smmvoid
853228753Smmarchive_entry_set_gname(struct archive_entry *entry, const char *name)
854228753Smm{
855232153Smm	archive_mstring_copy_mbs(&entry->ae_gname, name);
856228753Smm}
857228753Smm
858228753Smmvoid
859302001Smmarchive_entry_set_gname_utf8(struct archive_entry *entry, const char *name)
860302001Smm{
861302001Smm	archive_mstring_copy_utf8(&entry->ae_gname, name);
862302001Smm}
863302001Smm
864302001Smmvoid
865228753Smmarchive_entry_copy_gname(struct archive_entry *entry, const char *name)
866228753Smm{
867232153Smm	archive_mstring_copy_mbs(&entry->ae_gname, name);
868228753Smm}
869228753Smm
870228753Smmvoid
871228753Smmarchive_entry_copy_gname_w(struct archive_entry *entry, const wchar_t *name)
872228753Smm{
873232153Smm	archive_mstring_copy_wcs(&entry->ae_gname, name);
874228753Smm}
875228753Smm
876228753Smmint
877228753Smmarchive_entry_update_gname_utf8(struct archive_entry *entry, const char *name)
878228753Smm{
879232153Smm	if (archive_mstring_update_utf8(entry->archive,
880232153Smm	    &entry->ae_gname, name) == 0)
881232153Smm		return (1);
882238856Smm	if (errno == ENOMEM)
883238856Smm		__archive_errx(1, "No memory");
884232153Smm	return (0);
885228753Smm}
886228753Smm
887232153Smmint
888232153Smm_archive_entry_copy_gname_l(struct archive_entry *entry,
889232153Smm    const char *name, size_t len, struct archive_string_conv *sc)
890232153Smm{
891232153Smm	return (archive_mstring_copy_mbs_len_l(&entry->ae_gname, name, len, sc));
892232153Smm}
893232153Smm
894228753Smmvoid
895315433Smmarchive_entry_set_ino(struct archive_entry *entry, la_int64_t ino)
896228753Smm{
897228753Smm	entry->stat_valid = 0;
898232153Smm	entry->ae_set |= AE_SET_INO;
899228753Smm	entry->ae_stat.aest_ino = ino;
900228753Smm}
901228753Smm
902228753Smmvoid
903315433Smmarchive_entry_set_ino64(struct archive_entry *entry, la_int64_t ino)
904228753Smm{
905228753Smm	entry->stat_valid = 0;
906232153Smm	entry->ae_set |= AE_SET_INO;
907228753Smm	entry->ae_stat.aest_ino = ino;
908228753Smm}
909228753Smm
910228753Smmvoid
911228753Smmarchive_entry_set_hardlink(struct archive_entry *entry, const char *target)
912228753Smm{
913232153Smm	archive_mstring_copy_mbs(&entry->ae_hardlink, target);
914228753Smm	if (target != NULL)
915228753Smm		entry->ae_set |= AE_SET_HARDLINK;
916228753Smm	else
917228753Smm		entry->ae_set &= ~AE_SET_HARDLINK;
918228753Smm}
919228753Smm
920228753Smmvoid
921302001Smmarchive_entry_set_hardlink_utf8(struct archive_entry *entry, const char *target)
922302001Smm{
923302001Smm	archive_mstring_copy_utf8(&entry->ae_hardlink, target);
924302001Smm	if (target != NULL)
925302001Smm		entry->ae_set |= AE_SET_HARDLINK;
926302001Smm	else
927302001Smm		entry->ae_set &= ~AE_SET_HARDLINK;
928302001Smm}
929302001Smm
930302001Smmvoid
931228753Smmarchive_entry_copy_hardlink(struct archive_entry *entry, const char *target)
932228753Smm{
933232153Smm	archive_mstring_copy_mbs(&entry->ae_hardlink, target);
934228753Smm	if (target != NULL)
935228753Smm		entry->ae_set |= AE_SET_HARDLINK;
936228753Smm	else
937228753Smm		entry->ae_set &= ~AE_SET_HARDLINK;
938228753Smm}
939228753Smm
940228753Smmvoid
941228753Smmarchive_entry_copy_hardlink_w(struct archive_entry *entry, const wchar_t *target)
942228753Smm{
943232153Smm	archive_mstring_copy_wcs(&entry->ae_hardlink, target);
944228753Smm	if (target != NULL)
945228753Smm		entry->ae_set |= AE_SET_HARDLINK;
946228753Smm	else
947228753Smm		entry->ae_set &= ~AE_SET_HARDLINK;
948228753Smm}
949228753Smm
950228753Smmint
951228753Smmarchive_entry_update_hardlink_utf8(struct archive_entry *entry, const char *target)
952228753Smm{
953228753Smm	if (target != NULL)
954228753Smm		entry->ae_set |= AE_SET_HARDLINK;
955228753Smm	else
956228753Smm		entry->ae_set &= ~AE_SET_HARDLINK;
957232153Smm	if (archive_mstring_update_utf8(entry->archive,
958232153Smm	    &entry->ae_hardlink, target) == 0)
959232153Smm		return (1);
960238856Smm	if (errno == ENOMEM)
961238856Smm		__archive_errx(1, "No memory");
962232153Smm	return (0);
963228753Smm}
964228753Smm
965232153Smmint
966232153Smm_archive_entry_copy_hardlink_l(struct archive_entry *entry,
967232153Smm    const char *target, size_t len, struct archive_string_conv *sc)
968232153Smm{
969232153Smm	int r;
970232153Smm
971232153Smm	r = archive_mstring_copy_mbs_len_l(&entry->ae_hardlink,
972232153Smm	    target, len, sc);
973232153Smm	if (target != NULL && r == 0)
974232153Smm		entry->ae_set |= AE_SET_HARDLINK;
975232153Smm	else
976232153Smm		entry->ae_set &= ~AE_SET_HARDLINK;
977232153Smm	return (r);
978232153Smm}
979232153Smm
980228753Smmvoid
981228753Smmarchive_entry_set_atime(struct archive_entry *entry, time_t t, long ns)
982228753Smm{
983232153Smm	FIX_NS(t, ns);
984228753Smm	entry->stat_valid = 0;
985228753Smm	entry->ae_set |= AE_SET_ATIME;
986228753Smm	entry->ae_stat.aest_atime = t;
987228753Smm	entry->ae_stat.aest_atime_nsec = ns;
988228753Smm}
989228753Smm
990228753Smmvoid
991228753Smmarchive_entry_unset_atime(struct archive_entry *entry)
992228753Smm{
993228753Smm	archive_entry_set_atime(entry, 0, 0);
994228753Smm	entry->ae_set &= ~AE_SET_ATIME;
995228753Smm}
996228753Smm
997228753Smmvoid
998232153Smmarchive_entry_set_birthtime(struct archive_entry *entry, time_t t, long ns)
999228753Smm{
1000232153Smm	FIX_NS(t, ns);
1001228753Smm	entry->stat_valid = 0;
1002228753Smm	entry->ae_set |= AE_SET_BIRTHTIME;
1003232153Smm	entry->ae_stat.aest_birthtime = t;
1004228753Smm	entry->ae_stat.aest_birthtime_nsec = ns;
1005228753Smm}
1006228753Smm
1007228753Smmvoid
1008228753Smmarchive_entry_unset_birthtime(struct archive_entry *entry)
1009228753Smm{
1010228753Smm	archive_entry_set_birthtime(entry, 0, 0);
1011228753Smm	entry->ae_set &= ~AE_SET_BIRTHTIME;
1012228753Smm}
1013228753Smm
1014228753Smmvoid
1015228753Smmarchive_entry_set_ctime(struct archive_entry *entry, time_t t, long ns)
1016228753Smm{
1017232153Smm	FIX_NS(t, ns);
1018228753Smm	entry->stat_valid = 0;
1019228753Smm	entry->ae_set |= AE_SET_CTIME;
1020228753Smm	entry->ae_stat.aest_ctime = t;
1021228753Smm	entry->ae_stat.aest_ctime_nsec = ns;
1022228753Smm}
1023228753Smm
1024228753Smmvoid
1025228753Smmarchive_entry_unset_ctime(struct archive_entry *entry)
1026228753Smm{
1027228753Smm	archive_entry_set_ctime(entry, 0, 0);
1028228753Smm	entry->ae_set &= ~AE_SET_CTIME;
1029228753Smm}
1030228753Smm
1031228753Smmvoid
1032228753Smmarchive_entry_set_dev(struct archive_entry *entry, dev_t d)
1033228753Smm{
1034228753Smm	entry->stat_valid = 0;
1035232153Smm	entry->ae_set |= AE_SET_DEV;
1036228753Smm	entry->ae_stat.aest_dev_is_broken_down = 0;
1037228753Smm	entry->ae_stat.aest_dev = d;
1038228753Smm}
1039228753Smm
1040228753Smmvoid
1041228753Smmarchive_entry_set_devmajor(struct archive_entry *entry, dev_t m)
1042228753Smm{
1043228753Smm	entry->stat_valid = 0;
1044232153Smm	entry->ae_set |= AE_SET_DEV;
1045228753Smm	entry->ae_stat.aest_dev_is_broken_down = 1;
1046228753Smm	entry->ae_stat.aest_devmajor = m;
1047228753Smm}
1048228753Smm
1049228753Smmvoid
1050228753Smmarchive_entry_set_devminor(struct archive_entry *entry, dev_t m)
1051228753Smm{
1052228753Smm	entry->stat_valid = 0;
1053232153Smm	entry->ae_set |= AE_SET_DEV;
1054228753Smm	entry->ae_stat.aest_dev_is_broken_down = 1;
1055228753Smm	entry->ae_stat.aest_devminor = m;
1056228753Smm}
1057228753Smm
1058228753Smm/* Set symlink if symlink is already set, else set hardlink. */
1059228753Smmvoid
1060228753Smmarchive_entry_set_link(struct archive_entry *entry, const char *target)
1061228753Smm{
1062228753Smm	if (entry->ae_set & AE_SET_SYMLINK)
1063232153Smm		archive_mstring_copy_mbs(&entry->ae_symlink, target);
1064228753Smm	else
1065232153Smm		archive_mstring_copy_mbs(&entry->ae_hardlink, target);
1066228753Smm}
1067228753Smm
1068302001Smmvoid
1069302001Smmarchive_entry_set_link_utf8(struct archive_entry *entry, const char *target)
1070302001Smm{
1071302001Smm	if (entry->ae_set & AE_SET_SYMLINK)
1072302001Smm		archive_mstring_copy_utf8(&entry->ae_symlink, target);
1073302001Smm	else
1074302001Smm		archive_mstring_copy_utf8(&entry->ae_hardlink, target);
1075302001Smm}
1076302001Smm
1077228753Smm/* Set symlink if symlink is already set, else set hardlink. */
1078228753Smmvoid
1079228753Smmarchive_entry_copy_link(struct archive_entry *entry, const char *target)
1080228753Smm{
1081228753Smm	if (entry->ae_set & AE_SET_SYMLINK)
1082232153Smm		archive_mstring_copy_mbs(&entry->ae_symlink, target);
1083228753Smm	else
1084232153Smm		archive_mstring_copy_mbs(&entry->ae_hardlink, target);
1085228753Smm}
1086228753Smm
1087228753Smm/* Set symlink if symlink is already set, else set hardlink. */
1088228753Smmvoid
1089228753Smmarchive_entry_copy_link_w(struct archive_entry *entry, const wchar_t *target)
1090228753Smm{
1091228753Smm	if (entry->ae_set & AE_SET_SYMLINK)
1092232153Smm		archive_mstring_copy_wcs(&entry->ae_symlink, target);
1093228753Smm	else
1094232153Smm		archive_mstring_copy_wcs(&entry->ae_hardlink, target);
1095228753Smm}
1096228753Smm
1097228753Smmint
1098228753Smmarchive_entry_update_link_utf8(struct archive_entry *entry, const char *target)
1099228753Smm{
1100232153Smm	int r;
1101228753Smm	if (entry->ae_set & AE_SET_SYMLINK)
1102232153Smm		r = archive_mstring_update_utf8(entry->archive,
1103232153Smm		    &entry->ae_symlink, target);
1104228753Smm	else
1105232153Smm		r = archive_mstring_update_utf8(entry->archive,
1106232153Smm		    &entry->ae_hardlink, target);
1107238856Smm	if (r == 0)
1108238856Smm		return (1);
1109238856Smm	if (errno == ENOMEM)
1110238856Smm		__archive_errx(1, "No memory");
1111238856Smm	return (0);
1112228753Smm}
1113228753Smm
1114232153Smmint
1115232153Smm_archive_entry_copy_link_l(struct archive_entry *entry,
1116232153Smm    const char *target, size_t len, struct archive_string_conv *sc)
1117232153Smm{
1118232153Smm	int r;
1119232153Smm
1120232153Smm	if (entry->ae_set & AE_SET_SYMLINK)
1121232153Smm		r = archive_mstring_copy_mbs_len_l(&entry->ae_symlink,
1122232153Smm		    target, len, sc);
1123232153Smm	else
1124232153Smm		r = archive_mstring_copy_mbs_len_l(&entry->ae_hardlink,
1125232153Smm		    target, len, sc);
1126232153Smm	return (r);
1127232153Smm}
1128232153Smm
1129228753Smmvoid
1130228753Smmarchive_entry_set_mode(struct archive_entry *entry, mode_t m)
1131228753Smm{
1132228753Smm	entry->stat_valid = 0;
1133232153Smm	entry->acl.mode = m;
1134228753Smm}
1135228753Smm
1136228753Smmvoid
1137232153Smmarchive_entry_set_mtime(struct archive_entry *entry, time_t t, long ns)
1138228753Smm{
1139232153Smm	FIX_NS(t, ns);
1140228753Smm	entry->stat_valid = 0;
1141228753Smm	entry->ae_set |= AE_SET_MTIME;
1142232153Smm	entry->ae_stat.aest_mtime = t;
1143228753Smm	entry->ae_stat.aest_mtime_nsec = ns;
1144228753Smm}
1145228753Smm
1146228753Smmvoid
1147228753Smmarchive_entry_unset_mtime(struct archive_entry *entry)
1148228753Smm{
1149228753Smm	archive_entry_set_mtime(entry, 0, 0);
1150228753Smm	entry->ae_set &= ~AE_SET_MTIME;
1151228753Smm}
1152228753Smm
1153228753Smmvoid
1154228753Smmarchive_entry_set_nlink(struct archive_entry *entry, unsigned int nlink)
1155228753Smm{
1156228753Smm	entry->stat_valid = 0;
1157228753Smm	entry->ae_stat.aest_nlink = nlink;
1158228753Smm}
1159228753Smm
1160228753Smmvoid
1161228753Smmarchive_entry_set_pathname(struct archive_entry *entry, const char *name)
1162228753Smm{
1163232153Smm	archive_mstring_copy_mbs(&entry->ae_pathname, name);
1164228753Smm}
1165228753Smm
1166228753Smmvoid
1167302001Smmarchive_entry_set_pathname_utf8(struct archive_entry *entry, const char *name)
1168302001Smm{
1169302001Smm	archive_mstring_copy_utf8(&entry->ae_pathname, name);
1170302001Smm}
1171302001Smm
1172302001Smmvoid
1173228753Smmarchive_entry_copy_pathname(struct archive_entry *entry, const char *name)
1174228753Smm{
1175232153Smm	archive_mstring_copy_mbs(&entry->ae_pathname, name);
1176228753Smm}
1177228753Smm
1178228753Smmvoid
1179228753Smmarchive_entry_copy_pathname_w(struct archive_entry *entry, const wchar_t *name)
1180228753Smm{
1181232153Smm	archive_mstring_copy_wcs(&entry->ae_pathname, name);
1182228753Smm}
1183228753Smm
1184228753Smmint
1185228753Smmarchive_entry_update_pathname_utf8(struct archive_entry *entry, const char *name)
1186228753Smm{
1187232153Smm	if (archive_mstring_update_utf8(entry->archive,
1188232153Smm	    &entry->ae_pathname, name) == 0)
1189232153Smm		return (1);
1190238856Smm	if (errno == ENOMEM)
1191238856Smm		__archive_errx(1, "No memory");
1192232153Smm	return (0);
1193228753Smm}
1194228753Smm
1195232153Smmint
1196232153Smm_archive_entry_copy_pathname_l(struct archive_entry *entry,
1197232153Smm    const char *name, size_t len, struct archive_string_conv *sc)
1198232153Smm{
1199232153Smm	return (archive_mstring_copy_mbs_len_l(&entry->ae_pathname,
1200232153Smm	    name, len, sc));
1201232153Smm}
1202232153Smm
1203228753Smmvoid
1204228753Smmarchive_entry_set_perm(struct archive_entry *entry, mode_t p)
1205228753Smm{
1206228753Smm	entry->stat_valid = 0;
1207232153Smm	entry->acl.mode &= AE_IFMT;
1208232153Smm	entry->acl.mode |= ~AE_IFMT & p;
1209228753Smm}
1210228753Smm
1211228753Smmvoid
1212228753Smmarchive_entry_set_rdev(struct archive_entry *entry, dev_t m)
1213228753Smm{
1214228753Smm	entry->stat_valid = 0;
1215228753Smm	entry->ae_stat.aest_rdev = m;
1216228753Smm	entry->ae_stat.aest_rdev_is_broken_down = 0;
1217228753Smm}
1218228753Smm
1219228753Smmvoid
1220228753Smmarchive_entry_set_rdevmajor(struct archive_entry *entry, dev_t m)
1221228753Smm{
1222228753Smm	entry->stat_valid = 0;
1223228753Smm	entry->ae_stat.aest_rdev_is_broken_down = 1;
1224228753Smm	entry->ae_stat.aest_rdevmajor = m;
1225228753Smm}
1226228753Smm
1227228753Smmvoid
1228228753Smmarchive_entry_set_rdevminor(struct archive_entry *entry, dev_t m)
1229228753Smm{
1230228753Smm	entry->stat_valid = 0;
1231228753Smm	entry->ae_stat.aest_rdev_is_broken_down = 1;
1232228753Smm	entry->ae_stat.aest_rdevminor = m;
1233228753Smm}
1234228753Smm
1235228753Smmvoid
1236315433Smmarchive_entry_set_size(struct archive_entry *entry, la_int64_t s)
1237228753Smm{
1238228753Smm	entry->stat_valid = 0;
1239228753Smm	entry->ae_stat.aest_size = s;
1240228753Smm	entry->ae_set |= AE_SET_SIZE;
1241228753Smm}
1242228753Smm
1243228753Smmvoid
1244228753Smmarchive_entry_unset_size(struct archive_entry *entry)
1245228753Smm{
1246228753Smm	archive_entry_set_size(entry, 0);
1247228753Smm	entry->ae_set &= ~AE_SET_SIZE;
1248228753Smm}
1249228753Smm
1250228753Smmvoid
1251228753Smmarchive_entry_copy_sourcepath(struct archive_entry *entry, const char *path)
1252228753Smm{
1253232153Smm	archive_mstring_copy_mbs(&entry->ae_sourcepath, path);
1254228753Smm}
1255228753Smm
1256228753Smmvoid
1257232153Smmarchive_entry_copy_sourcepath_w(struct archive_entry *entry, const wchar_t *path)
1258232153Smm{
1259232153Smm	archive_mstring_copy_wcs(&entry->ae_sourcepath, path);
1260232153Smm}
1261232153Smm
1262232153Smmvoid
1263228753Smmarchive_entry_set_symlink(struct archive_entry *entry, const char *linkname)
1264228753Smm{
1265232153Smm	archive_mstring_copy_mbs(&entry->ae_symlink, linkname);
1266228753Smm	if (linkname != NULL)
1267228753Smm		entry->ae_set |= AE_SET_SYMLINK;
1268228753Smm	else
1269228753Smm		entry->ae_set &= ~AE_SET_SYMLINK;
1270228753Smm}
1271228753Smm
1272228753Smmvoid
1273348608Smmarchive_entry_set_symlink_type(struct archive_entry *entry, int type)
1274348608Smm{
1275348608Smm	entry->ae_symlink_type = type;
1276348608Smm}
1277348608Smm
1278348608Smmvoid
1279302001Smmarchive_entry_set_symlink_utf8(struct archive_entry *entry, const char *linkname)
1280302001Smm{
1281302001Smm	archive_mstring_copy_utf8(&entry->ae_symlink, linkname);
1282302001Smm	if (linkname != NULL)
1283302001Smm		entry->ae_set |= AE_SET_SYMLINK;
1284302001Smm	else
1285302001Smm		entry->ae_set &= ~AE_SET_SYMLINK;
1286302001Smm}
1287302001Smm
1288302001Smmvoid
1289228753Smmarchive_entry_copy_symlink(struct archive_entry *entry, const char *linkname)
1290228753Smm{
1291232153Smm	archive_mstring_copy_mbs(&entry->ae_symlink, linkname);
1292228753Smm	if (linkname != NULL)
1293228753Smm		entry->ae_set |= AE_SET_SYMLINK;
1294228753Smm	else
1295228753Smm		entry->ae_set &= ~AE_SET_SYMLINK;
1296228753Smm}
1297228753Smm
1298228753Smmvoid
1299228753Smmarchive_entry_copy_symlink_w(struct archive_entry *entry, const wchar_t *linkname)
1300228753Smm{
1301232153Smm	archive_mstring_copy_wcs(&entry->ae_symlink, linkname);
1302228753Smm	if (linkname != NULL)
1303228753Smm		entry->ae_set |= AE_SET_SYMLINK;
1304228753Smm	else
1305228753Smm		entry->ae_set &= ~AE_SET_SYMLINK;
1306228753Smm}
1307228753Smm
1308228753Smmint
1309228753Smmarchive_entry_update_symlink_utf8(struct archive_entry *entry, const char *linkname)
1310228753Smm{
1311228753Smm	if (linkname != NULL)
1312228753Smm		entry->ae_set |= AE_SET_SYMLINK;
1313228753Smm	else
1314228753Smm		entry->ae_set &= ~AE_SET_SYMLINK;
1315232153Smm	if (archive_mstring_update_utf8(entry->archive,
1316232153Smm	    &entry->ae_symlink, linkname) == 0)
1317232153Smm		return (1);
1318238856Smm	if (errno == ENOMEM)
1319238856Smm		__archive_errx(1, "No memory");
1320232153Smm	return (0);
1321228753Smm}
1322228753Smm
1323232153Smmint
1324232153Smm_archive_entry_copy_symlink_l(struct archive_entry *entry,
1325232153Smm    const char *linkname, size_t len, struct archive_string_conv *sc)
1326232153Smm{
1327232153Smm	int r;
1328232153Smm
1329232153Smm	r = archive_mstring_copy_mbs_len_l(&entry->ae_symlink,
1330232153Smm	    linkname, len, sc);
1331232153Smm	if (linkname != NULL && r == 0)
1332232153Smm		entry->ae_set |= AE_SET_SYMLINK;
1333232153Smm	else
1334232153Smm		entry->ae_set &= ~AE_SET_SYMLINK;
1335232153Smm	return (r);
1336232153Smm}
1337232153Smm
1338228753Smmvoid
1339315433Smmarchive_entry_set_uid(struct archive_entry *entry, la_int64_t u)
1340228753Smm{
1341228753Smm	entry->stat_valid = 0;
1342228753Smm	entry->ae_stat.aest_uid = u;
1343228753Smm}
1344228753Smm
1345228753Smmvoid
1346228753Smmarchive_entry_set_uname(struct archive_entry *entry, const char *name)
1347228753Smm{
1348232153Smm	archive_mstring_copy_mbs(&entry->ae_uname, name);
1349228753Smm}
1350228753Smm
1351228753Smmvoid
1352302001Smmarchive_entry_set_uname_utf8(struct archive_entry *entry, const char *name)
1353302001Smm{
1354302001Smm	archive_mstring_copy_utf8(&entry->ae_uname, name);
1355302001Smm}
1356302001Smm
1357302001Smmvoid
1358228753Smmarchive_entry_copy_uname(struct archive_entry *entry, const char *name)
1359228753Smm{
1360232153Smm	archive_mstring_copy_mbs(&entry->ae_uname, name);
1361228753Smm}
1362228753Smm
1363228753Smmvoid
1364228753Smmarchive_entry_copy_uname_w(struct archive_entry *entry, const wchar_t *name)
1365228753Smm{
1366232153Smm	archive_mstring_copy_wcs(&entry->ae_uname, name);
1367228753Smm}
1368228753Smm
1369228753Smmint
1370228753Smmarchive_entry_update_uname_utf8(struct archive_entry *entry, const char *name)
1371228753Smm{
1372232153Smm	if (archive_mstring_update_utf8(entry->archive,
1373232153Smm	    &entry->ae_uname, name) == 0)
1374232153Smm		return (1);
1375238856Smm	if (errno == ENOMEM)
1376238856Smm		__archive_errx(1, "No memory");
1377232153Smm	return (0);
1378228753Smm}
1379228753Smm
1380302001Smmvoid
1381302001Smmarchive_entry_set_is_data_encrypted(struct archive_entry *entry, char is_encrypted)
1382302001Smm{
1383302001Smm	if (is_encrypted) {
1384302001Smm		entry->encryption |= AE_ENCRYPTION_DATA;
1385302001Smm	} else {
1386302001Smm		entry->encryption &= ~AE_ENCRYPTION_DATA;
1387302001Smm	}
1388302001Smm}
1389302001Smm
1390302001Smmvoid
1391302001Smmarchive_entry_set_is_metadata_encrypted(struct archive_entry *entry, char is_encrypted)
1392302001Smm{
1393302001Smm	if (is_encrypted) {
1394302001Smm		entry->encryption |= AE_ENCRYPTION_METADATA;
1395302001Smm	} else {
1396302001Smm		entry->encryption &= ~AE_ENCRYPTION_METADATA;
1397302001Smm	}
1398302001Smm}
1399302001Smm
1400232153Smmint
1401232153Smm_archive_entry_copy_uname_l(struct archive_entry *entry,
1402232153Smm    const char *name, size_t len, struct archive_string_conv *sc)
1403232153Smm{
1404232153Smm	return (archive_mstring_copy_mbs_len_l(&entry->ae_uname,
1405232153Smm	    name, len, sc));
1406232153Smm}
1407232153Smm
1408232153Smmconst void *
1409232153Smmarchive_entry_mac_metadata(struct archive_entry *entry, size_t *s)
1410232153Smm{
1411232153Smm  *s = entry->mac_metadata_size;
1412232153Smm  return entry->mac_metadata;
1413232153Smm}
1414232153Smm
1415232153Smmvoid
1416232153Smmarchive_entry_copy_mac_metadata(struct archive_entry *entry,
1417232153Smm    const void *p, size_t s)
1418232153Smm{
1419232153Smm  free(entry->mac_metadata);
1420232153Smm  if (p == NULL || s == 0) {
1421232153Smm    entry->mac_metadata = NULL;
1422232153Smm    entry->mac_metadata_size = 0;
1423232153Smm  } else {
1424232153Smm    entry->mac_metadata_size = s;
1425232153Smm    entry->mac_metadata = malloc(s);
1426232153Smm    if (entry->mac_metadata == NULL)
1427232153Smm      abort();
1428232153Smm    memcpy(entry->mac_metadata, p, s);
1429232153Smm  }
1430232153Smm}
1431232153Smm
1432368708Smm/* Digest handling */
1433368708Smmconst unsigned char *
1434368708Smmarchive_entry_digest(struct archive_entry *entry, int type)
1435368708Smm{
1436368708Smm	switch (type) {
1437368708Smm	case ARCHIVE_ENTRY_DIGEST_MD5:
1438368708Smm		return entry->digest.md5;
1439368708Smm	case ARCHIVE_ENTRY_DIGEST_RMD160:
1440368708Smm		return entry->digest.rmd160;
1441368708Smm	case ARCHIVE_ENTRY_DIGEST_SHA1:
1442368708Smm		return entry->digest.sha1;
1443368708Smm	case ARCHIVE_ENTRY_DIGEST_SHA256:
1444368708Smm		return entry->digest.sha256;
1445368708Smm	case ARCHIVE_ENTRY_DIGEST_SHA384:
1446368708Smm		return entry->digest.sha384;
1447368708Smm	case ARCHIVE_ENTRY_DIGEST_SHA512:
1448368708Smm		return entry->digest.sha512;
1449368708Smm	default:
1450368708Smm		return NULL;
1451368708Smm	}
1452368708Smm}
1453368708Smm
1454368708Smmint
1455368708Smmarchive_entry_set_digest(struct archive_entry *entry, int type,
1456368708Smm    const unsigned char *digest)
1457368708Smm{
1458368708Smm#define copy_digest(_e, _t, _d)\
1459368708Smm	memcpy(_e->digest._t, _d, sizeof(_e->digest._t))
1460368708Smm
1461368708Smm	switch (type) {
1462368708Smm	case ARCHIVE_ENTRY_DIGEST_MD5:
1463368708Smm		copy_digest(entry, md5, digest);
1464368708Smm		break;
1465368708Smm	case ARCHIVE_ENTRY_DIGEST_RMD160:
1466368708Smm		copy_digest(entry, rmd160, digest);
1467368708Smm		break;
1468368708Smm	case ARCHIVE_ENTRY_DIGEST_SHA1:
1469368708Smm		copy_digest(entry, sha1, digest);
1470368708Smm		break;
1471368708Smm	case ARCHIVE_ENTRY_DIGEST_SHA256:
1472368708Smm		copy_digest(entry, sha256, digest);
1473368708Smm		break;
1474368708Smm	case ARCHIVE_ENTRY_DIGEST_SHA384:
1475368708Smm		copy_digest(entry, sha384, digest);
1476368708Smm		break;
1477368708Smm	case ARCHIVE_ENTRY_DIGEST_SHA512:
1478368708Smm		copy_digest(entry, sha512, digest);
1479368708Smm		break;
1480368708Smm	default:
1481368708Smm		return ARCHIVE_WARN;
1482368708Smm	}
1483368708Smm
1484368708Smm	return ARCHIVE_OK;
1485368708Smm#undef copy_digest
1486368708Smm}
1487368708Smm
1488228753Smm/*
1489228753Smm * ACL management.  The following would, of course, be a lot simpler
1490228753Smm * if: 1) the last draft of POSIX.1e were a really thorough and
1491228753Smm * complete standard that addressed the needs of ACL archiving and 2)
1492228753Smm * everyone followed it faithfully.  Alas, neither is true, so the
1493228753Smm * following is a lot more complex than might seem necessary to the
1494228753Smm * uninitiated.
1495228753Smm */
1496228753Smm
1497232153Smmstruct archive_acl *
1498232153Smmarchive_entry_acl(struct archive_entry *entry)
1499232153Smm{
1500232153Smm	return &entry->acl;
1501232153Smm}
1502232153Smm
1503228753Smmvoid
1504228753Smmarchive_entry_acl_clear(struct archive_entry *entry)
1505228753Smm{
1506232153Smm	archive_acl_clear(&entry->acl);
1507228753Smm}
1508228753Smm
1509228753Smm/*
1510228753Smm * Add a single ACL entry to the internal list of ACL data.
1511228753Smm */
1512232153Smmint
1513228753Smmarchive_entry_acl_add_entry(struct archive_entry *entry,
1514228753Smm    int type, int permset, int tag, int id, const char *name)
1515228753Smm{
1516232153Smm	return archive_acl_add_entry(&entry->acl, type, permset, tag, id, name);
1517228753Smm}
1518228753Smm
1519228753Smm/*
1520228753Smm * As above, but with a wide-character name.
1521228753Smm */
1522232153Smmint
1523228753Smmarchive_entry_acl_add_entry_w(struct archive_entry *entry,
1524228753Smm    int type, int permset, int tag, int id, const wchar_t *name)
1525228753Smm{
1526232153Smm	return archive_acl_add_entry_w_len(&entry->acl,
1527232153Smm	    type, permset, tag, id, name, wcslen(name));
1528228753Smm}
1529228753Smm
1530228753Smm/*
1531311042Smm * Return a bitmask of ACL types in an archive entry ACL list
1532311042Smm */
1533311042Smmint
1534311042Smmarchive_entry_acl_types(struct archive_entry *entry)
1535311042Smm{
1536313571Smm	return (archive_acl_types(&entry->acl));
1537311042Smm}
1538311042Smm
1539311042Smm/*
1540228753Smm * Return a count of entries matching "want_type".
1541228753Smm */
1542228753Smmint
1543228753Smmarchive_entry_acl_count(struct archive_entry *entry, int want_type)
1544228753Smm{
1545232153Smm	return archive_acl_count(&entry->acl, want_type);
1546228753Smm}
1547228753Smm
1548228753Smm/*
1549228753Smm * Prepare for reading entries from the ACL data.  Returns a count
1550228753Smm * of entries matching "want_type", or zero if there are no
1551228753Smm * non-extended ACL entries of that type.
1552228753Smm */
1553228753Smmint
1554228753Smmarchive_entry_acl_reset(struct archive_entry *entry, int want_type)
1555228753Smm{
1556232153Smm	return archive_acl_reset(&entry->acl, want_type);
1557228753Smm}
1558228753Smm
1559228753Smm/*
1560228753Smm * Return the next ACL entry in the list.  Fake entries for the
1561228753Smm * standard permissions and include them in the returned list.
1562228753Smm */
1563228753Smmint
1564228753Smmarchive_entry_acl_next(struct archive_entry *entry, int want_type, int *type,
1565228753Smm    int *permset, int *tag, int *id, const char **name)
1566228753Smm{
1567238856Smm	int r;
1568238856Smm	r = archive_acl_next(entry->archive, &entry->acl, want_type, type,
1569238856Smm		permset, tag, id, name);
1570238856Smm	if (r == ARCHIVE_FATAL && errno == ENOMEM)
1571238856Smm		__archive_errx(1, "No memory");
1572238856Smm	return (r);
1573228753Smm}
1574228753Smm
1575228753Smm/*
1576313571Smm * Generate a text version of the ACL. The flags parameter controls
1577228753Smm * the style of the generated ACL.
1578228753Smm */
1579313571Smmwchar_t *
1580337352Smmarchive_entry_acl_to_text_w(struct archive_entry *entry, la_ssize_t *len,
1581313571Smm    int flags)
1582313571Smm{
1583313571Smm	return (archive_acl_to_text_w(&entry->acl, len, flags,
1584313571Smm	    entry->archive));
1585313571Smm}
1586313571Smm
1587313571Smmchar *
1588337352Smmarchive_entry_acl_to_text(struct archive_entry *entry, la_ssize_t *len,
1589313571Smm    int flags)
1590313571Smm{
1591313571Smm	return (archive_acl_to_text_l(&entry->acl, len, flags, NULL));
1592313571Smm}
1593313571Smm
1594313571Smmchar *
1595313571Smm_archive_entry_acl_to_text_l(struct archive_entry *entry, ssize_t *len,
1596313571Smm   int flags, struct archive_string_conv *sc)
1597313571Smm{
1598313571Smm	return (archive_acl_to_text_l(&entry->acl, len, flags, sc));
1599313571Smm}
1600313571Smm
1601313571Smm/*
1602313571Smm * ACL text parser.
1603313571Smm */
1604313571Smmint
1605313571Smmarchive_entry_acl_from_text_w(struct archive_entry *entry,
1606313571Smm    const wchar_t *wtext, int type)
1607313571Smm{
1608313571Smm	return (archive_acl_from_text_w(&entry->acl, wtext, type));
1609313571Smm}
1610313571Smm
1611313571Smmint
1612313571Smmarchive_entry_acl_from_text(struct archive_entry *entry,
1613313571Smm    const char *text, int type)
1614313571Smm{
1615313571Smm	return (archive_acl_from_text_l(&entry->acl, text, type, NULL));
1616313571Smm}
1617313571Smm
1618313571Smmint
1619313571Smm_archive_entry_acl_from_text_l(struct archive_entry *entry, const char *text,
1620313571Smm    int type, struct archive_string_conv *sc)
1621313571Smm{
1622313571Smm	return (archive_acl_from_text_l(&entry->acl, text, type, sc));
1623313571Smm}
1624313571Smm
1625313571Smm/* Deprecated */
1626313571Smmstatic int
1627313571Smmarchive_entry_acl_text_compat(int *flags)
1628313571Smm{
1629313571Smm	if ((*flags & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) == 0)
1630313571Smm		return (1);
1631313571Smm
1632313571Smm	/* ABI compat with old ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID */
1633313571Smm	if ((*flags & OLD_ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID) != 0)
1634313571Smm		*flags |= ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID;
1635313571Smm
1636313571Smm	/* ABI compat with old ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT */
1637313571Smm	if ((*flags & OLD_ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT) != 0)
1638313571Smm		*flags |=  ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT;
1639313571Smm
1640313571Smm	*flags |= ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA;
1641313571Smm
1642313571Smm	return (0);
1643313571Smm}
1644313571Smm
1645313571Smm/* Deprecated */
1646228753Smmconst wchar_t *
1647228753Smmarchive_entry_acl_text_w(struct archive_entry *entry, int flags)
1648228753Smm{
1649344674Smm	free(entry->acl.acl_text_w);
1650344674Smm	entry->acl.acl_text_w = NULL;
1651313571Smm	if (archive_entry_acl_text_compat(&flags) == 0)
1652313571Smm		entry->acl.acl_text_w = archive_acl_to_text_w(&entry->acl,
1653313571Smm		    NULL, flags, entry->archive);
1654313571Smm	return (entry->acl.acl_text_w);
1655228753Smm}
1656228753Smm
1657313571Smm/* Deprecated */
1658232153Smmconst char *
1659232153Smmarchive_entry_acl_text(struct archive_entry *entry, int flags)
1660228753Smm{
1661344674Smm	free(entry->acl.acl_text);
1662344674Smm	entry->acl.acl_text = NULL;
1663313571Smm	if (archive_entry_acl_text_compat(&flags) == 0)
1664313571Smm		entry->acl.acl_text = archive_acl_to_text_l(&entry->acl, NULL,
1665313571Smm		    flags, NULL);
1666313571Smm
1667313571Smm	return (entry->acl.acl_text);
1668228753Smm}
1669228753Smm
1670313571Smm/* Deprecated */
1671228753Smmint
1672232153Smm_archive_entry_acl_text_l(struct archive_entry *entry, int flags,
1673232153Smm    const char **acl_text, size_t *len, struct archive_string_conv *sc)
1674228753Smm{
1675344674Smm	free(entry->acl.acl_text);
1676344674Smm	entry->acl.acl_text = NULL;
1677313571Smm
1678313571Smm	if (archive_entry_acl_text_compat(&flags) == 0)
1679313571Smm		entry->acl.acl_text = archive_acl_to_text_l(&entry->acl,
1680313571Smm		    (ssize_t *)len, flags, sc);
1681313571Smm
1682313571Smm	*acl_text = entry->acl.acl_text;
1683313571Smm
1684313571Smm	return (0);
1685228753Smm}
1686228753Smm
1687228753Smm/*
1688228753Smm * Following code is modified from UC Berkeley sources, and
1689228753Smm * is subject to the following copyright notice.
1690228753Smm */
1691228753Smm
1692228753Smm/*-
1693228753Smm * Copyright (c) 1993
1694228753Smm *	The Regents of the University of California.  All rights reserved.
1695228753Smm *
1696228753Smm * Redistribution and use in source and binary forms, with or without
1697228753Smm * modification, are permitted provided that the following conditions
1698228753Smm * are met:
1699228753Smm * 1. Redistributions of source code must retain the above copyright
1700228753Smm *    notice, this list of conditions and the following disclaimer.
1701228753Smm * 2. Redistributions in binary form must reproduce the above copyright
1702228753Smm *    notice, this list of conditions and the following disclaimer in the
1703228753Smm *    documentation and/or other materials provided with the distribution.
1704228753Smm * 4. Neither the name of the University nor the names of its contributors
1705228753Smm *    may be used to endorse or promote products derived from this software
1706228753Smm *    without specific prior written permission.
1707228753Smm *
1708228753Smm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
1709228753Smm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1710228753Smm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1711228753Smm * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
1712228753Smm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1713228753Smm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
1714228753Smm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
1715228753Smm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
1716228753Smm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
1717228753Smm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
1718228753Smm * SUCH DAMAGE.
1719228753Smm */
1720228753Smm
1721346105Smm/*
1722346105Smm * Supported file flags on FreeBSD and Mac OS:
1723346105Smm * sappnd,sappend		SF_APPEND
1724346105Smm * arch,archived		SF_ARCHIVED
1725346105Smm * schg,schange,simmutable	SF_IMMUTABLE
1726346105Smm * sunlnk,sunlink		SF_NOUNLINK	(FreeBSD only)
1727346105Smm * uappnd,uappend		UF_APPEND
1728346105Smm * compressed			UF_COMPRESSED	(Mac OS only)
1729346105Smm * hidden,uhidden		UF_HIDDEN
1730346105Smm * uchg,uchange,uimmutable	UF_IMMUTABLE
1731346105Smm * nodump			UF_NODUMP
1732346105Smm * uunlnk,uunlink		UF_NOUNLINK	(FreeBSD only)
1733346105Smm * offline,uoffline		UF_OFFLINE	(FreeBSD only)
1734346105Smm * opaque			UF_OPAQUE
1735346105Smm * rdonly,urdonly,readonly	UF_READONLY	(FreeBSD only)
1736346105Smm * reparse,ureparse		UF_REPARSE	(FreeBSD only)
1737346105Smm * sparse,usparse		UF_SPARSE	(FreeBSD only)
1738346105Smm * system,usystem		UF_SYSTEM	(FreeBSD only)
1739346105Smm *
1740346105Smm * See chflags(2) for more information
1741346105Smm *
1742346105Smm * Supported file attributes on Linux:
1743346105Smm * a	append only			FS_APPEND_FL		sappnd
1744346105Smm * A	no atime updates		FS_NOATIME_FL		atime
1745346105Smm * c	compress			FS_COMPR_FL		compress
1746346105Smm * C	no copy on write		FS_NOCOW_FL		cow
1747346105Smm * d	no dump				FS_NODUMP_FL		dump
1748346105Smm * D	synchronous directory updates	FS_DIRSYNC_FL		dirsync
1749346105Smm * i	immutable			FS_IMMUTABLE_FL		schg
1750346105Smm * j	data journalling		FS_JOURNAL_DATA_FL	journal
1751346105Smm * P	project hierarchy		FS_PROJINHERIT_FL	projinherit
1752346105Smm * s	secure deletion			FS_SECRM_FL		securedeletion
1753346105Smm * S	synchronous updates		FS_SYNC_FL		sync
1754346105Smm * t	no tail-merging			FS_NOTAIL_FL		tail
1755346105Smm * T	top of directory hierarchy	FS_TOPDIR_FL		topdir
1756346105Smm * u	undeletable			FS_UNRM_FL		undel
1757346105Smm *
1758346105Smm * See ioctl_iflags(2) for more information
1759346105Smm *
1760346105Smm * Equivalent file flags supported on FreeBSD / Mac OS and Linux:
1761346105Smm * SF_APPEND		FS_APPEND_FL		sappnd
1762346105Smm * SF_IMMUTABLE		FS_IMMUTABLE_FL		schg
1763346105Smm * UF_NODUMP		FS_NODUMP_FL		nodump
1764346105Smm */
1765346105Smm
1766316338Smmstatic const struct flag {
1767228753Smm	const char	*name;
1768228753Smm	const wchar_t	*wname;
1769228753Smm	unsigned long	 set;
1770228753Smm	unsigned long	 clear;
1771358090Smm} fileflags[] = {
1772228753Smm	/* Preferred (shorter) names per flag first, all prefixed by "no" */
1773228753Smm#ifdef SF_APPEND
1774346105Smm	{ "nosappnd",	L"nosappnd",		SF_APPEND,	0},
1775346105Smm	{ "nosappend",	L"nosappend",		SF_APPEND,	0},
1776228753Smm#endif
1777315433Smm#if defined(FS_APPEND_FL)			/* 'a' */
1778346105Smm	{ "nosappnd",	L"nosappnd",		FS_APPEND_FL,	0},
1779346105Smm	{ "nosappend",	L"nosappend",		FS_APPEND_FL,	0},
1780315433Smm#elif defined(EXT2_APPEND_FL)			/* 'a' */
1781346105Smm	{ "nosappnd",	L"nosappnd",		EXT2_APPEND_FL,	0},
1782346105Smm	{ "nosappend",	L"nosappend",		EXT2_APPEND_FL,	0},
1783228753Smm#endif
1784228753Smm#ifdef SF_ARCHIVED
1785346105Smm	{ "noarch",	L"noarch",		SF_ARCHIVED,	0},
1786346105Smm	{ "noarchived",	L"noarchived",       	SF_ARCHIVED,	0},
1787228753Smm#endif
1788228753Smm#ifdef SF_IMMUTABLE
1789346105Smm	{ "noschg",	L"noschg",		SF_IMMUTABLE,	0},
1790346105Smm	{ "noschange",	L"noschange",		SF_IMMUTABLE,	0},
1791346105Smm	{ "nosimmutable",	L"nosimmutable",	SF_IMMUTABLE,	0},
1792228753Smm#endif
1793315433Smm#if defined(FS_IMMUTABLE_FL)			/* 'i' */
1794346105Smm	{ "noschg",	L"noschg",		FS_IMMUTABLE_FL,	0},
1795346105Smm	{ "noschange",	L"noschange",		FS_IMMUTABLE_FL,	0},
1796346105Smm	{ "nosimmutable",	L"nosimmutable",	FS_IMMUTABLE_FL,	0},
1797315433Smm#elif defined(EXT2_IMMUTABLE_FL)		/* 'i' */
1798346105Smm	{ "noschg",	L"noschg",		EXT2_IMMUTABLE_FL,	0},
1799346105Smm	{ "noschange",	L"noschange",		EXT2_IMMUTABLE_FL,	0},
1800346105Smm	{ "nosimmutable",	L"nosimmutable",	EXT2_IMMUTABLE_FL,	0},
1801228753Smm#endif
1802228753Smm#ifdef SF_NOUNLINK
1803346105Smm	{ "nosunlnk",	L"nosunlnk",		SF_NOUNLINK,	0},
1804346105Smm	{ "nosunlink",	L"nosunlink",		SF_NOUNLINK,	0},
1805228753Smm#endif
1806228753Smm#ifdef UF_APPEND
1807346105Smm	{ "nouappnd",	L"nouappnd",		UF_APPEND,	0},
1808346105Smm	{ "nouappend",	L"nouappend",		UF_APPEND,	0},
1809228753Smm#endif
1810228753Smm#ifdef UF_IMMUTABLE
1811346105Smm	{ "nouchg",	L"nouchg",		UF_IMMUTABLE,	0},
1812346105Smm	{ "nouchange",	L"nouchange",		UF_IMMUTABLE,	0},
1813346105Smm	{ "nouimmutable",	L"nouimmutable",	UF_IMMUTABLE,	0},
1814228753Smm#endif
1815228753Smm#ifdef UF_NODUMP
1816228753Smm	{ "nodump",	L"nodump",		0,		UF_NODUMP},
1817228753Smm#endif
1818315433Smm#if defined(FS_NODUMP_FL)	/* 'd' */
1819315433Smm	{ "nodump",	L"nodump",		0,		FS_NODUMP_FL},
1820346105Smm#elif defined(EXT2_NODUMP_FL)
1821228753Smm	{ "nodump",	L"nodump",		0,		EXT2_NODUMP_FL},
1822228753Smm#endif
1823228753Smm#ifdef UF_OPAQUE
1824346105Smm	{ "noopaque",	L"noopaque",		UF_OPAQUE,	0},
1825228753Smm#endif
1826228753Smm#ifdef UF_NOUNLINK
1827346105Smm	{ "nouunlnk",	L"nouunlnk",		UF_NOUNLINK,	0},
1828346105Smm	{ "nouunlink",	L"nouunlink",		UF_NOUNLINK,	0},
1829228753Smm#endif
1830248616Smm#ifdef UF_COMPRESSED
1831346105Smm	/* Mac OS */
1832346105Smm	{ "nocompressed",	L"nocompressed",	UF_COMPRESSED,	0},
1833248616Smm#endif
1834316338Smm#ifdef UF_HIDDEN
1835346105Smm	{ "nohidden",	L"nohidden",		UF_HIDDEN,	0},
1836346105Smm	{ "nouhidden",	L"nouhidden",		UF_HIDDEN,	0},
1837316338Smm#endif
1838348608Smm#ifdef FILE_ATTRIBUTE_HIDDEN
1839348608Smm	{ "nohidden",	L"nohidden",	FILE_ATTRIBUTE_HIDDEN,	0},
1840348608Smm	{ "nouhidden",	L"nouhidden",	FILE_ATTRIBUTE_HIDDEN,	0},
1841348608Smm#endif
1842346105Smm#ifdef UF_OFFLINE
1843346105Smm	{ "nooffline",	L"nooffline",		UF_OFFLINE,	0},
1844346105Smm	{ "nouoffline",	L"nouoffline",		UF_OFFLINE,	0},
1845228753Smm#endif
1846346105Smm#ifdef UF_READONLY
1847346105Smm	{ "nordonly",	L"nordonly",		UF_READONLY,	0},
1848346105Smm	{ "nourdonly",	L"nourdonly",		UF_READONLY,	0},
1849346105Smm	{ "noreadonly",	L"noreadonly",		UF_READONLY,	0},
1850228753Smm#endif
1851348608Smm#ifdef FILE_ATTRIBUTE_READONLY
1852348608Smm	{ "nordonly",	L"nordonly",	FILE_ATTRIBUTE_READONLY,	0},
1853348608Smm	{ "nourdonly",	L"nourdonly",	FILE_ATTRIBUTE_READONLY,	0},
1854348608Smm	{ "noreadonly",	L"noreadonly",	FILE_ATTRIBUTE_READONLY,	0},
1855348608Smm#endif
1856346105Smm#ifdef UF_SPARSE
1857346105Smm	{ "nosparse",	L"nosparse",		UF_SPARSE,	0},
1858346105Smm	{ "nousparse",	L"nousparse",		UF_SPARSE,	0},
1859228753Smm#endif
1860346105Smm#ifdef UF_REPARSE
1861346105Smm	{ "noreparse",	L"noreparse",		UF_REPARSE,	0},
1862346105Smm	{ "noureparse",	L"noureparse",		UF_REPARSE,	0},
1863228753Smm#endif
1864346105Smm#ifdef UF_SYSTEM
1865346105Smm	{ "nosystem",	L"nosystem",		UF_SYSTEM,	0},
1866346105Smm	{ "nousystem",	L"nousystem",		UF_SYSTEM,	0},
1867228753Smm#endif
1868348608Smm#ifdef FILE_ATTRIBUTE_SYSTEM
1869348608Smm	{ "nosystem",	L"nosystem",	FILE_ATTRIBUTE_SYSTEM,	0},
1870348608Smm	{ "nousystem",	L"nousystem",	FILE_ATTRIBUTE_SYSTEM,	0},
1871348608Smm#endif
1872346105Smm#if defined(FS_UNRM_FL)		/* 'u' */
1873346105Smm	{ "noundel",	L"noundel",		FS_UNRM_FL,	0},
1874346105Smm#elif defined(EXT2_UNRM_FL)
1875346105Smm	{ "noundel",	L"noundel",		EXT2_UNRM_FL,	0},
1876346105Smm#endif
1877228753Smm
1878346105Smm#if defined(FS_COMPR_FL)	/* 'c' */
1879346105Smm	{ "nocompress",	L"nocompress",       	FS_COMPR_FL,	0},
1880346105Smm#elif defined(EXT2_COMPR_FL)
1881346105Smm	{ "nocompress",	L"nocompress",       	EXT2_COMPR_FL,	0},
1882228753Smm#endif
1883228753Smm
1884346105Smm#if defined(FS_NOATIME_FL)	/* 'A' */
1885346105Smm	{ "noatime",	L"noatime",		0,		FS_NOATIME_FL},
1886346105Smm#elif defined(EXT2_NOATIME_FL)
1887346105Smm	{ "noatime",	L"noatime",		0,		EXT2_NOATIME_FL},
1888315433Smm#endif
1889346105Smm#if defined(FS_DIRSYNC_FL)	/* 'D' */
1890346105Smm	{ "nodirsync",	L"nodirsync",		FS_DIRSYNC_FL,		0},
1891315433Smm#elif defined(EXT2_DIRSYNC_FL)
1892346105Smm	{ "nodirsync",	L"nodirsync",		EXT2_DIRSYNC_FL,	0},
1893228753Smm#endif
1894346105Smm#if defined(FS_JOURNAL_DATA_FL)	/* 'j' */
1895346105Smm	{ "nojournal-data",L"nojournal-data",	FS_JOURNAL_DATA_FL,	0},
1896346105Smm	{ "nojournal",	L"nojournal",		FS_JOURNAL_DATA_FL,	0},
1897315433Smm#elif defined(EXT3_JOURNAL_DATA_FL)
1898346105Smm	{ "nojournal-data",L"nojournal-data",	EXT3_JOURNAL_DATA_FL,	0},
1899346105Smm	{ "nojournal",	L"nojournal",		EXT3_JOURNAL_DATA_FL,	0},
1900228753Smm#endif
1901346105Smm#if defined(FS_SECRM_FL)	/* 's' */
1902346105Smm	{ "nosecdel",	L"nosecdel",		FS_SECRM_FL,		0},
1903346105Smm	{ "nosecuredeletion",L"nosecuredeletion",FS_SECRM_FL,		0},
1904315433Smm#elif defined(EXT2_SECRM_FL)
1905346105Smm	{ "nosecdel",	L"nosecdel",		EXT2_SECRM_FL,		0},
1906346105Smm	{ "nosecuredeletion",L"nosecuredeletion",EXT2_SECRM_FL,		0},
1907228753Smm#endif
1908346105Smm#if defined(FS_SYNC_FL)		/* 'S' */
1909346105Smm	{ "nosync",	L"nosync",		FS_SYNC_FL,		0},
1910315433Smm#elif defined(EXT2_SYNC_FL)
1911346105Smm	{ "nosync",	L"nosync",		EXT2_SYNC_FL,		0},
1912228753Smm#endif
1913346105Smm#if defined(FS_NOTAIL_FL)	/* 't' */
1914346105Smm	{ "notail",	L"notail",		0,		FS_NOTAIL_FL},
1915315433Smm#elif defined(EXT2_NOTAIL_FL)
1916346105Smm	{ "notail",	L"notail",		0,		EXT2_NOTAIL_FL},
1917228753Smm#endif
1918346105Smm#if defined(FS_TOPDIR_FL)	/* 'T' */
1919346105Smm	{ "notopdir",	L"notopdir",		FS_TOPDIR_FL,		0},
1920315433Smm#elif defined(EXT2_TOPDIR_FL)
1921346105Smm	{ "notopdir",	L"notopdir",		EXT2_TOPDIR_FL,		0},
1922228753Smm#endif
1923346105Smm#ifdef FS_NOCOW_FL	/* 'C' */
1924346105Smm	{ "nocow",	L"nocow",		0,	FS_NOCOW_FL},
1925315433Smm#endif
1926346105Smm#ifdef FS_PROJINHERIT_FL	/* 'P' */
1927346105Smm	{ "noprojinherit",L"noprojinherit",	FS_PROJINHERIT_FL,	0},
1928315433Smm#endif
1929346105Smm	{ NULL,		NULL,			0,		0}
1930228753Smm};
1931228753Smm
1932228753Smm/*
1933228753Smm * fflagstostr --
1934228753Smm *	Convert file flags to a comma-separated string.  If no flags
1935228753Smm *	are set, return the empty string.
1936228753Smm */
1937228753Smmstatic char *
1938228753Smmae_fflagstostr(unsigned long bitset, unsigned long bitclear)
1939228753Smm{
1940228753Smm	char *string, *dp;
1941228753Smm	const char *sp;
1942228753Smm	unsigned long bits;
1943316338Smm	const struct flag *flag;
1944228753Smm	size_t	length;
1945228753Smm
1946228753Smm	bits = bitset | bitclear;
1947228753Smm	length = 0;
1948358090Smm	for (flag = fileflags; flag->name != NULL; flag++)
1949228753Smm		if (bits & (flag->set | flag->clear)) {
1950228753Smm			length += strlen(flag->name) + 1;
1951228753Smm			bits &= ~(flag->set | flag->clear);
1952228753Smm		}
1953228753Smm
1954228753Smm	if (length == 0)
1955228753Smm		return (NULL);
1956228753Smm	string = (char *)malloc(length);
1957228753Smm	if (string == NULL)
1958228753Smm		return (NULL);
1959228753Smm
1960228753Smm	dp = string;
1961358090Smm	for (flag = fileflags; flag->name != NULL; flag++) {
1962228753Smm		if (bitset & flag->set || bitclear & flag->clear) {
1963228753Smm			sp = flag->name + 2;
1964228753Smm		} else if (bitset & flag->clear  ||  bitclear & flag->set) {
1965228753Smm			sp = flag->name;
1966228753Smm		} else
1967228753Smm			continue;
1968228753Smm		bitset &= ~(flag->set | flag->clear);
1969228753Smm		bitclear &= ~(flag->set | flag->clear);
1970228753Smm		if (dp > string)
1971228753Smm			*dp++ = ',';
1972228753Smm		while ((*dp++ = *sp++) != '\0')
1973228753Smm			;
1974228753Smm		dp--;
1975228753Smm	}
1976228753Smm
1977228753Smm	*dp = '\0';
1978228753Smm	return (string);
1979228753Smm}
1980228753Smm
1981228753Smm/*
1982228753Smm * strtofflags --
1983228753Smm *	Take string of arguments and return file flags.  This
1984228753Smm *	version works a little differently than strtofflags(3).
1985228753Smm *	In particular, it always tests every token, skipping any
1986228753Smm *	unrecognized tokens.  It returns a pointer to the first
1987228753Smm *	unrecognized token, or NULL if every token was recognized.
1988228753Smm *	This version is also const-correct and does not modify the
1989228753Smm *	provided string.
1990228753Smm */
1991228753Smmstatic const char *
1992228753Smmae_strtofflags(const char *s, unsigned long *setp, unsigned long *clrp)
1993228753Smm{
1994228753Smm	const char *start, *end;
1995316338Smm	const struct flag *flag;
1996228753Smm	unsigned long set, clear;
1997228753Smm	const char *failed;
1998228753Smm
1999228753Smm	set = clear = 0;
2000228753Smm	start = s;
2001228753Smm	failed = NULL;
2002228753Smm	/* Find start of first token. */
2003228753Smm	while (*start == '\t'  ||  *start == ' '  ||  *start == ',')
2004228753Smm		start++;
2005228753Smm	while (*start != '\0') {
2006302001Smm		size_t length;
2007228753Smm		/* Locate end of token. */
2008228753Smm		end = start;
2009228753Smm		while (*end != '\0'  &&  *end != '\t'  &&
2010228753Smm		    *end != ' '  &&  *end != ',')
2011228753Smm			end++;
2012302001Smm		length = end - start;
2013358090Smm		for (flag = fileflags; flag->name != NULL; flag++) {
2014302001Smm			size_t flag_length = strlen(flag->name);
2015302001Smm			if (length == flag_length
2016302001Smm			    && memcmp(start, flag->name, length) == 0) {
2017228753Smm				/* Matched "noXXXX", so reverse the sense. */
2018228753Smm				clear |= flag->set;
2019228753Smm				set |= flag->clear;
2020228753Smm				break;
2021302001Smm			} else if (length == flag_length - 2
2022302001Smm			    && memcmp(start, flag->name + 2, length) == 0) {
2023228753Smm				/* Matched "XXXX", so don't reverse. */
2024228753Smm				set |= flag->set;
2025228753Smm				clear |= flag->clear;
2026228753Smm				break;
2027228753Smm			}
2028228753Smm		}
2029228753Smm		/* Ignore unknown flag names. */
2030228753Smm		if (flag->name == NULL  &&  failed == NULL)
2031228753Smm			failed = start;
2032228753Smm
2033228753Smm		/* Find start of next token. */
2034228753Smm		start = end;
2035228753Smm		while (*start == '\t'  ||  *start == ' '  ||  *start == ',')
2036228753Smm			start++;
2037228753Smm
2038228753Smm	}
2039228753Smm
2040228753Smm	if (setp)
2041228753Smm		*setp = set;
2042228753Smm	if (clrp)
2043228753Smm		*clrp = clear;
2044228753Smm
2045228753Smm	/* Return location of first failure. */
2046228753Smm	return (failed);
2047228753Smm}
2048228753Smm
2049228753Smm/*
2050228753Smm * wcstofflags --
2051228753Smm *	Take string of arguments and return file flags.  This
2052228753Smm *	version works a little differently than strtofflags(3).
2053228753Smm *	In particular, it always tests every token, skipping any
2054228753Smm *	unrecognized tokens.  It returns a pointer to the first
2055228753Smm *	unrecognized token, or NULL if every token was recognized.
2056228753Smm *	This version is also const-correct and does not modify the
2057228753Smm *	provided string.
2058228753Smm */
2059228753Smmstatic const wchar_t *
2060228753Smmae_wcstofflags(const wchar_t *s, unsigned long *setp, unsigned long *clrp)
2061228753Smm{
2062228753Smm	const wchar_t *start, *end;
2063316338Smm	const struct flag *flag;
2064228753Smm	unsigned long set, clear;
2065228753Smm	const wchar_t *failed;
2066228753Smm
2067228753Smm	set = clear = 0;
2068228753Smm	start = s;
2069228753Smm	failed = NULL;
2070228753Smm	/* Find start of first token. */
2071228753Smm	while (*start == L'\t'  ||  *start == L' '  ||  *start == L',')
2072228753Smm		start++;
2073228753Smm	while (*start != L'\0') {
2074302001Smm		size_t length;
2075228753Smm		/* Locate end of token. */
2076228753Smm		end = start;
2077228753Smm		while (*end != L'\0'  &&  *end != L'\t'  &&
2078228753Smm		    *end != L' '  &&  *end != L',')
2079228753Smm			end++;
2080302001Smm		length = end - start;
2081358090Smm		for (flag = fileflags; flag->wname != NULL; flag++) {
2082302001Smm			size_t flag_length = wcslen(flag->wname);
2083302001Smm			if (length == flag_length
2084302001Smm			    && wmemcmp(start, flag->wname, length) == 0) {
2085228753Smm				/* Matched "noXXXX", so reverse the sense. */
2086228753Smm				clear |= flag->set;
2087228753Smm				set |= flag->clear;
2088228753Smm				break;
2089302001Smm			} else if (length == flag_length - 2
2090302001Smm			    && wmemcmp(start, flag->wname + 2, length) == 0) {
2091228753Smm				/* Matched "XXXX", so don't reverse. */
2092228753Smm				set |= flag->set;
2093228753Smm				clear |= flag->clear;
2094228753Smm				break;
2095228753Smm			}
2096228753Smm		}
2097228753Smm		/* Ignore unknown flag names. */
2098228753Smm		if (flag->wname == NULL  &&  failed == NULL)
2099228753Smm			failed = start;
2100228753Smm
2101228753Smm		/* Find start of next token. */
2102228753Smm		start = end;
2103228753Smm		while (*start == L'\t'  ||  *start == L' '  ||  *start == L',')
2104228753Smm			start++;
2105228753Smm
2106228753Smm	}
2107228753Smm
2108228753Smm	if (setp)
2109228753Smm		*setp = set;
2110228753Smm	if (clrp)
2111228753Smm		*clrp = clear;
2112228753Smm
2113228753Smm	/* Return location of first failure. */
2114228753Smm	return (failed);
2115228753Smm}
2116228753Smm
2117228753Smm
2118228753Smm#ifdef TEST
2119228753Smm#include <stdio.h>
2120228753Smmint
2121228753Smmmain(int argc, char **argv)
2122228753Smm{
2123228753Smm	struct archive_entry *entry = archive_entry_new();
2124228753Smm	unsigned long set, clear;
2125228753Smm	const wchar_t *remainder;
2126228753Smm
2127228753Smm	remainder = archive_entry_copy_fflags_text_w(entry, L"nosappnd dump archive,,,,,,,");
2128228753Smm	archive_entry_fflags(entry, &set, &clear);
2129228753Smm
2130228753Smm	wprintf(L"set=0x%lX clear=0x%lX remainder='%ls'\n", set, clear, remainder);
2131228753Smm
2132228753Smm	wprintf(L"new flags='%s'\n", archive_entry_fflags_text(entry));
2133228753Smm	return (0);
2134228753Smm}
2135228753Smm#endif
2136