1/*-
2 * Copyright (c) 2003-2007 Tim Kientzle
3 * Copyright (c) 2016 Martin Matuska
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include "archive_platform.h"
28__FBSDID("$FreeBSD: stable/11/contrib/libarchive/libarchive/archive_entry.c 368707 2020-12-16 22:25:20Z mm $");
29
30#ifdef HAVE_SYS_STAT_H
31#include <sys/stat.h>
32#endif
33#ifdef HAVE_SYS_TYPES_H
34#include <sys/types.h>
35#endif
36#if MAJOR_IN_MKDEV
37#include <sys/mkdev.h>
38#define HAVE_MAJOR
39#elif MAJOR_IN_SYSMACROS
40#include <sys/sysmacros.h>
41#define HAVE_MAJOR
42#endif
43#ifdef HAVE_ERRNO_H
44#include <errno.h>
45#endif
46#ifdef HAVE_LIMITS_H
47#include <limits.h>
48#endif
49#ifdef HAVE_LINUX_FS_H
50#include <linux/fs.h>	/* for Linux file flags */
51#endif
52/*
53 * Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h.
54 * As the include guards don't agree, the order of include is important.
55 */
56#ifdef HAVE_LINUX_EXT2_FS_H
57#include <linux/ext2_fs.h>	/* for Linux file flags */
58#endif
59#if defined(HAVE_EXT2FS_EXT2_FS_H) && !defined(__CYGWIN__)
60#include <ext2fs/ext2_fs.h>	/* for Linux file flags */
61#endif
62#include <stddef.h>
63#include <stdio.h>
64#ifdef HAVE_STDLIB_H
65#include <stdlib.h>
66#endif
67#ifdef HAVE_STRING_H
68#include <string.h>
69#endif
70#ifdef HAVE_WCHAR_H
71#include <wchar.h>
72#endif
73
74#include "archive.h"
75#include "archive_acl_private.h"
76#include "archive_entry.h"
77#include "archive_entry_locale.h"
78#include "archive_private.h"
79#include "archive_entry_private.h"
80
81#if !defined(HAVE_MAJOR) && !defined(major)
82/* Replacement for major/minor/makedev. */
83#define	major(x) ((int)(0x00ff & ((x) >> 8)))
84#define	minor(x) ((int)(0xffff00ff & (x)))
85#define	makedev(maj,min) ((0xff00 & ((maj)<<8)) | (0xffff00ff & (min)))
86#endif
87
88/* Play games to come up with a suitable makedev() definition. */
89#ifdef __QNXNTO__
90/* QNX.  <sigh> */
91#include <sys/netmgr.h>
92#define ae_makedev(maj, min) makedev(ND_LOCAL_NODE, (maj), (min))
93#elif defined makedev
94/* There's a "makedev" macro. */
95#define ae_makedev(maj, min) makedev((maj), (min))
96#elif defined mkdev || ((defined _WIN32 || defined __WIN32__) && !defined(__CYGWIN__))
97/* Windows. <sigh> */
98#define ae_makedev(maj, min) mkdev((maj), (min))
99#else
100/* There's a "makedev" function. */
101#define ae_makedev(maj, min) makedev((maj), (min))
102#endif
103
104/*
105 * This adjustment is needed to support the following idiom for adding
106 * 1000ns to the stored time:
107 * archive_entry_set_atime(archive_entry_atime(),
108 *                         archive_entry_atime_nsec() + 1000)
109 * The additional if() here compensates for ambiguity in the C standard,
110 * which permits two possible interpretations of a % b when a is negative.
111 */
112#define FIX_NS(t,ns) \
113	do {	\
114		t += ns / 1000000000; \
115		ns %= 1000000000; \
116		if (ns < 0) { --t; ns += 1000000000; } \
117	} while (0)
118
119static char *	 ae_fflagstostr(unsigned long bitset, unsigned long bitclear);
120static const wchar_t	*ae_wcstofflags(const wchar_t *stringp,
121		    unsigned long *setp, unsigned long *clrp);
122static const char	*ae_strtofflags(const char *stringp,
123		    unsigned long *setp, unsigned long *clrp);
124
125#ifndef HAVE_WCSCPY
126static wchar_t * wcscpy(wchar_t *s1, const wchar_t *s2)
127{
128	wchar_t *dest = s1;
129	while ((*s1 = *s2) != L'\0')
130		++s1, ++s2;
131	return dest;
132}
133#endif
134#ifndef HAVE_WCSLEN
135static size_t wcslen(const wchar_t *s)
136{
137	const wchar_t *p = s;
138	while (*p != L'\0')
139		++p;
140	return p - s;
141}
142#endif
143#ifndef HAVE_WMEMCMP
144/* Good enough for simple equality testing, but not for sorting. */
145#define wmemcmp(a,b,i)  memcmp((a), (b), (i) * sizeof(wchar_t))
146#endif
147
148/****************************************************************************
149 *
150 * Public Interface
151 *
152 ****************************************************************************/
153
154struct archive_entry *
155archive_entry_clear(struct archive_entry *entry)
156{
157	if (entry == NULL)
158		return (NULL);
159	archive_mstring_clean(&entry->ae_fflags_text);
160	archive_mstring_clean(&entry->ae_gname);
161	archive_mstring_clean(&entry->ae_hardlink);
162	archive_mstring_clean(&entry->ae_pathname);
163	archive_mstring_clean(&entry->ae_sourcepath);
164	archive_mstring_clean(&entry->ae_symlink);
165	archive_mstring_clean(&entry->ae_uname);
166	archive_entry_copy_mac_metadata(entry, NULL, 0);
167	archive_acl_clear(&entry->acl);
168	archive_entry_xattr_clear(entry);
169	archive_entry_sparse_clear(entry);
170	free(entry->stat);
171	entry->ae_symlink_type = AE_SYMLINK_TYPE_UNDEFINED;
172	memset(entry, 0, sizeof(*entry));
173	return entry;
174}
175
176struct archive_entry *
177archive_entry_clone(struct archive_entry *entry)
178{
179	struct archive_entry *entry2;
180	struct ae_xattr *xp;
181	struct ae_sparse *sp;
182	size_t s;
183	const void *p;
184
185	/* Allocate new structure and copy over all of the fields. */
186	/* TODO: Should we copy the archive over?  Or require a new archive
187	 * as an argument? */
188	entry2 = archive_entry_new2(entry->archive);
189	if (entry2 == NULL)
190		return (NULL);
191	entry2->ae_stat = entry->ae_stat;
192	entry2->ae_fflags_set = entry->ae_fflags_set;
193	entry2->ae_fflags_clear = entry->ae_fflags_clear;
194
195	/* TODO: XXX If clone can have a different archive, what do we do here if
196	 * character sets are different? XXX */
197	archive_mstring_copy(&entry2->ae_fflags_text, &entry->ae_fflags_text);
198	archive_mstring_copy(&entry2->ae_gname, &entry->ae_gname);
199	archive_mstring_copy(&entry2->ae_hardlink, &entry->ae_hardlink);
200	archive_mstring_copy(&entry2->ae_pathname, &entry->ae_pathname);
201	archive_mstring_copy(&entry2->ae_sourcepath, &entry->ae_sourcepath);
202	archive_mstring_copy(&entry2->ae_symlink, &entry->ae_symlink);
203	entry2->ae_set = entry->ae_set;
204	archive_mstring_copy(&entry2->ae_uname, &entry->ae_uname);
205
206	/* Copy symlink type */
207	entry2->ae_symlink_type = entry->ae_symlink_type;
208
209	/* Copy encryption status */
210	entry2->encryption = entry->encryption;
211
212	/* Copy digests */
213#define copy_digest(_e2, _e, _t) \
214	memcpy(_e2->digest._t, _e->digest._t, sizeof(_e2->digest._t))
215
216	copy_digest(entry2, entry, md5);
217	copy_digest(entry2, entry, rmd160);
218	copy_digest(entry2, entry, sha1);
219	copy_digest(entry2, entry, sha256);
220	copy_digest(entry2, entry, sha384);
221	copy_digest(entry2, entry, sha512);
222
223#undef copy_digest
224
225	/* Copy ACL data over. */
226	archive_acl_copy(&entry2->acl, &entry->acl);
227
228	/* Copy Mac OS metadata. */
229	p = archive_entry_mac_metadata(entry, &s);
230	archive_entry_copy_mac_metadata(entry2, p, s);
231
232	/* Copy xattr data over. */
233	xp = entry->xattr_head;
234	while (xp != NULL) {
235		archive_entry_xattr_add_entry(entry2,
236		    xp->name, xp->value, xp->size);
237		xp = xp->next;
238	}
239
240	/* Copy sparse data over. */
241	sp = entry->sparse_head;
242	while (sp != NULL) {
243		archive_entry_sparse_add_entry(entry2,
244		    sp->offset, sp->length);
245		sp = sp->next;
246	}
247
248	return (entry2);
249}
250
251void
252archive_entry_free(struct archive_entry *entry)
253{
254	archive_entry_clear(entry);
255	free(entry);
256}
257
258struct archive_entry *
259archive_entry_new(void)
260{
261	return archive_entry_new2(NULL);
262}
263
264struct archive_entry *
265archive_entry_new2(struct archive *a)
266{
267	struct archive_entry *entry;
268
269	entry = (struct archive_entry *)calloc(1, sizeof(*entry));
270	if (entry == NULL)
271		return (NULL);
272	entry->archive = a;
273	entry->ae_symlink_type = AE_SYMLINK_TYPE_UNDEFINED;
274	return (entry);
275}
276
277/*
278 * Functions for reading fields from an archive_entry.
279 */
280
281time_t
282archive_entry_atime(struct archive_entry *entry)
283{
284	return (entry->ae_stat.aest_atime);
285}
286
287long
288archive_entry_atime_nsec(struct archive_entry *entry)
289{
290	return (entry->ae_stat.aest_atime_nsec);
291}
292
293int
294archive_entry_atime_is_set(struct archive_entry *entry)
295{
296	return (entry->ae_set & AE_SET_ATIME);
297}
298
299time_t
300archive_entry_birthtime(struct archive_entry *entry)
301{
302	return (entry->ae_stat.aest_birthtime);
303}
304
305long
306archive_entry_birthtime_nsec(struct archive_entry *entry)
307{
308	return (entry->ae_stat.aest_birthtime_nsec);
309}
310
311int
312archive_entry_birthtime_is_set(struct archive_entry *entry)
313{
314	return (entry->ae_set & AE_SET_BIRTHTIME);
315}
316
317time_t
318archive_entry_ctime(struct archive_entry *entry)
319{
320	return (entry->ae_stat.aest_ctime);
321}
322
323int
324archive_entry_ctime_is_set(struct archive_entry *entry)
325{
326	return (entry->ae_set & AE_SET_CTIME);
327}
328
329long
330archive_entry_ctime_nsec(struct archive_entry *entry)
331{
332	return (entry->ae_stat.aest_ctime_nsec);
333}
334
335dev_t
336archive_entry_dev(struct archive_entry *entry)
337{
338	if (entry->ae_stat.aest_dev_is_broken_down)
339		return ae_makedev(entry->ae_stat.aest_devmajor,
340		    entry->ae_stat.aest_devminor);
341	else
342		return (entry->ae_stat.aest_dev);
343}
344
345int
346archive_entry_dev_is_set(struct archive_entry *entry)
347{
348	return (entry->ae_set & AE_SET_DEV);
349}
350
351dev_t
352archive_entry_devmajor(struct archive_entry *entry)
353{
354	if (entry->ae_stat.aest_dev_is_broken_down)
355		return (entry->ae_stat.aest_devmajor);
356	else
357		return major(entry->ae_stat.aest_dev);
358}
359
360dev_t
361archive_entry_devminor(struct archive_entry *entry)
362{
363	if (entry->ae_stat.aest_dev_is_broken_down)
364		return (entry->ae_stat.aest_devminor);
365	else
366		return minor(entry->ae_stat.aest_dev);
367}
368
369__LA_MODE_T
370archive_entry_filetype(struct archive_entry *entry)
371{
372	return (AE_IFMT & entry->acl.mode);
373}
374
375void
376archive_entry_fflags(struct archive_entry *entry,
377    unsigned long *set, unsigned long *clear)
378{
379	*set = entry->ae_fflags_set;
380	*clear = entry->ae_fflags_clear;
381}
382
383/*
384 * Note: if text was provided, this just returns that text.  If you
385 * really need the text to be rebuilt in a canonical form, set the
386 * text, ask for the bitmaps, then set the bitmaps.  (Setting the
387 * bitmaps clears any stored text.)  This design is deliberate: if
388 * we're editing archives, we don't want to discard flags just because
389 * they aren't supported on the current system.  The bitmap<->text
390 * conversions are platform-specific (see below).
391 */
392const char *
393archive_entry_fflags_text(struct archive_entry *entry)
394{
395	const char *f;
396	char *p;
397
398	if (archive_mstring_get_mbs(entry->archive,
399	    &entry->ae_fflags_text, &f) == 0) {
400		if (f != NULL)
401			return (f);
402	} else if (errno == ENOMEM)
403		__archive_errx(1, "No memory");
404
405	if (entry->ae_fflags_set == 0  &&  entry->ae_fflags_clear == 0)
406		return (NULL);
407
408	p = ae_fflagstostr(entry->ae_fflags_set, entry->ae_fflags_clear);
409	if (p == NULL)
410		return (NULL);
411
412	archive_mstring_copy_mbs(&entry->ae_fflags_text, p);
413	free(p);
414	if (archive_mstring_get_mbs(entry->archive,
415	    &entry->ae_fflags_text, &f) == 0)
416		return (f);
417	if (errno == ENOMEM)
418		__archive_errx(1, "No memory");
419	return (NULL);
420}
421
422la_int64_t
423archive_entry_gid(struct archive_entry *entry)
424{
425	return (entry->ae_stat.aest_gid);
426}
427
428const char *
429archive_entry_gname(struct archive_entry *entry)
430{
431	const char *p;
432	if (archive_mstring_get_mbs(entry->archive, &entry->ae_gname, &p) == 0)
433		return (p);
434	if (errno == ENOMEM)
435		__archive_errx(1, "No memory");
436	return (NULL);
437}
438
439const char *
440archive_entry_gname_utf8(struct archive_entry *entry)
441{
442	const char *p;
443	if (archive_mstring_get_utf8(entry->archive, &entry->ae_gname, &p) == 0)
444		return (p);
445	if (errno == ENOMEM)
446		__archive_errx(1, "No memory");
447	return (NULL);
448}
449
450
451const wchar_t *
452archive_entry_gname_w(struct archive_entry *entry)
453{
454	const wchar_t *p;
455	if (archive_mstring_get_wcs(entry->archive, &entry->ae_gname, &p) == 0)
456		return (p);
457	if (errno == ENOMEM)
458		__archive_errx(1, "No memory");
459	return (NULL);
460}
461
462int
463_archive_entry_gname_l(struct archive_entry *entry,
464    const char **p, size_t *len, struct archive_string_conv *sc)
465{
466	return (archive_mstring_get_mbs_l(entry->archive, &entry->ae_gname, p, len, sc));
467}
468
469const char *
470archive_entry_hardlink(struct archive_entry *entry)
471{
472	const char *p;
473	if ((entry->ae_set & AE_SET_HARDLINK) == 0)
474		return (NULL);
475	if (archive_mstring_get_mbs(
476	    entry->archive, &entry->ae_hardlink, &p) == 0)
477		return (p);
478	if (errno == ENOMEM)
479		__archive_errx(1, "No memory");
480	return (NULL);
481}
482
483const char *
484archive_entry_hardlink_utf8(struct archive_entry *entry)
485{
486	const char *p;
487	if ((entry->ae_set & AE_SET_HARDLINK) == 0)
488		return (NULL);
489	if (archive_mstring_get_utf8(
490	    entry->archive, &entry->ae_hardlink, &p) == 0)
491		return (p);
492	if (errno == ENOMEM)
493		__archive_errx(1, "No memory");
494	return (NULL);
495}
496
497const wchar_t *
498archive_entry_hardlink_w(struct archive_entry *entry)
499{
500	const wchar_t *p;
501	if ((entry->ae_set & AE_SET_HARDLINK) == 0)
502		return (NULL);
503	if (archive_mstring_get_wcs(
504	    entry->archive, &entry->ae_hardlink, &p) == 0)
505		return (p);
506	if (errno == ENOMEM)
507		__archive_errx(1, "No memory");
508	return (NULL);
509}
510
511int
512_archive_entry_hardlink_l(struct archive_entry *entry,
513    const char **p, size_t *len, struct archive_string_conv *sc)
514{
515	if ((entry->ae_set & AE_SET_HARDLINK) == 0) {
516		*p = NULL;
517		*len = 0;
518		return (0);
519	}
520	return (archive_mstring_get_mbs_l(entry->archive, &entry->ae_hardlink, p, len, sc));
521}
522
523la_int64_t
524archive_entry_ino(struct archive_entry *entry)
525{
526	return (entry->ae_stat.aest_ino);
527}
528
529int
530archive_entry_ino_is_set(struct archive_entry *entry)
531{
532	return (entry->ae_set & AE_SET_INO);
533}
534
535la_int64_t
536archive_entry_ino64(struct archive_entry *entry)
537{
538	return (entry->ae_stat.aest_ino);
539}
540
541__LA_MODE_T
542archive_entry_mode(struct archive_entry *entry)
543{
544	return (entry->acl.mode);
545}
546
547time_t
548archive_entry_mtime(struct archive_entry *entry)
549{
550	return (entry->ae_stat.aest_mtime);
551}
552
553long
554archive_entry_mtime_nsec(struct archive_entry *entry)
555{
556	return (entry->ae_stat.aest_mtime_nsec);
557}
558
559int
560archive_entry_mtime_is_set(struct archive_entry *entry)
561{
562	return (entry->ae_set & AE_SET_MTIME);
563}
564
565unsigned int
566archive_entry_nlink(struct archive_entry *entry)
567{
568	return (entry->ae_stat.aest_nlink);
569}
570
571const char *
572archive_entry_pathname(struct archive_entry *entry)
573{
574	const char *p;
575	if (archive_mstring_get_mbs(
576	    entry->archive, &entry->ae_pathname, &p) == 0)
577		return (p);
578	if (errno == ENOMEM)
579		__archive_errx(1, "No memory");
580	return (NULL);
581}
582
583const char *
584archive_entry_pathname_utf8(struct archive_entry *entry)
585{
586	const char *p;
587	if (archive_mstring_get_utf8(
588	    entry->archive, &entry->ae_pathname, &p) == 0)
589		return (p);
590	if (errno == ENOMEM)
591		__archive_errx(1, "No memory");
592	return (NULL);
593}
594
595const wchar_t *
596archive_entry_pathname_w(struct archive_entry *entry)
597{
598	const wchar_t *p;
599	if (archive_mstring_get_wcs(
600	    entry->archive, &entry->ae_pathname, &p) == 0)
601		return (p);
602	if (errno == ENOMEM)
603		__archive_errx(1, "No memory");
604	return (NULL);
605}
606
607int
608_archive_entry_pathname_l(struct archive_entry *entry,
609    const char **p, size_t *len, struct archive_string_conv *sc)
610{
611	return (archive_mstring_get_mbs_l(entry->archive, &entry->ae_pathname, p, len, sc));
612}
613
614__LA_MODE_T
615archive_entry_perm(struct archive_entry *entry)
616{
617	return (~AE_IFMT & entry->acl.mode);
618}
619
620dev_t
621archive_entry_rdev(struct archive_entry *entry)
622{
623	if (entry->ae_stat.aest_rdev_is_broken_down)
624		return ae_makedev(entry->ae_stat.aest_rdevmajor,
625		    entry->ae_stat.aest_rdevminor);
626	else
627		return (entry->ae_stat.aest_rdev);
628}
629
630dev_t
631archive_entry_rdevmajor(struct archive_entry *entry)
632{
633	if (entry->ae_stat.aest_rdev_is_broken_down)
634		return (entry->ae_stat.aest_rdevmajor);
635	else
636		return major(entry->ae_stat.aest_rdev);
637}
638
639dev_t
640archive_entry_rdevminor(struct archive_entry *entry)
641{
642	if (entry->ae_stat.aest_rdev_is_broken_down)
643		return (entry->ae_stat.aest_rdevminor);
644	else
645		return minor(entry->ae_stat.aest_rdev);
646}
647
648la_int64_t
649archive_entry_size(struct archive_entry *entry)
650{
651	return (entry->ae_stat.aest_size);
652}
653
654int
655archive_entry_size_is_set(struct archive_entry *entry)
656{
657	return (entry->ae_set & AE_SET_SIZE);
658}
659
660const char *
661archive_entry_sourcepath(struct archive_entry *entry)
662{
663	const char *p;
664	if (archive_mstring_get_mbs(
665	    entry->archive, &entry->ae_sourcepath, &p) == 0)
666		return (p);
667	if (errno == ENOMEM)
668		__archive_errx(1, "No memory");
669	return (NULL);
670}
671
672const wchar_t *
673archive_entry_sourcepath_w(struct archive_entry *entry)
674{
675	const wchar_t *p;
676	if (archive_mstring_get_wcs(
677	    entry->archive, &entry->ae_sourcepath, &p) == 0)
678		return (p);
679	return (NULL);
680}
681
682const char *
683archive_entry_symlink(struct archive_entry *entry)
684{
685	const char *p;
686	if ((entry->ae_set & AE_SET_SYMLINK) == 0)
687		return (NULL);
688	if (archive_mstring_get_mbs(
689	    entry->archive, &entry->ae_symlink, &p) == 0)
690		return (p);
691	if (errno == ENOMEM)
692		__archive_errx(1, "No memory");
693	return (NULL);
694}
695
696int
697archive_entry_symlink_type(struct archive_entry *entry)
698{
699	return (entry->ae_symlink_type);
700}
701
702const char *
703archive_entry_symlink_utf8(struct archive_entry *entry)
704{
705	const char *p;
706	if ((entry->ae_set & AE_SET_SYMLINK) == 0)
707		return (NULL);
708	if (archive_mstring_get_utf8(
709	    entry->archive, &entry->ae_symlink, &p) == 0)
710		return (p);
711	if (errno == ENOMEM)
712		__archive_errx(1, "No memory");
713	return (NULL);
714}
715
716const wchar_t *
717archive_entry_symlink_w(struct archive_entry *entry)
718{
719	const wchar_t *p;
720	if ((entry->ae_set & AE_SET_SYMLINK) == 0)
721		return (NULL);
722	if (archive_mstring_get_wcs(
723	    entry->archive, &entry->ae_symlink, &p) == 0)
724		return (p);
725	if (errno == ENOMEM)
726		__archive_errx(1, "No memory");
727	return (NULL);
728}
729
730int
731_archive_entry_symlink_l(struct archive_entry *entry,
732    const char **p, size_t *len, struct archive_string_conv *sc)
733{
734	if ((entry->ae_set & AE_SET_SYMLINK) == 0) {
735		*p = NULL;
736		*len = 0;
737		return (0);
738	}
739	return (archive_mstring_get_mbs_l(entry->archive, &entry->ae_symlink, p, len, sc));
740}
741
742la_int64_t
743archive_entry_uid(struct archive_entry *entry)
744{
745	return (entry->ae_stat.aest_uid);
746}
747
748const char *
749archive_entry_uname(struct archive_entry *entry)
750{
751	const char *p;
752	if (archive_mstring_get_mbs(entry->archive, &entry->ae_uname, &p) == 0)
753		return (p);
754	if (errno == ENOMEM)
755		__archive_errx(1, "No memory");
756	return (NULL);
757}
758
759const char *
760archive_entry_uname_utf8(struct archive_entry *entry)
761{
762	const char *p;
763	if (archive_mstring_get_utf8(entry->archive, &entry->ae_uname, &p) == 0)
764		return (p);
765	if (errno == ENOMEM)
766		__archive_errx(1, "No memory");
767	return (NULL);
768}
769
770const wchar_t *
771archive_entry_uname_w(struct archive_entry *entry)
772{
773	const wchar_t *p;
774	if (archive_mstring_get_wcs(entry->archive, &entry->ae_uname, &p) == 0)
775		return (p);
776	if (errno == ENOMEM)
777		__archive_errx(1, "No memory");
778	return (NULL);
779}
780
781int
782_archive_entry_uname_l(struct archive_entry *entry,
783    const char **p, size_t *len, struct archive_string_conv *sc)
784{
785	return (archive_mstring_get_mbs_l(entry->archive, &entry->ae_uname, p, len, sc));
786}
787
788int
789archive_entry_is_data_encrypted(struct archive_entry *entry)
790{
791	return ((entry->encryption & AE_ENCRYPTION_DATA) == AE_ENCRYPTION_DATA);
792}
793
794int
795archive_entry_is_metadata_encrypted(struct archive_entry *entry)
796{
797	return ((entry->encryption & AE_ENCRYPTION_METADATA) == AE_ENCRYPTION_METADATA);
798}
799
800int
801archive_entry_is_encrypted(struct archive_entry *entry)
802{
803	return (entry->encryption & (AE_ENCRYPTION_DATA|AE_ENCRYPTION_METADATA));
804}
805
806/*
807 * Functions to set archive_entry properties.
808 */
809
810void
811archive_entry_set_filetype(struct archive_entry *entry, unsigned int type)
812{
813	entry->stat_valid = 0;
814	entry->acl.mode &= ~AE_IFMT;
815	entry->acl.mode |= AE_IFMT & type;
816}
817
818void
819archive_entry_set_fflags(struct archive_entry *entry,
820    unsigned long set, unsigned long clear)
821{
822	archive_mstring_clean(&entry->ae_fflags_text);
823	entry->ae_fflags_set = set;
824	entry->ae_fflags_clear = clear;
825}
826
827const char *
828archive_entry_copy_fflags_text(struct archive_entry *entry,
829    const char *flags)
830{
831	archive_mstring_copy_mbs(&entry->ae_fflags_text, flags);
832	return (ae_strtofflags(flags,
833		    &entry->ae_fflags_set, &entry->ae_fflags_clear));
834}
835
836const wchar_t *
837archive_entry_copy_fflags_text_w(struct archive_entry *entry,
838    const wchar_t *flags)
839{
840	archive_mstring_copy_wcs(&entry->ae_fflags_text, flags);
841	return (ae_wcstofflags(flags,
842		    &entry->ae_fflags_set, &entry->ae_fflags_clear));
843}
844
845void
846archive_entry_set_gid(struct archive_entry *entry, la_int64_t g)
847{
848	entry->stat_valid = 0;
849	entry->ae_stat.aest_gid = g;
850}
851
852void
853archive_entry_set_gname(struct archive_entry *entry, const char *name)
854{
855	archive_mstring_copy_mbs(&entry->ae_gname, name);
856}
857
858void
859archive_entry_set_gname_utf8(struct archive_entry *entry, const char *name)
860{
861	archive_mstring_copy_utf8(&entry->ae_gname, name);
862}
863
864void
865archive_entry_copy_gname(struct archive_entry *entry, const char *name)
866{
867	archive_mstring_copy_mbs(&entry->ae_gname, name);
868}
869
870void
871archive_entry_copy_gname_w(struct archive_entry *entry, const wchar_t *name)
872{
873	archive_mstring_copy_wcs(&entry->ae_gname, name);
874}
875
876int
877archive_entry_update_gname_utf8(struct archive_entry *entry, const char *name)
878{
879	if (archive_mstring_update_utf8(entry->archive,
880	    &entry->ae_gname, name) == 0)
881		return (1);
882	if (errno == ENOMEM)
883		__archive_errx(1, "No memory");
884	return (0);
885}
886
887int
888_archive_entry_copy_gname_l(struct archive_entry *entry,
889    const char *name, size_t len, struct archive_string_conv *sc)
890{
891	return (archive_mstring_copy_mbs_len_l(&entry->ae_gname, name, len, sc));
892}
893
894void
895archive_entry_set_ino(struct archive_entry *entry, la_int64_t ino)
896{
897	entry->stat_valid = 0;
898	entry->ae_set |= AE_SET_INO;
899	entry->ae_stat.aest_ino = ino;
900}
901
902void
903archive_entry_set_ino64(struct archive_entry *entry, la_int64_t ino)
904{
905	entry->stat_valid = 0;
906	entry->ae_set |= AE_SET_INO;
907	entry->ae_stat.aest_ino = ino;
908}
909
910void
911archive_entry_set_hardlink(struct archive_entry *entry, const char *target)
912{
913	archive_mstring_copy_mbs(&entry->ae_hardlink, target);
914	if (target != NULL)
915		entry->ae_set |= AE_SET_HARDLINK;
916	else
917		entry->ae_set &= ~AE_SET_HARDLINK;
918}
919
920void
921archive_entry_set_hardlink_utf8(struct archive_entry *entry, const char *target)
922{
923	archive_mstring_copy_utf8(&entry->ae_hardlink, target);
924	if (target != NULL)
925		entry->ae_set |= AE_SET_HARDLINK;
926	else
927		entry->ae_set &= ~AE_SET_HARDLINK;
928}
929
930void
931archive_entry_copy_hardlink(struct archive_entry *entry, const char *target)
932{
933	archive_mstring_copy_mbs(&entry->ae_hardlink, target);
934	if (target != NULL)
935		entry->ae_set |= AE_SET_HARDLINK;
936	else
937		entry->ae_set &= ~AE_SET_HARDLINK;
938}
939
940void
941archive_entry_copy_hardlink_w(struct archive_entry *entry, const wchar_t *target)
942{
943	archive_mstring_copy_wcs(&entry->ae_hardlink, target);
944	if (target != NULL)
945		entry->ae_set |= AE_SET_HARDLINK;
946	else
947		entry->ae_set &= ~AE_SET_HARDLINK;
948}
949
950int
951archive_entry_update_hardlink_utf8(struct archive_entry *entry, const char *target)
952{
953	if (target != NULL)
954		entry->ae_set |= AE_SET_HARDLINK;
955	else
956		entry->ae_set &= ~AE_SET_HARDLINK;
957	if (archive_mstring_update_utf8(entry->archive,
958	    &entry->ae_hardlink, target) == 0)
959		return (1);
960	if (errno == ENOMEM)
961		__archive_errx(1, "No memory");
962	return (0);
963}
964
965int
966_archive_entry_copy_hardlink_l(struct archive_entry *entry,
967    const char *target, size_t len, struct archive_string_conv *sc)
968{
969	int r;
970
971	r = archive_mstring_copy_mbs_len_l(&entry->ae_hardlink,
972	    target, len, sc);
973	if (target != NULL && r == 0)
974		entry->ae_set |= AE_SET_HARDLINK;
975	else
976		entry->ae_set &= ~AE_SET_HARDLINK;
977	return (r);
978}
979
980void
981archive_entry_set_atime(struct archive_entry *entry, time_t t, long ns)
982{
983	FIX_NS(t, ns);
984	entry->stat_valid = 0;
985	entry->ae_set |= AE_SET_ATIME;
986	entry->ae_stat.aest_atime = t;
987	entry->ae_stat.aest_atime_nsec = ns;
988}
989
990void
991archive_entry_unset_atime(struct archive_entry *entry)
992{
993	archive_entry_set_atime(entry, 0, 0);
994	entry->ae_set &= ~AE_SET_ATIME;
995}
996
997void
998archive_entry_set_birthtime(struct archive_entry *entry, time_t t, long ns)
999{
1000	FIX_NS(t, ns);
1001	entry->stat_valid = 0;
1002	entry->ae_set |= AE_SET_BIRTHTIME;
1003	entry->ae_stat.aest_birthtime = t;
1004	entry->ae_stat.aest_birthtime_nsec = ns;
1005}
1006
1007void
1008archive_entry_unset_birthtime(struct archive_entry *entry)
1009{
1010	archive_entry_set_birthtime(entry, 0, 0);
1011	entry->ae_set &= ~AE_SET_BIRTHTIME;
1012}
1013
1014void
1015archive_entry_set_ctime(struct archive_entry *entry, time_t t, long ns)
1016{
1017	FIX_NS(t, ns);
1018	entry->stat_valid = 0;
1019	entry->ae_set |= AE_SET_CTIME;
1020	entry->ae_stat.aest_ctime = t;
1021	entry->ae_stat.aest_ctime_nsec = ns;
1022}
1023
1024void
1025archive_entry_unset_ctime(struct archive_entry *entry)
1026{
1027	archive_entry_set_ctime(entry, 0, 0);
1028	entry->ae_set &= ~AE_SET_CTIME;
1029}
1030
1031void
1032archive_entry_set_dev(struct archive_entry *entry, dev_t d)
1033{
1034	entry->stat_valid = 0;
1035	entry->ae_set |= AE_SET_DEV;
1036	entry->ae_stat.aest_dev_is_broken_down = 0;
1037	entry->ae_stat.aest_dev = d;
1038}
1039
1040void
1041archive_entry_set_devmajor(struct archive_entry *entry, dev_t m)
1042{
1043	entry->stat_valid = 0;
1044	entry->ae_set |= AE_SET_DEV;
1045	entry->ae_stat.aest_dev_is_broken_down = 1;
1046	entry->ae_stat.aest_devmajor = m;
1047}
1048
1049void
1050archive_entry_set_devminor(struct archive_entry *entry, dev_t m)
1051{
1052	entry->stat_valid = 0;
1053	entry->ae_set |= AE_SET_DEV;
1054	entry->ae_stat.aest_dev_is_broken_down = 1;
1055	entry->ae_stat.aest_devminor = m;
1056}
1057
1058/* Set symlink if symlink is already set, else set hardlink. */
1059void
1060archive_entry_set_link(struct archive_entry *entry, const char *target)
1061{
1062	if (entry->ae_set & AE_SET_SYMLINK)
1063		archive_mstring_copy_mbs(&entry->ae_symlink, target);
1064	else
1065		archive_mstring_copy_mbs(&entry->ae_hardlink, target);
1066}
1067
1068void
1069archive_entry_set_link_utf8(struct archive_entry *entry, const char *target)
1070{
1071	if (entry->ae_set & AE_SET_SYMLINK)
1072		archive_mstring_copy_utf8(&entry->ae_symlink, target);
1073	else
1074		archive_mstring_copy_utf8(&entry->ae_hardlink, target);
1075}
1076
1077/* Set symlink if symlink is already set, else set hardlink. */
1078void
1079archive_entry_copy_link(struct archive_entry *entry, const char *target)
1080{
1081	if (entry->ae_set & AE_SET_SYMLINK)
1082		archive_mstring_copy_mbs(&entry->ae_symlink, target);
1083	else
1084		archive_mstring_copy_mbs(&entry->ae_hardlink, target);
1085}
1086
1087/* Set symlink if symlink is already set, else set hardlink. */
1088void
1089archive_entry_copy_link_w(struct archive_entry *entry, const wchar_t *target)
1090{
1091	if (entry->ae_set & AE_SET_SYMLINK)
1092		archive_mstring_copy_wcs(&entry->ae_symlink, target);
1093	else
1094		archive_mstring_copy_wcs(&entry->ae_hardlink, target);
1095}
1096
1097int
1098archive_entry_update_link_utf8(struct archive_entry *entry, const char *target)
1099{
1100	int r;
1101	if (entry->ae_set & AE_SET_SYMLINK)
1102		r = archive_mstring_update_utf8(entry->archive,
1103		    &entry->ae_symlink, target);
1104	else
1105		r = archive_mstring_update_utf8(entry->archive,
1106		    &entry->ae_hardlink, target);
1107	if (r == 0)
1108		return (1);
1109	if (errno == ENOMEM)
1110		__archive_errx(1, "No memory");
1111	return (0);
1112}
1113
1114int
1115_archive_entry_copy_link_l(struct archive_entry *entry,
1116    const char *target, size_t len, struct archive_string_conv *sc)
1117{
1118	int r;
1119
1120	if (entry->ae_set & AE_SET_SYMLINK)
1121		r = archive_mstring_copy_mbs_len_l(&entry->ae_symlink,
1122		    target, len, sc);
1123	else
1124		r = archive_mstring_copy_mbs_len_l(&entry->ae_hardlink,
1125		    target, len, sc);
1126	return (r);
1127}
1128
1129void
1130archive_entry_set_mode(struct archive_entry *entry, mode_t m)
1131{
1132	entry->stat_valid = 0;
1133	entry->acl.mode = m;
1134}
1135
1136void
1137archive_entry_set_mtime(struct archive_entry *entry, time_t t, long ns)
1138{
1139	FIX_NS(t, ns);
1140	entry->stat_valid = 0;
1141	entry->ae_set |= AE_SET_MTIME;
1142	entry->ae_stat.aest_mtime = t;
1143	entry->ae_stat.aest_mtime_nsec = ns;
1144}
1145
1146void
1147archive_entry_unset_mtime(struct archive_entry *entry)
1148{
1149	archive_entry_set_mtime(entry, 0, 0);
1150	entry->ae_set &= ~AE_SET_MTIME;
1151}
1152
1153void
1154archive_entry_set_nlink(struct archive_entry *entry, unsigned int nlink)
1155{
1156	entry->stat_valid = 0;
1157	entry->ae_stat.aest_nlink = nlink;
1158}
1159
1160void
1161archive_entry_set_pathname(struct archive_entry *entry, const char *name)
1162{
1163	archive_mstring_copy_mbs(&entry->ae_pathname, name);
1164}
1165
1166void
1167archive_entry_set_pathname_utf8(struct archive_entry *entry, const char *name)
1168{
1169	archive_mstring_copy_utf8(&entry->ae_pathname, name);
1170}
1171
1172void
1173archive_entry_copy_pathname(struct archive_entry *entry, const char *name)
1174{
1175	archive_mstring_copy_mbs(&entry->ae_pathname, name);
1176}
1177
1178void
1179archive_entry_copy_pathname_w(struct archive_entry *entry, const wchar_t *name)
1180{
1181	archive_mstring_copy_wcs(&entry->ae_pathname, name);
1182}
1183
1184int
1185archive_entry_update_pathname_utf8(struct archive_entry *entry, const char *name)
1186{
1187	if (archive_mstring_update_utf8(entry->archive,
1188	    &entry->ae_pathname, name) == 0)
1189		return (1);
1190	if (errno == ENOMEM)
1191		__archive_errx(1, "No memory");
1192	return (0);
1193}
1194
1195int
1196_archive_entry_copy_pathname_l(struct archive_entry *entry,
1197    const char *name, size_t len, struct archive_string_conv *sc)
1198{
1199	return (archive_mstring_copy_mbs_len_l(&entry->ae_pathname,
1200	    name, len, sc));
1201}
1202
1203void
1204archive_entry_set_perm(struct archive_entry *entry, mode_t p)
1205{
1206	entry->stat_valid = 0;
1207	entry->acl.mode &= AE_IFMT;
1208	entry->acl.mode |= ~AE_IFMT & p;
1209}
1210
1211void
1212archive_entry_set_rdev(struct archive_entry *entry, dev_t m)
1213{
1214	entry->stat_valid = 0;
1215	entry->ae_stat.aest_rdev = m;
1216	entry->ae_stat.aest_rdev_is_broken_down = 0;
1217}
1218
1219void
1220archive_entry_set_rdevmajor(struct archive_entry *entry, dev_t m)
1221{
1222	entry->stat_valid = 0;
1223	entry->ae_stat.aest_rdev_is_broken_down = 1;
1224	entry->ae_stat.aest_rdevmajor = m;
1225}
1226
1227void
1228archive_entry_set_rdevminor(struct archive_entry *entry, dev_t m)
1229{
1230	entry->stat_valid = 0;
1231	entry->ae_stat.aest_rdev_is_broken_down = 1;
1232	entry->ae_stat.aest_rdevminor = m;
1233}
1234
1235void
1236archive_entry_set_size(struct archive_entry *entry, la_int64_t s)
1237{
1238	entry->stat_valid = 0;
1239	entry->ae_stat.aest_size = s;
1240	entry->ae_set |= AE_SET_SIZE;
1241}
1242
1243void
1244archive_entry_unset_size(struct archive_entry *entry)
1245{
1246	archive_entry_set_size(entry, 0);
1247	entry->ae_set &= ~AE_SET_SIZE;
1248}
1249
1250void
1251archive_entry_copy_sourcepath(struct archive_entry *entry, const char *path)
1252{
1253	archive_mstring_copy_mbs(&entry->ae_sourcepath, path);
1254}
1255
1256void
1257archive_entry_copy_sourcepath_w(struct archive_entry *entry, const wchar_t *path)
1258{
1259	archive_mstring_copy_wcs(&entry->ae_sourcepath, path);
1260}
1261
1262void
1263archive_entry_set_symlink(struct archive_entry *entry, const char *linkname)
1264{
1265	archive_mstring_copy_mbs(&entry->ae_symlink, linkname);
1266	if (linkname != NULL)
1267		entry->ae_set |= AE_SET_SYMLINK;
1268	else
1269		entry->ae_set &= ~AE_SET_SYMLINK;
1270}
1271
1272void
1273archive_entry_set_symlink_type(struct archive_entry *entry, int type)
1274{
1275	entry->ae_symlink_type = type;
1276}
1277
1278void
1279archive_entry_set_symlink_utf8(struct archive_entry *entry, const char *linkname)
1280{
1281	archive_mstring_copy_utf8(&entry->ae_symlink, linkname);
1282	if (linkname != NULL)
1283		entry->ae_set |= AE_SET_SYMLINK;
1284	else
1285		entry->ae_set &= ~AE_SET_SYMLINK;
1286}
1287
1288void
1289archive_entry_copy_symlink(struct archive_entry *entry, const char *linkname)
1290{
1291	archive_mstring_copy_mbs(&entry->ae_symlink, linkname);
1292	if (linkname != NULL)
1293		entry->ae_set |= AE_SET_SYMLINK;
1294	else
1295		entry->ae_set &= ~AE_SET_SYMLINK;
1296}
1297
1298void
1299archive_entry_copy_symlink_w(struct archive_entry *entry, const wchar_t *linkname)
1300{
1301	archive_mstring_copy_wcs(&entry->ae_symlink, linkname);
1302	if (linkname != NULL)
1303		entry->ae_set |= AE_SET_SYMLINK;
1304	else
1305		entry->ae_set &= ~AE_SET_SYMLINK;
1306}
1307
1308int
1309archive_entry_update_symlink_utf8(struct archive_entry *entry, const char *linkname)
1310{
1311	if (linkname != NULL)
1312		entry->ae_set |= AE_SET_SYMLINK;
1313	else
1314		entry->ae_set &= ~AE_SET_SYMLINK;
1315	if (archive_mstring_update_utf8(entry->archive,
1316	    &entry->ae_symlink, linkname) == 0)
1317		return (1);
1318	if (errno == ENOMEM)
1319		__archive_errx(1, "No memory");
1320	return (0);
1321}
1322
1323int
1324_archive_entry_copy_symlink_l(struct archive_entry *entry,
1325    const char *linkname, size_t len, struct archive_string_conv *sc)
1326{
1327	int r;
1328
1329	r = archive_mstring_copy_mbs_len_l(&entry->ae_symlink,
1330	    linkname, len, sc);
1331	if (linkname != NULL && r == 0)
1332		entry->ae_set |= AE_SET_SYMLINK;
1333	else
1334		entry->ae_set &= ~AE_SET_SYMLINK;
1335	return (r);
1336}
1337
1338void
1339archive_entry_set_uid(struct archive_entry *entry, la_int64_t u)
1340{
1341	entry->stat_valid = 0;
1342	entry->ae_stat.aest_uid = u;
1343}
1344
1345void
1346archive_entry_set_uname(struct archive_entry *entry, const char *name)
1347{
1348	archive_mstring_copy_mbs(&entry->ae_uname, name);
1349}
1350
1351void
1352archive_entry_set_uname_utf8(struct archive_entry *entry, const char *name)
1353{
1354	archive_mstring_copy_utf8(&entry->ae_uname, name);
1355}
1356
1357void
1358archive_entry_copy_uname(struct archive_entry *entry, const char *name)
1359{
1360	archive_mstring_copy_mbs(&entry->ae_uname, name);
1361}
1362
1363void
1364archive_entry_copy_uname_w(struct archive_entry *entry, const wchar_t *name)
1365{
1366	archive_mstring_copy_wcs(&entry->ae_uname, name);
1367}
1368
1369int
1370archive_entry_update_uname_utf8(struct archive_entry *entry, const char *name)
1371{
1372	if (archive_mstring_update_utf8(entry->archive,
1373	    &entry->ae_uname, name) == 0)
1374		return (1);
1375	if (errno == ENOMEM)
1376		__archive_errx(1, "No memory");
1377	return (0);
1378}
1379
1380void
1381archive_entry_set_is_data_encrypted(struct archive_entry *entry, char is_encrypted)
1382{
1383	if (is_encrypted) {
1384		entry->encryption |= AE_ENCRYPTION_DATA;
1385	} else {
1386		entry->encryption &= ~AE_ENCRYPTION_DATA;
1387	}
1388}
1389
1390void
1391archive_entry_set_is_metadata_encrypted(struct archive_entry *entry, char is_encrypted)
1392{
1393	if (is_encrypted) {
1394		entry->encryption |= AE_ENCRYPTION_METADATA;
1395	} else {
1396		entry->encryption &= ~AE_ENCRYPTION_METADATA;
1397	}
1398}
1399
1400int
1401_archive_entry_copy_uname_l(struct archive_entry *entry,
1402    const char *name, size_t len, struct archive_string_conv *sc)
1403{
1404	return (archive_mstring_copy_mbs_len_l(&entry->ae_uname,
1405	    name, len, sc));
1406}
1407
1408const void *
1409archive_entry_mac_metadata(struct archive_entry *entry, size_t *s)
1410{
1411  *s = entry->mac_metadata_size;
1412  return entry->mac_metadata;
1413}
1414
1415void
1416archive_entry_copy_mac_metadata(struct archive_entry *entry,
1417    const void *p, size_t s)
1418{
1419  free(entry->mac_metadata);
1420  if (p == NULL || s == 0) {
1421    entry->mac_metadata = NULL;
1422    entry->mac_metadata_size = 0;
1423  } else {
1424    entry->mac_metadata_size = s;
1425    entry->mac_metadata = malloc(s);
1426    if (entry->mac_metadata == NULL)
1427      abort();
1428    memcpy(entry->mac_metadata, p, s);
1429  }
1430}
1431
1432/* Digest handling */
1433const unsigned char *
1434archive_entry_digest(struct archive_entry *entry, int type)
1435{
1436	switch (type) {
1437	case ARCHIVE_ENTRY_DIGEST_MD5:
1438		return entry->digest.md5;
1439	case ARCHIVE_ENTRY_DIGEST_RMD160:
1440		return entry->digest.rmd160;
1441	case ARCHIVE_ENTRY_DIGEST_SHA1:
1442		return entry->digest.sha1;
1443	case ARCHIVE_ENTRY_DIGEST_SHA256:
1444		return entry->digest.sha256;
1445	case ARCHIVE_ENTRY_DIGEST_SHA384:
1446		return entry->digest.sha384;
1447	case ARCHIVE_ENTRY_DIGEST_SHA512:
1448		return entry->digest.sha512;
1449	default:
1450		return NULL;
1451	}
1452}
1453
1454int
1455archive_entry_set_digest(struct archive_entry *entry, int type,
1456    const unsigned char *digest)
1457{
1458#define copy_digest(_e, _t, _d)\
1459	memcpy(_e->digest._t, _d, sizeof(_e->digest._t))
1460
1461	switch (type) {
1462	case ARCHIVE_ENTRY_DIGEST_MD5:
1463		copy_digest(entry, md5, digest);
1464		break;
1465	case ARCHIVE_ENTRY_DIGEST_RMD160:
1466		copy_digest(entry, rmd160, digest);
1467		break;
1468	case ARCHIVE_ENTRY_DIGEST_SHA1:
1469		copy_digest(entry, sha1, digest);
1470		break;
1471	case ARCHIVE_ENTRY_DIGEST_SHA256:
1472		copy_digest(entry, sha256, digest);
1473		break;
1474	case ARCHIVE_ENTRY_DIGEST_SHA384:
1475		copy_digest(entry, sha384, digest);
1476		break;
1477	case ARCHIVE_ENTRY_DIGEST_SHA512:
1478		copy_digest(entry, sha512, digest);
1479		break;
1480	default:
1481		return ARCHIVE_WARN;
1482	}
1483
1484	return ARCHIVE_OK;
1485#undef copy_digest
1486}
1487
1488/*
1489 * ACL management.  The following would, of course, be a lot simpler
1490 * if: 1) the last draft of POSIX.1e were a really thorough and
1491 * complete standard that addressed the needs of ACL archiving and 2)
1492 * everyone followed it faithfully.  Alas, neither is true, so the
1493 * following is a lot more complex than might seem necessary to the
1494 * uninitiated.
1495 */
1496
1497struct archive_acl *
1498archive_entry_acl(struct archive_entry *entry)
1499{
1500	return &entry->acl;
1501}
1502
1503void
1504archive_entry_acl_clear(struct archive_entry *entry)
1505{
1506	archive_acl_clear(&entry->acl);
1507}
1508
1509/*
1510 * Add a single ACL entry to the internal list of ACL data.
1511 */
1512int
1513archive_entry_acl_add_entry(struct archive_entry *entry,
1514    int type, int permset, int tag, int id, const char *name)
1515{
1516	return archive_acl_add_entry(&entry->acl, type, permset, tag, id, name);
1517}
1518
1519/*
1520 * As above, but with a wide-character name.
1521 */
1522int
1523archive_entry_acl_add_entry_w(struct archive_entry *entry,
1524    int type, int permset, int tag, int id, const wchar_t *name)
1525{
1526	return archive_acl_add_entry_w_len(&entry->acl,
1527	    type, permset, tag, id, name, wcslen(name));
1528}
1529
1530/*
1531 * Return a bitmask of ACL types in an archive entry ACL list
1532 */
1533int
1534archive_entry_acl_types(struct archive_entry *entry)
1535{
1536	return (archive_acl_types(&entry->acl));
1537}
1538
1539/*
1540 * Return a count of entries matching "want_type".
1541 */
1542int
1543archive_entry_acl_count(struct archive_entry *entry, int want_type)
1544{
1545	return archive_acl_count(&entry->acl, want_type);
1546}
1547
1548/*
1549 * Prepare for reading entries from the ACL data.  Returns a count
1550 * of entries matching "want_type", or zero if there are no
1551 * non-extended ACL entries of that type.
1552 */
1553int
1554archive_entry_acl_reset(struct archive_entry *entry, int want_type)
1555{
1556	return archive_acl_reset(&entry->acl, want_type);
1557}
1558
1559/*
1560 * Return the next ACL entry in the list.  Fake entries for the
1561 * standard permissions and include them in the returned list.
1562 */
1563int
1564archive_entry_acl_next(struct archive_entry *entry, int want_type, int *type,
1565    int *permset, int *tag, int *id, const char **name)
1566{
1567	int r;
1568	r = archive_acl_next(entry->archive, &entry->acl, want_type, type,
1569		permset, tag, id, name);
1570	if (r == ARCHIVE_FATAL && errno == ENOMEM)
1571		__archive_errx(1, "No memory");
1572	return (r);
1573}
1574
1575/*
1576 * Generate a text version of the ACL. The flags parameter controls
1577 * the style of the generated ACL.
1578 */
1579wchar_t *
1580archive_entry_acl_to_text_w(struct archive_entry *entry, la_ssize_t *len,
1581    int flags)
1582{
1583	return (archive_acl_to_text_w(&entry->acl, len, flags,
1584	    entry->archive));
1585}
1586
1587char *
1588archive_entry_acl_to_text(struct archive_entry *entry, la_ssize_t *len,
1589    int flags)
1590{
1591	return (archive_acl_to_text_l(&entry->acl, len, flags, NULL));
1592}
1593
1594char *
1595_archive_entry_acl_to_text_l(struct archive_entry *entry, ssize_t *len,
1596   int flags, struct archive_string_conv *sc)
1597{
1598	return (archive_acl_to_text_l(&entry->acl, len, flags, sc));
1599}
1600
1601/*
1602 * ACL text parser.
1603 */
1604int
1605archive_entry_acl_from_text_w(struct archive_entry *entry,
1606    const wchar_t *wtext, int type)
1607{
1608	return (archive_acl_from_text_w(&entry->acl, wtext, type));
1609}
1610
1611int
1612archive_entry_acl_from_text(struct archive_entry *entry,
1613    const char *text, int type)
1614{
1615	return (archive_acl_from_text_l(&entry->acl, text, type, NULL));
1616}
1617
1618int
1619_archive_entry_acl_from_text_l(struct archive_entry *entry, const char *text,
1620    int type, struct archive_string_conv *sc)
1621{
1622	return (archive_acl_from_text_l(&entry->acl, text, type, sc));
1623}
1624
1625/* Deprecated */
1626static int
1627archive_entry_acl_text_compat(int *flags)
1628{
1629	if ((*flags & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) == 0)
1630		return (1);
1631
1632	/* ABI compat with old ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID */
1633	if ((*flags & OLD_ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID) != 0)
1634		*flags |= ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID;
1635
1636	/* ABI compat with old ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT */
1637	if ((*flags & OLD_ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT) != 0)
1638		*flags |=  ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT;
1639
1640	*flags |= ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA;
1641
1642	return (0);
1643}
1644
1645/* Deprecated */
1646const wchar_t *
1647archive_entry_acl_text_w(struct archive_entry *entry, int flags)
1648{
1649	free(entry->acl.acl_text_w);
1650	entry->acl.acl_text_w = NULL;
1651	if (archive_entry_acl_text_compat(&flags) == 0)
1652		entry->acl.acl_text_w = archive_acl_to_text_w(&entry->acl,
1653		    NULL, flags, entry->archive);
1654	return (entry->acl.acl_text_w);
1655}
1656
1657/* Deprecated */
1658const char *
1659archive_entry_acl_text(struct archive_entry *entry, int flags)
1660{
1661	free(entry->acl.acl_text);
1662	entry->acl.acl_text = NULL;
1663	if (archive_entry_acl_text_compat(&flags) == 0)
1664		entry->acl.acl_text = archive_acl_to_text_l(&entry->acl, NULL,
1665		    flags, NULL);
1666
1667	return (entry->acl.acl_text);
1668}
1669
1670/* Deprecated */
1671int
1672_archive_entry_acl_text_l(struct archive_entry *entry, int flags,
1673    const char **acl_text, size_t *len, struct archive_string_conv *sc)
1674{
1675	free(entry->acl.acl_text);
1676	entry->acl.acl_text = NULL;
1677
1678	if (archive_entry_acl_text_compat(&flags) == 0)
1679		entry->acl.acl_text = archive_acl_to_text_l(&entry->acl,
1680		    (ssize_t *)len, flags, sc);
1681
1682	*acl_text = entry->acl.acl_text;
1683
1684	return (0);
1685}
1686
1687/*
1688 * Following code is modified from UC Berkeley sources, and
1689 * is subject to the following copyright notice.
1690 */
1691
1692/*-
1693 * Copyright (c) 1993
1694 *	The Regents of the University of California.  All rights reserved.
1695 *
1696 * Redistribution and use in source and binary forms, with or without
1697 * modification, are permitted provided that the following conditions
1698 * are met:
1699 * 1. Redistributions of source code must retain the above copyright
1700 *    notice, this list of conditions and the following disclaimer.
1701 * 2. Redistributions in binary form must reproduce the above copyright
1702 *    notice, this list of conditions and the following disclaimer in the
1703 *    documentation and/or other materials provided with the distribution.
1704 * 4. Neither the name of the University nor the names of its contributors
1705 *    may be used to endorse or promote products derived from this software
1706 *    without specific prior written permission.
1707 *
1708 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
1709 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1710 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1711 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
1712 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1713 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
1714 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
1715 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
1716 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
1717 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
1718 * SUCH DAMAGE.
1719 */
1720
1721/*
1722 * Supported file flags on FreeBSD and Mac OS:
1723 * sappnd,sappend		SF_APPEND
1724 * arch,archived		SF_ARCHIVED
1725 * schg,schange,simmutable	SF_IMMUTABLE
1726 * sunlnk,sunlink		SF_NOUNLINK	(FreeBSD only)
1727 * uappnd,uappend		UF_APPEND
1728 * compressed			UF_COMPRESSED	(Mac OS only)
1729 * hidden,uhidden		UF_HIDDEN
1730 * uchg,uchange,uimmutable	UF_IMMUTABLE
1731 * nodump			UF_NODUMP
1732 * uunlnk,uunlink		UF_NOUNLINK	(FreeBSD only)
1733 * offline,uoffline		UF_OFFLINE	(FreeBSD only)
1734 * opaque			UF_OPAQUE
1735 * rdonly,urdonly,readonly	UF_READONLY	(FreeBSD only)
1736 * reparse,ureparse		UF_REPARSE	(FreeBSD only)
1737 * sparse,usparse		UF_SPARSE	(FreeBSD only)
1738 * system,usystem		UF_SYSTEM	(FreeBSD only)
1739 *
1740 * See chflags(2) for more information
1741 *
1742 * Supported file attributes on Linux:
1743 * a	append only			FS_APPEND_FL		sappnd
1744 * A	no atime updates		FS_NOATIME_FL		atime
1745 * c	compress			FS_COMPR_FL		compress
1746 * C	no copy on write		FS_NOCOW_FL		cow
1747 * d	no dump				FS_NODUMP_FL		dump
1748 * D	synchronous directory updates	FS_DIRSYNC_FL		dirsync
1749 * i	immutable			FS_IMMUTABLE_FL		schg
1750 * j	data journalling		FS_JOURNAL_DATA_FL	journal
1751 * P	project hierarchy		FS_PROJINHERIT_FL	projinherit
1752 * s	secure deletion			FS_SECRM_FL		securedeletion
1753 * S	synchronous updates		FS_SYNC_FL		sync
1754 * t	no tail-merging			FS_NOTAIL_FL		tail
1755 * T	top of directory hierarchy	FS_TOPDIR_FL		topdir
1756 * u	undeletable			FS_UNRM_FL		undel
1757 *
1758 * See ioctl_iflags(2) for more information
1759 *
1760 * Equivalent file flags supported on FreeBSD / Mac OS and Linux:
1761 * SF_APPEND		FS_APPEND_FL		sappnd
1762 * SF_IMMUTABLE		FS_IMMUTABLE_FL		schg
1763 * UF_NODUMP		FS_NODUMP_FL		nodump
1764 */
1765
1766static const struct flag {
1767	const char	*name;
1768	const wchar_t	*wname;
1769	unsigned long	 set;
1770	unsigned long	 clear;
1771} fileflags[] = {
1772	/* Preferred (shorter) names per flag first, all prefixed by "no" */
1773#ifdef SF_APPEND
1774	{ "nosappnd",	L"nosappnd",		SF_APPEND,	0},
1775	{ "nosappend",	L"nosappend",		SF_APPEND,	0},
1776#endif
1777#if defined(FS_APPEND_FL)			/* 'a' */
1778	{ "nosappnd",	L"nosappnd",		FS_APPEND_FL,	0},
1779	{ "nosappend",	L"nosappend",		FS_APPEND_FL,	0},
1780#elif defined(EXT2_APPEND_FL)			/* 'a' */
1781	{ "nosappnd",	L"nosappnd",		EXT2_APPEND_FL,	0},
1782	{ "nosappend",	L"nosappend",		EXT2_APPEND_FL,	0},
1783#endif
1784#ifdef SF_ARCHIVED
1785	{ "noarch",	L"noarch",		SF_ARCHIVED,	0},
1786	{ "noarchived",	L"noarchived",       	SF_ARCHIVED,	0},
1787#endif
1788#ifdef SF_IMMUTABLE
1789	{ "noschg",	L"noschg",		SF_IMMUTABLE,	0},
1790	{ "noschange",	L"noschange",		SF_IMMUTABLE,	0},
1791	{ "nosimmutable",	L"nosimmutable",	SF_IMMUTABLE,	0},
1792#endif
1793#if defined(FS_IMMUTABLE_FL)			/* 'i' */
1794	{ "noschg",	L"noschg",		FS_IMMUTABLE_FL,	0},
1795	{ "noschange",	L"noschange",		FS_IMMUTABLE_FL,	0},
1796	{ "nosimmutable",	L"nosimmutable",	FS_IMMUTABLE_FL,	0},
1797#elif defined(EXT2_IMMUTABLE_FL)		/* 'i' */
1798	{ "noschg",	L"noschg",		EXT2_IMMUTABLE_FL,	0},
1799	{ "noschange",	L"noschange",		EXT2_IMMUTABLE_FL,	0},
1800	{ "nosimmutable",	L"nosimmutable",	EXT2_IMMUTABLE_FL,	0},
1801#endif
1802#ifdef SF_NOUNLINK
1803	{ "nosunlnk",	L"nosunlnk",		SF_NOUNLINK,	0},
1804	{ "nosunlink",	L"nosunlink",		SF_NOUNLINK,	0},
1805#endif
1806#ifdef UF_APPEND
1807	{ "nouappnd",	L"nouappnd",		UF_APPEND,	0},
1808	{ "nouappend",	L"nouappend",		UF_APPEND,	0},
1809#endif
1810#ifdef UF_IMMUTABLE
1811	{ "nouchg",	L"nouchg",		UF_IMMUTABLE,	0},
1812	{ "nouchange",	L"nouchange",		UF_IMMUTABLE,	0},
1813	{ "nouimmutable",	L"nouimmutable",	UF_IMMUTABLE,	0},
1814#endif
1815#ifdef UF_NODUMP
1816	{ "nodump",	L"nodump",		0,		UF_NODUMP},
1817#endif
1818#if defined(FS_NODUMP_FL)	/* 'd' */
1819	{ "nodump",	L"nodump",		0,		FS_NODUMP_FL},
1820#elif defined(EXT2_NODUMP_FL)
1821	{ "nodump",	L"nodump",		0,		EXT2_NODUMP_FL},
1822#endif
1823#ifdef UF_OPAQUE
1824	{ "noopaque",	L"noopaque",		UF_OPAQUE,	0},
1825#endif
1826#ifdef UF_NOUNLINK
1827	{ "nouunlnk",	L"nouunlnk",		UF_NOUNLINK,	0},
1828	{ "nouunlink",	L"nouunlink",		UF_NOUNLINK,	0},
1829#endif
1830#ifdef UF_COMPRESSED
1831	/* Mac OS */
1832	{ "nocompressed",	L"nocompressed",	UF_COMPRESSED,	0},
1833#endif
1834#ifdef UF_HIDDEN
1835	{ "nohidden",	L"nohidden",		UF_HIDDEN,	0},
1836	{ "nouhidden",	L"nouhidden",		UF_HIDDEN,	0},
1837#endif
1838#ifdef FILE_ATTRIBUTE_HIDDEN
1839	{ "nohidden",	L"nohidden",	FILE_ATTRIBUTE_HIDDEN,	0},
1840	{ "nouhidden",	L"nouhidden",	FILE_ATTRIBUTE_HIDDEN,	0},
1841#endif
1842#ifdef UF_OFFLINE
1843	{ "nooffline",	L"nooffline",		UF_OFFLINE,	0},
1844	{ "nouoffline",	L"nouoffline",		UF_OFFLINE,	0},
1845#endif
1846#ifdef UF_READONLY
1847	{ "nordonly",	L"nordonly",		UF_READONLY,	0},
1848	{ "nourdonly",	L"nourdonly",		UF_READONLY,	0},
1849	{ "noreadonly",	L"noreadonly",		UF_READONLY,	0},
1850#endif
1851#ifdef FILE_ATTRIBUTE_READONLY
1852	{ "nordonly",	L"nordonly",	FILE_ATTRIBUTE_READONLY,	0},
1853	{ "nourdonly",	L"nourdonly",	FILE_ATTRIBUTE_READONLY,	0},
1854	{ "noreadonly",	L"noreadonly",	FILE_ATTRIBUTE_READONLY,	0},
1855#endif
1856#ifdef UF_SPARSE
1857	{ "nosparse",	L"nosparse",		UF_SPARSE,	0},
1858	{ "nousparse",	L"nousparse",		UF_SPARSE,	0},
1859#endif
1860#ifdef UF_REPARSE
1861	{ "noreparse",	L"noreparse",		UF_REPARSE,	0},
1862	{ "noureparse",	L"noureparse",		UF_REPARSE,	0},
1863#endif
1864#ifdef UF_SYSTEM
1865	{ "nosystem",	L"nosystem",		UF_SYSTEM,	0},
1866	{ "nousystem",	L"nousystem",		UF_SYSTEM,	0},
1867#endif
1868#ifdef FILE_ATTRIBUTE_SYSTEM
1869	{ "nosystem",	L"nosystem",	FILE_ATTRIBUTE_SYSTEM,	0},
1870	{ "nousystem",	L"nousystem",	FILE_ATTRIBUTE_SYSTEM,	0},
1871#endif
1872#if defined(FS_UNRM_FL)		/* 'u' */
1873	{ "noundel",	L"noundel",		FS_UNRM_FL,	0},
1874#elif defined(EXT2_UNRM_FL)
1875	{ "noundel",	L"noundel",		EXT2_UNRM_FL,	0},
1876#endif
1877
1878#if defined(FS_COMPR_FL)	/* 'c' */
1879	{ "nocompress",	L"nocompress",       	FS_COMPR_FL,	0},
1880#elif defined(EXT2_COMPR_FL)
1881	{ "nocompress",	L"nocompress",       	EXT2_COMPR_FL,	0},
1882#endif
1883
1884#if defined(FS_NOATIME_FL)	/* 'A' */
1885	{ "noatime",	L"noatime",		0,		FS_NOATIME_FL},
1886#elif defined(EXT2_NOATIME_FL)
1887	{ "noatime",	L"noatime",		0,		EXT2_NOATIME_FL},
1888#endif
1889#if defined(FS_DIRSYNC_FL)	/* 'D' */
1890	{ "nodirsync",	L"nodirsync",		FS_DIRSYNC_FL,		0},
1891#elif defined(EXT2_DIRSYNC_FL)
1892	{ "nodirsync",	L"nodirsync",		EXT2_DIRSYNC_FL,	0},
1893#endif
1894#if defined(FS_JOURNAL_DATA_FL)	/* 'j' */
1895	{ "nojournal-data",L"nojournal-data",	FS_JOURNAL_DATA_FL,	0},
1896	{ "nojournal",	L"nojournal",		FS_JOURNAL_DATA_FL,	0},
1897#elif defined(EXT3_JOURNAL_DATA_FL)
1898	{ "nojournal-data",L"nojournal-data",	EXT3_JOURNAL_DATA_FL,	0},
1899	{ "nojournal",	L"nojournal",		EXT3_JOURNAL_DATA_FL,	0},
1900#endif
1901#if defined(FS_SECRM_FL)	/* 's' */
1902	{ "nosecdel",	L"nosecdel",		FS_SECRM_FL,		0},
1903	{ "nosecuredeletion",L"nosecuredeletion",FS_SECRM_FL,		0},
1904#elif defined(EXT2_SECRM_FL)
1905	{ "nosecdel",	L"nosecdel",		EXT2_SECRM_FL,		0},
1906	{ "nosecuredeletion",L"nosecuredeletion",EXT2_SECRM_FL,		0},
1907#endif
1908#if defined(FS_SYNC_FL)		/* 'S' */
1909	{ "nosync",	L"nosync",		FS_SYNC_FL,		0},
1910#elif defined(EXT2_SYNC_FL)
1911	{ "nosync",	L"nosync",		EXT2_SYNC_FL,		0},
1912#endif
1913#if defined(FS_NOTAIL_FL)	/* 't' */
1914	{ "notail",	L"notail",		0,		FS_NOTAIL_FL},
1915#elif defined(EXT2_NOTAIL_FL)
1916	{ "notail",	L"notail",		0,		EXT2_NOTAIL_FL},
1917#endif
1918#if defined(FS_TOPDIR_FL)	/* 'T' */
1919	{ "notopdir",	L"notopdir",		FS_TOPDIR_FL,		0},
1920#elif defined(EXT2_TOPDIR_FL)
1921	{ "notopdir",	L"notopdir",		EXT2_TOPDIR_FL,		0},
1922#endif
1923#ifdef FS_NOCOW_FL	/* 'C' */
1924	{ "nocow",	L"nocow",		0,	FS_NOCOW_FL},
1925#endif
1926#ifdef FS_PROJINHERIT_FL	/* 'P' */
1927	{ "noprojinherit",L"noprojinherit",	FS_PROJINHERIT_FL,	0},
1928#endif
1929	{ NULL,		NULL,			0,		0}
1930};
1931
1932/*
1933 * fflagstostr --
1934 *	Convert file flags to a comma-separated string.  If no flags
1935 *	are set, return the empty string.
1936 */
1937static char *
1938ae_fflagstostr(unsigned long bitset, unsigned long bitclear)
1939{
1940	char *string, *dp;
1941	const char *sp;
1942	unsigned long bits;
1943	const struct flag *flag;
1944	size_t	length;
1945
1946	bits = bitset | bitclear;
1947	length = 0;
1948	for (flag = fileflags; flag->name != NULL; flag++)
1949		if (bits & (flag->set | flag->clear)) {
1950			length += strlen(flag->name) + 1;
1951			bits &= ~(flag->set | flag->clear);
1952		}
1953
1954	if (length == 0)
1955		return (NULL);
1956	string = (char *)malloc(length);
1957	if (string == NULL)
1958		return (NULL);
1959
1960	dp = string;
1961	for (flag = fileflags; flag->name != NULL; flag++) {
1962		if (bitset & flag->set || bitclear & flag->clear) {
1963			sp = flag->name + 2;
1964		} else if (bitset & flag->clear  ||  bitclear & flag->set) {
1965			sp = flag->name;
1966		} else
1967			continue;
1968		bitset &= ~(flag->set | flag->clear);
1969		bitclear &= ~(flag->set | flag->clear);
1970		if (dp > string)
1971			*dp++ = ',';
1972		while ((*dp++ = *sp++) != '\0')
1973			;
1974		dp--;
1975	}
1976
1977	*dp = '\0';
1978	return (string);
1979}
1980
1981/*
1982 * strtofflags --
1983 *	Take string of arguments and return file flags.  This
1984 *	version works a little differently than strtofflags(3).
1985 *	In particular, it always tests every token, skipping any
1986 *	unrecognized tokens.  It returns a pointer to the first
1987 *	unrecognized token, or NULL if every token was recognized.
1988 *	This version is also const-correct and does not modify the
1989 *	provided string.
1990 */
1991static const char *
1992ae_strtofflags(const char *s, unsigned long *setp, unsigned long *clrp)
1993{
1994	const char *start, *end;
1995	const struct flag *flag;
1996	unsigned long set, clear;
1997	const char *failed;
1998
1999	set = clear = 0;
2000	start = s;
2001	failed = NULL;
2002	/* Find start of first token. */
2003	while (*start == '\t'  ||  *start == ' '  ||  *start == ',')
2004		start++;
2005	while (*start != '\0') {
2006		size_t length;
2007		/* Locate end of token. */
2008		end = start;
2009		while (*end != '\0'  &&  *end != '\t'  &&
2010		    *end != ' '  &&  *end != ',')
2011			end++;
2012		length = end - start;
2013		for (flag = fileflags; flag->name != NULL; flag++) {
2014			size_t flag_length = strlen(flag->name);
2015			if (length == flag_length
2016			    && memcmp(start, flag->name, length) == 0) {
2017				/* Matched "noXXXX", so reverse the sense. */
2018				clear |= flag->set;
2019				set |= flag->clear;
2020				break;
2021			} else if (length == flag_length - 2
2022			    && memcmp(start, flag->name + 2, length) == 0) {
2023				/* Matched "XXXX", so don't reverse. */
2024				set |= flag->set;
2025				clear |= flag->clear;
2026				break;
2027			}
2028		}
2029		/* Ignore unknown flag names. */
2030		if (flag->name == NULL  &&  failed == NULL)
2031			failed = start;
2032
2033		/* Find start of next token. */
2034		start = end;
2035		while (*start == '\t'  ||  *start == ' '  ||  *start == ',')
2036			start++;
2037
2038	}
2039
2040	if (setp)
2041		*setp = set;
2042	if (clrp)
2043		*clrp = clear;
2044
2045	/* Return location of first failure. */
2046	return (failed);
2047}
2048
2049/*
2050 * wcstofflags --
2051 *	Take string of arguments and return file flags.  This
2052 *	version works a little differently than strtofflags(3).
2053 *	In particular, it always tests every token, skipping any
2054 *	unrecognized tokens.  It returns a pointer to the first
2055 *	unrecognized token, or NULL if every token was recognized.
2056 *	This version is also const-correct and does not modify the
2057 *	provided string.
2058 */
2059static const wchar_t *
2060ae_wcstofflags(const wchar_t *s, unsigned long *setp, unsigned long *clrp)
2061{
2062	const wchar_t *start, *end;
2063	const struct flag *flag;
2064	unsigned long set, clear;
2065	const wchar_t *failed;
2066
2067	set = clear = 0;
2068	start = s;
2069	failed = NULL;
2070	/* Find start of first token. */
2071	while (*start == L'\t'  ||  *start == L' '  ||  *start == L',')
2072		start++;
2073	while (*start != L'\0') {
2074		size_t length;
2075		/* Locate end of token. */
2076		end = start;
2077		while (*end != L'\0'  &&  *end != L'\t'  &&
2078		    *end != L' '  &&  *end != L',')
2079			end++;
2080		length = end - start;
2081		for (flag = fileflags; flag->wname != NULL; flag++) {
2082			size_t flag_length = wcslen(flag->wname);
2083			if (length == flag_length
2084			    && wmemcmp(start, flag->wname, length) == 0) {
2085				/* Matched "noXXXX", so reverse the sense. */
2086				clear |= flag->set;
2087				set |= flag->clear;
2088				break;
2089			} else if (length == flag_length - 2
2090			    && wmemcmp(start, flag->wname + 2, length) == 0) {
2091				/* Matched "XXXX", so don't reverse. */
2092				set |= flag->set;
2093				clear |= flag->clear;
2094				break;
2095			}
2096		}
2097		/* Ignore unknown flag names. */
2098		if (flag->wname == NULL  &&  failed == NULL)
2099			failed = start;
2100
2101		/* Find start of next token. */
2102		start = end;
2103		while (*start == L'\t'  ||  *start == L' '  ||  *start == L',')
2104			start++;
2105
2106	}
2107
2108	if (setp)
2109		*setp = set;
2110	if (clrp)
2111		*clrp = clear;
2112
2113	/* Return location of first failure. */
2114	return (failed);
2115}
2116
2117
2118#ifdef TEST
2119#include <stdio.h>
2120int
2121main(int argc, char **argv)
2122{
2123	struct archive_entry *entry = archive_entry_new();
2124	unsigned long set, clear;
2125	const wchar_t *remainder;
2126
2127	remainder = archive_entry_copy_fflags_text_w(entry, L"nosappnd dump archive,,,,,,,");
2128	archive_entry_fflags(entry, &set, &clear);
2129
2130	wprintf(L"set=0x%lX clear=0x%lX remainder='%ls'\n", set, clear, remainder);
2131
2132	wprintf(L"new flags='%s'\n", archive_entry_fflags_text(entry));
2133	return (0);
2134}
2135#endif
2136