1228753Smm/*-
2228753Smm * Copyright (c) 2003-2007 Tim Kientzle
3228753Smm * All rights reserved.
4228753Smm *
5228753Smm * Redistribution and use in source and binary forms, with or without
6228753Smm * modification, are permitted provided that the following conditions
7228753Smm * are met:
8228753Smm * 1. Redistributions of source code must retain the above copyright
9228753Smm *    notice, this list of conditions and the following disclaimer.
10228753Smm * 2. Redistributions in binary form must reproduce the above copyright
11228753Smm *    notice, this list of conditions and the following disclaimer in the
12228753Smm *    documentation and/or other materials provided with the distribution.
13228753Smm *
14228753Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15228753Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16228753Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17228753Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18228753Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19228753Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20228753Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21228753Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22228753Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23228753Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24228753Smm */
25228753Smm
26228753Smm#include "archive_platform.h"
27228763Smm__FBSDID("$FreeBSD$");
28228753Smm
29228753Smm#ifdef HAVE_SYS_STAT_H
30228753Smm#include <sys/stat.h>
31228753Smm#endif
32228753Smm#ifdef HAVE_SYS_TYPES_H
33228753Smm#include <sys/types.h>
34228753Smm#endif
35228753Smm#if MAJOR_IN_MKDEV
36228753Smm#include <sys/mkdev.h>
37228753Smm#define HAVE_MAJOR
38228753Smm#elif MAJOR_IN_SYSMACROS
39228753Smm#include <sys/sysmacros.h>
40228753Smm#define HAVE_MAJOR
41228753Smm#endif
42232153Smm#ifdef HAVE_ERRNO_H
43232153Smm#include <errno.h>
44232153Smm#endif
45228753Smm#ifdef HAVE_LIMITS_H
46228753Smm#include <limits.h>
47228753Smm#endif
48228753Smm#ifdef HAVE_LINUX_FS_H
49228753Smm#include <linux/fs.h>	/* for Linux file flags */
50228753Smm#endif
51228753Smm/*
52228753Smm * Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h.
53228753Smm * As the include guards don't agree, the order of include is important.
54228753Smm */
55228753Smm#ifdef HAVE_LINUX_EXT2_FS_H
56228753Smm#include <linux/ext2_fs.h>	/* for Linux file flags */
57228753Smm#endif
58228753Smm#if defined(HAVE_EXT2FS_EXT2_FS_H) && !defined(__CYGWIN__)
59228753Smm#include <ext2fs/ext2_fs.h>	/* for Linux file flags */
60228753Smm#endif
61228753Smm#include <stddef.h>
62228753Smm#include <stdio.h>
63228753Smm#ifdef HAVE_STDLIB_H
64228753Smm#include <stdlib.h>
65228753Smm#endif
66228753Smm#ifdef HAVE_STRING_H
67228753Smm#include <string.h>
68228753Smm#endif
69228753Smm#ifdef HAVE_WCHAR_H
70228753Smm#include <wchar.h>
71228753Smm#endif
72228753Smm
73228753Smm#include "archive.h"
74232153Smm#include "archive_acl_private.h"
75228753Smm#include "archive_entry.h"
76232153Smm#include "archive_entry_locale.h"
77228753Smm#include "archive_private.h"
78228753Smm#include "archive_entry_private.h"
79228753Smm
80228753Smm#if !defined(HAVE_MAJOR) && !defined(major)
81228753Smm/* Replacement for major/minor/makedev. */
82228753Smm#define	major(x) ((int)(0x00ff & ((x) >> 8)))
83228753Smm#define	minor(x) ((int)(0xffff00ff & (x)))
84228753Smm#define	makedev(maj,min) ((0xff00 & ((maj)<<8)) | (0xffff00ff & (min)))
85228753Smm#endif
86228753Smm
87228753Smm/* Play games to come up with a suitable makedev() definition. */
88228753Smm#ifdef __QNXNTO__
89228753Smm/* QNX.  <sigh> */
90228753Smm#include <sys/netmgr.h>
91228753Smm#define ae_makedev(maj, min) makedev(ND_LOCAL_NODE, (maj), (min))
92228753Smm#elif defined makedev
93228753Smm/* There's a "makedev" macro. */
94228753Smm#define ae_makedev(maj, min) makedev((maj), (min))
95228753Smm#elif defined mkdev || ((defined _WIN32 || defined __WIN32__) && !defined(__CYGWIN__))
96228753Smm/* Windows. <sigh> */
97228753Smm#define ae_makedev(maj, min) mkdev((maj), (min))
98228753Smm#else
99228753Smm/* There's a "makedev" function. */
100228753Smm#define ae_makedev(maj, min) makedev((maj), (min))
101228753Smm#endif
102228753Smm
103232153Smm/*
104232153Smm * This adjustment is needed to support the following idiom for adding
105232153Smm * 1000ns to the stored time:
106232153Smm * archive_entry_set_atime(archive_entry_atime(),
107232153Smm *                         archive_entry_atime_nsec() + 1000)
108232153Smm * The additional if() here compensates for ambiguity in the C standard,
109232153Smm * which permits two possible interpretations of a % b when a is negative.
110232153Smm */
111232153Smm#define FIX_NS(t,ns) \
112232153Smm	do {	\
113232153Smm		t += ns / 1000000000; \
114232153Smm		ns %= 1000000000; \
115232153Smm		if (ns < 0) { --t; ns += 1000000000; } \
116232153Smm	} while (0)
117228753Smm
118228753Smmstatic char *	 ae_fflagstostr(unsigned long bitset, unsigned long bitclear);
119228753Smmstatic const wchar_t	*ae_wcstofflags(const wchar_t *stringp,
120228753Smm		    unsigned long *setp, unsigned long *clrp);
121228753Smmstatic const char	*ae_strtofflags(const char *stringp,
122228753Smm		    unsigned long *setp, unsigned long *clrp);
123228753Smm
124228753Smm#ifndef HAVE_WCSCPY
125228753Smmstatic wchar_t * wcscpy(wchar_t *s1, const wchar_t *s2)
126228753Smm{
127228753Smm	wchar_t *dest = s1;
128228753Smm	while ((*s1 = *s2) != L'\0')
129228753Smm		++s1, ++s2;
130228753Smm	return dest;
131228753Smm}
132228753Smm#endif
133228753Smm#ifndef HAVE_WCSLEN
134228753Smmstatic size_t wcslen(const wchar_t *s)
135228753Smm{
136228753Smm	const wchar_t *p = s;
137228753Smm	while (*p != L'\0')
138228753Smm		++p;
139228753Smm	return p - s;
140228753Smm}
141228753Smm#endif
142228753Smm#ifndef HAVE_WMEMCMP
143228753Smm/* Good enough for simple equality testing, but not for sorting. */
144228753Smm#define wmemcmp(a,b,i)  memcmp((a), (b), (i) * sizeof(wchar_t))
145228753Smm#endif
146228753Smm
147228753Smm/****************************************************************************
148228753Smm *
149228753Smm * Public Interface
150228753Smm *
151228753Smm ****************************************************************************/
152228753Smm
153228753Smmstruct archive_entry *
154228753Smmarchive_entry_clear(struct archive_entry *entry)
155228753Smm{
156228753Smm	if (entry == NULL)
157228753Smm		return (NULL);
158232153Smm	archive_mstring_clean(&entry->ae_fflags_text);
159232153Smm	archive_mstring_clean(&entry->ae_gname);
160232153Smm	archive_mstring_clean(&entry->ae_hardlink);
161232153Smm	archive_mstring_clean(&entry->ae_pathname);
162232153Smm	archive_mstring_clean(&entry->ae_sourcepath);
163232153Smm	archive_mstring_clean(&entry->ae_symlink);
164232153Smm	archive_mstring_clean(&entry->ae_uname);
165232153Smm	archive_entry_copy_mac_metadata(entry, NULL, 0);
166232153Smm	archive_acl_clear(&entry->acl);
167228753Smm	archive_entry_xattr_clear(entry);
168232153Smm	archive_entry_sparse_clear(entry);
169228753Smm	free(entry->stat);
170228753Smm	memset(entry, 0, sizeof(*entry));
171228753Smm	return entry;
172228753Smm}
173228753Smm
174228753Smmstruct archive_entry *
175228753Smmarchive_entry_clone(struct archive_entry *entry)
176228753Smm{
177228753Smm	struct archive_entry *entry2;
178228753Smm	struct ae_xattr *xp;
179232153Smm	struct ae_sparse *sp;
180232153Smm	size_t s;
181232153Smm	const void *p;
182228753Smm
183228753Smm	/* Allocate new structure and copy over all of the fields. */
184232153Smm	/* TODO: Should we copy the archive over?  Or require a new archive
185232153Smm	 * as an argument? */
186232153Smm	entry2 = archive_entry_new2(entry->archive);
187228753Smm	if (entry2 == NULL)
188228753Smm		return (NULL);
189228753Smm	entry2->ae_stat = entry->ae_stat;
190228753Smm	entry2->ae_fflags_set = entry->ae_fflags_set;
191228753Smm	entry2->ae_fflags_clear = entry->ae_fflags_clear;
192228753Smm
193232153Smm	/* TODO: XXX If clone can have a different archive, what do we do here if
194232153Smm	 * character sets are different? XXX */
195232153Smm	archive_mstring_copy(&entry2->ae_fflags_text, &entry->ae_fflags_text);
196232153Smm	archive_mstring_copy(&entry2->ae_gname, &entry->ae_gname);
197232153Smm	archive_mstring_copy(&entry2->ae_hardlink, &entry->ae_hardlink);
198232153Smm	archive_mstring_copy(&entry2->ae_pathname, &entry->ae_pathname);
199232153Smm	archive_mstring_copy(&entry2->ae_sourcepath, &entry->ae_sourcepath);
200232153Smm	archive_mstring_copy(&entry2->ae_symlink, &entry->ae_symlink);
201228753Smm	entry2->ae_set = entry->ae_set;
202232153Smm	archive_mstring_copy(&entry2->ae_uname, &entry->ae_uname);
203228753Smm
204228753Smm	/* Copy ACL data over. */
205232153Smm	archive_acl_copy(&entry2->acl, &entry->acl);
206228753Smm
207232153Smm	/* Copy Mac OS metadata. */
208232153Smm	p = archive_entry_mac_metadata(entry, &s);
209232153Smm	archive_entry_copy_mac_metadata(entry2, p, s);
210232153Smm
211228753Smm	/* Copy xattr data over. */
212228753Smm	xp = entry->xattr_head;
213228753Smm	while (xp != NULL) {
214228753Smm		archive_entry_xattr_add_entry(entry2,
215228753Smm		    xp->name, xp->value, xp->size);
216228753Smm		xp = xp->next;
217228753Smm	}
218228753Smm
219232153Smm	/* Copy sparse data over. */
220232153Smm	sp = entry->sparse_head;
221232153Smm	while (sp != NULL) {
222232153Smm		archive_entry_sparse_add_entry(entry2,
223232153Smm		    sp->offset, sp->length);
224232153Smm		sp = sp->next;
225232153Smm	}
226232153Smm
227228753Smm	return (entry2);
228228753Smm}
229228753Smm
230228753Smmvoid
231228753Smmarchive_entry_free(struct archive_entry *entry)
232228753Smm{
233228753Smm	archive_entry_clear(entry);
234228753Smm	free(entry);
235228753Smm}
236228753Smm
237228753Smmstruct archive_entry *
238228753Smmarchive_entry_new(void)
239228753Smm{
240232153Smm	return archive_entry_new2(NULL);
241232153Smm}
242232153Smm
243232153Smmstruct archive_entry *
244232153Smmarchive_entry_new2(struct archive *a)
245232153Smm{
246228753Smm	struct archive_entry *entry;
247228753Smm
248228753Smm	entry = (struct archive_entry *)malloc(sizeof(*entry));
249228753Smm	if (entry == NULL)
250228753Smm		return (NULL);
251228753Smm	memset(entry, 0, sizeof(*entry));
252232153Smm	entry->archive = a;
253228753Smm	return (entry);
254228753Smm}
255228753Smm
256228753Smm/*
257228753Smm * Functions for reading fields from an archive_entry.
258228753Smm */
259228753Smm
260228753Smmtime_t
261228753Smmarchive_entry_atime(struct archive_entry *entry)
262228753Smm{
263228753Smm	return (entry->ae_stat.aest_atime);
264228753Smm}
265228753Smm
266228753Smmlong
267228753Smmarchive_entry_atime_nsec(struct archive_entry *entry)
268228753Smm{
269228753Smm	return (entry->ae_stat.aest_atime_nsec);
270228753Smm}
271228753Smm
272228753Smmint
273228753Smmarchive_entry_atime_is_set(struct archive_entry *entry)
274228753Smm{
275228753Smm	return (entry->ae_set & AE_SET_ATIME);
276228753Smm}
277228753Smm
278228753Smmtime_t
279228753Smmarchive_entry_birthtime(struct archive_entry *entry)
280228753Smm{
281228753Smm	return (entry->ae_stat.aest_birthtime);
282228753Smm}
283228753Smm
284228753Smmlong
285228753Smmarchive_entry_birthtime_nsec(struct archive_entry *entry)
286228753Smm{
287228753Smm	return (entry->ae_stat.aest_birthtime_nsec);
288228753Smm}
289228753Smm
290228753Smmint
291228753Smmarchive_entry_birthtime_is_set(struct archive_entry *entry)
292228753Smm{
293228753Smm	return (entry->ae_set & AE_SET_BIRTHTIME);
294228753Smm}
295228753Smm
296228753Smmtime_t
297228753Smmarchive_entry_ctime(struct archive_entry *entry)
298228753Smm{
299228753Smm	return (entry->ae_stat.aest_ctime);
300228753Smm}
301228753Smm
302228753Smmint
303228753Smmarchive_entry_ctime_is_set(struct archive_entry *entry)
304228753Smm{
305228753Smm	return (entry->ae_set & AE_SET_CTIME);
306228753Smm}
307228753Smm
308228753Smmlong
309228753Smmarchive_entry_ctime_nsec(struct archive_entry *entry)
310228753Smm{
311228753Smm	return (entry->ae_stat.aest_ctime_nsec);
312228753Smm}
313228753Smm
314228753Smmdev_t
315228753Smmarchive_entry_dev(struct archive_entry *entry)
316228753Smm{
317228753Smm	if (entry->ae_stat.aest_dev_is_broken_down)
318228753Smm		return ae_makedev(entry->ae_stat.aest_devmajor,
319228753Smm		    entry->ae_stat.aest_devminor);
320228753Smm	else
321228753Smm		return (entry->ae_stat.aest_dev);
322228753Smm}
323228753Smm
324232153Smmint
325232153Smmarchive_entry_dev_is_set(struct archive_entry *entry)
326232153Smm{
327232153Smm	return (entry->ae_set & AE_SET_DEV);
328232153Smm}
329232153Smm
330228753Smmdev_t
331228753Smmarchive_entry_devmajor(struct archive_entry *entry)
332228753Smm{
333228753Smm	if (entry->ae_stat.aest_dev_is_broken_down)
334228753Smm		return (entry->ae_stat.aest_devmajor);
335228753Smm	else
336228753Smm		return major(entry->ae_stat.aest_dev);
337228753Smm}
338228753Smm
339228753Smmdev_t
340228753Smmarchive_entry_devminor(struct archive_entry *entry)
341228753Smm{
342228753Smm	if (entry->ae_stat.aest_dev_is_broken_down)
343228753Smm		return (entry->ae_stat.aest_devminor);
344228753Smm	else
345228753Smm		return minor(entry->ae_stat.aest_dev);
346228753Smm}
347228753Smm
348228753Smmmode_t
349228753Smmarchive_entry_filetype(struct archive_entry *entry)
350228753Smm{
351232153Smm	return (AE_IFMT & entry->acl.mode);
352228753Smm}
353228753Smm
354228753Smmvoid
355228753Smmarchive_entry_fflags(struct archive_entry *entry,
356228753Smm    unsigned long *set, unsigned long *clear)
357228753Smm{
358228753Smm	*set = entry->ae_fflags_set;
359228753Smm	*clear = entry->ae_fflags_clear;
360228753Smm}
361228753Smm
362228753Smm/*
363228753Smm * Note: if text was provided, this just returns that text.  If you
364228753Smm * really need the text to be rebuilt in a canonical form, set the
365228753Smm * text, ask for the bitmaps, then set the bitmaps.  (Setting the
366228753Smm * bitmaps clears any stored text.)  This design is deliberate: if
367228753Smm * we're editing archives, we don't want to discard flags just because
368228753Smm * they aren't supported on the current system.  The bitmap<->text
369228753Smm * conversions are platform-specific (see below).
370228753Smm */
371228753Smmconst char *
372228753Smmarchive_entry_fflags_text(struct archive_entry *entry)
373228753Smm{
374228753Smm	const char *f;
375228753Smm	char *p;
376228753Smm
377232153Smm	if (archive_mstring_get_mbs(entry->archive,
378238856Smm	    &entry->ae_fflags_text, &f) == 0) {
379238856Smm		if (f != NULL)
380238856Smm			return (f);
381238856Smm	} else if (errno == ENOMEM)
382238856Smm		__archive_errx(1, "No memory");
383228753Smm
384228753Smm	if (entry->ae_fflags_set == 0  &&  entry->ae_fflags_clear == 0)
385228753Smm		return (NULL);
386228753Smm
387228753Smm	p = ae_fflagstostr(entry->ae_fflags_set, entry->ae_fflags_clear);
388228753Smm	if (p == NULL)
389228753Smm		return (NULL);
390228753Smm
391232153Smm	archive_mstring_copy_mbs(&entry->ae_fflags_text, p);
392228753Smm	free(p);
393232153Smm	if (archive_mstring_get_mbs(entry->archive,
394232153Smm	    &entry->ae_fflags_text, &f) == 0)
395232153Smm		return (f);
396238856Smm	if (errno == ENOMEM)
397238856Smm		__archive_errx(1, "No memory");
398232153Smm	return (NULL);
399228753Smm}
400228753Smm
401232153Smmint64_t
402228753Smmarchive_entry_gid(struct archive_entry *entry)
403228753Smm{
404228753Smm	return (entry->ae_stat.aest_gid);
405228753Smm}
406228753Smm
407228753Smmconst char *
408228753Smmarchive_entry_gname(struct archive_entry *entry)
409228753Smm{
410232153Smm	const char *p;
411232153Smm	if (archive_mstring_get_mbs(entry->archive, &entry->ae_gname, &p) == 0)
412232153Smm		return (p);
413238856Smm	if (errno == ENOMEM)
414238856Smm		__archive_errx(1, "No memory");
415232153Smm	return (NULL);
416228753Smm}
417228753Smm
418228753Smmconst wchar_t *
419228753Smmarchive_entry_gname_w(struct archive_entry *entry)
420228753Smm{
421232153Smm	const wchar_t *p;
422232153Smm	if (archive_mstring_get_wcs(entry->archive, &entry->ae_gname, &p) == 0)
423232153Smm		return (p);
424238856Smm	if (errno == ENOMEM)
425238856Smm		__archive_errx(1, "No memory");
426232153Smm	return (NULL);
427228753Smm}
428228753Smm
429232153Smmint
430232153Smm_archive_entry_gname_l(struct archive_entry *entry,
431232153Smm    const char **p, size_t *len, struct archive_string_conv *sc)
432232153Smm{
433232153Smm	return (archive_mstring_get_mbs_l(&entry->ae_gname, p, len, sc));
434232153Smm}
435232153Smm
436228753Smmconst char *
437228753Smmarchive_entry_hardlink(struct archive_entry *entry)
438228753Smm{
439232153Smm	const char *p;
440238856Smm	if ((entry->ae_set & AE_SET_HARDLINK) == 0)
441238856Smm		return (NULL);
442238856Smm	if (archive_mstring_get_mbs(
443232153Smm	    entry->archive, &entry->ae_hardlink, &p) == 0)
444232153Smm		return (p);
445238856Smm	if (errno == ENOMEM)
446238856Smm		__archive_errx(1, "No memory");
447228753Smm	return (NULL);
448228753Smm}
449228753Smm
450228753Smmconst wchar_t *
451228753Smmarchive_entry_hardlink_w(struct archive_entry *entry)
452228753Smm{
453232153Smm	const wchar_t *p;
454238856Smm	if ((entry->ae_set & AE_SET_HARDLINK) == 0)
455238856Smm		return (NULL);
456238856Smm	if (archive_mstring_get_wcs(
457232153Smm	    entry->archive, &entry->ae_hardlink, &p) == 0)
458232153Smm		return (p);
459238856Smm	if (errno == ENOMEM)
460238856Smm		__archive_errx(1, "No memory");
461228753Smm	return (NULL);
462228753Smm}
463228753Smm
464232153Smmint
465232153Smm_archive_entry_hardlink_l(struct archive_entry *entry,
466232153Smm    const char **p, size_t *len, struct archive_string_conv *sc)
467232153Smm{
468232153Smm	if ((entry->ae_set & AE_SET_HARDLINK) == 0) {
469232153Smm		*p = NULL;
470232153Smm		*len = 0;
471232153Smm		return (0);
472232153Smm	}
473232153Smm	return (archive_mstring_get_mbs_l(&entry->ae_hardlink, p, len, sc));
474232153Smm}
475232153Smm
476232153Smmint64_t
477228753Smmarchive_entry_ino(struct archive_entry *entry)
478228753Smm{
479228753Smm	return (entry->ae_stat.aest_ino);
480228753Smm}
481228753Smm
482232153Smmint
483232153Smmarchive_entry_ino_is_set(struct archive_entry *entry)
484232153Smm{
485232153Smm	return (entry->ae_set & AE_SET_INO);
486232153Smm}
487232153Smm
488228753Smmint64_t
489228753Smmarchive_entry_ino64(struct archive_entry *entry)
490228753Smm{
491228753Smm	return (entry->ae_stat.aest_ino);
492228753Smm}
493228753Smm
494228753Smmmode_t
495228753Smmarchive_entry_mode(struct archive_entry *entry)
496228753Smm{
497232153Smm	return (entry->acl.mode);
498228753Smm}
499228753Smm
500228753Smmtime_t
501228753Smmarchive_entry_mtime(struct archive_entry *entry)
502228753Smm{
503228753Smm	return (entry->ae_stat.aest_mtime);
504228753Smm}
505228753Smm
506228753Smmlong
507228753Smmarchive_entry_mtime_nsec(struct archive_entry *entry)
508228753Smm{
509228753Smm	return (entry->ae_stat.aest_mtime_nsec);
510228753Smm}
511228753Smm
512228753Smmint
513228753Smmarchive_entry_mtime_is_set(struct archive_entry *entry)
514228753Smm{
515228753Smm	return (entry->ae_set & AE_SET_MTIME);
516228753Smm}
517228753Smm
518228753Smmunsigned int
519228753Smmarchive_entry_nlink(struct archive_entry *entry)
520228753Smm{
521228753Smm	return (entry->ae_stat.aest_nlink);
522228753Smm}
523228753Smm
524228753Smmconst char *
525228753Smmarchive_entry_pathname(struct archive_entry *entry)
526228753Smm{
527232153Smm	const char *p;
528232153Smm	if (archive_mstring_get_mbs(
529232153Smm	    entry->archive, &entry->ae_pathname, &p) == 0)
530232153Smm		return (p);
531238856Smm	if (errno == ENOMEM)
532238856Smm		__archive_errx(1, "No memory");
533232153Smm	return (NULL);
534228753Smm}
535228753Smm
536228753Smmconst wchar_t *
537228753Smmarchive_entry_pathname_w(struct archive_entry *entry)
538228753Smm{
539232153Smm	const wchar_t *p;
540232153Smm	if (archive_mstring_get_wcs(
541232153Smm	    entry->archive, &entry->ae_pathname, &p) == 0)
542232153Smm		return (p);
543238856Smm	if (errno == ENOMEM)
544238856Smm		__archive_errx(1, "No memory");
545232153Smm	return (NULL);
546228753Smm}
547228753Smm
548232153Smmint
549232153Smm_archive_entry_pathname_l(struct archive_entry *entry,
550232153Smm    const char **p, size_t *len, struct archive_string_conv *sc)
551232153Smm{
552232153Smm	return (archive_mstring_get_mbs_l(&entry->ae_pathname, p, len, sc));
553232153Smm}
554232153Smm
555232153Smmmode_t
556232153Smmarchive_entry_perm(struct archive_entry *entry)
557232153Smm{
558232153Smm	return (~AE_IFMT & entry->acl.mode);
559232153Smm}
560232153Smm
561228753Smmdev_t
562228753Smmarchive_entry_rdev(struct archive_entry *entry)
563228753Smm{
564228753Smm	if (entry->ae_stat.aest_rdev_is_broken_down)
565228753Smm		return ae_makedev(entry->ae_stat.aest_rdevmajor,
566228753Smm		    entry->ae_stat.aest_rdevminor);
567228753Smm	else
568228753Smm		return (entry->ae_stat.aest_rdev);
569228753Smm}
570228753Smm
571228753Smmdev_t
572228753Smmarchive_entry_rdevmajor(struct archive_entry *entry)
573228753Smm{
574228753Smm	if (entry->ae_stat.aest_rdev_is_broken_down)
575228753Smm		return (entry->ae_stat.aest_rdevmajor);
576228753Smm	else
577228753Smm		return major(entry->ae_stat.aest_rdev);
578228753Smm}
579228753Smm
580228753Smmdev_t
581228753Smmarchive_entry_rdevminor(struct archive_entry *entry)
582228753Smm{
583228753Smm	if (entry->ae_stat.aest_rdev_is_broken_down)
584228753Smm		return (entry->ae_stat.aest_rdevminor);
585228753Smm	else
586228753Smm		return minor(entry->ae_stat.aest_rdev);
587228753Smm}
588228753Smm
589228753Smmint64_t
590228753Smmarchive_entry_size(struct archive_entry *entry)
591228753Smm{
592228753Smm	return (entry->ae_stat.aest_size);
593228753Smm}
594228753Smm
595228753Smmint
596228753Smmarchive_entry_size_is_set(struct archive_entry *entry)
597228753Smm{
598228753Smm	return (entry->ae_set & AE_SET_SIZE);
599228753Smm}
600228753Smm
601228753Smmconst char *
602228753Smmarchive_entry_sourcepath(struct archive_entry *entry)
603228753Smm{
604232153Smm	const char *p;
605232153Smm	if (archive_mstring_get_mbs(
606232153Smm	    entry->archive, &entry->ae_sourcepath, &p) == 0)
607232153Smm		return (p);
608238856Smm	if (errno == ENOMEM)
609238856Smm		__archive_errx(1, "No memory");
610232153Smm	return (NULL);
611228753Smm}
612228753Smm
613232153Smmconst wchar_t *
614232153Smmarchive_entry_sourcepath_w(struct archive_entry *entry)
615232153Smm{
616232153Smm	const wchar_t *p;
617232153Smm	if (archive_mstring_get_wcs(
618232153Smm	    entry->archive, &entry->ae_sourcepath, &p) == 0)
619232153Smm		return (p);
620232153Smm	return (NULL);
621232153Smm}
622232153Smm
623228753Smmconst char *
624228753Smmarchive_entry_symlink(struct archive_entry *entry)
625228753Smm{
626232153Smm	const char *p;
627238856Smm	if ((entry->ae_set & AE_SET_SYMLINK) == 0)
628238856Smm		return (NULL);
629238856Smm	if (archive_mstring_get_mbs(
630232153Smm	    entry->archive, &entry->ae_symlink, &p) == 0)
631232153Smm		return (p);
632238856Smm	if (errno == ENOMEM)
633238856Smm		__archive_errx(1, "No memory");
634228753Smm	return (NULL);
635228753Smm}
636228753Smm
637228753Smmconst wchar_t *
638228753Smmarchive_entry_symlink_w(struct archive_entry *entry)
639228753Smm{
640232153Smm	const wchar_t *p;
641238856Smm	if ((entry->ae_set & AE_SET_SYMLINK) == 0)
642238856Smm		return (NULL);
643238856Smm	if (archive_mstring_get_wcs(
644232153Smm	    entry->archive, &entry->ae_symlink, &p) == 0)
645232153Smm		return (p);
646238856Smm	if (errno == ENOMEM)
647238856Smm		__archive_errx(1, "No memory");
648228753Smm	return (NULL);
649228753Smm}
650228753Smm
651232153Smmint
652232153Smm_archive_entry_symlink_l(struct archive_entry *entry,
653232153Smm    const char **p, size_t *len, struct archive_string_conv *sc)
654232153Smm{
655232153Smm	if ((entry->ae_set & AE_SET_SYMLINK) == 0) {
656232153Smm		*p = NULL;
657232153Smm		*len = 0;
658232153Smm		return (0);
659232153Smm	}
660232153Smm	return (archive_mstring_get_mbs_l( &entry->ae_symlink, p, len, sc));
661232153Smm}
662232153Smm
663232153Smmint64_t
664228753Smmarchive_entry_uid(struct archive_entry *entry)
665228753Smm{
666228753Smm	return (entry->ae_stat.aest_uid);
667228753Smm}
668228753Smm
669228753Smmconst char *
670228753Smmarchive_entry_uname(struct archive_entry *entry)
671228753Smm{
672232153Smm	const char *p;
673232153Smm	if (archive_mstring_get_mbs(entry->archive, &entry->ae_uname, &p) == 0)
674232153Smm		return (p);
675238856Smm	if (errno == ENOMEM)
676238856Smm		__archive_errx(1, "No memory");
677232153Smm	return (NULL);
678228753Smm}
679228753Smm
680228753Smmconst wchar_t *
681228753Smmarchive_entry_uname_w(struct archive_entry *entry)
682228753Smm{
683232153Smm	const wchar_t *p;
684232153Smm	if (archive_mstring_get_wcs(entry->archive, &entry->ae_uname, &p) == 0)
685232153Smm		return (p);
686238856Smm	if (errno == ENOMEM)
687238856Smm		__archive_errx(1, "No memory");
688232153Smm	return (NULL);
689228753Smm}
690228753Smm
691232153Smmint
692232153Smm_archive_entry_uname_l(struct archive_entry *entry,
693232153Smm    const char **p, size_t *len, struct archive_string_conv *sc)
694232153Smm{
695232153Smm	return (archive_mstring_get_mbs_l(&entry->ae_uname, p, len, sc));
696232153Smm}
697232153Smm
698228753Smm/*
699228753Smm * Functions to set archive_entry properties.
700228753Smm */
701228753Smm
702228753Smmvoid
703228753Smmarchive_entry_set_filetype(struct archive_entry *entry, unsigned int type)
704228753Smm{
705228753Smm	entry->stat_valid = 0;
706232153Smm	entry->acl.mode &= ~AE_IFMT;
707232153Smm	entry->acl.mode |= AE_IFMT & type;
708228753Smm}
709228753Smm
710228753Smmvoid
711228753Smmarchive_entry_set_fflags(struct archive_entry *entry,
712228753Smm    unsigned long set, unsigned long clear)
713228753Smm{
714232153Smm	archive_mstring_clean(&entry->ae_fflags_text);
715228753Smm	entry->ae_fflags_set = set;
716228753Smm	entry->ae_fflags_clear = clear;
717228753Smm}
718228753Smm
719228753Smmconst char *
720228753Smmarchive_entry_copy_fflags_text(struct archive_entry *entry,
721228753Smm    const char *flags)
722228753Smm{
723232153Smm	archive_mstring_copy_mbs(&entry->ae_fflags_text, flags);
724228753Smm	return (ae_strtofflags(flags,
725228753Smm		    &entry->ae_fflags_set, &entry->ae_fflags_clear));
726228753Smm}
727228753Smm
728228753Smmconst wchar_t *
729228753Smmarchive_entry_copy_fflags_text_w(struct archive_entry *entry,
730228753Smm    const wchar_t *flags)
731228753Smm{
732232153Smm	archive_mstring_copy_wcs(&entry->ae_fflags_text, flags);
733228753Smm	return (ae_wcstofflags(flags,
734228753Smm		    &entry->ae_fflags_set, &entry->ae_fflags_clear));
735228753Smm}
736228753Smm
737228753Smmvoid
738232153Smmarchive_entry_set_gid(struct archive_entry *entry, int64_t g)
739228753Smm{
740228753Smm	entry->stat_valid = 0;
741228753Smm	entry->ae_stat.aest_gid = g;
742228753Smm}
743228753Smm
744228753Smmvoid
745228753Smmarchive_entry_set_gname(struct archive_entry *entry, const char *name)
746228753Smm{
747232153Smm	archive_mstring_copy_mbs(&entry->ae_gname, name);
748228753Smm}
749228753Smm
750228753Smmvoid
751228753Smmarchive_entry_copy_gname(struct archive_entry *entry, const char *name)
752228753Smm{
753232153Smm	archive_mstring_copy_mbs(&entry->ae_gname, name);
754228753Smm}
755228753Smm
756228753Smmvoid
757228753Smmarchive_entry_copy_gname_w(struct archive_entry *entry, const wchar_t *name)
758228753Smm{
759232153Smm	archive_mstring_copy_wcs(&entry->ae_gname, name);
760228753Smm}
761228753Smm
762228753Smmint
763228753Smmarchive_entry_update_gname_utf8(struct archive_entry *entry, const char *name)
764228753Smm{
765232153Smm	if (archive_mstring_update_utf8(entry->archive,
766232153Smm	    &entry->ae_gname, name) == 0)
767232153Smm		return (1);
768238856Smm	if (errno == ENOMEM)
769238856Smm		__archive_errx(1, "No memory");
770232153Smm	return (0);
771228753Smm}
772228753Smm
773232153Smmint
774232153Smm_archive_entry_copy_gname_l(struct archive_entry *entry,
775232153Smm    const char *name, size_t len, struct archive_string_conv *sc)
776232153Smm{
777232153Smm	return (archive_mstring_copy_mbs_len_l(&entry->ae_gname, name, len, sc));
778232153Smm}
779232153Smm
780228753Smmvoid
781232153Smmarchive_entry_set_ino(struct archive_entry *entry, int64_t ino)
782228753Smm{
783228753Smm	entry->stat_valid = 0;
784232153Smm	entry->ae_set |= AE_SET_INO;
785228753Smm	entry->ae_stat.aest_ino = ino;
786228753Smm}
787228753Smm
788228753Smmvoid
789228753Smmarchive_entry_set_ino64(struct archive_entry *entry, int64_t ino)
790228753Smm{
791228753Smm	entry->stat_valid = 0;
792232153Smm	entry->ae_set |= AE_SET_INO;
793228753Smm	entry->ae_stat.aest_ino = ino;
794228753Smm}
795228753Smm
796228753Smmvoid
797228753Smmarchive_entry_set_hardlink(struct archive_entry *entry, const char *target)
798228753Smm{
799232153Smm	archive_mstring_copy_mbs(&entry->ae_hardlink, target);
800228753Smm	if (target != NULL)
801228753Smm		entry->ae_set |= AE_SET_HARDLINK;
802228753Smm	else
803228753Smm		entry->ae_set &= ~AE_SET_HARDLINK;
804228753Smm}
805228753Smm
806228753Smmvoid
807228753Smmarchive_entry_copy_hardlink(struct archive_entry *entry, const char *target)
808228753Smm{
809232153Smm	archive_mstring_copy_mbs(&entry->ae_hardlink, target);
810228753Smm	if (target != NULL)
811228753Smm		entry->ae_set |= AE_SET_HARDLINK;
812228753Smm	else
813228753Smm		entry->ae_set &= ~AE_SET_HARDLINK;
814228753Smm}
815228753Smm
816228753Smmvoid
817228753Smmarchive_entry_copy_hardlink_w(struct archive_entry *entry, const wchar_t *target)
818228753Smm{
819232153Smm	archive_mstring_copy_wcs(&entry->ae_hardlink, target);
820228753Smm	if (target != NULL)
821228753Smm		entry->ae_set |= AE_SET_HARDLINK;
822228753Smm	else
823228753Smm		entry->ae_set &= ~AE_SET_HARDLINK;
824228753Smm}
825228753Smm
826228753Smmint
827228753Smmarchive_entry_update_hardlink_utf8(struct archive_entry *entry, const char *target)
828228753Smm{
829228753Smm	if (target != NULL)
830228753Smm		entry->ae_set |= AE_SET_HARDLINK;
831228753Smm	else
832228753Smm		entry->ae_set &= ~AE_SET_HARDLINK;
833232153Smm	if (archive_mstring_update_utf8(entry->archive,
834232153Smm	    &entry->ae_hardlink, target) == 0)
835232153Smm		return (1);
836238856Smm	if (errno == ENOMEM)
837238856Smm		__archive_errx(1, "No memory");
838232153Smm	return (0);
839228753Smm}
840228753Smm
841232153Smmint
842232153Smm_archive_entry_copy_hardlink_l(struct archive_entry *entry,
843232153Smm    const char *target, size_t len, struct archive_string_conv *sc)
844232153Smm{
845232153Smm	int r;
846232153Smm
847232153Smm	r = archive_mstring_copy_mbs_len_l(&entry->ae_hardlink,
848232153Smm	    target, len, sc);
849232153Smm	if (target != NULL && r == 0)
850232153Smm		entry->ae_set |= AE_SET_HARDLINK;
851232153Smm	else
852232153Smm		entry->ae_set &= ~AE_SET_HARDLINK;
853232153Smm	return (r);
854232153Smm}
855232153Smm
856228753Smmvoid
857228753Smmarchive_entry_set_atime(struct archive_entry *entry, time_t t, long ns)
858228753Smm{
859232153Smm	FIX_NS(t, ns);
860228753Smm	entry->stat_valid = 0;
861228753Smm	entry->ae_set |= AE_SET_ATIME;
862228753Smm	entry->ae_stat.aest_atime = t;
863228753Smm	entry->ae_stat.aest_atime_nsec = ns;
864228753Smm}
865228753Smm
866228753Smmvoid
867228753Smmarchive_entry_unset_atime(struct archive_entry *entry)
868228753Smm{
869228753Smm	archive_entry_set_atime(entry, 0, 0);
870228753Smm	entry->ae_set &= ~AE_SET_ATIME;
871228753Smm}
872228753Smm
873228753Smmvoid
874232153Smmarchive_entry_set_birthtime(struct archive_entry *entry, time_t t, long ns)
875228753Smm{
876232153Smm	FIX_NS(t, ns);
877228753Smm	entry->stat_valid = 0;
878228753Smm	entry->ae_set |= AE_SET_BIRTHTIME;
879232153Smm	entry->ae_stat.aest_birthtime = t;
880228753Smm	entry->ae_stat.aest_birthtime_nsec = ns;
881228753Smm}
882228753Smm
883228753Smmvoid
884228753Smmarchive_entry_unset_birthtime(struct archive_entry *entry)
885228753Smm{
886228753Smm	archive_entry_set_birthtime(entry, 0, 0);
887228753Smm	entry->ae_set &= ~AE_SET_BIRTHTIME;
888228753Smm}
889228753Smm
890228753Smmvoid
891228753Smmarchive_entry_set_ctime(struct archive_entry *entry, time_t t, long ns)
892228753Smm{
893232153Smm	FIX_NS(t, ns);
894228753Smm	entry->stat_valid = 0;
895228753Smm	entry->ae_set |= AE_SET_CTIME;
896228753Smm	entry->ae_stat.aest_ctime = t;
897228753Smm	entry->ae_stat.aest_ctime_nsec = ns;
898228753Smm}
899228753Smm
900228753Smmvoid
901228753Smmarchive_entry_unset_ctime(struct archive_entry *entry)
902228753Smm{
903228753Smm	archive_entry_set_ctime(entry, 0, 0);
904228753Smm	entry->ae_set &= ~AE_SET_CTIME;
905228753Smm}
906228753Smm
907228753Smmvoid
908228753Smmarchive_entry_set_dev(struct archive_entry *entry, dev_t d)
909228753Smm{
910228753Smm	entry->stat_valid = 0;
911232153Smm	entry->ae_set |= AE_SET_DEV;
912228753Smm	entry->ae_stat.aest_dev_is_broken_down = 0;
913228753Smm	entry->ae_stat.aest_dev = d;
914228753Smm}
915228753Smm
916228753Smmvoid
917228753Smmarchive_entry_set_devmajor(struct archive_entry *entry, dev_t m)
918228753Smm{
919228753Smm	entry->stat_valid = 0;
920232153Smm	entry->ae_set |= AE_SET_DEV;
921228753Smm	entry->ae_stat.aest_dev_is_broken_down = 1;
922228753Smm	entry->ae_stat.aest_devmajor = m;
923228753Smm}
924228753Smm
925228753Smmvoid
926228753Smmarchive_entry_set_devminor(struct archive_entry *entry, dev_t m)
927228753Smm{
928228753Smm	entry->stat_valid = 0;
929232153Smm	entry->ae_set |= AE_SET_DEV;
930228753Smm	entry->ae_stat.aest_dev_is_broken_down = 1;
931228753Smm	entry->ae_stat.aest_devminor = m;
932228753Smm}
933228753Smm
934228753Smm/* Set symlink if symlink is already set, else set hardlink. */
935228753Smmvoid
936228753Smmarchive_entry_set_link(struct archive_entry *entry, const char *target)
937228753Smm{
938228753Smm	if (entry->ae_set & AE_SET_SYMLINK)
939232153Smm		archive_mstring_copy_mbs(&entry->ae_symlink, target);
940228753Smm	else
941232153Smm		archive_mstring_copy_mbs(&entry->ae_hardlink, target);
942228753Smm}
943228753Smm
944228753Smm/* Set symlink if symlink is already set, else set hardlink. */
945228753Smmvoid
946228753Smmarchive_entry_copy_link(struct archive_entry *entry, const char *target)
947228753Smm{
948228753Smm	if (entry->ae_set & AE_SET_SYMLINK)
949232153Smm		archive_mstring_copy_mbs(&entry->ae_symlink, target);
950228753Smm	else
951232153Smm		archive_mstring_copy_mbs(&entry->ae_hardlink, target);
952228753Smm}
953228753Smm
954228753Smm/* Set symlink if symlink is already set, else set hardlink. */
955228753Smmvoid
956228753Smmarchive_entry_copy_link_w(struct archive_entry *entry, const wchar_t *target)
957228753Smm{
958228753Smm	if (entry->ae_set & AE_SET_SYMLINK)
959232153Smm		archive_mstring_copy_wcs(&entry->ae_symlink, target);
960228753Smm	else
961232153Smm		archive_mstring_copy_wcs(&entry->ae_hardlink, target);
962228753Smm}
963228753Smm
964228753Smmint
965228753Smmarchive_entry_update_link_utf8(struct archive_entry *entry, const char *target)
966228753Smm{
967232153Smm	int r;
968228753Smm	if (entry->ae_set & AE_SET_SYMLINK)
969232153Smm		r = archive_mstring_update_utf8(entry->archive,
970232153Smm		    &entry->ae_symlink, target);
971228753Smm	else
972232153Smm		r = archive_mstring_update_utf8(entry->archive,
973232153Smm		    &entry->ae_hardlink, target);
974238856Smm	if (r == 0)
975238856Smm		return (1);
976238856Smm	if (errno == ENOMEM)
977238856Smm		__archive_errx(1, "No memory");
978238856Smm	return (0);
979228753Smm}
980228753Smm
981232153Smmint
982232153Smm_archive_entry_copy_link_l(struct archive_entry *entry,
983232153Smm    const char *target, size_t len, struct archive_string_conv *sc)
984232153Smm{
985232153Smm	int r;
986232153Smm
987232153Smm	if (entry->ae_set & AE_SET_SYMLINK)
988232153Smm		r = archive_mstring_copy_mbs_len_l(&entry->ae_symlink,
989232153Smm		    target, len, sc);
990232153Smm	else
991232153Smm		r = archive_mstring_copy_mbs_len_l(&entry->ae_hardlink,
992232153Smm		    target, len, sc);
993232153Smm	return (r);
994232153Smm}
995232153Smm
996228753Smmvoid
997228753Smmarchive_entry_set_mode(struct archive_entry *entry, mode_t m)
998228753Smm{
999228753Smm	entry->stat_valid = 0;
1000232153Smm	entry->acl.mode = m;
1001228753Smm}
1002228753Smm
1003228753Smmvoid
1004232153Smmarchive_entry_set_mtime(struct archive_entry *entry, time_t t, long ns)
1005228753Smm{
1006232153Smm	FIX_NS(t, ns);
1007228753Smm	entry->stat_valid = 0;
1008228753Smm	entry->ae_set |= AE_SET_MTIME;
1009232153Smm	entry->ae_stat.aest_mtime = t;
1010228753Smm	entry->ae_stat.aest_mtime_nsec = ns;
1011228753Smm}
1012228753Smm
1013228753Smmvoid
1014228753Smmarchive_entry_unset_mtime(struct archive_entry *entry)
1015228753Smm{
1016228753Smm	archive_entry_set_mtime(entry, 0, 0);
1017228753Smm	entry->ae_set &= ~AE_SET_MTIME;
1018228753Smm}
1019228753Smm
1020228753Smmvoid
1021228753Smmarchive_entry_set_nlink(struct archive_entry *entry, unsigned int nlink)
1022228753Smm{
1023228753Smm	entry->stat_valid = 0;
1024228753Smm	entry->ae_stat.aest_nlink = nlink;
1025228753Smm}
1026228753Smm
1027228753Smmvoid
1028228753Smmarchive_entry_set_pathname(struct archive_entry *entry, const char *name)
1029228753Smm{
1030232153Smm	archive_mstring_copy_mbs(&entry->ae_pathname, name);
1031228753Smm}
1032228753Smm
1033228753Smmvoid
1034228753Smmarchive_entry_copy_pathname(struct archive_entry *entry, const char *name)
1035228753Smm{
1036232153Smm	archive_mstring_copy_mbs(&entry->ae_pathname, name);
1037228753Smm}
1038228753Smm
1039228753Smmvoid
1040228753Smmarchive_entry_copy_pathname_w(struct archive_entry *entry, const wchar_t *name)
1041228753Smm{
1042232153Smm	archive_mstring_copy_wcs(&entry->ae_pathname, name);
1043228753Smm}
1044228753Smm
1045228753Smmint
1046228753Smmarchive_entry_update_pathname_utf8(struct archive_entry *entry, const char *name)
1047228753Smm{
1048232153Smm	if (archive_mstring_update_utf8(entry->archive,
1049232153Smm	    &entry->ae_pathname, name) == 0)
1050232153Smm		return (1);
1051238856Smm	if (errno == ENOMEM)
1052238856Smm		__archive_errx(1, "No memory");
1053232153Smm	return (0);
1054228753Smm}
1055228753Smm
1056232153Smmint
1057232153Smm_archive_entry_copy_pathname_l(struct archive_entry *entry,
1058232153Smm    const char *name, size_t len, struct archive_string_conv *sc)
1059232153Smm{
1060232153Smm	return (archive_mstring_copy_mbs_len_l(&entry->ae_pathname,
1061232153Smm	    name, len, sc));
1062232153Smm}
1063232153Smm
1064228753Smmvoid
1065228753Smmarchive_entry_set_perm(struct archive_entry *entry, mode_t p)
1066228753Smm{
1067228753Smm	entry->stat_valid = 0;
1068232153Smm	entry->acl.mode &= AE_IFMT;
1069232153Smm	entry->acl.mode |= ~AE_IFMT & p;
1070228753Smm}
1071228753Smm
1072228753Smmvoid
1073228753Smmarchive_entry_set_rdev(struct archive_entry *entry, dev_t m)
1074228753Smm{
1075228753Smm	entry->stat_valid = 0;
1076228753Smm	entry->ae_stat.aest_rdev = m;
1077228753Smm	entry->ae_stat.aest_rdev_is_broken_down = 0;
1078228753Smm}
1079228753Smm
1080228753Smmvoid
1081228753Smmarchive_entry_set_rdevmajor(struct archive_entry *entry, dev_t m)
1082228753Smm{
1083228753Smm	entry->stat_valid = 0;
1084228753Smm	entry->ae_stat.aest_rdev_is_broken_down = 1;
1085228753Smm	entry->ae_stat.aest_rdevmajor = m;
1086228753Smm}
1087228753Smm
1088228753Smmvoid
1089228753Smmarchive_entry_set_rdevminor(struct archive_entry *entry, dev_t m)
1090228753Smm{
1091228753Smm	entry->stat_valid = 0;
1092228753Smm	entry->ae_stat.aest_rdev_is_broken_down = 1;
1093228753Smm	entry->ae_stat.aest_rdevminor = m;
1094228753Smm}
1095228753Smm
1096228753Smmvoid
1097228753Smmarchive_entry_set_size(struct archive_entry *entry, int64_t s)
1098228753Smm{
1099228753Smm	entry->stat_valid = 0;
1100228753Smm	entry->ae_stat.aest_size = s;
1101228753Smm	entry->ae_set |= AE_SET_SIZE;
1102228753Smm}
1103228753Smm
1104228753Smmvoid
1105228753Smmarchive_entry_unset_size(struct archive_entry *entry)
1106228753Smm{
1107228753Smm	archive_entry_set_size(entry, 0);
1108228753Smm	entry->ae_set &= ~AE_SET_SIZE;
1109228753Smm}
1110228753Smm
1111228753Smmvoid
1112228753Smmarchive_entry_copy_sourcepath(struct archive_entry *entry, const char *path)
1113228753Smm{
1114232153Smm	archive_mstring_copy_mbs(&entry->ae_sourcepath, path);
1115228753Smm}
1116228753Smm
1117228753Smmvoid
1118232153Smmarchive_entry_copy_sourcepath_w(struct archive_entry *entry, const wchar_t *path)
1119232153Smm{
1120232153Smm	archive_mstring_copy_wcs(&entry->ae_sourcepath, path);
1121232153Smm}
1122232153Smm
1123232153Smmvoid
1124228753Smmarchive_entry_set_symlink(struct archive_entry *entry, const char *linkname)
1125228753Smm{
1126232153Smm	archive_mstring_copy_mbs(&entry->ae_symlink, linkname);
1127228753Smm	if (linkname != NULL)
1128228753Smm		entry->ae_set |= AE_SET_SYMLINK;
1129228753Smm	else
1130228753Smm		entry->ae_set &= ~AE_SET_SYMLINK;
1131228753Smm}
1132228753Smm
1133228753Smmvoid
1134228753Smmarchive_entry_copy_symlink(struct archive_entry *entry, const char *linkname)
1135228753Smm{
1136232153Smm	archive_mstring_copy_mbs(&entry->ae_symlink, linkname);
1137228753Smm	if (linkname != NULL)
1138228753Smm		entry->ae_set |= AE_SET_SYMLINK;
1139228753Smm	else
1140228753Smm		entry->ae_set &= ~AE_SET_SYMLINK;
1141228753Smm}
1142228753Smm
1143228753Smmvoid
1144228753Smmarchive_entry_copy_symlink_w(struct archive_entry *entry, const wchar_t *linkname)
1145228753Smm{
1146232153Smm	archive_mstring_copy_wcs(&entry->ae_symlink, linkname);
1147228753Smm	if (linkname != NULL)
1148228753Smm		entry->ae_set |= AE_SET_SYMLINK;
1149228753Smm	else
1150228753Smm		entry->ae_set &= ~AE_SET_SYMLINK;
1151228753Smm}
1152228753Smm
1153228753Smmint
1154228753Smmarchive_entry_update_symlink_utf8(struct archive_entry *entry, const char *linkname)
1155228753Smm{
1156228753Smm	if (linkname != NULL)
1157228753Smm		entry->ae_set |= AE_SET_SYMLINK;
1158228753Smm	else
1159228753Smm		entry->ae_set &= ~AE_SET_SYMLINK;
1160232153Smm	if (archive_mstring_update_utf8(entry->archive,
1161232153Smm	    &entry->ae_symlink, linkname) == 0)
1162232153Smm		return (1);
1163238856Smm	if (errno == ENOMEM)
1164238856Smm		__archive_errx(1, "No memory");
1165232153Smm	return (0);
1166228753Smm}
1167228753Smm
1168232153Smmint
1169232153Smm_archive_entry_copy_symlink_l(struct archive_entry *entry,
1170232153Smm    const char *linkname, size_t len, struct archive_string_conv *sc)
1171232153Smm{
1172232153Smm	int r;
1173232153Smm
1174232153Smm	r = archive_mstring_copy_mbs_len_l(&entry->ae_symlink,
1175232153Smm	    linkname, len, sc);
1176232153Smm	if (linkname != NULL && r == 0)
1177232153Smm		entry->ae_set |= AE_SET_SYMLINK;
1178232153Smm	else
1179232153Smm		entry->ae_set &= ~AE_SET_SYMLINK;
1180232153Smm	return (r);
1181232153Smm}
1182232153Smm
1183228753Smmvoid
1184232153Smmarchive_entry_set_uid(struct archive_entry *entry, int64_t u)
1185228753Smm{
1186228753Smm	entry->stat_valid = 0;
1187228753Smm	entry->ae_stat.aest_uid = u;
1188228753Smm}
1189228753Smm
1190228753Smmvoid
1191228753Smmarchive_entry_set_uname(struct archive_entry *entry, const char *name)
1192228753Smm{
1193232153Smm	archive_mstring_copy_mbs(&entry->ae_uname, name);
1194228753Smm}
1195228753Smm
1196228753Smmvoid
1197228753Smmarchive_entry_copy_uname(struct archive_entry *entry, const char *name)
1198228753Smm{
1199232153Smm	archive_mstring_copy_mbs(&entry->ae_uname, name);
1200228753Smm}
1201228753Smm
1202228753Smmvoid
1203228753Smmarchive_entry_copy_uname_w(struct archive_entry *entry, const wchar_t *name)
1204228753Smm{
1205232153Smm	archive_mstring_copy_wcs(&entry->ae_uname, name);
1206228753Smm}
1207228753Smm
1208228753Smmint
1209228753Smmarchive_entry_update_uname_utf8(struct archive_entry *entry, const char *name)
1210228753Smm{
1211232153Smm	if (archive_mstring_update_utf8(entry->archive,
1212232153Smm	    &entry->ae_uname, name) == 0)
1213232153Smm		return (1);
1214238856Smm	if (errno == ENOMEM)
1215238856Smm		__archive_errx(1, "No memory");
1216232153Smm	return (0);
1217228753Smm}
1218228753Smm
1219232153Smmint
1220232153Smm_archive_entry_copy_uname_l(struct archive_entry *entry,
1221232153Smm    const char *name, size_t len, struct archive_string_conv *sc)
1222232153Smm{
1223232153Smm	return (archive_mstring_copy_mbs_len_l(&entry->ae_uname,
1224232153Smm	    name, len, sc));
1225232153Smm}
1226232153Smm
1227232153Smmconst void *
1228232153Smmarchive_entry_mac_metadata(struct archive_entry *entry, size_t *s)
1229232153Smm{
1230232153Smm  *s = entry->mac_metadata_size;
1231232153Smm  return entry->mac_metadata;
1232232153Smm}
1233232153Smm
1234232153Smmvoid
1235232153Smmarchive_entry_copy_mac_metadata(struct archive_entry *entry,
1236232153Smm    const void *p, size_t s)
1237232153Smm{
1238232153Smm  free(entry->mac_metadata);
1239232153Smm  if (p == NULL || s == 0) {
1240232153Smm    entry->mac_metadata = NULL;
1241232153Smm    entry->mac_metadata_size = 0;
1242232153Smm  } else {
1243232153Smm    entry->mac_metadata_size = s;
1244232153Smm    entry->mac_metadata = malloc(s);
1245232153Smm    if (entry->mac_metadata == NULL)
1246232153Smm      abort();
1247232153Smm    memcpy(entry->mac_metadata, p, s);
1248232153Smm  }
1249232153Smm}
1250232153Smm
1251228753Smm/*
1252228753Smm * ACL management.  The following would, of course, be a lot simpler
1253228753Smm * if: 1) the last draft of POSIX.1e were a really thorough and
1254228753Smm * complete standard that addressed the needs of ACL archiving and 2)
1255228753Smm * everyone followed it faithfully.  Alas, neither is true, so the
1256228753Smm * following is a lot more complex than might seem necessary to the
1257228753Smm * uninitiated.
1258228753Smm */
1259228753Smm
1260232153Smmstruct archive_acl *
1261232153Smmarchive_entry_acl(struct archive_entry *entry)
1262232153Smm{
1263232153Smm	return &entry->acl;
1264232153Smm}
1265232153Smm
1266228753Smmvoid
1267228753Smmarchive_entry_acl_clear(struct archive_entry *entry)
1268228753Smm{
1269232153Smm	archive_acl_clear(&entry->acl);
1270228753Smm}
1271228753Smm
1272228753Smm/*
1273228753Smm * Add a single ACL entry to the internal list of ACL data.
1274228753Smm */
1275232153Smmint
1276228753Smmarchive_entry_acl_add_entry(struct archive_entry *entry,
1277228753Smm    int type, int permset, int tag, int id, const char *name)
1278228753Smm{
1279232153Smm	return archive_acl_add_entry(&entry->acl, type, permset, tag, id, name);
1280228753Smm}
1281228753Smm
1282228753Smm/*
1283228753Smm * As above, but with a wide-character name.
1284228753Smm */
1285232153Smmint
1286228753Smmarchive_entry_acl_add_entry_w(struct archive_entry *entry,
1287228753Smm    int type, int permset, int tag, int id, const wchar_t *name)
1288228753Smm{
1289232153Smm	return archive_acl_add_entry_w_len(&entry->acl,
1290232153Smm	    type, permset, tag, id, name, wcslen(name));
1291228753Smm}
1292228753Smm
1293228753Smm/*
1294228753Smm * Return a count of entries matching "want_type".
1295228753Smm */
1296228753Smmint
1297228753Smmarchive_entry_acl_count(struct archive_entry *entry, int want_type)
1298228753Smm{
1299232153Smm	return archive_acl_count(&entry->acl, want_type);
1300228753Smm}
1301228753Smm
1302228753Smm/*
1303228753Smm * Prepare for reading entries from the ACL data.  Returns a count
1304228753Smm * of entries matching "want_type", or zero if there are no
1305228753Smm * non-extended ACL entries of that type.
1306228753Smm */
1307228753Smmint
1308228753Smmarchive_entry_acl_reset(struct archive_entry *entry, int want_type)
1309228753Smm{
1310232153Smm	return archive_acl_reset(&entry->acl, want_type);
1311228753Smm}
1312228753Smm
1313228753Smm/*
1314228753Smm * Return the next ACL entry in the list.  Fake entries for the
1315228753Smm * standard permissions and include them in the returned list.
1316228753Smm */
1317228753Smmint
1318228753Smmarchive_entry_acl_next(struct archive_entry *entry, int want_type, int *type,
1319228753Smm    int *permset, int *tag, int *id, const char **name)
1320228753Smm{
1321238856Smm	int r;
1322238856Smm	r = archive_acl_next(entry->archive, &entry->acl, want_type, type,
1323238856Smm		permset, tag, id, name);
1324238856Smm	if (r == ARCHIVE_FATAL && errno == ENOMEM)
1325238856Smm		__archive_errx(1, "No memory");
1326238856Smm	return (r);
1327228753Smm}
1328228753Smm
1329228753Smm/*
1330228753Smm * Generate a text version of the ACL.  The flags parameter controls
1331228753Smm * the style of the generated ACL.
1332228753Smm */
1333228753Smmconst wchar_t *
1334228753Smmarchive_entry_acl_text_w(struct archive_entry *entry, int flags)
1335228753Smm{
1336238856Smm	const wchar_t *r;
1337238856Smm	r = archive_acl_text_w(entry->archive, &entry->acl, flags);
1338238856Smm	if (r == NULL && errno == ENOMEM)
1339238856Smm		__archive_errx(1, "No memory");
1340238856Smm	return (r);
1341228753Smm}
1342228753Smm
1343232153Smmconst char *
1344232153Smmarchive_entry_acl_text(struct archive_entry *entry, int flags)
1345228753Smm{
1346232153Smm	const char *p;
1347232153Smm	if (archive_acl_text_l(&entry->acl, flags, &p, NULL, NULL) != 0
1348232153Smm	    && errno == ENOMEM)
1349238856Smm		__archive_errx(1, "No memory");
1350232153Smm	return (p);
1351228753Smm}
1352228753Smm
1353228753Smmint
1354232153Smm_archive_entry_acl_text_l(struct archive_entry *entry, int flags,
1355232153Smm    const char **acl_text, size_t *len, struct archive_string_conv *sc)
1356228753Smm{
1357232153Smm	return (archive_acl_text_l(&entry->acl, flags, acl_text, len, sc));
1358228753Smm}
1359228753Smm
1360228753Smm/*
1361228753Smm * Following code is modified from UC Berkeley sources, and
1362228753Smm * is subject to the following copyright notice.
1363228753Smm */
1364228753Smm
1365228753Smm/*-
1366228753Smm * Copyright (c) 1993
1367228753Smm *	The Regents of the University of California.  All rights reserved.
1368228753Smm *
1369228753Smm * Redistribution and use in source and binary forms, with or without
1370228753Smm * modification, are permitted provided that the following conditions
1371228753Smm * are met:
1372228753Smm * 1. Redistributions of source code must retain the above copyright
1373228753Smm *    notice, this list of conditions and the following disclaimer.
1374228753Smm * 2. Redistributions in binary form must reproduce the above copyright
1375228753Smm *    notice, this list of conditions and the following disclaimer in the
1376228753Smm *    documentation and/or other materials provided with the distribution.
1377228753Smm * 4. Neither the name of the University nor the names of its contributors
1378228753Smm *    may be used to endorse or promote products derived from this software
1379228753Smm *    without specific prior written permission.
1380228753Smm *
1381228753Smm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
1382228753Smm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1383228753Smm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1384228753Smm * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
1385228753Smm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1386228753Smm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
1387228753Smm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
1388228753Smm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
1389228753Smm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
1390228753Smm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
1391228753Smm * SUCH DAMAGE.
1392228753Smm */
1393228753Smm
1394228753Smmstatic struct flag {
1395228753Smm	const char	*name;
1396228753Smm	const wchar_t	*wname;
1397228753Smm	unsigned long	 set;
1398228753Smm	unsigned long	 clear;
1399228753Smm} flags[] = {
1400228753Smm	/* Preferred (shorter) names per flag first, all prefixed by "no" */
1401228753Smm#ifdef SF_APPEND
1402228753Smm	{ "nosappnd",	L"nosappnd",		SF_APPEND,	0 },
1403228753Smm	{ "nosappend",	L"nosappend",		SF_APPEND,	0 },
1404228753Smm#endif
1405228753Smm#ifdef  EXT2_APPEND_FL				/* 'a' */
1406228753Smm	{ "nosappnd",	L"nosappnd",		EXT2_APPEND_FL,	0 },
1407228753Smm	{ "nosappend",	L"nosappend",		EXT2_APPEND_FL,	0 },
1408228753Smm#endif
1409228753Smm#ifdef SF_ARCHIVED
1410228753Smm	{ "noarch",	L"noarch",		SF_ARCHIVED,	0 },
1411228753Smm	{ "noarchived",	L"noarchived",       	SF_ARCHIVED,	0 },
1412228753Smm#endif
1413228753Smm#ifdef SF_IMMUTABLE
1414228753Smm	{ "noschg",	L"noschg",		SF_IMMUTABLE,	0 },
1415228753Smm	{ "noschange",	L"noschange",		SF_IMMUTABLE,	0 },
1416228753Smm	{ "nosimmutable",	L"nosimmutable",	SF_IMMUTABLE,	0 },
1417228753Smm#endif
1418228753Smm#ifdef EXT2_IMMUTABLE_FL			/* 'i' */
1419228753Smm	{ "noschg",	L"noschg",		EXT2_IMMUTABLE_FL,	0 },
1420228753Smm	{ "noschange",	L"noschange",		EXT2_IMMUTABLE_FL,	0 },
1421228753Smm	{ "nosimmutable",	L"nosimmutable",	EXT2_IMMUTABLE_FL,	0 },
1422228753Smm#endif
1423228753Smm#ifdef SF_NOUNLINK
1424228753Smm	{ "nosunlnk",	L"nosunlnk",		SF_NOUNLINK,	0 },
1425228753Smm	{ "nosunlink",	L"nosunlink",		SF_NOUNLINK,	0 },
1426228753Smm#endif
1427228753Smm#ifdef SF_SNAPSHOT
1428228753Smm	{ "nosnapshot",	L"nosnapshot",	SF_SNAPSHOT,	0 },
1429228753Smm#endif
1430228753Smm#ifdef UF_APPEND
1431228753Smm	{ "nouappnd",	L"nouappnd",		UF_APPEND,	0 },
1432228753Smm	{ "nouappend",	L"nouappend",		UF_APPEND,	0 },
1433228753Smm#endif
1434228753Smm#ifdef UF_IMMUTABLE
1435228753Smm	{ "nouchg",	L"nouchg",		UF_IMMUTABLE,	0 },
1436228753Smm	{ "nouchange",	L"nouchange",		UF_IMMUTABLE,	0 },
1437228753Smm	{ "nouimmutable",	L"nouimmutable",	UF_IMMUTABLE,	0 },
1438228753Smm#endif
1439228753Smm#ifdef UF_NODUMP
1440228753Smm	{ "nodump",	L"nodump",		0,		UF_NODUMP},
1441228753Smm#endif
1442228753Smm#ifdef EXT2_NODUMP_FL				/* 'd' */
1443228753Smm	{ "nodump",	L"nodump",		0,		EXT2_NODUMP_FL},
1444228753Smm#endif
1445228753Smm#ifdef UF_OPAQUE
1446228753Smm	{ "noopaque",	L"noopaque",		UF_OPAQUE,	0 },
1447228753Smm#endif
1448228753Smm#ifdef UF_NOUNLINK
1449228753Smm	{ "nouunlnk",	L"nouunlnk",		UF_NOUNLINK,	0 },
1450228753Smm	{ "nouunlink",	L"nouunlink",		UF_NOUNLINK,	0 },
1451228753Smm#endif
1452248616Smm#ifdef UF_COMPRESSED
1453248616Smm	{ "nocompressed",L"nocompressed",	UF_COMPRESSED,	0 },
1454248616Smm#endif
1455228753Smm#ifdef EXT2_UNRM_FL
1456228753Smm        { "nouunlink",	L"nouunlink",		EXT2_UNRM_FL,	0},
1457228753Smm#endif
1458228753Smm
1459228753Smm#ifdef EXT2_BTREE_FL
1460228753Smm        { "nobtree",	L"nobtree",       	EXT2_BTREE_FL,	0 },
1461228753Smm#endif
1462228753Smm
1463228753Smm#ifdef EXT2_ECOMPR_FL
1464228753Smm        { "nocomperr",	L"nocomperr",       	EXT2_ECOMPR_FL,	0 },
1465228753Smm#endif
1466228753Smm
1467228753Smm#ifdef EXT2_COMPR_FL				/* 'c' */
1468228753Smm        { "nocompress",	L"nocompress",       	EXT2_COMPR_FL,	0 },
1469228753Smm#endif
1470228753Smm
1471228753Smm#ifdef EXT2_NOATIME_FL				/* 'A' */
1472228753Smm        { "noatime",	L"noatime",		0,		EXT2_NOATIME_FL},
1473228753Smm#endif
1474228753Smm
1475228753Smm#ifdef EXT2_DIRTY_FL
1476228753Smm        { "nocompdirty",L"nocompdirty",		EXT2_DIRTY_FL,		0},
1477228753Smm#endif
1478228753Smm
1479228753Smm#ifdef EXT2_COMPRBLK_FL
1480228753Smm#ifdef EXT2_NOCOMPR_FL
1481228753Smm        { "nocomprblk",	L"nocomprblk",		EXT2_COMPRBLK_FL, EXT2_NOCOMPR_FL},
1482228753Smm#else
1483228753Smm        { "nocomprblk",	L"nocomprblk",		EXT2_COMPRBLK_FL,	0},
1484228753Smm#endif
1485228753Smm#endif
1486228753Smm#ifdef EXT2_DIRSYNC_FL
1487228753Smm        { "nodirsync",	L"nodirsync",		EXT2_DIRSYNC_FL,	0},
1488228753Smm#endif
1489228753Smm#ifdef EXT2_INDEX_FL
1490228753Smm        { "nohashidx",	L"nohashidx",		EXT2_INDEX_FL,		0},
1491228753Smm#endif
1492228753Smm#ifdef EXT2_IMAGIC_FL
1493228753Smm        { "noimagic",	L"noimagic",		EXT2_IMAGIC_FL,		0},
1494228753Smm#endif
1495228753Smm#ifdef EXT3_JOURNAL_DATA_FL
1496228753Smm        { "nojournal",	L"nojournal",		EXT3_JOURNAL_DATA_FL,	0},
1497228753Smm#endif
1498228753Smm#ifdef EXT2_SECRM_FL
1499228753Smm        { "nosecuredeletion",L"nosecuredeletion",EXT2_SECRM_FL,		0},
1500228753Smm#endif
1501228753Smm#ifdef EXT2_SYNC_FL
1502228753Smm        { "nosync",	L"nosync",		EXT2_SYNC_FL,		0},
1503228753Smm#endif
1504228753Smm#ifdef EXT2_NOTAIL_FL
1505228753Smm        { "notail",	L"notail",		0,		EXT2_NOTAIL_FL},
1506228753Smm#endif
1507228753Smm#ifdef EXT2_TOPDIR_FL
1508228753Smm        { "notopdir",	L"notopdir",		EXT2_TOPDIR_FL,		0},
1509228753Smm#endif
1510228753Smm#ifdef EXT2_RESERVED_FL
1511228753Smm        { "noreserved",	L"noreserved",		EXT2_RESERVED_FL,	0},
1512228753Smm#endif
1513228753Smm
1514228753Smm	{ NULL,		NULL,			0,		0 }
1515228753Smm};
1516228753Smm
1517228753Smm/*
1518228753Smm * fflagstostr --
1519228753Smm *	Convert file flags to a comma-separated string.  If no flags
1520228753Smm *	are set, return the empty string.
1521228753Smm */
1522228753Smmstatic char *
1523228753Smmae_fflagstostr(unsigned long bitset, unsigned long bitclear)
1524228753Smm{
1525228753Smm	char *string, *dp;
1526228753Smm	const char *sp;
1527228753Smm	unsigned long bits;
1528228753Smm	struct flag *flag;
1529228753Smm	size_t	length;
1530228753Smm
1531228753Smm	bits = bitset | bitclear;
1532228753Smm	length = 0;
1533228753Smm	for (flag = flags; flag->name != NULL; flag++)
1534228753Smm		if (bits & (flag->set | flag->clear)) {
1535228753Smm			length += strlen(flag->name) + 1;
1536228753Smm			bits &= ~(flag->set | flag->clear);
1537228753Smm		}
1538228753Smm
1539228753Smm	if (length == 0)
1540228753Smm		return (NULL);
1541228753Smm	string = (char *)malloc(length);
1542228753Smm	if (string == NULL)
1543228753Smm		return (NULL);
1544228753Smm
1545228753Smm	dp = string;
1546228753Smm	for (flag = flags; flag->name != NULL; flag++) {
1547228753Smm		if (bitset & flag->set || bitclear & flag->clear) {
1548228753Smm			sp = flag->name + 2;
1549228753Smm		} else if (bitset & flag->clear  ||  bitclear & flag->set) {
1550228753Smm			sp = flag->name;
1551228753Smm		} else
1552228753Smm			continue;
1553228753Smm		bitset &= ~(flag->set | flag->clear);
1554228753Smm		bitclear &= ~(flag->set | flag->clear);
1555228753Smm		if (dp > string)
1556228753Smm			*dp++ = ',';
1557228753Smm		while ((*dp++ = *sp++) != '\0')
1558228753Smm			;
1559228753Smm		dp--;
1560228753Smm	}
1561228753Smm
1562228753Smm	*dp = '\0';
1563228753Smm	return (string);
1564228753Smm}
1565228753Smm
1566228753Smm/*
1567228753Smm * strtofflags --
1568228753Smm *	Take string of arguments and return file flags.  This
1569228753Smm *	version works a little differently than strtofflags(3).
1570228753Smm *	In particular, it always tests every token, skipping any
1571228753Smm *	unrecognized tokens.  It returns a pointer to the first
1572228753Smm *	unrecognized token, or NULL if every token was recognized.
1573228753Smm *	This version is also const-correct and does not modify the
1574228753Smm *	provided string.
1575228753Smm */
1576228753Smmstatic const char *
1577228753Smmae_strtofflags(const char *s, unsigned long *setp, unsigned long *clrp)
1578228753Smm{
1579228753Smm	const char *start, *end;
1580228753Smm	struct flag *flag;
1581228753Smm	unsigned long set, clear;
1582228753Smm	const char *failed;
1583228753Smm
1584228753Smm	set = clear = 0;
1585228753Smm	start = s;
1586228753Smm	failed = NULL;
1587228753Smm	/* Find start of first token. */
1588228753Smm	while (*start == '\t'  ||  *start == ' '  ||  *start == ',')
1589228753Smm		start++;
1590228753Smm	while (*start != '\0') {
1591228753Smm		/* Locate end of token. */
1592228753Smm		end = start;
1593228753Smm		while (*end != '\0'  &&  *end != '\t'  &&
1594228753Smm		    *end != ' '  &&  *end != ',')
1595228753Smm			end++;
1596228753Smm		for (flag = flags; flag->name != NULL; flag++) {
1597228753Smm			if (memcmp(start, flag->name, end - start) == 0) {
1598228753Smm				/* Matched "noXXXX", so reverse the sense. */
1599228753Smm				clear |= flag->set;
1600228753Smm				set |= flag->clear;
1601228753Smm				break;
1602228753Smm			} else if (memcmp(start, flag->name + 2, end - start)
1603228753Smm			    == 0) {
1604228753Smm				/* Matched "XXXX", so don't reverse. */
1605228753Smm				set |= flag->set;
1606228753Smm				clear |= flag->clear;
1607228753Smm				break;
1608228753Smm			}
1609228753Smm		}
1610228753Smm		/* Ignore unknown flag names. */
1611228753Smm		if (flag->name == NULL  &&  failed == NULL)
1612228753Smm			failed = start;
1613228753Smm
1614228753Smm		/* Find start of next token. */
1615228753Smm		start = end;
1616228753Smm		while (*start == '\t'  ||  *start == ' '  ||  *start == ',')
1617228753Smm			start++;
1618228753Smm
1619228753Smm	}
1620228753Smm
1621228753Smm	if (setp)
1622228753Smm		*setp = set;
1623228753Smm	if (clrp)
1624228753Smm		*clrp = clear;
1625228753Smm
1626228753Smm	/* Return location of first failure. */
1627228753Smm	return (failed);
1628228753Smm}
1629228753Smm
1630228753Smm/*
1631228753Smm * wcstofflags --
1632228753Smm *	Take string of arguments and return file flags.  This
1633228753Smm *	version works a little differently than strtofflags(3).
1634228753Smm *	In particular, it always tests every token, skipping any
1635228753Smm *	unrecognized tokens.  It returns a pointer to the first
1636228753Smm *	unrecognized token, or NULL if every token was recognized.
1637228753Smm *	This version is also const-correct and does not modify the
1638228753Smm *	provided string.
1639228753Smm */
1640228753Smmstatic const wchar_t *
1641228753Smmae_wcstofflags(const wchar_t *s, unsigned long *setp, unsigned long *clrp)
1642228753Smm{
1643228753Smm	const wchar_t *start, *end;
1644228753Smm	struct flag *flag;
1645228753Smm	unsigned long set, clear;
1646228753Smm	const wchar_t *failed;
1647228753Smm
1648228753Smm	set = clear = 0;
1649228753Smm	start = s;
1650228753Smm	failed = NULL;
1651228753Smm	/* Find start of first token. */
1652228753Smm	while (*start == L'\t'  ||  *start == L' '  ||  *start == L',')
1653228753Smm		start++;
1654228753Smm	while (*start != L'\0') {
1655228753Smm		/* Locate end of token. */
1656228753Smm		end = start;
1657228753Smm		while (*end != L'\0'  &&  *end != L'\t'  &&
1658228753Smm		    *end != L' '  &&  *end != L',')
1659228753Smm			end++;
1660228753Smm		for (flag = flags; flag->wname != NULL; flag++) {
1661228753Smm			if (wmemcmp(start, flag->wname, end - start) == 0) {
1662228753Smm				/* Matched "noXXXX", so reverse the sense. */
1663228753Smm				clear |= flag->set;
1664228753Smm				set |= flag->clear;
1665228753Smm				break;
1666228753Smm			} else if (wmemcmp(start, flag->wname + 2, end - start)
1667228753Smm			    == 0) {
1668228753Smm				/* Matched "XXXX", so don't reverse. */
1669228753Smm				set |= flag->set;
1670228753Smm				clear |= flag->clear;
1671228753Smm				break;
1672228753Smm			}
1673228753Smm		}
1674228753Smm		/* Ignore unknown flag names. */
1675228753Smm		if (flag->wname == NULL  &&  failed == NULL)
1676228753Smm			failed = start;
1677228753Smm
1678228753Smm		/* Find start of next token. */
1679228753Smm		start = end;
1680228753Smm		while (*start == L'\t'  ||  *start == L' '  ||  *start == L',')
1681228753Smm			start++;
1682228753Smm
1683228753Smm	}
1684228753Smm
1685228753Smm	if (setp)
1686228753Smm		*setp = set;
1687228753Smm	if (clrp)
1688228753Smm		*clrp = clear;
1689228753Smm
1690228753Smm	/* Return location of first failure. */
1691228753Smm	return (failed);
1692228753Smm}
1693228753Smm
1694228753Smm
1695228753Smm#ifdef TEST
1696228753Smm#include <stdio.h>
1697228753Smmint
1698228753Smmmain(int argc, char **argv)
1699228753Smm{
1700228753Smm	struct archive_entry *entry = archive_entry_new();
1701228753Smm	unsigned long set, clear;
1702228753Smm	const wchar_t *remainder;
1703228753Smm
1704228753Smm	remainder = archive_entry_copy_fflags_text_w(entry, L"nosappnd dump archive,,,,,,,");
1705228753Smm	archive_entry_fflags(entry, &set, &clear);
1706228753Smm
1707228753Smm	wprintf(L"set=0x%lX clear=0x%lX remainder='%ls'\n", set, clear, remainder);
1708228753Smm
1709228753Smm	wprintf(L"new flags='%s'\n", archive_entry_fflags_text(entry));
1710228753Smm	return (0);
1711228753Smm}
1712228753Smm#endif
1713