archive_entry.c revision 316337
160484Sobrien/*-
2218822Sdim * Copyright (c) 2003-2007 Tim Kientzle
3218822Sdim * Copyright (c) 2016 Martin Matuska
460484Sobrien * All rights reserved.
560484Sobrien *
660484Sobrien * Redistribution and use in source and binary forms, with or without
7130561Sobrien * modification, are permitted provided that the following conditions
860484Sobrien * are met:
9130561Sobrien * 1. Redistributions of source code must retain the above copyright
10130561Sobrien *    notice, this list of conditions and the following disclaimer.
11130561Sobrien * 2. Redistributions in binary form must reproduce the above copyright
12130561Sobrien *    notice, this list of conditions and the following disclaimer in the
1360484Sobrien *    documentation and/or other materials provided with the distribution.
14130561Sobrien *
15130561Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
16130561Sobrien * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17130561Sobrien * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1860484Sobrien * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
19130561Sobrien * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20130561Sobrien * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21218822Sdim * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2260484Sobrien * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2360484Sobrien * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24218822Sdim * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2560484Sobrien */
26218822Sdim
2760484Sobrien#include "archive_platform.h"
28130561Sobrien__FBSDID("$FreeBSD: stable/11/contrib/libarchive/libarchive/archive_entry.c 316337 2017-03-31 20:16:24Z mm $");
29218822Sdim
3060484Sobrien#ifdef HAVE_SYS_STAT_H
31104834Sobrien#include <sys/stat.h>
32218822Sdim#endif
33218822Sdim#ifdef HAVE_SYS_TYPES_H
3460484Sobrien#include <sys/types.h>
3560484Sobrien#endif
3660484Sobrien#if MAJOR_IN_MKDEV
3760484Sobrien#include <sys/mkdev.h>
38218822Sdim#define HAVE_MAJOR
3960484Sobrien#elif MAJOR_IN_SYSMACROS
4060484Sobrien#include <sys/sysmacros.h>
4160484Sobrien#define HAVE_MAJOR
4260484Sobrien#endif
4360484Sobrien#ifdef HAVE_ERRNO_H
4460484Sobrien#include <errno.h>
4560484Sobrien#endif
4660484Sobrien#ifdef HAVE_LIMITS_H
47218822Sdim#include <limits.h>
48218822Sdim#endif
49218822Sdim#ifdef HAVE_LINUX_FS_H
50218822Sdim#include <linux/fs.h>	/* for Linux file flags */
51218822Sdim#endif
52218822Sdim/*
53218822Sdim * Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h.
54218822Sdim * As the include guards don't agree, the order of include is important.
55218822Sdim */
56218822Sdim#ifdef HAVE_LINUX_EXT2_FS_H
57218822Sdim#include <linux/ext2_fs.h>	/* for Linux file flags */
58218822Sdim#endif
59218822Sdim#if defined(HAVE_EXT2FS_EXT2_FS_H) && !defined(__CYGWIN__)
60218822Sdim#include <ext2fs/ext2_fs.h>	/* for Linux file flags */
61218822Sdim#endif
62218822Sdim#include <stddef.h>
63218822Sdim#include <stdio.h>
64218822Sdim#ifdef HAVE_STDLIB_H
65218822Sdim#include <stdlib.h>
66218822Sdim#endif
67218822Sdim#ifdef HAVE_STRING_H
68218822Sdim#include <string.h>
69218822Sdim#endif
70218822Sdim#ifdef HAVE_WCHAR_H
71218822Sdim#include <wchar.h>
72218822Sdim#endif
73218822Sdim
74218822Sdim#include "archive.h"
75218822Sdim#include "archive_acl_private.h"
76218822Sdim#include "archive_entry.h"
77218822Sdim#include "archive_entry_locale.h"
78218822Sdim#include "archive_private.h"
79218822Sdim#include "archive_entry_private.h"
80218822Sdim
81218822Sdim#if !defined(HAVE_MAJOR) && !defined(major)
82218822Sdim/* Replacement for major/minor/makedev. */
83218822Sdim#define	major(x) ((int)(0x00ff & ((x) >> 8)))
84218822Sdim#define	minor(x) ((int)(0xffff00ff & (x)))
85218822Sdim#define	makedev(maj,min) ((0xff00 & ((maj)<<8)) | (0xffff00ff & (min)))
86218822Sdim#endif
87218822Sdim
88218822Sdim/* Play games to come up with a suitable makedev() definition. */
89218822Sdim#ifdef __QNXNTO__
90218822Sdim/* QNX.  <sigh> */
91218822Sdim#include <sys/netmgr.h>
92218822Sdim#define ae_makedev(maj, min) makedev(ND_LOCAL_NODE, (maj), (min))
93218822Sdim#elif defined makedev
94218822Sdim/* There's a "makedev" macro. */
95218822Sdim#define ae_makedev(maj, min) makedev((maj), (min))
96218822Sdim#elif defined mkdev || ((defined _WIN32 || defined __WIN32__) && !defined(__CYGWIN__))
97218822Sdim/* Windows. <sigh> */
98218822Sdim#define ae_makedev(maj, min) mkdev((maj), (min))
99218822Sdim#else
100218822Sdim/* There's a "makedev" function. */
101218822Sdim#define ae_makedev(maj, min) makedev((maj), (min))
102218822Sdim#endif
103218822Sdim
104218822Sdim/*
105218822Sdim * This adjustment is needed to support the following idiom for adding
106218822Sdim * 1000ns to the stored time:
107218822Sdim * archive_entry_set_atime(archive_entry_atime(),
108218822Sdim *                         archive_entry_atime_nsec() + 1000)
109218822Sdim * The additional if() here compensates for ambiguity in the C standard,
110218822Sdim * which permits two possible interpretations of a % b when a is negative.
111218822Sdim */
112218822Sdim#define FIX_NS(t,ns) \
113218822Sdim	do {	\
114218822Sdim		t += ns / 1000000000; \
115218822Sdim		ns %= 1000000000; \
116218822Sdim		if (ns < 0) { --t; ns += 1000000000; } \
117218822Sdim	} while (0)
118218822Sdim
119218822Sdimstatic char *	 ae_fflagstostr(unsigned long bitset, unsigned long bitclear);
120218822Sdimstatic const wchar_t	*ae_wcstofflags(const wchar_t *stringp,
121218822Sdim		    unsigned long *setp, unsigned long *clrp);
122218822Sdimstatic const char	*ae_strtofflags(const char *stringp,
123218822Sdim		    unsigned long *setp, unsigned long *clrp);
124218822Sdim
125218822Sdim#ifndef HAVE_WCSCPY
126218822Sdimstatic wchar_t * wcscpy(wchar_t *s1, const wchar_t *s2)
127218822Sdim{
128218822Sdim	wchar_t *dest = s1;
129218822Sdim	while ((*s1 = *s2) != L'\0')
130218822Sdim		++s1, ++s2;
131218822Sdim	return dest;
132218822Sdim}
133218822Sdim#endif
134218822Sdim#ifndef HAVE_WCSLEN
135218822Sdimstatic size_t wcslen(const wchar_t *s)
136218822Sdim{
137218822Sdim	const wchar_t *p = s;
138218822Sdim	while (*p != L'\0')
139218822Sdim		++p;
140218822Sdim	return p - s;
141218822Sdim}
142218822Sdim#endif
143218822Sdim#ifndef HAVE_WMEMCMP
144218822Sdim/* Good enough for simple equality testing, but not for sorting. */
145218822Sdim#define wmemcmp(a,b,i)  memcmp((a), (b), (i) * sizeof(wchar_t))
146218822Sdim#endif
147218822Sdim
148218822Sdim/****************************************************************************
149218822Sdim *
150218822Sdim * Public Interface
151218822Sdim *
152218822Sdim ****************************************************************************/
153218822Sdim
154218822Sdimstruct archive_entry *
155218822Sdimarchive_entry_clear(struct archive_entry *entry)
156218822Sdim{
157218822Sdim	if (entry == NULL)
158218822Sdim		return (NULL);
159218822Sdim	archive_mstring_clean(&entry->ae_fflags_text);
160218822Sdim	archive_mstring_clean(&entry->ae_gname);
161218822Sdim	archive_mstring_clean(&entry->ae_hardlink);
162218822Sdim	archive_mstring_clean(&entry->ae_pathname);
163218822Sdim	archive_mstring_clean(&entry->ae_sourcepath);
164218822Sdim	archive_mstring_clean(&entry->ae_symlink);
165218822Sdim	archive_mstring_clean(&entry->ae_uname);
166218822Sdim	archive_entry_copy_mac_metadata(entry, NULL, 0);
167218822Sdim	archive_acl_clear(&entry->acl);
168218822Sdim	archive_entry_xattr_clear(entry);
169218822Sdim	archive_entry_sparse_clear(entry);
170218822Sdim	free(entry->stat);
171218822Sdim	memset(entry, 0, sizeof(*entry));
172218822Sdim	return entry;
173218822Sdim}
174218822Sdim
175218822Sdimstruct archive_entry *
176218822Sdimarchive_entry_clone(struct archive_entry *entry)
177218822Sdim{
178218822Sdim	struct archive_entry *entry2;
179218822Sdim	struct ae_xattr *xp;
180218822Sdim	struct ae_sparse *sp;
181218822Sdim	size_t s;
182218822Sdim	const void *p;
183218822Sdim
184218822Sdim	/* Allocate new structure and copy over all of the fields. */
185218822Sdim	/* TODO: Should we copy the archive over?  Or require a new archive
186218822Sdim	 * as an argument? */
187218822Sdim	entry2 = archive_entry_new2(entry->archive);
188218822Sdim	if (entry2 == NULL)
189218822Sdim		return (NULL);
190218822Sdim	entry2->ae_stat = entry->ae_stat;
191218822Sdim	entry2->ae_fflags_set = entry->ae_fflags_set;
192218822Sdim	entry2->ae_fflags_clear = entry->ae_fflags_clear;
193218822Sdim
194218822Sdim	/* TODO: XXX If clone can have a different archive, what do we do here if
195218822Sdim	 * character sets are different? XXX */
196218822Sdim	archive_mstring_copy(&entry2->ae_fflags_text, &entry->ae_fflags_text);
197218822Sdim	archive_mstring_copy(&entry2->ae_gname, &entry->ae_gname);
198218822Sdim	archive_mstring_copy(&entry2->ae_hardlink, &entry->ae_hardlink);
199218822Sdim	archive_mstring_copy(&entry2->ae_pathname, &entry->ae_pathname);
200218822Sdim	archive_mstring_copy(&entry2->ae_sourcepath, &entry->ae_sourcepath);
201218822Sdim	archive_mstring_copy(&entry2->ae_symlink, &entry->ae_symlink);
202218822Sdim	entry2->ae_set = entry->ae_set;
203218822Sdim	archive_mstring_copy(&entry2->ae_uname, &entry->ae_uname);
204218822Sdim
205218822Sdim	/* Copy encryption status */
206218822Sdim	entry2->encryption = entry->encryption;
207218822Sdim
208218822Sdim	/* Copy ACL data over. */
209218822Sdim	archive_acl_copy(&entry2->acl, &entry->acl);
210218822Sdim
211218822Sdim	/* Copy Mac OS metadata. */
212218822Sdim	p = archive_entry_mac_metadata(entry, &s);
213218822Sdim	archive_entry_copy_mac_metadata(entry2, p, s);
214218822Sdim
215218822Sdim	/* Copy xattr data over. */
216218822Sdim	xp = entry->xattr_head;
217218822Sdim	while (xp != NULL) {
218218822Sdim		archive_entry_xattr_add_entry(entry2,
219218822Sdim		    xp->name, xp->value, xp->size);
220218822Sdim		xp = xp->next;
221218822Sdim	}
222218822Sdim
223218822Sdim	/* Copy sparse data over. */
224218822Sdim	sp = entry->sparse_head;
225218822Sdim	while (sp != NULL) {
226218822Sdim		archive_entry_sparse_add_entry(entry2,
227218822Sdim		    sp->offset, sp->length);
228218822Sdim		sp = sp->next;
229218822Sdim	}
230218822Sdim
231218822Sdim	return (entry2);
232218822Sdim}
233218822Sdim
234218822Sdimvoid
235218822Sdimarchive_entry_free(struct archive_entry *entry)
236218822Sdim{
237218822Sdim	archive_entry_clear(entry);
238218822Sdim	free(entry);
239218822Sdim}
240218822Sdim
241218822Sdimstruct archive_entry *
242218822Sdimarchive_entry_new(void)
243218822Sdim{
244218822Sdim	return archive_entry_new2(NULL);
245218822Sdim}
246218822Sdim
247218822Sdimstruct archive_entry *
248218822Sdimarchive_entry_new2(struct archive *a)
249218822Sdim{
250218822Sdim	struct archive_entry *entry;
251218822Sdim
252218822Sdim	entry = (struct archive_entry *)calloc(1, sizeof(*entry));
253218822Sdim	if (entry == NULL)
254218822Sdim		return (NULL);
255218822Sdim	entry->archive = a;
256218822Sdim	return (entry);
257218822Sdim}
258218822Sdim
259218822Sdim/*
260218822Sdim * Functions for reading fields from an archive_entry.
261218822Sdim */
262218822Sdim
263218822Sdimtime_t
264218822Sdimarchive_entry_atime(struct archive_entry *entry)
265218822Sdim{
266218822Sdim	return (entry->ae_stat.aest_atime);
267218822Sdim}
268218822Sdim
269218822Sdimlong
270218822Sdimarchive_entry_atime_nsec(struct archive_entry *entry)
271218822Sdim{
272218822Sdim	return (entry->ae_stat.aest_atime_nsec);
273218822Sdim}
274218822Sdim
275218822Sdimint
276218822Sdimarchive_entry_atime_is_set(struct archive_entry *entry)
277218822Sdim{
278218822Sdim	return (entry->ae_set & AE_SET_ATIME);
279218822Sdim}
280218822Sdim
281218822Sdimtime_t
282218822Sdimarchive_entry_birthtime(struct archive_entry *entry)
283218822Sdim{
284218822Sdim	return (entry->ae_stat.aest_birthtime);
285218822Sdim}
286218822Sdim
287218822Sdimlong
288218822Sdimarchive_entry_birthtime_nsec(struct archive_entry *entry)
289218822Sdim{
290218822Sdim	return (entry->ae_stat.aest_birthtime_nsec);
291218822Sdim}
292218822Sdim
293218822Sdimint
294218822Sdimarchive_entry_birthtime_is_set(struct archive_entry *entry)
295218822Sdim{
296218822Sdim	return (entry->ae_set & AE_SET_BIRTHTIME);
297218822Sdim}
298218822Sdim
299218822Sdimtime_t
300218822Sdimarchive_entry_ctime(struct archive_entry *entry)
301218822Sdim{
302218822Sdim	return (entry->ae_stat.aest_ctime);
303218822Sdim}
304218822Sdim
305218822Sdimint
306218822Sdimarchive_entry_ctime_is_set(struct archive_entry *entry)
307218822Sdim{
308218822Sdim	return (entry->ae_set & AE_SET_CTIME);
309218822Sdim}
310218822Sdim
311218822Sdimlong
312218822Sdimarchive_entry_ctime_nsec(struct archive_entry *entry)
313218822Sdim{
314218822Sdim	return (entry->ae_stat.aest_ctime_nsec);
315218822Sdim}
316218822Sdim
317218822Sdimdev_t
318218822Sdimarchive_entry_dev(struct archive_entry *entry)
319218822Sdim{
320218822Sdim	if (entry->ae_stat.aest_dev_is_broken_down)
321218822Sdim		return ae_makedev(entry->ae_stat.aest_devmajor,
322218822Sdim		    entry->ae_stat.aest_devminor);
323218822Sdim	else
324218822Sdim		return (entry->ae_stat.aest_dev);
325218822Sdim}
326218822Sdim
327218822Sdimint
328218822Sdimarchive_entry_dev_is_set(struct archive_entry *entry)
329218822Sdim{
330218822Sdim	return (entry->ae_set & AE_SET_DEV);
331218822Sdim}
332218822Sdim
333218822Sdimdev_t
334218822Sdimarchive_entry_devmajor(struct archive_entry *entry)
335218822Sdim{
336218822Sdim	if (entry->ae_stat.aest_dev_is_broken_down)
337218822Sdim		return (entry->ae_stat.aest_devmajor);
338218822Sdim	else
339218822Sdim		return major(entry->ae_stat.aest_dev);
340218822Sdim}
341218822Sdim
342218822Sdimdev_t
343218822Sdimarchive_entry_devminor(struct archive_entry *entry)
344218822Sdim{
345218822Sdim	if (entry->ae_stat.aest_dev_is_broken_down)
346218822Sdim		return (entry->ae_stat.aest_devminor);
347218822Sdim	else
348218822Sdim		return minor(entry->ae_stat.aest_dev);
349218822Sdim}
350218822Sdim
351218822Sdimmode_t
352218822Sdimarchive_entry_filetype(struct archive_entry *entry)
353218822Sdim{
354218822Sdim	return (AE_IFMT & entry->acl.mode);
355218822Sdim}
356218822Sdim
357218822Sdimvoid
358218822Sdimarchive_entry_fflags(struct archive_entry *entry,
359218822Sdim    unsigned long *set, unsigned long *clear)
360218822Sdim{
361218822Sdim	*set = entry->ae_fflags_set;
362218822Sdim	*clear = entry->ae_fflags_clear;
363218822Sdim}
364218822Sdim
365218822Sdim/*
366218822Sdim * Note: if text was provided, this just returns that text.  If you
367218822Sdim * really need the text to be rebuilt in a canonical form, set the
368218822Sdim * text, ask for the bitmaps, then set the bitmaps.  (Setting the
369218822Sdim * bitmaps clears any stored text.)  This design is deliberate: if
370218822Sdim * we're editing archives, we don't want to discard flags just because
371218822Sdim * they aren't supported on the current system.  The bitmap<->text
372218822Sdim * conversions are platform-specific (see below).
373218822Sdim */
374218822Sdimconst char *
375218822Sdimarchive_entry_fflags_text(struct archive_entry *entry)
376218822Sdim{
377218822Sdim	const char *f;
378218822Sdim	char *p;
379218822Sdim
380218822Sdim	if (archive_mstring_get_mbs(entry->archive,
381218822Sdim	    &entry->ae_fflags_text, &f) == 0) {
382218822Sdim		if (f != NULL)
383218822Sdim			return (f);
384218822Sdim	} else if (errno == ENOMEM)
385218822Sdim		__archive_errx(1, "No memory");
386218822Sdim
387218822Sdim	if (entry->ae_fflags_set == 0  &&  entry->ae_fflags_clear == 0)
388218822Sdim		return (NULL);
389218822Sdim
390218822Sdim	p = ae_fflagstostr(entry->ae_fflags_set, entry->ae_fflags_clear);
391218822Sdim	if (p == NULL)
392218822Sdim		return (NULL);
393218822Sdim
394218822Sdim	archive_mstring_copy_mbs(&entry->ae_fflags_text, p);
395218822Sdim	free(p);
396218822Sdim	if (archive_mstring_get_mbs(entry->archive,
397218822Sdim	    &entry->ae_fflags_text, &f) == 0)
398218822Sdim		return (f);
399218822Sdim	if (errno == ENOMEM)
400218822Sdim		__archive_errx(1, "No memory");
401218822Sdim	return (NULL);
402218822Sdim}
403218822Sdim
404218822Sdimla_int64_t
405218822Sdimarchive_entry_gid(struct archive_entry *entry)
406218822Sdim{
407218822Sdim	return (entry->ae_stat.aest_gid);
408218822Sdim}
409218822Sdim
410218822Sdimconst char *
411218822Sdimarchive_entry_gname(struct archive_entry *entry)
412218822Sdim{
413218822Sdim	const char *p;
414218822Sdim	if (archive_mstring_get_mbs(entry->archive, &entry->ae_gname, &p) == 0)
415218822Sdim		return (p);
416218822Sdim	if (errno == ENOMEM)
417218822Sdim		__archive_errx(1, "No memory");
418218822Sdim	return (NULL);
419218822Sdim}
420218822Sdim
421218822Sdimconst char *
422218822Sdimarchive_entry_gname_utf8(struct archive_entry *entry)
423218822Sdim{
424218822Sdim	const char *p;
425218822Sdim	if (archive_mstring_get_utf8(entry->archive, &entry->ae_gname, &p) == 0)
426218822Sdim		return (p);
427218822Sdim	if (errno == ENOMEM)
428218822Sdim		__archive_errx(1, "No memory");
429218822Sdim	return (NULL);
430218822Sdim}
431218822Sdim
432218822Sdim
433218822Sdimconst wchar_t *
434218822Sdimarchive_entry_gname_w(struct archive_entry *entry)
435218822Sdim{
436218822Sdim	const wchar_t *p;
437218822Sdim	if (archive_mstring_get_wcs(entry->archive, &entry->ae_gname, &p) == 0)
438218822Sdim		return (p);
439218822Sdim	if (errno == ENOMEM)
440218822Sdim		__archive_errx(1, "No memory");
441218822Sdim	return (NULL);
442218822Sdim}
443218822Sdim
444218822Sdimint
445218822Sdim_archive_entry_gname_l(struct archive_entry *entry,
446218822Sdim    const char **p, size_t *len, struct archive_string_conv *sc)
447218822Sdim{
448218822Sdim	return (archive_mstring_get_mbs_l(&entry->ae_gname, p, len, sc));
449218822Sdim}
450218822Sdim
451218822Sdimconst char *
452218822Sdimarchive_entry_hardlink(struct archive_entry *entry)
453218822Sdim{
454218822Sdim	const char *p;
455218822Sdim	if ((entry->ae_set & AE_SET_HARDLINK) == 0)
456218822Sdim		return (NULL);
457218822Sdim	if (archive_mstring_get_mbs(
458218822Sdim	    entry->archive, &entry->ae_hardlink, &p) == 0)
459218822Sdim		return (p);
460218822Sdim	if (errno == ENOMEM)
461218822Sdim		__archive_errx(1, "No memory");
462218822Sdim	return (NULL);
463218822Sdim}
464218822Sdim
465218822Sdimconst char *
466218822Sdimarchive_entry_hardlink_utf8(struct archive_entry *entry)
467218822Sdim{
468218822Sdim	const char *p;
469218822Sdim	if ((entry->ae_set & AE_SET_HARDLINK) == 0)
470218822Sdim		return (NULL);
471218822Sdim	if (archive_mstring_get_utf8(
472218822Sdim	    entry->archive, &entry->ae_hardlink, &p) == 0)
473218822Sdim		return (p);
474218822Sdim	if (errno == ENOMEM)
475218822Sdim		__archive_errx(1, "No memory");
476218822Sdim	return (NULL);
477218822Sdim}
478218822Sdim
479218822Sdimconst wchar_t *
480218822Sdimarchive_entry_hardlink_w(struct archive_entry *entry)
481218822Sdim{
482218822Sdim	const wchar_t *p;
483218822Sdim	if ((entry->ae_set & AE_SET_HARDLINK) == 0)
484218822Sdim		return (NULL);
485218822Sdim	if (archive_mstring_get_wcs(
486218822Sdim	    entry->archive, &entry->ae_hardlink, &p) == 0)
487218822Sdim		return (p);
488218822Sdim	if (errno == ENOMEM)
489218822Sdim		__archive_errx(1, "No memory");
490218822Sdim	return (NULL);
491218822Sdim}
492218822Sdim
493218822Sdimint
494218822Sdim_archive_entry_hardlink_l(struct archive_entry *entry,
495218822Sdim    const char **p, size_t *len, struct archive_string_conv *sc)
496218822Sdim{
497218822Sdim	if ((entry->ae_set & AE_SET_HARDLINK) == 0) {
498218822Sdim		*p = NULL;
499218822Sdim		*len = 0;
500218822Sdim		return (0);
501218822Sdim	}
502218822Sdim	return (archive_mstring_get_mbs_l(&entry->ae_hardlink, p, len, sc));
503218822Sdim}
504218822Sdim
505218822Sdimla_int64_t
506218822Sdimarchive_entry_ino(struct archive_entry *entry)
507218822Sdim{
508218822Sdim	return (entry->ae_stat.aest_ino);
509218822Sdim}
510218822Sdim
511218822Sdimint
512218822Sdimarchive_entry_ino_is_set(struct archive_entry *entry)
513218822Sdim{
514218822Sdim	return (entry->ae_set & AE_SET_INO);
515218822Sdim}
516218822Sdim
517218822Sdimla_int64_t
518218822Sdimarchive_entry_ino64(struct archive_entry *entry)
519218822Sdim{
520218822Sdim	return (entry->ae_stat.aest_ino);
521218822Sdim}
522218822Sdim
523218822Sdimmode_t
524218822Sdimarchive_entry_mode(struct archive_entry *entry)
525218822Sdim{
526218822Sdim	return (entry->acl.mode);
527218822Sdim}
528218822Sdim
529218822Sdimtime_t
530218822Sdimarchive_entry_mtime(struct archive_entry *entry)
531218822Sdim{
532218822Sdim	return (entry->ae_stat.aest_mtime);
533218822Sdim}
534218822Sdim
535218822Sdimlong
536218822Sdimarchive_entry_mtime_nsec(struct archive_entry *entry)
537218822Sdim{
538218822Sdim	return (entry->ae_stat.aest_mtime_nsec);
539218822Sdim}
540218822Sdim
541218822Sdimint
542218822Sdimarchive_entry_mtime_is_set(struct archive_entry *entry)
543218822Sdim{
544218822Sdim	return (entry->ae_set & AE_SET_MTIME);
545218822Sdim}
546218822Sdim
547218822Sdimunsigned int
548218822Sdimarchive_entry_nlink(struct archive_entry *entry)
549218822Sdim{
550218822Sdim	return (entry->ae_stat.aest_nlink);
551218822Sdim}
552218822Sdim
553218822Sdimconst char *
554218822Sdimarchive_entry_pathname(struct archive_entry *entry)
555218822Sdim{
556218822Sdim	const char *p;
557218822Sdim	if (archive_mstring_get_mbs(
558218822Sdim	    entry->archive, &entry->ae_pathname, &p) == 0)
559218822Sdim		return (p);
560218822Sdim	if (errno == ENOMEM)
561218822Sdim		__archive_errx(1, "No memory");
562218822Sdim	return (NULL);
563218822Sdim}
564218822Sdim
565218822Sdimconst char *
566218822Sdimarchive_entry_pathname_utf8(struct archive_entry *entry)
567218822Sdim{
568218822Sdim	const char *p;
569218822Sdim	if (archive_mstring_get_utf8(
570218822Sdim	    entry->archive, &entry->ae_pathname, &p) == 0)
571218822Sdim		return (p);
572218822Sdim	if (errno == ENOMEM)
573218822Sdim		__archive_errx(1, "No memory");
574218822Sdim	return (NULL);
575218822Sdim}
576218822Sdim
577218822Sdimconst wchar_t *
578218822Sdimarchive_entry_pathname_w(struct archive_entry *entry)
579218822Sdim{
580218822Sdim	const wchar_t *p;
581218822Sdim	if (archive_mstring_get_wcs(
582218822Sdim	    entry->archive, &entry->ae_pathname, &p) == 0)
583218822Sdim		return (p);
584218822Sdim	if (errno == ENOMEM)
585218822Sdim		__archive_errx(1, "No memory");
586218822Sdim	return (NULL);
587218822Sdim}
588218822Sdim
589218822Sdimint
590218822Sdim_archive_entry_pathname_l(struct archive_entry *entry,
591218822Sdim    const char **p, size_t *len, struct archive_string_conv *sc)
592218822Sdim{
593218822Sdim	return (archive_mstring_get_mbs_l(&entry->ae_pathname, p, len, sc));
594218822Sdim}
595218822Sdim
596218822Sdimmode_t
597218822Sdimarchive_entry_perm(struct archive_entry *entry)
598218822Sdim{
599218822Sdim	return (~AE_IFMT & entry->acl.mode);
600218822Sdim}
601218822Sdim
602218822Sdimdev_t
603218822Sdimarchive_entry_rdev(struct archive_entry *entry)
604218822Sdim{
605218822Sdim	if (entry->ae_stat.aest_rdev_is_broken_down)
606218822Sdim		return ae_makedev(entry->ae_stat.aest_rdevmajor,
607218822Sdim		    entry->ae_stat.aest_rdevminor);
608218822Sdim	else
609218822Sdim		return (entry->ae_stat.aest_rdev);
610218822Sdim}
611218822Sdim
612218822Sdimdev_t
613218822Sdimarchive_entry_rdevmajor(struct archive_entry *entry)
614218822Sdim{
615218822Sdim	if (entry->ae_stat.aest_rdev_is_broken_down)
616218822Sdim		return (entry->ae_stat.aest_rdevmajor);
617218822Sdim	else
618218822Sdim		return major(entry->ae_stat.aest_rdev);
619218822Sdim}
620218822Sdim
621218822Sdimdev_t
622218822Sdimarchive_entry_rdevminor(struct archive_entry *entry)
623218822Sdim{
624218822Sdim	if (entry->ae_stat.aest_rdev_is_broken_down)
625218822Sdim		return (entry->ae_stat.aest_rdevminor);
626218822Sdim	else
627218822Sdim		return minor(entry->ae_stat.aest_rdev);
628218822Sdim}
629218822Sdim
630218822Sdimla_int64_t
631218822Sdimarchive_entry_size(struct archive_entry *entry)
632218822Sdim{
633218822Sdim	return (entry->ae_stat.aest_size);
634218822Sdim}
635218822Sdim
636218822Sdimint
637218822Sdimarchive_entry_size_is_set(struct archive_entry *entry)
638218822Sdim{
639218822Sdim	return (entry->ae_set & AE_SET_SIZE);
640218822Sdim}
641218822Sdim
642218822Sdimconst char *
643218822Sdimarchive_entry_sourcepath(struct archive_entry *entry)
644218822Sdim{
645218822Sdim	const char *p;
646218822Sdim	if (archive_mstring_get_mbs(
647218822Sdim	    entry->archive, &entry->ae_sourcepath, &p) == 0)
648218822Sdim		return (p);
649218822Sdim	if (errno == ENOMEM)
650218822Sdim		__archive_errx(1, "No memory");
651218822Sdim	return (NULL);
652218822Sdim}
653218822Sdim
654218822Sdimconst wchar_t *
655218822Sdimarchive_entry_sourcepath_w(struct archive_entry *entry)
656218822Sdim{
657218822Sdim	const wchar_t *p;
658218822Sdim	if (archive_mstring_get_wcs(
659218822Sdim	    entry->archive, &entry->ae_sourcepath, &p) == 0)
660218822Sdim		return (p);
661218822Sdim	return (NULL);
662218822Sdim}
663218822Sdim
664218822Sdimconst char *
665218822Sdimarchive_entry_symlink(struct archive_entry *entry)
666218822Sdim{
667218822Sdim	const char *p;
668218822Sdim	if ((entry->ae_set & AE_SET_SYMLINK) == 0)
669218822Sdim		return (NULL);
670218822Sdim	if (archive_mstring_get_mbs(
671218822Sdim	    entry->archive, &entry->ae_symlink, &p) == 0)
672218822Sdim		return (p);
673218822Sdim	if (errno == ENOMEM)
674218822Sdim		__archive_errx(1, "No memory");
675218822Sdim	return (NULL);
676218822Sdim}
677218822Sdim
678218822Sdimconst char *
679218822Sdimarchive_entry_symlink_utf8(struct archive_entry *entry)
680218822Sdim{
681218822Sdim	const char *p;
682218822Sdim	if ((entry->ae_set & AE_SET_SYMLINK) == 0)
683218822Sdim		return (NULL);
684218822Sdim	if (archive_mstring_get_utf8(
685218822Sdim	    entry->archive, &entry->ae_symlink, &p) == 0)
686218822Sdim		return (p);
687218822Sdim	if (errno == ENOMEM)
688218822Sdim		__archive_errx(1, "No memory");
689218822Sdim	return (NULL);
690218822Sdim}
691218822Sdim
692218822Sdimconst wchar_t *
693218822Sdimarchive_entry_symlink_w(struct archive_entry *entry)
694218822Sdim{
695218822Sdim	const wchar_t *p;
696218822Sdim	if ((entry->ae_set & AE_SET_SYMLINK) == 0)
697218822Sdim		return (NULL);
698218822Sdim	if (archive_mstring_get_wcs(
699218822Sdim	    entry->archive, &entry->ae_symlink, &p) == 0)
700218822Sdim		return (p);
701218822Sdim	if (errno == ENOMEM)
702218822Sdim		__archive_errx(1, "No memory");
703218822Sdim	return (NULL);
704218822Sdim}
705218822Sdim
706218822Sdimint
707218822Sdim_archive_entry_symlink_l(struct archive_entry *entry,
708218822Sdim    const char **p, size_t *len, struct archive_string_conv *sc)
709218822Sdim{
710218822Sdim	if ((entry->ae_set & AE_SET_SYMLINK) == 0) {
711218822Sdim		*p = NULL;
712218822Sdim		*len = 0;
713218822Sdim		return (0);
714218822Sdim	}
715218822Sdim	return (archive_mstring_get_mbs_l( &entry->ae_symlink, p, len, sc));
716218822Sdim}
717218822Sdim
718218822Sdimla_int64_t
719218822Sdimarchive_entry_uid(struct archive_entry *entry)
720218822Sdim{
721218822Sdim	return (entry->ae_stat.aest_uid);
722218822Sdim}
723218822Sdim
724218822Sdimconst char *
725218822Sdimarchive_entry_uname(struct archive_entry *entry)
726218822Sdim{
727218822Sdim	const char *p;
728218822Sdim	if (archive_mstring_get_mbs(entry->archive, &entry->ae_uname, &p) == 0)
729218822Sdim		return (p);
730218822Sdim	if (errno == ENOMEM)
731218822Sdim		__archive_errx(1, "No memory");
732218822Sdim	return (NULL);
733218822Sdim}
734218822Sdim
735218822Sdimconst char *
736218822Sdimarchive_entry_uname_utf8(struct archive_entry *entry)
737218822Sdim{
738218822Sdim	const char *p;
739218822Sdim	if (archive_mstring_get_utf8(entry->archive, &entry->ae_uname, &p) == 0)
740218822Sdim		return (p);
741218822Sdim	if (errno == ENOMEM)
742218822Sdim		__archive_errx(1, "No memory");
743218822Sdim	return (NULL);
744218822Sdim}
745218822Sdim
746218822Sdimconst wchar_t *
747218822Sdimarchive_entry_uname_w(struct archive_entry *entry)
748218822Sdim{
749218822Sdim	const wchar_t *p;
750218822Sdim	if (archive_mstring_get_wcs(entry->archive, &entry->ae_uname, &p) == 0)
751218822Sdim		return (p);
752218822Sdim	if (errno == ENOMEM)
753218822Sdim		__archive_errx(1, "No memory");
754218822Sdim	return (NULL);
755218822Sdim}
756218822Sdim
757218822Sdimint
758218822Sdim_archive_entry_uname_l(struct archive_entry *entry,
759218822Sdim    const char **p, size_t *len, struct archive_string_conv *sc)
760218822Sdim{
761218822Sdim	return (archive_mstring_get_mbs_l(&entry->ae_uname, p, len, sc));
762218822Sdim}
763218822Sdim
764218822Sdimint
765218822Sdimarchive_entry_is_data_encrypted(struct archive_entry *entry)
766218822Sdim{
767218822Sdim	return ((entry->encryption & AE_ENCRYPTION_DATA) == AE_ENCRYPTION_DATA);
768218822Sdim}
769218822Sdim
770218822Sdimint
771218822Sdimarchive_entry_is_metadata_encrypted(struct archive_entry *entry)
772218822Sdim{
773218822Sdim	return ((entry->encryption & AE_ENCRYPTION_METADATA) == AE_ENCRYPTION_METADATA);
774218822Sdim}
775218822Sdim
776218822Sdimint
777218822Sdimarchive_entry_is_encrypted(struct archive_entry *entry)
778218822Sdim{
779218822Sdim	return (entry->encryption & (AE_ENCRYPTION_DATA|AE_ENCRYPTION_METADATA));
780218822Sdim}
781218822Sdim
782218822Sdim/*
783218822Sdim * Functions to set archive_entry properties.
784218822Sdim */
785218822Sdim
786218822Sdimvoid
787218822Sdimarchive_entry_set_filetype(struct archive_entry *entry, unsigned int type)
788218822Sdim{
789218822Sdim	entry->stat_valid = 0;
790218822Sdim	entry->acl.mode &= ~AE_IFMT;
791218822Sdim	entry->acl.mode |= AE_IFMT & type;
792218822Sdim}
793218822Sdim
794218822Sdimvoid
795218822Sdimarchive_entry_set_fflags(struct archive_entry *entry,
796218822Sdim    unsigned long set, unsigned long clear)
797218822Sdim{
798218822Sdim	archive_mstring_clean(&entry->ae_fflags_text);
799218822Sdim	entry->ae_fflags_set = set;
800218822Sdim	entry->ae_fflags_clear = clear;
801218822Sdim}
802218822Sdim
803218822Sdimconst char *
804218822Sdimarchive_entry_copy_fflags_text(struct archive_entry *entry,
805218822Sdim    const char *flags)
806218822Sdim{
807218822Sdim	archive_mstring_copy_mbs(&entry->ae_fflags_text, flags);
808218822Sdim	return (ae_strtofflags(flags,
809218822Sdim		    &entry->ae_fflags_set, &entry->ae_fflags_clear));
810218822Sdim}
811218822Sdim
812218822Sdimconst wchar_t *
813218822Sdimarchive_entry_copy_fflags_text_w(struct archive_entry *entry,
814218822Sdim    const wchar_t *flags)
815218822Sdim{
816218822Sdim	archive_mstring_copy_wcs(&entry->ae_fflags_text, flags);
817218822Sdim	return (ae_wcstofflags(flags,
818218822Sdim		    &entry->ae_fflags_set, &entry->ae_fflags_clear));
819218822Sdim}
820218822Sdim
821218822Sdimvoid
822218822Sdimarchive_entry_set_gid(struct archive_entry *entry, la_int64_t g)
823218822Sdim{
824218822Sdim	entry->stat_valid = 0;
825218822Sdim	entry->ae_stat.aest_gid = g;
826218822Sdim}
827218822Sdim
828218822Sdimvoid
829218822Sdimarchive_entry_set_gname(struct archive_entry *entry, const char *name)
830218822Sdim{
831218822Sdim	archive_mstring_copy_mbs(&entry->ae_gname, name);
832218822Sdim}
833218822Sdim
834218822Sdimvoid
835218822Sdimarchive_entry_set_gname_utf8(struct archive_entry *entry, const char *name)
836218822Sdim{
837218822Sdim	archive_mstring_copy_utf8(&entry->ae_gname, name);
838218822Sdim}
839218822Sdim
840218822Sdimvoid
841218822Sdimarchive_entry_copy_gname(struct archive_entry *entry, const char *name)
842218822Sdim{
843218822Sdim	archive_mstring_copy_mbs(&entry->ae_gname, name);
844218822Sdim}
845218822Sdim
846218822Sdimvoid
847218822Sdimarchive_entry_copy_gname_w(struct archive_entry *entry, const wchar_t *name)
848218822Sdim{
849218822Sdim	archive_mstring_copy_wcs(&entry->ae_gname, name);
850218822Sdim}
851218822Sdim
852218822Sdimint
853218822Sdimarchive_entry_update_gname_utf8(struct archive_entry *entry, const char *name)
854218822Sdim{
855218822Sdim	if (archive_mstring_update_utf8(entry->archive,
856218822Sdim	    &entry->ae_gname, name) == 0)
857218822Sdim		return (1);
858218822Sdim	if (errno == ENOMEM)
859218822Sdim		__archive_errx(1, "No memory");
860218822Sdim	return (0);
861218822Sdim}
862218822Sdim
863218822Sdimint
864218822Sdim_archive_entry_copy_gname_l(struct archive_entry *entry,
865218822Sdim    const char *name, size_t len, struct archive_string_conv *sc)
866218822Sdim{
867218822Sdim	return (archive_mstring_copy_mbs_len_l(&entry->ae_gname, name, len, sc));
868218822Sdim}
869218822Sdim
870218822Sdimvoid
871218822Sdimarchive_entry_set_ino(struct archive_entry *entry, la_int64_t ino)
872218822Sdim{
873218822Sdim	entry->stat_valid = 0;
874218822Sdim	entry->ae_set |= AE_SET_INO;
875218822Sdim	entry->ae_stat.aest_ino = ino;
876218822Sdim}
877218822Sdim
878218822Sdimvoid
879218822Sdimarchive_entry_set_ino64(struct archive_entry *entry, la_int64_t ino)
880218822Sdim{
881218822Sdim	entry->stat_valid = 0;
882218822Sdim	entry->ae_set |= AE_SET_INO;
883218822Sdim	entry->ae_stat.aest_ino = ino;
884218822Sdim}
885218822Sdim
886218822Sdimvoid
887218822Sdimarchive_entry_set_hardlink(struct archive_entry *entry, const char *target)
888218822Sdim{
889218822Sdim	archive_mstring_copy_mbs(&entry->ae_hardlink, target);
890218822Sdim	if (target != NULL)
891218822Sdim		entry->ae_set |= AE_SET_HARDLINK;
892218822Sdim	else
893218822Sdim		entry->ae_set &= ~AE_SET_HARDLINK;
894218822Sdim}
895218822Sdim
896218822Sdimvoid
897218822Sdimarchive_entry_set_hardlink_utf8(struct archive_entry *entry, const char *target)
898218822Sdim{
899218822Sdim	archive_mstring_copy_utf8(&entry->ae_hardlink, target);
900218822Sdim	if (target != NULL)
901218822Sdim		entry->ae_set |= AE_SET_HARDLINK;
902218822Sdim	else
903218822Sdim		entry->ae_set &= ~AE_SET_HARDLINK;
904218822Sdim}
905218822Sdim
906218822Sdimvoid
907218822Sdimarchive_entry_copy_hardlink(struct archive_entry *entry, const char *target)
908218822Sdim{
909218822Sdim	archive_mstring_copy_mbs(&entry->ae_hardlink, target);
910218822Sdim	if (target != NULL)
911218822Sdim		entry->ae_set |= AE_SET_HARDLINK;
912218822Sdim	else
913218822Sdim		entry->ae_set &= ~AE_SET_HARDLINK;
914218822Sdim}
915218822Sdim
916218822Sdimvoid
917218822Sdimarchive_entry_copy_hardlink_w(struct archive_entry *entry, const wchar_t *target)
918218822Sdim{
919218822Sdim	archive_mstring_copy_wcs(&entry->ae_hardlink, target);
920218822Sdim	if (target != NULL)
921218822Sdim		entry->ae_set |= AE_SET_HARDLINK;
922218822Sdim	else
923218822Sdim		entry->ae_set &= ~AE_SET_HARDLINK;
924218822Sdim}
925218822Sdim
926218822Sdimint
927218822Sdimarchive_entry_update_hardlink_utf8(struct archive_entry *entry, const char *target)
928218822Sdim{
929218822Sdim	if (target != NULL)
930218822Sdim		entry->ae_set |= AE_SET_HARDLINK;
931218822Sdim	else
932218822Sdim		entry->ae_set &= ~AE_SET_HARDLINK;
933218822Sdim	if (archive_mstring_update_utf8(entry->archive,
934218822Sdim	    &entry->ae_hardlink, target) == 0)
935218822Sdim		return (1);
936218822Sdim	if (errno == ENOMEM)
937218822Sdim		__archive_errx(1, "No memory");
938218822Sdim	return (0);
939218822Sdim}
940218822Sdim
941218822Sdimint
942218822Sdim_archive_entry_copy_hardlink_l(struct archive_entry *entry,
943218822Sdim    const char *target, size_t len, struct archive_string_conv *sc)
944218822Sdim{
945218822Sdim	int r;
946218822Sdim
947218822Sdim	r = archive_mstring_copy_mbs_len_l(&entry->ae_hardlink,
948218822Sdim	    target, len, sc);
949218822Sdim	if (target != NULL && r == 0)
950218822Sdim		entry->ae_set |= AE_SET_HARDLINK;
951218822Sdim	else
952218822Sdim		entry->ae_set &= ~AE_SET_HARDLINK;
953218822Sdim	return (r);
954218822Sdim}
955218822Sdim
956218822Sdimvoid
957218822Sdimarchive_entry_set_atime(struct archive_entry *entry, time_t t, long ns)
958218822Sdim{
959218822Sdim	FIX_NS(t, ns);
960218822Sdim	entry->stat_valid = 0;
961218822Sdim	entry->ae_set |= AE_SET_ATIME;
962218822Sdim	entry->ae_stat.aest_atime = t;
963218822Sdim	entry->ae_stat.aest_atime_nsec = ns;
964218822Sdim}
965218822Sdim
966218822Sdimvoid
967218822Sdimarchive_entry_unset_atime(struct archive_entry *entry)
968218822Sdim{
969218822Sdim	archive_entry_set_atime(entry, 0, 0);
970218822Sdim	entry->ae_set &= ~AE_SET_ATIME;
971218822Sdim}
972218822Sdim
973218822Sdimvoid
974218822Sdimarchive_entry_set_birthtime(struct archive_entry *entry, time_t t, long ns)
975218822Sdim{
976218822Sdim	FIX_NS(t, ns);
977218822Sdim	entry->stat_valid = 0;
978218822Sdim	entry->ae_set |= AE_SET_BIRTHTIME;
979218822Sdim	entry->ae_stat.aest_birthtime = t;
980218822Sdim	entry->ae_stat.aest_birthtime_nsec = ns;
981218822Sdim}
982218822Sdim
983218822Sdimvoid
984218822Sdimarchive_entry_unset_birthtime(struct archive_entry *entry)
985218822Sdim{
986218822Sdim	archive_entry_set_birthtime(entry, 0, 0);
987218822Sdim	entry->ae_set &= ~AE_SET_BIRTHTIME;
988218822Sdim}
989218822Sdim
990218822Sdimvoid
991218822Sdimarchive_entry_set_ctime(struct archive_entry *entry, time_t t, long ns)
992218822Sdim{
993218822Sdim	FIX_NS(t, ns);
994218822Sdim	entry->stat_valid = 0;
995218822Sdim	entry->ae_set |= AE_SET_CTIME;
996218822Sdim	entry->ae_stat.aest_ctime = t;
997218822Sdim	entry->ae_stat.aest_ctime_nsec = ns;
998218822Sdim}
999218822Sdim
1000218822Sdimvoid
1001218822Sdimarchive_entry_unset_ctime(struct archive_entry *entry)
1002218822Sdim{
1003218822Sdim	archive_entry_set_ctime(entry, 0, 0);
1004218822Sdim	entry->ae_set &= ~AE_SET_CTIME;
1005218822Sdim}
1006218822Sdim
1007218822Sdimvoid
1008218822Sdimarchive_entry_set_dev(struct archive_entry *entry, dev_t d)
1009218822Sdim{
1010218822Sdim	entry->stat_valid = 0;
1011218822Sdim	entry->ae_set |= AE_SET_DEV;
1012218822Sdim	entry->ae_stat.aest_dev_is_broken_down = 0;
1013218822Sdim	entry->ae_stat.aest_dev = d;
1014218822Sdim}
1015218822Sdim
1016218822Sdimvoid
1017218822Sdimarchive_entry_set_devmajor(struct archive_entry *entry, dev_t m)
1018218822Sdim{
1019218822Sdim	entry->stat_valid = 0;
1020218822Sdim	entry->ae_set |= AE_SET_DEV;
1021218822Sdim	entry->ae_stat.aest_dev_is_broken_down = 1;
1022218822Sdim	entry->ae_stat.aest_devmajor = m;
1023218822Sdim}
1024218822Sdim
1025218822Sdimvoid
1026218822Sdimarchive_entry_set_devminor(struct archive_entry *entry, dev_t m)
1027218822Sdim{
1028218822Sdim	entry->stat_valid = 0;
1029218822Sdim	entry->ae_set |= AE_SET_DEV;
1030218822Sdim	entry->ae_stat.aest_dev_is_broken_down = 1;
1031218822Sdim	entry->ae_stat.aest_devminor = m;
1032218822Sdim}
1033218822Sdim
1034218822Sdim/* Set symlink if symlink is already set, else set hardlink. */
1035218822Sdimvoid
1036218822Sdimarchive_entry_set_link(struct archive_entry *entry, const char *target)
1037218822Sdim{
1038218822Sdim	if (entry->ae_set & AE_SET_SYMLINK)
1039218822Sdim		archive_mstring_copy_mbs(&entry->ae_symlink, target);
1040218822Sdim	else
1041218822Sdim		archive_mstring_copy_mbs(&entry->ae_hardlink, target);
1042218822Sdim}
1043218822Sdim
1044218822Sdimvoid
1045218822Sdimarchive_entry_set_link_utf8(struct archive_entry *entry, const char *target)
1046218822Sdim{
1047218822Sdim	if (entry->ae_set & AE_SET_SYMLINK)
1048218822Sdim		archive_mstring_copy_utf8(&entry->ae_symlink, target);
1049218822Sdim	else
1050218822Sdim		archive_mstring_copy_utf8(&entry->ae_hardlink, target);
1051218822Sdim}
1052218822Sdim
1053218822Sdim/* Set symlink if symlink is already set, else set hardlink. */
1054218822Sdimvoid
1055218822Sdimarchive_entry_copy_link(struct archive_entry *entry, const char *target)
1056218822Sdim{
1057218822Sdim	if (entry->ae_set & AE_SET_SYMLINK)
1058218822Sdim		archive_mstring_copy_mbs(&entry->ae_symlink, target);
1059218822Sdim	else
1060218822Sdim		archive_mstring_copy_mbs(&entry->ae_hardlink, target);
1061218822Sdim}
1062218822Sdim
1063218822Sdim/* Set symlink if symlink is already set, else set hardlink. */
1064218822Sdimvoid
1065218822Sdimarchive_entry_copy_link_w(struct archive_entry *entry, const wchar_t *target)
1066218822Sdim{
1067218822Sdim	if (entry->ae_set & AE_SET_SYMLINK)
1068218822Sdim		archive_mstring_copy_wcs(&entry->ae_symlink, target);
1069218822Sdim	else
1070218822Sdim		archive_mstring_copy_wcs(&entry->ae_hardlink, target);
1071218822Sdim}
1072218822Sdim
1073218822Sdimint
1074218822Sdimarchive_entry_update_link_utf8(struct archive_entry *entry, const char *target)
1075218822Sdim{
1076218822Sdim	int r;
1077218822Sdim	if (entry->ae_set & AE_SET_SYMLINK)
1078218822Sdim		r = archive_mstring_update_utf8(entry->archive,
1079218822Sdim		    &entry->ae_symlink, target);
1080218822Sdim	else
1081218822Sdim		r = archive_mstring_update_utf8(entry->archive,
1082218822Sdim		    &entry->ae_hardlink, target);
1083218822Sdim	if (r == 0)
1084218822Sdim		return (1);
1085218822Sdim	if (errno == ENOMEM)
1086218822Sdim		__archive_errx(1, "No memory");
1087218822Sdim	return (0);
1088218822Sdim}
1089218822Sdim
1090218822Sdimint
1091218822Sdim_archive_entry_copy_link_l(struct archive_entry *entry,
1092218822Sdim    const char *target, size_t len, struct archive_string_conv *sc)
1093218822Sdim{
1094218822Sdim	int r;
1095218822Sdim
1096218822Sdim	if (entry->ae_set & AE_SET_SYMLINK)
1097218822Sdim		r = archive_mstring_copy_mbs_len_l(&entry->ae_symlink,
1098218822Sdim		    target, len, sc);
1099218822Sdim	else
1100218822Sdim		r = archive_mstring_copy_mbs_len_l(&entry->ae_hardlink,
1101218822Sdim		    target, len, sc);
1102218822Sdim	return (r);
1103218822Sdim}
1104218822Sdim
1105218822Sdimvoid
1106218822Sdimarchive_entry_set_mode(struct archive_entry *entry, mode_t m)
1107218822Sdim{
1108218822Sdim	entry->stat_valid = 0;
1109218822Sdim	entry->acl.mode = m;
1110218822Sdim}
1111218822Sdim
1112218822Sdimvoid
1113218822Sdimarchive_entry_set_mtime(struct archive_entry *entry, time_t t, long ns)
1114218822Sdim{
1115218822Sdim	FIX_NS(t, ns);
1116218822Sdim	entry->stat_valid = 0;
1117218822Sdim	entry->ae_set |= AE_SET_MTIME;
1118218822Sdim	entry->ae_stat.aest_mtime = t;
1119218822Sdim	entry->ae_stat.aest_mtime_nsec = ns;
1120218822Sdim}
1121218822Sdim
1122218822Sdimvoid
1123218822Sdimarchive_entry_unset_mtime(struct archive_entry *entry)
1124218822Sdim{
1125218822Sdim	archive_entry_set_mtime(entry, 0, 0);
1126218822Sdim	entry->ae_set &= ~AE_SET_MTIME;
1127218822Sdim}
1128218822Sdim
1129218822Sdimvoid
1130218822Sdimarchive_entry_set_nlink(struct archive_entry *entry, unsigned int nlink)
1131218822Sdim{
1132218822Sdim	entry->stat_valid = 0;
1133218822Sdim	entry->ae_stat.aest_nlink = nlink;
1134218822Sdim}
1135218822Sdim
1136218822Sdimvoid
1137218822Sdimarchive_entry_set_pathname(struct archive_entry *entry, const char *name)
1138218822Sdim{
1139218822Sdim	archive_mstring_copy_mbs(&entry->ae_pathname, name);
1140218822Sdim}
1141218822Sdim
1142218822Sdimvoid
1143218822Sdimarchive_entry_set_pathname_utf8(struct archive_entry *entry, const char *name)
1144218822Sdim{
1145218822Sdim	archive_mstring_copy_utf8(&entry->ae_pathname, name);
1146218822Sdim}
1147218822Sdim
1148218822Sdimvoid
1149218822Sdimarchive_entry_copy_pathname(struct archive_entry *entry, const char *name)
1150218822Sdim{
1151218822Sdim	archive_mstring_copy_mbs(&entry->ae_pathname, name);
1152218822Sdim}
1153218822Sdim
1154218822Sdimvoid
1155218822Sdimarchive_entry_copy_pathname_w(struct archive_entry *entry, const wchar_t *name)
1156218822Sdim{
1157218822Sdim	archive_mstring_copy_wcs(&entry->ae_pathname, name);
1158218822Sdim}
1159218822Sdim
1160218822Sdimint
1161218822Sdimarchive_entry_update_pathname_utf8(struct archive_entry *entry, const char *name)
1162218822Sdim{
1163218822Sdim	if (archive_mstring_update_utf8(entry->archive,
1164218822Sdim	    &entry->ae_pathname, name) == 0)
1165218822Sdim		return (1);
1166218822Sdim	if (errno == ENOMEM)
1167218822Sdim		__archive_errx(1, "No memory");
1168218822Sdim	return (0);
1169218822Sdim}
1170218822Sdim
1171218822Sdimint
1172218822Sdim_archive_entry_copy_pathname_l(struct archive_entry *entry,
1173218822Sdim    const char *name, size_t len, struct archive_string_conv *sc)
1174218822Sdim{
1175218822Sdim	return (archive_mstring_copy_mbs_len_l(&entry->ae_pathname,
1176218822Sdim	    name, len, sc));
1177218822Sdim}
1178218822Sdim
1179218822Sdimvoid
1180218822Sdimarchive_entry_set_perm(struct archive_entry *entry, mode_t p)
1181218822Sdim{
1182218822Sdim	entry->stat_valid = 0;
1183218822Sdim	entry->acl.mode &= AE_IFMT;
1184218822Sdim	entry->acl.mode |= ~AE_IFMT & p;
1185218822Sdim}
1186218822Sdim
1187218822Sdimvoid
1188218822Sdimarchive_entry_set_rdev(struct archive_entry *entry, dev_t m)
1189218822Sdim{
1190218822Sdim	entry->stat_valid = 0;
1191218822Sdim	entry->ae_stat.aest_rdev = m;
1192218822Sdim	entry->ae_stat.aest_rdev_is_broken_down = 0;
1193218822Sdim}
1194218822Sdim
1195218822Sdimvoid
1196218822Sdimarchive_entry_set_rdevmajor(struct archive_entry *entry, dev_t m)
1197218822Sdim{
1198218822Sdim	entry->stat_valid = 0;
1199218822Sdim	entry->ae_stat.aest_rdev_is_broken_down = 1;
1200218822Sdim	entry->ae_stat.aest_rdevmajor = m;
1201218822Sdim}
1202218822Sdim
1203218822Sdimvoid
1204218822Sdimarchive_entry_set_rdevminor(struct archive_entry *entry, dev_t m)
1205218822Sdim{
1206218822Sdim	entry->stat_valid = 0;
1207218822Sdim	entry->ae_stat.aest_rdev_is_broken_down = 1;
1208218822Sdim	entry->ae_stat.aest_rdevminor = m;
1209218822Sdim}
1210218822Sdim
1211218822Sdimvoid
1212218822Sdimarchive_entry_set_size(struct archive_entry *entry, la_int64_t s)
1213218822Sdim{
1214218822Sdim	entry->stat_valid = 0;
1215218822Sdim	entry->ae_stat.aest_size = s;
1216218822Sdim	entry->ae_set |= AE_SET_SIZE;
1217218822Sdim}
1218218822Sdim
1219218822Sdimvoid
1220218822Sdimarchive_entry_unset_size(struct archive_entry *entry)
1221218822Sdim{
1222218822Sdim	archive_entry_set_size(entry, 0);
1223218822Sdim	entry->ae_set &= ~AE_SET_SIZE;
1224218822Sdim}
1225218822Sdim
1226218822Sdimvoid
1227218822Sdimarchive_entry_copy_sourcepath(struct archive_entry *entry, const char *path)
1228218822Sdim{
1229218822Sdim	archive_mstring_copy_mbs(&entry->ae_sourcepath, path);
1230218822Sdim}
1231218822Sdim
1232218822Sdimvoid
1233218822Sdimarchive_entry_copy_sourcepath_w(struct archive_entry *entry, const wchar_t *path)
1234218822Sdim{
1235218822Sdim	archive_mstring_copy_wcs(&entry->ae_sourcepath, path);
1236218822Sdim}
1237218822Sdim
1238218822Sdimvoid
1239218822Sdimarchive_entry_set_symlink(struct archive_entry *entry, const char *linkname)
1240218822Sdim{
1241218822Sdim	archive_mstring_copy_mbs(&entry->ae_symlink, linkname);
1242218822Sdim	if (linkname != NULL)
1243218822Sdim		entry->ae_set |= AE_SET_SYMLINK;
1244218822Sdim	else
1245218822Sdim		entry->ae_set &= ~AE_SET_SYMLINK;
1246218822Sdim}
1247218822Sdim
1248218822Sdimvoid
1249218822Sdimarchive_entry_set_symlink_utf8(struct archive_entry *entry, const char *linkname)
1250218822Sdim{
1251218822Sdim	archive_mstring_copy_utf8(&entry->ae_symlink, linkname);
1252218822Sdim	if (linkname != NULL)
1253218822Sdim		entry->ae_set |= AE_SET_SYMLINK;
1254218822Sdim	else
1255218822Sdim		entry->ae_set &= ~AE_SET_SYMLINK;
1256218822Sdim}
1257218822Sdim
1258218822Sdimvoid
1259218822Sdimarchive_entry_copy_symlink(struct archive_entry *entry, const char *linkname)
1260218822Sdim{
1261218822Sdim	archive_mstring_copy_mbs(&entry->ae_symlink, linkname);
1262218822Sdim	if (linkname != NULL)
1263218822Sdim		entry->ae_set |= AE_SET_SYMLINK;
1264218822Sdim	else
1265218822Sdim		entry->ae_set &= ~AE_SET_SYMLINK;
1266218822Sdim}
1267218822Sdim
1268218822Sdimvoid
1269218822Sdimarchive_entry_copy_symlink_w(struct archive_entry *entry, const wchar_t *linkname)
1270218822Sdim{
1271218822Sdim	archive_mstring_copy_wcs(&entry->ae_symlink, linkname);
1272218822Sdim	if (linkname != NULL)
1273218822Sdim		entry->ae_set |= AE_SET_SYMLINK;
1274218822Sdim	else
1275218822Sdim		entry->ae_set &= ~AE_SET_SYMLINK;
1276218822Sdim}
1277218822Sdim
1278218822Sdimint
1279218822Sdimarchive_entry_update_symlink_utf8(struct archive_entry *entry, const char *linkname)
1280218822Sdim{
1281218822Sdim	if (linkname != NULL)
1282218822Sdim		entry->ae_set |= AE_SET_SYMLINK;
1283218822Sdim	else
1284218822Sdim		entry->ae_set &= ~AE_SET_SYMLINK;
1285218822Sdim	if (archive_mstring_update_utf8(entry->archive,
1286218822Sdim	    &entry->ae_symlink, linkname) == 0)
1287218822Sdim		return (1);
1288218822Sdim	if (errno == ENOMEM)
1289218822Sdim		__archive_errx(1, "No memory");
1290218822Sdim	return (0);
1291218822Sdim}
1292218822Sdim
1293218822Sdimint
1294218822Sdim_archive_entry_copy_symlink_l(struct archive_entry *entry,
1295218822Sdim    const char *linkname, size_t len, struct archive_string_conv *sc)
1296218822Sdim{
1297218822Sdim	int r;
1298218822Sdim
1299218822Sdim	r = archive_mstring_copy_mbs_len_l(&entry->ae_symlink,
1300218822Sdim	    linkname, len, sc);
1301218822Sdim	if (linkname != NULL && r == 0)
1302218822Sdim		entry->ae_set |= AE_SET_SYMLINK;
1303218822Sdim	else
1304218822Sdim		entry->ae_set &= ~AE_SET_SYMLINK;
1305218822Sdim	return (r);
1306218822Sdim}
1307218822Sdim
1308218822Sdimvoid
1309218822Sdimarchive_entry_set_uid(struct archive_entry *entry, la_int64_t u)
1310218822Sdim{
1311218822Sdim	entry->stat_valid = 0;
1312218822Sdim	entry->ae_stat.aest_uid = u;
1313218822Sdim}
1314218822Sdim
1315218822Sdimvoid
1316218822Sdimarchive_entry_set_uname(struct archive_entry *entry, const char *name)
1317218822Sdim{
1318218822Sdim	archive_mstring_copy_mbs(&entry->ae_uname, name);
1319218822Sdim}
1320218822Sdim
1321218822Sdimvoid
1322218822Sdimarchive_entry_set_uname_utf8(struct archive_entry *entry, const char *name)
1323218822Sdim{
1324218822Sdim	archive_mstring_copy_utf8(&entry->ae_uname, name);
1325218822Sdim}
1326218822Sdim
1327218822Sdimvoid
1328218822Sdimarchive_entry_copy_uname(struct archive_entry *entry, const char *name)
1329218822Sdim{
1330218822Sdim	archive_mstring_copy_mbs(&entry->ae_uname, name);
1331218822Sdim}
1332218822Sdim
1333218822Sdimvoid
1334218822Sdimarchive_entry_copy_uname_w(struct archive_entry *entry, const wchar_t *name)
1335218822Sdim{
1336218822Sdim	archive_mstring_copy_wcs(&entry->ae_uname, name);
1337218822Sdim}
1338218822Sdim
1339218822Sdimint
1340218822Sdimarchive_entry_update_uname_utf8(struct archive_entry *entry, const char *name)
1341218822Sdim{
1342218822Sdim	if (archive_mstring_update_utf8(entry->archive,
1343218822Sdim	    &entry->ae_uname, name) == 0)
1344218822Sdim		return (1);
1345218822Sdim	if (errno == ENOMEM)
1346218822Sdim		__archive_errx(1, "No memory");
1347218822Sdim	return (0);
1348218822Sdim}
1349218822Sdim
1350218822Sdimvoid
1351218822Sdimarchive_entry_set_is_data_encrypted(struct archive_entry *entry, char is_encrypted)
1352218822Sdim{
1353218822Sdim	if (is_encrypted) {
1354218822Sdim		entry->encryption |= AE_ENCRYPTION_DATA;
1355218822Sdim	} else {
1356218822Sdim		entry->encryption &= ~AE_ENCRYPTION_DATA;
1357218822Sdim	}
1358218822Sdim}
1359218822Sdim
1360218822Sdimvoid
1361218822Sdimarchive_entry_set_is_metadata_encrypted(struct archive_entry *entry, char is_encrypted)
1362218822Sdim{
1363218822Sdim	if (is_encrypted) {
1364218822Sdim		entry->encryption |= AE_ENCRYPTION_METADATA;
1365218822Sdim	} else {
1366218822Sdim		entry->encryption &= ~AE_ENCRYPTION_METADATA;
1367218822Sdim	}
1368218822Sdim}
1369218822Sdim
1370218822Sdimint
1371218822Sdim_archive_entry_copy_uname_l(struct archive_entry *entry,
1372218822Sdim    const char *name, size_t len, struct archive_string_conv *sc)
1373218822Sdim{
1374218822Sdim	return (archive_mstring_copy_mbs_len_l(&entry->ae_uname,
1375218822Sdim	    name, len, sc));
1376218822Sdim}
1377218822Sdim
1378218822Sdimconst void *
1379218822Sdimarchive_entry_mac_metadata(struct archive_entry *entry, size_t *s)
1380218822Sdim{
1381218822Sdim  *s = entry->mac_metadata_size;
1382218822Sdim  return entry->mac_metadata;
1383218822Sdim}
1384218822Sdim
1385218822Sdimvoid
1386218822Sdimarchive_entry_copy_mac_metadata(struct archive_entry *entry,
1387218822Sdim    const void *p, size_t s)
1388218822Sdim{
1389218822Sdim  free(entry->mac_metadata);
1390218822Sdim  if (p == NULL || s == 0) {
1391218822Sdim    entry->mac_metadata = NULL;
1392218822Sdim    entry->mac_metadata_size = 0;
1393218822Sdim  } else {
1394218822Sdim    entry->mac_metadata_size = s;
1395218822Sdim    entry->mac_metadata = malloc(s);
1396218822Sdim    if (entry->mac_metadata == NULL)
1397218822Sdim      abort();
1398218822Sdim    memcpy(entry->mac_metadata, p, s);
1399218822Sdim  }
1400218822Sdim}
1401218822Sdim
1402218822Sdim/*
1403218822Sdim * ACL management.  The following would, of course, be a lot simpler
1404218822Sdim * if: 1) the last draft of POSIX.1e were a really thorough and
1405218822Sdim * complete standard that addressed the needs of ACL archiving and 2)
1406218822Sdim * everyone followed it faithfully.  Alas, neither is true, so the
1407218822Sdim * following is a lot more complex than might seem necessary to the
1408218822Sdim * uninitiated.
1409218822Sdim */
1410218822Sdim
1411218822Sdimstruct archive_acl *
1412218822Sdimarchive_entry_acl(struct archive_entry *entry)
1413218822Sdim{
1414218822Sdim	return &entry->acl;
1415218822Sdim}
1416218822Sdim
1417218822Sdimvoid
1418218822Sdimarchive_entry_acl_clear(struct archive_entry *entry)
1419218822Sdim{
1420218822Sdim	archive_acl_clear(&entry->acl);
1421218822Sdim}
1422218822Sdim
1423218822Sdim/*
1424218822Sdim * Add a single ACL entry to the internal list of ACL data.
1425218822Sdim */
1426218822Sdimint
1427218822Sdimarchive_entry_acl_add_entry(struct archive_entry *entry,
1428218822Sdim    int type, int permset, int tag, int id, const char *name)
1429218822Sdim{
1430218822Sdim	return archive_acl_add_entry(&entry->acl, type, permset, tag, id, name);
1431218822Sdim}
1432218822Sdim
143360484Sobrien/*
1434218822Sdim * As above, but with a wide-character name.
143560484Sobrien */
1436218822Sdimint
1437218822Sdimarchive_entry_acl_add_entry_w(struct archive_entry *entry,
1438218822Sdim    int type, int permset, int tag, int id, const wchar_t *name)
1439218822Sdim{
1440218822Sdim	return archive_acl_add_entry_w_len(&entry->acl,
1441218822Sdim	    type, permset, tag, id, name, wcslen(name));
144260484Sobrien}
144360484Sobrien
1444218822Sdim/*
1445218822Sdim * Return a bitmask of ACL types in an archive entry ACL list
1446218822Sdim */
144760484Sobrienint
144860484Sobrienarchive_entry_acl_types(struct archive_entry *entry)
144960484Sobrien{
1450218822Sdim	return (archive_acl_types(&entry->acl));
145160484Sobrien}
145260484Sobrien
145360484Sobrien/*
145477298Sobrien * Return a count of entries matching "want_type".
145577298Sobrien */
145660484Sobrienint
145760484Sobrienarchive_entry_acl_count(struct archive_entry *entry, int want_type)
145860484Sobrien{
145960484Sobrien	return archive_acl_count(&entry->acl, want_type);
146060484Sobrien}
146160484Sobrien
146260484Sobrien/*
1463130561Sobrien * Prepare for reading entries from the ACL data.  Returns a count
146460484Sobrien * of entries matching "want_type", or zero if there are no
146560484Sobrien * non-extended ACL entries of that type.
1466218822Sdim */
1467130561Sobrienint
1468130561Sobrienarchive_entry_acl_reset(struct archive_entry *entry, int want_type)
1469218822Sdim{
1470218822Sdim	return archive_acl_reset(&entry->acl, want_type);
1471218822Sdim}
1472218822Sdim
1473218822Sdim/*
1474130561Sobrien * Return the next ACL entry in the list.  Fake entries for the
1475130561Sobrien * standard permissions and include them in the returned list.
1476218822Sdim */
1477218822Sdimint
1478218822Sdimarchive_entry_acl_next(struct archive_entry *entry, int want_type, int *type,
1479218822Sdim    int *permset, int *tag, int *id, const char **name)
1480218822Sdim{
1481218822Sdim	int r;
1482218822Sdim	r = archive_acl_next(entry->archive, &entry->acl, want_type, type,
1483218822Sdim		permset, tag, id, name);
1484218822Sdim	if (r == ARCHIVE_FATAL && errno == ENOMEM)
1485218822Sdim		__archive_errx(1, "No memory");
148677298Sobrien	return (r);
148760484Sobrien}
148860484Sobrien
148960484Sobrien/*
149060484Sobrien * Generate a text version of the ACL. The flags parameter controls
149160484Sobrien * the style of the generated ACL.
1492130561Sobrien */
149360484Sobrienwchar_t *
1494218822Sdimarchive_entry_acl_to_text_w(struct archive_entry *entry, ssize_t *len,
1495218822Sdim    int flags)
1496218822Sdim{
1497218822Sdim	return (archive_acl_to_text_w(&entry->acl, len, flags,
1498218822Sdim	    entry->archive));
1499218822Sdim}
1500218822Sdim
1501218822Sdimchar *
150260484Sobrienarchive_entry_acl_to_text(struct archive_entry *entry, ssize_t *len,
1503218822Sdim    int flags)
1504218822Sdim{
1505218822Sdim	return (archive_acl_to_text_l(&entry->acl, len, flags, NULL));
1506218822Sdim}
1507218822Sdim
1508218822Sdimchar *
1509130561Sobrien_archive_entry_acl_to_text_l(struct archive_entry *entry, ssize_t *len,
1510218822Sdim   int flags, struct archive_string_conv *sc)
1511218822Sdim{
1512218822Sdim	return (archive_acl_to_text_l(&entry->acl, len, flags, sc));
1513218822Sdim}
151460484Sobrien
1515104834Sobrien/*
151660484Sobrien * ACL text parser.
1517218822Sdim */
151860484Sobrienint
151960484Sobrienarchive_entry_acl_from_text_w(struct archive_entry *entry,
152060484Sobrien    const wchar_t *wtext, int type)
152160484Sobrien{
152260484Sobrien	return (archive_acl_from_text_w(&entry->acl, wtext, type));
1523218822Sdim}
152460484Sobrien
152560484Sobrienint
152660484Sobrienarchive_entry_acl_from_text(struct archive_entry *entry,
152760484Sobrien    const char *text, int type)
152860484Sobrien{
152960484Sobrien	return (archive_acl_from_text_l(&entry->acl, text, type, NULL));
153060484Sobrien}
1531218822Sdim
1532218822Sdimint
153360484Sobrien_archive_entry_acl_from_text_l(struct archive_entry *entry, const char *text,
153460484Sobrien    int type, struct archive_string_conv *sc)
153560484Sobrien{
153660484Sobrien	return (archive_acl_from_text_l(&entry->acl, text, type, sc));
153760484Sobrien}
153860484Sobrien
153960484Sobrien/* Deprecated */
1540218822Sdimstatic int
1541218822Sdimarchive_entry_acl_text_compat(int *flags)
1542218822Sdim{
1543218822Sdim	if ((*flags & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) == 0)
1544218822Sdim		return (1);
1545218822Sdim
1546218822Sdim	/* ABI compat with old ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID */
1547218822Sdim	if ((*flags & OLD_ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID) != 0)
1548218822Sdim		*flags |= ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID;
1549218822Sdim
1550218822Sdim	/* ABI compat with old ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT */
1551218822Sdim	if ((*flags & OLD_ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT) != 0)
1552218822Sdim		*flags |=  ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT;
1553218822Sdim
1554218822Sdim	*flags |= ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA;
1555218822Sdim
1556218822Sdim	return (0);
1557218822Sdim}
1558218822Sdim
1559218822Sdim/* Deprecated */
1560218822Sdimconst wchar_t *
1561218822Sdimarchive_entry_acl_text_w(struct archive_entry *entry, int flags)
1562218822Sdim{
1563218822Sdim	if (entry->acl.acl_text_w != NULL) {
1564218822Sdim		free(entry->acl.acl_text_w);
1565218822Sdim		entry->acl.acl_text_w = NULL;
1566218822Sdim	}
1567218822Sdim	if (archive_entry_acl_text_compat(&flags) == 0)
1568218822Sdim		entry->acl.acl_text_w = archive_acl_to_text_w(&entry->acl,
1569218822Sdim		    NULL, flags, entry->archive);
1570218822Sdim	return (entry->acl.acl_text_w);
1571218822Sdim}
1572218822Sdim
1573218822Sdim/* Deprecated */
1574218822Sdimconst char *
1575218822Sdimarchive_entry_acl_text(struct archive_entry *entry, int flags)
1576218822Sdim{
157760484Sobrien	if (entry->acl.acl_text != NULL) {
1578218822Sdim		free(entry->acl.acl_text);
1579218822Sdim		entry->acl.acl_text = NULL;
158060484Sobrien	}
158160484Sobrien	if (archive_entry_acl_text_compat(&flags) == 0)
1582130561Sobrien		entry->acl.acl_text = archive_acl_to_text_l(&entry->acl, NULL,
158360484Sobrien		    flags, NULL);
158460484Sobrien
158560484Sobrien	return (entry->acl.acl_text);
158660484Sobrien}
158760484Sobrien
158860484Sobrien/* Deprecated */
1589130561Sobrienint
159060484Sobrien_archive_entry_acl_text_l(struct archive_entry *entry, int flags,
159160484Sobrien    const char **acl_text, size_t *len, struct archive_string_conv *sc)
159260484Sobrien{
159360484Sobrien	if (entry->acl.acl_text != NULL) {
159460484Sobrien		free(entry->acl.acl_text);
159560484Sobrien		entry->acl.acl_text = NULL;
159660484Sobrien        }
1597130561Sobrien
159860484Sobrien	if (archive_entry_acl_text_compat(&flags) == 0)
159960484Sobrien		entry->acl.acl_text = archive_acl_to_text_l(&entry->acl,
1600130561Sobrien		    (ssize_t *)len, flags, sc);
1601218822Sdim
1602218822Sdim	*acl_text = entry->acl.acl_text;
1603218822Sdim
1604218822Sdim	return (0);
160560484Sobrien}
1606218822Sdim
160760484Sobrien/*
160860484Sobrien * Following code is modified from UC Berkeley sources, and
1609218822Sdim * is subject to the following copyright notice.
1610218822Sdim */
161160484Sobrien
161260484Sobrien/*-
161360484Sobrien * Copyright (c) 1993
1614218822Sdim *	The Regents of the University of California.  All rights reserved.
1615218822Sdim *
1616218822Sdim * Redistribution and use in source and binary forms, with or without
1617130561Sobrien * modification, are permitted provided that the following conditions
1618218822Sdim * are met:
1619218822Sdim * 1. Redistributions of source code must retain the above copyright
1620218822Sdim *    notice, this list of conditions and the following disclaimer.
162160484Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1622218822Sdim *    notice, this list of conditions and the following disclaimer in the
1623130561Sobrien *    documentation and/or other materials provided with the distribution.
1624218822Sdim * 4. Neither the name of the University nor the names of its contributors
1625218822Sdim *    may be used to endorse or promote products derived from this software
1626218822Sdim *    without specific prior written permission.
1627218822Sdim *
162860484Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
1629218822Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
163060484Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1631130561Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
1632130561Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1633218822Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
1634218822Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
1635130561Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
1636130561Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
1637218822Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
1638218822Sdim * SUCH DAMAGE.
1639218822Sdim */
164060484Sobrien
1641218822Sdimstatic const struct flag {
1642218822Sdim	const char	*name;
1643218822Sdim	const wchar_t	*wname;
1644218822Sdim	unsigned long	 set;
1645218822Sdim	unsigned long	 clear;
1646218822Sdim} flags[] = {
1647218822Sdim	/* Preferred (shorter) names per flag first, all prefixed by "no" */
1648218822Sdim#ifdef SF_APPEND
1649218822Sdim	{ "nosappnd",	L"nosappnd",		SF_APPEND,	0 },
1650218822Sdim	{ "nosappend",	L"nosappend",		SF_APPEND,	0 },
1651218822Sdim#endif
1652218822Sdim#if defined(FS_APPEND_FL)			/* 'a' */
1653218822Sdim	{ "nosappnd",	L"nosappnd",		FS_APPEND_FL,	0 },
1654218822Sdim	{ "nosappend",	L"nosappend",		FS_APPEND_FL,	0 },
1655218822Sdim#elif defined(EXT2_APPEND_FL)			/* 'a' */
1656218822Sdim	{ "nosappnd",	L"nosappnd",		EXT2_APPEND_FL,	0 },
1657218822Sdim	{ "nosappend",	L"nosappend",		EXT2_APPEND_FL,	0 },
1658218822Sdim#endif
1659218822Sdim#ifdef SF_ARCHIVED
1660218822Sdim	{ "noarch",	L"noarch",		SF_ARCHIVED,	0 },
1661218822Sdim	{ "noarchived",	L"noarchived",       	SF_ARCHIVED,	0 },
1662218822Sdim#endif
1663218822Sdim#ifdef SF_IMMUTABLE
1664218822Sdim	{ "noschg",	L"noschg",		SF_IMMUTABLE,	0 },
1665218822Sdim	{ "noschange",	L"noschange",		SF_IMMUTABLE,	0 },
1666218822Sdim	{ "nosimmutable",	L"nosimmutable",	SF_IMMUTABLE,	0 },
1667218822Sdim#endif
1668218822Sdim#if defined(FS_IMMUTABLE_FL)			/* 'i' */
1669218822Sdim	{ "noschg",	L"noschg",		FS_IMMUTABLE_FL,	0 },
1670130561Sobrien	{ "noschange",	L"noschange",		FS_IMMUTABLE_FL,	0 },
167160484Sobrien	{ "nosimmutable",	L"nosimmutable",	FS_IMMUTABLE_FL,	0 },
167260484Sobrien#elif defined(EXT2_IMMUTABLE_FL)		/* 'i' */
167360484Sobrien	{ "noschg",	L"noschg",		EXT2_IMMUTABLE_FL,	0 },
167460484Sobrien	{ "noschange",	L"noschange",		EXT2_IMMUTABLE_FL,	0 },
167560484Sobrien	{ "nosimmutable",	L"nosimmutable",	EXT2_IMMUTABLE_FL,	0 },
167660484Sobrien#endif
167760484Sobrien#ifdef SF_NOUNLINK
167860484Sobrien	{ "nosunlnk",	L"nosunlnk",		SF_NOUNLINK,	0 },
167960484Sobrien	{ "nosunlink",	L"nosunlink",		SF_NOUNLINK,	0 },
168060484Sobrien#endif
1681218822Sdim#ifdef SF_SNAPSHOT
1682218822Sdim	{ "nosnapshot",	L"nosnapshot",	SF_SNAPSHOT,	0 },
1683218822Sdim#endif
1684218822Sdim#ifdef UF_APPEND
168560484Sobrien	{ "nouappnd",	L"nouappnd",		UF_APPEND,	0 },
1686218822Sdim	{ "nouappend",	L"nouappend",		UF_APPEND,	0 },
1687130561Sobrien#endif
1688218822Sdim#ifdef UF_IMMUTABLE
1689218822Sdim	{ "nouchg",	L"nouchg",		UF_IMMUTABLE,	0 },
1690218822Sdim	{ "nouchange",	L"nouchange",		UF_IMMUTABLE,	0 },
1691218822Sdim	{ "nouimmutable",	L"nouimmutable",	UF_IMMUTABLE,	0 },
1692218822Sdim#endif
1693218822Sdim#ifdef UF_NODUMP
1694218822Sdim	{ "nodump",	L"nodump",		0,		UF_NODUMP},
1695218822Sdim#endif
1696218822Sdim#if defined(FS_NODUMP_FL)	/* 'd' */
1697218822Sdim	{ "nodump",	L"nodump",		0,		FS_NODUMP_FL},
1698218822Sdim#elif defined(EXT2_NODUMP_FL) 	/* 'd' */
1699130561Sobrien	{ "nodump",	L"nodump",		0,		EXT2_NODUMP_FL},
1700218822Sdim#endif
1701218822Sdim#ifdef UF_OPAQUE
1702218822Sdim	{ "noopaque",	L"noopaque",		UF_OPAQUE,	0 },
170360484Sobrien#endif
1704218822Sdim#ifdef UF_NOUNLINK
1705218822Sdim	{ "nouunlnk",	L"nouunlnk",		UF_NOUNLINK,	0 },
1706218822Sdim	{ "nouunlink",	L"nouunlink",		UF_NOUNLINK,	0 },
1707218822Sdim#endif
1708218822Sdim#ifdef UF_COMPRESSED
1709218822Sdim	{ "nocompressed",L"nocompressed",	UF_COMPRESSED,	0 },
1710218822Sdim#endif
1711218822Sdim#ifdef UF_HIDDEN
1712218822Sdim	{ "nohidden",	L"nohidden",		UF_HIDDEN,	0 },
1713130561Sobrien#endif
1714218822Sdim#if defined(FS_UNRM_FL)
1715218822Sdim        { "nouunlink",	L"nouunlink",		FS_UNRM_FL,	0},
1716218822Sdim#elif defined(EXT2_UNRM_FL)
1717218822Sdim        { "nouunlink",	L"nouunlink",		EXT2_UNRM_FL,	0},
1718218822Sdim#endif
1719218822Sdim
1720218822Sdim#if defined(FS_BTREE_FL)
1721218822Sdim        { "nobtree",	L"nobtree",       	FS_BTREE_FL,	0 },
1722218822Sdim#elif defined(EXT2_BTREE_FL)
1723218822Sdim        { "nobtree",	L"nobtree",       	EXT2_BTREE_FL,	0 },
1724218822Sdim#endif
1725218822Sdim
1726218822Sdim#if defined(FS_ECOMPR_FL)
1727218822Sdim        { "nocomperr",	L"nocomperr",       	FS_ECOMPR_FL,	0 },
1728218822Sdim#elif defined(EXT2_ECOMPR_FL)
1729218822Sdim        { "nocomperr",	L"nocomperr",       	EXT2_ECOMPR_FL,	0 },
1730218822Sdim#endif
1731218822Sdim
1732218822Sdim#if defined(FS_COMPR_FL)			/* 'c' */
1733218822Sdim        { "nocompress",	L"nocompress",       	FS_COMPR_FL,	0 },
1734218822Sdim#elif defined(EXT2_COMPR_FL)			/* 'c' */
1735218822Sdim        { "nocompress",	L"nocompress",       	EXT2_COMPR_FL,	0 },
1736218822Sdim#endif
1737218822Sdim
1738218822Sdim#if defined(FS_NOATIME_FL)			/* 'A' */
1739218822Sdim        { "noatime",	L"noatime",		0,		FS_NOATIME_FL},
1740218822Sdim#elif defined(EXT2_NOATIME_FL)			/* 'A' */
1741218822Sdim        { "noatime",	L"noatime",		0,		EXT2_NOATIME_FL},
1742218822Sdim#endif
1743218822Sdim
1744218822Sdim#if defined(FS_DIRTY_FL)
1745218822Sdim        { "nocompdirty",L"nocompdirty",		FS_DIRTY_FL,		0},
1746218822Sdim#elif defined(EXT2_DIRTY_FL)
1747218822Sdim        { "nocompdirty",L"nocompdirty",		EXT2_DIRTY_FL,		0},
1748218822Sdim#endif
1749218822Sdim
1750218822Sdim#if defined(FS_COMPRBLK_FL)
1751218822Sdim#if defined(FS_NOCOMPR_FL)
1752218822Sdim        { "nocomprblk",	L"nocomprblk",		FS_COMPRBLK_FL, FS_NOCOMPR_FL},
175360484Sobrien#else
1754218822Sdim        { "nocomprblk",	L"nocomprblk",		FS_COMPRBLK_FL,	0},
1755218822Sdim#endif
1756218822Sdim#elif defined(EXT2_COMPRBLK_FL)
175760484Sobrien#if defined(EXT2_NOCOMPR_FL)
1758218822Sdim        { "nocomprblk",	L"nocomprblk",		EXT2_COMPRBLK_FL, EXT2_NOCOMPR_FL},
1759218822Sdim#else
1760218822Sdim        { "nocomprblk",	L"nocomprblk",		EXT2_COMPRBLK_FL,	0},
1761218822Sdim#endif
1762218822Sdim#endif
1763218822Sdim#if defined(FS_DIRSYNC_FL)
1764218822Sdim        { "nodirsync",	L"nodirsync",		FS_DIRSYNC_FL,	0},
176560484Sobrien#elif defined(EXT2_DIRSYNC_FL)
1766218822Sdim        { "nodirsync",	L"nodirsync",		EXT2_DIRSYNC_FL,	0},
1767130561Sobrien#endif
1768218822Sdim#if defined(FS_INDEX_FL)
1769218822Sdim        { "nohashidx",	L"nohashidx",		FS_INDEX_FL,		0},
1770218822Sdim#elif defined(EXT2_INDEX_FL)
1771218822Sdim        { "nohashidx",	L"nohashidx",		EXT2_INDEX_FL,		0},
1772218822Sdim#endif
1773218822Sdim#if defined(FS_IMAGIC_FL)
1774218822Sdim        { "noimagic",	L"noimagic",		FS_IMAGIC_FL,		0},
1775218822Sdim#elif defined(EXT2_IMAGIC_FL)
1776218822Sdim        { "noimagic",	L"noimagic",		EXT2_IMAGIC_FL,		0},
1777218822Sdim#endif
1778218822Sdim#if defined(FS_JOURNAL_DATA_FL)
1779218822Sdim        { "nojournal",	L"nojournal",		FS_JOURNAL_DATA_FL,	0},
1780218822Sdim#elif defined(EXT3_JOURNAL_DATA_FL)
1781218822Sdim        { "nojournal",	L"nojournal",		EXT3_JOURNAL_DATA_FL,	0},
1782218822Sdim#endif
1783218822Sdim#if defined(FS_SECRM_FL)
1784218822Sdim        { "nosecuredeletion",L"nosecuredeletion",FS_SECRM_FL,		0},
1785218822Sdim#elif defined(EXT2_SECRM_FL)
1786218822Sdim        { "nosecuredeletion",L"nosecuredeletion",EXT2_SECRM_FL,		0},
1787218822Sdim#endif
1788218822Sdim#if defined(FS_SYNC_FL)
1789218822Sdim        { "nosync",	L"nosync",		FS_SYNC_FL,		0},
1790218822Sdim#elif defined(EXT2_SYNC_FL)
179160484Sobrien        { "nosync",	L"nosync",		EXT2_SYNC_FL,		0},
1792218822Sdim#endif
1793218822Sdim#if defined(FS_NOTAIL_FL)
1794218822Sdim        { "notail",	L"notail",		0,		FS_NOTAIL_FL},
1795218822Sdim#elif defined(EXT2_NOTAIL_FL)
179660484Sobrien        { "notail",	L"notail",		0,		EXT2_NOTAIL_FL},
1797218822Sdim#endif
1798218822Sdim#if defined(FS_TOPDIR_FL)
1799218822Sdim        { "notopdir",	L"notopdir",		FS_TOPDIR_FL,		0},
1800218822Sdim#elif defined(EXT2_TOPDIR_FL)
1801218822Sdim        { "notopdir",	L"notopdir",		EXT2_TOPDIR_FL,		0},
1802218822Sdim#endif
1803218822Sdim#ifdef FS_ENCRYPT_FL
1804218822Sdim        { "noencrypt",	L"noencrypt",		FS_ENCRYPT_FL,	0},
1805218822Sdim#endif
1806218822Sdim#ifdef FS_HUGE_FILE_FL
1807218822Sdim        { "nohugefile",	L"nohugefile",		FS_HUGE_FILE_FL,	0},
1808218822Sdim#endif
1809218822Sdim#ifdef FS_EXTENT_FL
1810218822Sdim        { "noextent",	L"noextent",		FS_EXTENT_FL,	0},
1811218822Sdim#endif
1812218822Sdim#ifdef FS_EA_INODE_FL
1813218822Sdim        { "noeainode",	L"noeainode",		FS_EA_INODE_FL,	0},
1814218822Sdim#endif
1815218822Sdim#ifdef FS_EOFBLOCKS_FL
1816218822Sdim        { "noeofblocks",L"noeofblocks",		FS_EOFBLOCKS_FL,	0},
1817218822Sdim#endif
1818218822Sdim#ifdef FS_NOCOW_FL
1819218822Sdim        { "nocow",	L"nocow",		FS_NOCOW_FL,	0},
1820218822Sdim#endif
1821218822Sdim#ifdef FS_INLINE_DATA_FL
1822218822Sdim        { "noinlinedata",L"noinlinedata",	FS_INLINE_DATA_FL,	0},
1823218822Sdim#endif
1824218822Sdim#ifdef FS_PROJINHERIT_FL
1825218822Sdim        { "noprojinherit",L"noprojinherit",	FS_PROJINHERIT_FL,	0},
1826218822Sdim#endif
1827218822Sdim#if defined(FS_RESERVED_FL)
1828218822Sdim        { "noreserved",	L"noreserved",		FS_RESERVED_FL,	0},
1829218822Sdim#elif defined(EXT2_RESERVED_FL)
1830218822Sdim        { "noreserved",	L"noreserved",		EXT2_RESERVED_FL,	0},
1831218822Sdim#endif
1832218822Sdim	{ NULL,		NULL,			0,		0 }
1833218822Sdim};
1834218822Sdim
1835218822Sdim/*
1836218822Sdim * fflagstostr --
1837218822Sdim *	Convert file flags to a comma-separated string.  If no flags
1838218822Sdim *	are set, return the empty string.
1839218822Sdim */
1840218822Sdimstatic char *
1841218822Sdimae_fflagstostr(unsigned long bitset, unsigned long bitclear)
1842218822Sdim{
1843218822Sdim	char *string, *dp;
1844218822Sdim	const char *sp;
1845218822Sdim	unsigned long bits;
1846218822Sdim	const struct flag *flag;
1847218822Sdim	size_t	length;
1848218822Sdim
1849218822Sdim	bits = bitset | bitclear;
1850218822Sdim	length = 0;
1851218822Sdim	for (flag = flags; flag->name != NULL; flag++)
1852218822Sdim		if (bits & (flag->set | flag->clear)) {
1853218822Sdim			length += strlen(flag->name) + 1;
1854218822Sdim			bits &= ~(flag->set | flag->clear);
1855218822Sdim		}
1856218822Sdim
1857218822Sdim	if (length == 0)
1858218822Sdim		return (NULL);
1859218822Sdim	string = (char *)malloc(length);
1860218822Sdim	if (string == NULL)
1861218822Sdim		return (NULL);
1862218822Sdim
1863218822Sdim	dp = string;
1864218822Sdim	for (flag = flags; flag->name != NULL; flag++) {
1865218822Sdim		if (bitset & flag->set || bitclear & flag->clear) {
1866218822Sdim			sp = flag->name + 2;
1867218822Sdim		} else if (bitset & flag->clear  ||  bitclear & flag->set) {
1868218822Sdim			sp = flag->name;
1869218822Sdim		} else
1870218822Sdim			continue;
1871218822Sdim		bitset &= ~(flag->set | flag->clear);
1872218822Sdim		bitclear &= ~(flag->set | flag->clear);
1873218822Sdim		if (dp > string)
1874218822Sdim			*dp++ = ',';
1875218822Sdim		while ((*dp++ = *sp++) != '\0')
1876218822Sdim			;
1877218822Sdim		dp--;
1878218822Sdim	}
1879218822Sdim
1880218822Sdim	*dp = '\0';
1881218822Sdim	return (string);
1882218822Sdim}
1883218822Sdim
1884218822Sdim/*
1885218822Sdim * strtofflags --
1886218822Sdim *	Take string of arguments and return file flags.  This
1887218822Sdim *	version works a little differently than strtofflags(3).
1888218822Sdim *	In particular, it always tests every token, skipping any
1889218822Sdim *	unrecognized tokens.  It returns a pointer to the first
1890218822Sdim *	unrecognized token, or NULL if every token was recognized.
1891218822Sdim *	This version is also const-correct and does not modify the
1892218822Sdim *	provided string.
1893218822Sdim */
1894218822Sdimstatic const char *
1895218822Sdimae_strtofflags(const char *s, unsigned long *setp, unsigned long *clrp)
1896218822Sdim{
1897218822Sdim	const char *start, *end;
1898218822Sdim	const struct flag *flag;
1899218822Sdim	unsigned long set, clear;
1900218822Sdim	const char *failed;
1901218822Sdim
1902218822Sdim	set = clear = 0;
1903218822Sdim	start = s;
1904218822Sdim	failed = NULL;
1905218822Sdim	/* Find start of first token. */
1906218822Sdim	while (*start == '\t'  ||  *start == ' '  ||  *start == ',')
1907218822Sdim		start++;
1908218822Sdim	while (*start != '\0') {
1909218822Sdim		size_t length;
1910218822Sdim		/* Locate end of token. */
1911218822Sdim		end = start;
1912218822Sdim		while (*end != '\0'  &&  *end != '\t'  &&
1913218822Sdim		    *end != ' '  &&  *end != ',')
1914218822Sdim			end++;
1915218822Sdim		length = end - start;
1916218822Sdim		for (flag = flags; flag->name != NULL; flag++) {
1917218822Sdim			size_t flag_length = strlen(flag->name);
1918218822Sdim			if (length == flag_length
1919218822Sdim			    && memcmp(start, flag->name, length) == 0) {
1920218822Sdim				/* Matched "noXXXX", so reverse the sense. */
1921218822Sdim				clear |= flag->set;
1922218822Sdim				set |= flag->clear;
1923218822Sdim				break;
1924218822Sdim			} else if (length == flag_length - 2
1925218822Sdim			    && memcmp(start, flag->name + 2, length) == 0) {
1926218822Sdim				/* Matched "XXXX", so don't reverse. */
1927218822Sdim				set |= flag->set;
192860484Sobrien				clear |= flag->clear;
1929218822Sdim				break;
1930218822Sdim			}
1931218822Sdim		}
1932218822Sdim		/* Ignore unknown flag names. */
1933218822Sdim		if (flag->name == NULL  &&  failed == NULL)
1934218822Sdim			failed = start;
193560484Sobrien
1936218822Sdim		/* Find start of next token. */
1937218822Sdim		start = end;
193860484Sobrien		while (*start == '\t'  ||  *start == ' '  ||  *start == ',')
1939218822Sdim			start++;
1940218822Sdim
1941218822Sdim	}
1942218822Sdim
1943218822Sdim	if (setp)
1944218822Sdim		*setp = set;
1945218822Sdim	if (clrp)
194660484Sobrien		*clrp = clear;
1947218822Sdim
1948218822Sdim	/* Return location of first failure. */
194960484Sobrien	return (failed);
1950218822Sdim}
1951218822Sdim
1952218822Sdim/*
195360484Sobrien * wcstofflags --
1954218822Sdim *	Take string of arguments and return file flags.  This
1955218822Sdim *	version works a little differently than strtofflags(3).
1956218822Sdim *	In particular, it always tests every token, skipping any
1957218822Sdim *	unrecognized tokens.  It returns a pointer to the first
1958218822Sdim *	unrecognized token, or NULL if every token was recognized.
1959218822Sdim *	This version is also const-correct and does not modify the
1960218822Sdim *	provided string.
1961218822Sdim */
1962218822Sdimstatic const wchar_t *
1963218822Sdimae_wcstofflags(const wchar_t *s, unsigned long *setp, unsigned long *clrp)
1964218822Sdim{
1965218822Sdim	const wchar_t *start, *end;
1966218822Sdim	const struct flag *flag;
1967218822Sdim	unsigned long set, clear;
1968218822Sdim	const wchar_t *failed;
1969218822Sdim
1970218822Sdim	set = clear = 0;
1971218822Sdim	start = s;
1972218822Sdim	failed = NULL;
1973218822Sdim	/* Find start of first token. */
1974218822Sdim	while (*start == L'\t'  ||  *start == L' '  ||  *start == L',')
1975218822Sdim		start++;
1976218822Sdim	while (*start != L'\0') {
1977218822Sdim		size_t length;
1978218822Sdim		/* Locate end of token. */
197960484Sobrien		end = start;
1980218822Sdim		while (*end != L'\0'  &&  *end != L'\t'  &&
1981218822Sdim		    *end != L' '  &&  *end != L',')
1982218822Sdim			end++;
1983218822Sdim		length = end - start;
198460484Sobrien		for (flag = flags; flag->wname != NULL; flag++) {
1985218822Sdim			size_t flag_length = wcslen(flag->wname);
1986218822Sdim			if (length == flag_length
1987218822Sdim			    && wmemcmp(start, flag->wname, length) == 0) {
1988218822Sdim				/* Matched "noXXXX", so reverse the sense. */
1989218822Sdim				clear |= flag->set;
1990218822Sdim				set |= flag->clear;
199160484Sobrien				break;
1992218822Sdim			} else if (length == flag_length - 2
1993218822Sdim			    && wmemcmp(start, flag->wname + 2, length) == 0) {
1994218822Sdim				/* Matched "XXXX", so don't reverse. */
199560484Sobrien				set |= flag->set;
1996218822Sdim				clear |= flag->clear;
1997218822Sdim				break;
1998218822Sdim			}
1999218822Sdim		}
2000218822Sdim		/* Ignore unknown flag names. */
2001218822Sdim		if (flag->wname == NULL  &&  failed == NULL)
2002218822Sdim			failed = start;
2003218822Sdim
2004218822Sdim		/* Find start of next token. */
2005218822Sdim		start = end;
2006218822Sdim		while (*start == L'\t'  ||  *start == L' '  ||  *start == L',')
2007218822Sdim			start++;
2008218822Sdim
2009218822Sdim	}
2010218822Sdim
2011218822Sdim	if (setp)
2012218822Sdim		*setp = set;
2013218822Sdim	if (clrp)
2014218822Sdim		*clrp = clear;
2015218822Sdim
2016218822Sdim	/* Return location of first failure. */
2017218822Sdim	return (failed);
2018218822Sdim}
2019218822Sdim
2020218822Sdim
2021218822Sdim#ifdef TEST
2022218822Sdim#include <stdio.h>
2023218822Sdimint
2024218822Sdimmain(int argc, char **argv)
2025218822Sdim{
2026218822Sdim	struct archive_entry *entry = archive_entry_new();
2027218822Sdim	unsigned long set, clear;
2028218822Sdim	const wchar_t *remainder;
2029218822Sdim
2030218822Sdim	remainder = archive_entry_copy_fflags_text_w(entry, L"nosappnd dump archive,,,,,,,");
2031218822Sdim	archive_entry_fflags(entry, &set, &clear);
2032218822Sdim
2033218822Sdim	wprintf(L"set=0x%lX clear=0x%lX remainder='%ls'\n", set, clear, remainder);
2034218822Sdim
2035218822Sdim	wprintf(L"new flags='%s'\n", archive_entry_fflags_text(entry));
2036218822Sdim	return (0);
2037218822Sdim}
2038218822Sdim#endif
2039218822Sdim