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