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