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