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