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