]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libarchive/archive_entry.c
This commit was generated by cvs2svn to compensate for changes in r155832,
[FreeBSD/FreeBSD.git] / lib / libarchive / archive_entry.c
1 /*-
2  * Copyright (c) 2003-2004 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  *    in this position and unchanged.
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 #include <sys/stat.h>
31 #include <sys/types.h>
32 #ifdef MAJOR_IN_MKDEV
33 #include <sys/mkdev.h>
34 #else
35 #ifdef MAJOR_IN_SYSMACROS
36 #include <sys/sysmacros.h>
37 #endif
38 #endif
39 #ifdef HAVE_EXT2FS_EXT2_FS_H
40 #include <ext2fs/ext2_fs.h>     /* for Linux file flags */
41 #endif
42 #include <limits.h>
43 #include <stddef.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47
48 /* Obtain suitable wide-character manipulation functions. */
49 #ifdef HAVE_WCHAR_H
50 #include <wchar.h>
51 #else
52 static size_t wcslen(const wchar_t *s)
53 {
54         const wchar_t *p = s;
55         while (*p != L'\0')
56                 ++p;
57         return p - s;
58 }
59 static wchar_t * wcscpy(wchar_t *s1, const wchar_t *s2)
60 {
61         wchar_t *dest = s1;
62         while((*s1 = *s2) != L'\0')
63                 ++s1, ++s2;
64         return dest;
65 }
66 #define wmemcpy(a,b,i)  (wchar_t *)memcpy((a),(b),(i)*sizeof(wchar_t))
67 /* Good enough for simple equality testing, but not for sorting. */
68 #define wmemcmp(a,b,i)  memcmp((a),(b),(i)*sizeof(wchar_t))
69 #endif
70
71 #include "archive.h"
72 #include "archive_entry.h"
73 #include "archive_private.h"
74
75 #undef max
76 #define max(a, b)       ((a)>(b)?(a):(b))
77
78 /*
79  * Handle wide character (i.e., Unicode) and non-wide character
80  * strings transparently.
81  *
82  */
83
84 struct aes {
85         const char *aes_mbs;
86         char *aes_mbs_alloc;
87         const wchar_t *aes_wcs;
88         wchar_t *aes_wcs_alloc;
89 };
90
91 struct ae_acl {
92         struct ae_acl *next;
93         int     type;                   /* E.g., access or default */
94         int     tag;                    /* E.g., user/group/other/mask */
95         int     permset;                /* r/w/x bits */
96         int     id;                     /* uid/gid for user/group */
97         struct aes name;                /* uname/gname */
98 };
99
100 static void     aes_clean(struct aes *);
101 static void     aes_copy(struct aes *dest, struct aes *src);
102 static const char *     aes_get_mbs(struct aes *);
103 static const wchar_t *  aes_get_wcs(struct aes *);
104 static void     aes_set_mbs(struct aes *, const char *mbs);
105 static void     aes_copy_mbs(struct aes *, const char *mbs);
106 /* static void  aes_set_wcs(struct aes *, const wchar_t *wcs); */
107 static void     aes_copy_wcs(struct aes *, const wchar_t *wcs);
108
109 static char *    ae_fflagstostr(unsigned long bitset, unsigned long bitclear);
110 static const wchar_t    *ae_wcstofflags(const wchar_t *stringp,
111                     unsigned long *setp, unsigned long *clrp);
112 static void     append_entry_w(wchar_t **wp, const wchar_t *prefix, int tag,
113                     const wchar_t *wname, int perm, int id);
114 static void     append_id_w(wchar_t **wp, int id);
115
116 static int      acl_special(struct archive_entry *entry,
117                     int type, int permset, int tag);
118 static struct ae_acl *acl_new_entry(struct archive_entry *entry,
119                     int type, int permset, int tag, int id);
120 static void     next_field_w(const wchar_t **wp, const wchar_t **start,
121                     const wchar_t **end, wchar_t *sep);
122 static int      prefix_w(const wchar_t *start, const wchar_t *end,
123                     const wchar_t *test);
124
125
126 /*
127  * Description of an archive entry.
128  *
129  * Basically, this is a "struct stat" with a few text fields added in.
130  *
131  * TODO: Add "comment", "charset", and possibly other entries
132  * that are supported by "pax interchange" format.  However, GNU, ustar,
133  * cpio, and other variants don't support these features, so they're not an
134  * excruciatingly high priority right now.
135  *
136  * TODO: "pax interchange" format allows essentially arbitrary
137  * key/value attributes to be attached to any entry.  Supporting
138  * such extensions may make this library useful for special
139  * applications (e.g., a package manager could attach special
140  * package-management attributes to each entry).  There are tricky
141  * API issues involved, so this is not going to happen until
142  * there's a real demand for it.
143  *
144  * TODO: Design a good API for handling sparse files.
145  */
146 struct archive_entry {
147         /*
148          * Note that ae_stat.st_mode & S_IFMT  can be  0!
149          *
150          * This occurs when the actual file type of the object is not
151          * in the archive.  For example, 'tar' archives store
152          * hardlinks without marking the type of the underlying
153          * object.
154          */
155         struct stat ae_stat;
156
157         /*
158          * Use aes here so that we get transparent mbs<->wcs conversions.
159          */
160         struct aes ae_fflags_text;      /* Text fflags per fflagstostr(3) */
161         unsigned long ae_fflags_set;            /* Bitmap fflags */
162         unsigned long ae_fflags_clear;
163         struct aes ae_gname;            /* Name of owning group */
164         struct aes ae_hardlink; /* Name of target for hardlink */
165         struct aes ae_pathname; /* Name of entry */
166         struct aes ae_symlink;          /* symlink contents */
167         struct aes ae_uname;            /* Name of owner */
168
169         struct ae_acl   *acl_head;
170         struct ae_acl   *acl_p;
171         int              acl_state;     /* See acl_next for details. */
172         wchar_t         *acl_text_w;
173 };
174
175 static void
176 aes_clean(struct aes *aes)
177 {
178         if (aes->aes_mbs_alloc) {
179                 free(aes->aes_mbs_alloc);
180                 aes->aes_mbs_alloc = NULL;
181         }
182         if (aes->aes_wcs_alloc) {
183                 free(aes->aes_wcs_alloc);
184                 aes->aes_wcs_alloc = NULL;
185         }
186         memset(aes, 0, sizeof(*aes));
187 }
188
189 static void
190 aes_copy(struct aes *dest, struct aes *src)
191 {
192         *dest = *src;
193         if (src->aes_mbs != NULL) {
194                 dest->aes_mbs_alloc = strdup(src->aes_mbs);
195                 dest->aes_mbs = dest->aes_mbs_alloc;
196                 if (dest->aes_mbs == NULL)
197                         __archive_errx(1, "No memory for aes_copy()");
198         }
199
200         if (src->aes_wcs != NULL) {
201                 dest->aes_wcs_alloc = malloc((wcslen(src->aes_wcs) + 1)
202                     * sizeof(wchar_t));
203                 dest->aes_wcs = dest->aes_wcs_alloc;
204                 if (dest->aes_wcs == NULL)
205                         __archive_errx(1, "No memory for aes_copy()");
206                 wcscpy(dest->aes_wcs_alloc, src->aes_wcs);
207         }
208 }
209
210 static const char *
211 aes_get_mbs(struct aes *aes)
212 {
213         if (aes->aes_mbs == NULL && aes->aes_wcs == NULL)
214                 return NULL;
215         if (aes->aes_mbs == NULL && aes->aes_wcs != NULL) {
216                 /*
217                  * XXX Need to estimate the number of byte in the
218                  * multi-byte form.  Assume that, on average, wcs
219                  * chars encode to no more than 3 bytes.  There must
220                  * be a better way... XXX
221                  */
222                 int mbs_length = wcslen(aes->aes_wcs) * 3 + 64;
223                 aes->aes_mbs_alloc = malloc(mbs_length);
224                 aes->aes_mbs = aes->aes_mbs_alloc;
225                 if (aes->aes_mbs == NULL)
226                         __archive_errx(1, "No memory for aes_get_mbs()");
227                 wcstombs(aes->aes_mbs_alloc, aes->aes_wcs, mbs_length - 1);
228                 aes->aes_mbs_alloc[mbs_length - 1] = 0;
229         }
230         return (aes->aes_mbs);
231 }
232
233 static const wchar_t *
234 aes_get_wcs(struct aes *aes)
235 {
236         if (aes->aes_wcs == NULL && aes->aes_mbs == NULL)
237                 return NULL;
238         if (aes->aes_wcs == NULL && aes->aes_mbs != NULL) {
239                 /*
240                  * No single byte will be more than one wide character,
241                  * so this length estimate will always be big enough.
242                  */
243                 int wcs_length = strlen(aes->aes_mbs);
244                 aes->aes_wcs_alloc
245                     = malloc((wcs_length + 1) * sizeof(wchar_t));
246                 aes->aes_wcs = aes->aes_wcs_alloc;
247                 if (aes->aes_wcs == NULL)
248                         __archive_errx(1, "No memory for aes_get_wcs()");
249                 mbstowcs(aes->aes_wcs_alloc, aes->aes_mbs, wcs_length);
250                 aes->aes_wcs_alloc[wcs_length] = 0;
251         }
252         return (aes->aes_wcs);
253 }
254
255 static void
256 aes_set_mbs(struct aes *aes, const char *mbs)
257 {
258         if (aes->aes_mbs_alloc) {
259                 free(aes->aes_mbs_alloc);
260                 aes->aes_mbs_alloc = NULL;
261         }
262         if (aes->aes_wcs_alloc) {
263                 free(aes->aes_wcs_alloc);
264                 aes->aes_wcs_alloc = NULL;
265         }
266         aes->aes_mbs = mbs;
267         aes->aes_wcs = NULL;
268 }
269
270 static void
271 aes_copy_mbs(struct aes *aes, const char *mbs)
272 {
273         if (aes->aes_mbs_alloc) {
274                 free(aes->aes_mbs_alloc);
275                 aes->aes_mbs_alloc = NULL;
276         }
277         if (aes->aes_wcs_alloc) {
278                 free(aes->aes_wcs_alloc);
279                 aes->aes_wcs_alloc = NULL;
280         }
281         aes->aes_mbs_alloc = malloc((strlen(mbs) + 1) * sizeof(char));
282         if (aes->aes_mbs_alloc == NULL)
283                 __archive_errx(1, "No memory for aes_copy_mbs()");
284         strcpy(aes->aes_mbs_alloc, mbs);
285         aes->aes_mbs = aes->aes_mbs_alloc;
286         aes->aes_wcs = NULL;
287 }
288
289 #if 0
290 static void
291 aes_set_wcs(struct aes *aes, const wchar_t *wcs)
292 {
293         if (aes->aes_mbs_alloc) {
294                 free(aes->aes_mbs_alloc);
295                 aes->aes_mbs_alloc = NULL;
296         }
297         if (aes->aes_wcs_alloc) {
298                 free(aes->aes_wcs_alloc);
299                 aes->aes_wcs_alloc = NULL;
300         }
301         aes->aes_mbs = NULL;
302         aes->aes_wcs = wcs;
303 }
304 #endif
305
306 static void
307 aes_copy_wcs(struct aes *aes, const wchar_t *wcs)
308 {
309         if (aes->aes_mbs_alloc) {
310                 free(aes->aes_mbs_alloc);
311                 aes->aes_mbs_alloc = NULL;
312         }
313         if (aes->aes_wcs_alloc) {
314                 free(aes->aes_wcs_alloc);
315                 aes->aes_wcs_alloc = NULL;
316         }
317         aes->aes_mbs = NULL;
318         aes->aes_wcs_alloc = malloc((wcslen(wcs) + 1) * sizeof(wchar_t));
319         if (aes->aes_wcs_alloc == NULL)
320                 __archive_errx(1, "No memory for aes_copy_wcs()");
321         wcscpy(aes->aes_wcs_alloc, wcs);
322         aes->aes_wcs = aes->aes_wcs_alloc;
323 }
324
325 struct archive_entry *
326 archive_entry_clear(struct archive_entry *entry)
327 {
328         aes_clean(&entry->ae_fflags_text);
329         aes_clean(&entry->ae_gname);
330         aes_clean(&entry->ae_hardlink);
331         aes_clean(&entry->ae_pathname);
332         aes_clean(&entry->ae_symlink);
333         aes_clean(&entry->ae_uname);
334         archive_entry_acl_clear(entry);
335         memset(entry, 0, sizeof(*entry));
336         return entry;
337 }
338
339 struct archive_entry *
340 archive_entry_clone(struct archive_entry *entry)
341 {
342         struct archive_entry *entry2;
343
344         /* Allocate new structure and copy over all of the fields. */
345         entry2 = malloc(sizeof(*entry2));
346         if (entry2 == NULL)
347                 return (NULL);
348         memset(entry2, 0, sizeof(*entry2));
349         entry2->ae_stat = entry->ae_stat;
350         entry2->ae_fflags_set = entry->ae_fflags_set;
351         entry2->ae_fflags_clear = entry->ae_fflags_clear;
352
353         aes_copy(&entry2->ae_fflags_text, &entry->ae_fflags_text);
354         aes_copy(&entry2->ae_gname, &entry->ae_gname);
355         aes_copy(&entry2->ae_hardlink, &entry->ae_hardlink);
356         aes_copy(&entry2->ae_pathname, &entry->ae_pathname);
357         aes_copy(&entry2->ae_symlink, &entry->ae_symlink);
358         aes_copy(&entry2->ae_uname, &entry->ae_uname);
359
360         /* XXX TODO: Copy ACL data over as well. XXX */
361         return (entry2);
362 }
363
364 void
365 archive_entry_free(struct archive_entry *entry)
366 {
367         archive_entry_clear(entry);
368         free(entry);
369 }
370
371 struct archive_entry *
372 archive_entry_new(void)
373 {
374         struct archive_entry *entry;
375
376         entry = malloc(sizeof(*entry));
377         if (entry == NULL)
378                 return (NULL);
379         memset(entry, 0, sizeof(*entry));
380         return (entry);
381 }
382
383 /*
384  * Functions for reading fields from an archive_entry.
385  */
386
387 time_t
388 archive_entry_atime(struct archive_entry *entry)
389 {
390         return (entry->ae_stat.st_atime);
391 }
392
393 long
394 archive_entry_atime_nsec(struct archive_entry *entry)
395 {
396         (void)entry; /* entry can be unused here. */
397         return (ARCHIVE_STAT_ATIME_NANOS(&entry->ae_stat));
398 }
399
400 time_t
401 archive_entry_ctime(struct archive_entry *entry)
402 {
403         return (entry->ae_stat.st_ctime);
404 }
405
406 long
407 archive_entry_ctime_nsec(struct archive_entry *entry)
408 {
409         (void)entry; /* entry can be unused here. */
410         return (ARCHIVE_STAT_CTIME_NANOS(&entry->ae_stat));
411 }
412
413 dev_t
414 archive_entry_dev(struct archive_entry *entry)
415 {
416         return (entry->ae_stat.st_dev);
417 }
418
419 void
420 archive_entry_fflags(struct archive_entry *entry,
421     unsigned long *set, unsigned long *clear)
422 {
423         *set = entry->ae_fflags_set;
424         *clear = entry->ae_fflags_clear;
425 }
426
427 /*
428  * Note: if text was provided, this just returns that text.  If you
429  * really need the text to be rebuilt in a canonical form, set the
430  * text, ask for the bitmaps, then set the bitmaps.  (Setting the
431  * bitmaps clears any stored text.)  This design is deliberate: if
432  * we're editing archives, we don't want to discard flags just because
433  * they aren't supported on the current system.  The bitmap<->text
434  * conversions are platform-specific (see below).
435  */
436 const char *
437 archive_entry_fflags_text(struct archive_entry *entry)
438 {
439         const char *f;
440         char *p;
441
442         f = aes_get_mbs(&entry->ae_fflags_text);
443         if (f != NULL)
444                 return (f);
445
446         if (entry->ae_fflags_set == 0  &&  entry->ae_fflags_clear == 0)
447                 return (NULL);
448
449         p = ae_fflagstostr(entry->ae_fflags_set, entry->ae_fflags_clear);
450         if (p == NULL)
451                 return (NULL);
452
453         aes_copy_mbs(&entry->ae_fflags_text, p);
454         free(p);
455         f = aes_get_mbs(&entry->ae_fflags_text);
456         return (f);
457 }
458
459 gid_t
460 archive_entry_gid(struct archive_entry *entry)
461 {
462         return (entry->ae_stat.st_gid);
463 }
464
465 const char *
466 archive_entry_gname(struct archive_entry *entry)
467 {
468         return (aes_get_mbs(&entry->ae_gname));
469 }
470
471 const wchar_t *
472 archive_entry_gname_w(struct archive_entry *entry)
473 {
474         return (aes_get_wcs(&entry->ae_gname));
475 }
476
477 const char *
478 archive_entry_hardlink(struct archive_entry *entry)
479 {
480         return (aes_get_mbs(&entry->ae_hardlink));
481 }
482
483 const wchar_t *
484 archive_entry_hardlink_w(struct archive_entry *entry)
485 {
486         return (aes_get_wcs(&entry->ae_hardlink));
487 }
488
489 ino_t
490 archive_entry_ino(struct archive_entry *entry)
491 {
492         return (entry->ae_stat.st_ino);
493 }
494
495 mode_t
496 archive_entry_mode(struct archive_entry *entry)
497 {
498         return (entry->ae_stat.st_mode);
499 }
500
501 time_t
502 archive_entry_mtime(struct archive_entry *entry)
503 {
504         return (entry->ae_stat.st_mtime);
505 }
506
507 long
508 archive_entry_mtime_nsec(struct archive_entry *entry)
509 {
510         (void)entry; /* entry can be unused here. */
511         return (ARCHIVE_STAT_MTIME_NANOS(&entry->ae_stat));
512 }
513
514 const char *
515 archive_entry_pathname(struct archive_entry *entry)
516 {
517         return (aes_get_mbs(&entry->ae_pathname));
518 }
519
520 const wchar_t *
521 archive_entry_pathname_w(struct archive_entry *entry)
522 {
523         return (aes_get_wcs(&entry->ae_pathname));
524 }
525
526 dev_t
527 archive_entry_rdev(struct archive_entry *entry)
528 {
529         return (entry->ae_stat.st_rdev);
530 }
531
532 dev_t
533 archive_entry_rdevmajor(struct archive_entry *entry)
534 {
535         return (major(entry->ae_stat.st_rdev));
536 }
537
538 dev_t
539 archive_entry_rdevminor(struct archive_entry *entry)
540 {
541         return (minor(entry->ae_stat.st_rdev));
542 }
543
544 int64_t
545 archive_entry_size(struct archive_entry *entry)
546 {
547         return (entry->ae_stat.st_size);
548 }
549
550 const struct stat *
551 archive_entry_stat(struct archive_entry *entry)
552 {
553         return (&entry->ae_stat);
554 }
555
556 const char *
557 archive_entry_symlink(struct archive_entry *entry)
558 {
559         return (aes_get_mbs(&entry->ae_symlink));
560 }
561
562 const wchar_t *
563 archive_entry_symlink_w(struct archive_entry *entry)
564 {
565         return (aes_get_wcs(&entry->ae_symlink));
566 }
567
568 uid_t
569 archive_entry_uid(struct archive_entry *entry)
570 {
571         return (entry->ae_stat.st_uid);
572 }
573
574 const char *
575 archive_entry_uname(struct archive_entry *entry)
576 {
577         return (aes_get_mbs(&entry->ae_uname));
578 }
579
580 const wchar_t *
581 archive_entry_uname_w(struct archive_entry *entry)
582 {
583         return (aes_get_wcs(&entry->ae_uname));
584 }
585
586 /*
587  * Functions to set archive_entry properties.
588  */
589
590 /*
591  * Note "copy" not "set" here.  The "set" functions that accept a pointer
592  * only store the pointer; they don't copy the underlying object.
593  */
594 void
595 archive_entry_copy_stat(struct archive_entry *entry, const struct stat *st)
596 {
597         entry->ae_stat = *st;
598 }
599
600 void
601 archive_entry_set_fflags(struct archive_entry *entry,
602     unsigned long set, unsigned long clear)
603 {
604         aes_clean(&entry->ae_fflags_text);
605         entry->ae_fflags_set = set;
606         entry->ae_fflags_clear = clear;
607 }
608
609 const wchar_t *
610 archive_entry_copy_fflags_text_w(struct archive_entry *entry,
611     const wchar_t *flags)
612 {
613         aes_copy_wcs(&entry->ae_fflags_text, flags);
614         return (ae_wcstofflags(flags,
615                     &entry->ae_fflags_set, &entry->ae_fflags_clear));
616 }
617
618 void
619 archive_entry_set_gid(struct archive_entry *entry, gid_t g)
620 {
621         entry->ae_stat.st_gid = g;
622 }
623
624 void
625 archive_entry_set_gname(struct archive_entry *entry, const char *name)
626 {
627         aes_set_mbs(&entry->ae_gname, name);
628 }
629
630 void
631 archive_entry_copy_gname_w(struct archive_entry *entry, const wchar_t *name)
632 {
633         aes_copy_wcs(&entry->ae_gname, name);
634 }
635
636 void
637 archive_entry_set_hardlink(struct archive_entry *entry, const char *target)
638 {
639         aes_set_mbs(&entry->ae_hardlink, target);
640 }
641
642 void
643 archive_entry_copy_hardlink(struct archive_entry *entry, const char *target)
644 {
645         aes_copy_mbs(&entry->ae_hardlink, target);
646 }
647
648 void
649 archive_entry_copy_hardlink_w(struct archive_entry *entry, const wchar_t *target)
650 {
651         aes_copy_wcs(&entry->ae_hardlink, target);
652 }
653
654 void
655 archive_entry_set_atime(struct archive_entry *entry, time_t t, long ns)
656 {
657         entry->ae_stat.st_atime = t;
658         ARCHIVE_STAT_SET_ATIME_NANOS(&entry->ae_stat, ns);
659 }
660
661 void
662 archive_entry_set_ctime(struct archive_entry *entry, time_t t, long ns)
663 {
664         entry->ae_stat.st_ctime = t;
665         ARCHIVE_STAT_SET_CTIME_NANOS(&entry->ae_stat, ns);
666 }
667
668 /* Set symlink if symlink is already set, else set hardlink. */
669 void
670 archive_entry_set_link(struct archive_entry *entry, const char *target)
671 {
672         if (entry->ae_symlink.aes_mbs != NULL ||
673             entry->ae_symlink.aes_wcs != NULL)
674                 aes_set_mbs(&entry->ae_symlink, target);
675         else
676                 aes_set_mbs(&entry->ae_hardlink, target);
677 }
678
679 void
680 archive_entry_set_mode(struct archive_entry *entry, mode_t m)
681 {
682         entry->ae_stat.st_mode = m;
683 }
684
685 void
686 archive_entry_set_mtime(struct archive_entry *entry, time_t m, long ns)
687 {
688         entry->ae_stat.st_mtime = m;
689         ARCHIVE_STAT_SET_MTIME_NANOS(&entry->ae_stat, ns);
690 }
691
692 void
693 archive_entry_set_pathname(struct archive_entry *entry, const char *name)
694 {
695         aes_set_mbs(&entry->ae_pathname, name);
696 }
697
698 void
699 archive_entry_copy_pathname(struct archive_entry *entry, const char *name)
700 {
701         aes_copy_mbs(&entry->ae_pathname, name);
702 }
703
704 void
705 archive_entry_copy_pathname_w(struct archive_entry *entry, const wchar_t *name)
706 {
707         aes_copy_wcs(&entry->ae_pathname, name);
708 }
709
710 void
711 archive_entry_set_rdevmajor(struct archive_entry *entry, dev_t m)
712 {
713         dev_t d;
714
715         d = entry->ae_stat.st_rdev;
716         entry->ae_stat.st_rdev = makedev(major(m), minor(d));
717 }
718
719 void
720 archive_entry_set_rdevminor(struct archive_entry *entry, dev_t m)
721 {
722         dev_t d;
723
724         d = entry->ae_stat.st_rdev;
725         entry->ae_stat.st_rdev = makedev(major(d), minor(m));
726 }
727
728 void
729 archive_entry_set_size(struct archive_entry *entry, int64_t s)
730 {
731         entry->ae_stat.st_size = s;
732 }
733
734 void
735 archive_entry_set_symlink(struct archive_entry *entry, const char *linkname)
736 {
737         aes_set_mbs(&entry->ae_symlink, linkname);
738 }
739
740 void
741 archive_entry_copy_symlink_w(struct archive_entry *entry, const wchar_t *linkname)
742 {
743         aes_copy_wcs(&entry->ae_symlink, linkname);
744 }
745
746 void
747 archive_entry_set_uid(struct archive_entry *entry, uid_t u)
748 {
749         entry->ae_stat.st_uid = u;
750 }
751
752 void
753 archive_entry_set_uname(struct archive_entry *entry, const char *name)
754 {
755         aes_set_mbs(&entry->ae_uname, name);
756 }
757
758 void
759 archive_entry_copy_uname_w(struct archive_entry *entry, const wchar_t *name)
760 {
761         aes_copy_wcs(&entry->ae_uname, name);
762 }
763
764 /*
765  * ACL management.  The following would, of course, be a lot simpler
766  * if: 1) the last draft of POSIX.1e were a really thorough and
767  * complete standard that addressed the needs of ACL archiving and 2)
768  * everyone followed it faithfully.  Alas, neither is true, so the
769  * following is a lot more complex than might seem necessary to the
770  * uninitiated.
771  */
772
773 void
774 archive_entry_acl_clear(struct archive_entry *entry)
775 {
776         struct ae_acl   *ap;
777
778         while (entry->acl_head != NULL) {
779                 ap = entry->acl_head->next;
780                 aes_clean(&entry->acl_head->name);
781                 free(entry->acl_head);
782                 entry->acl_head = ap;
783         }
784         if (entry->acl_text_w != NULL) {
785                 free(entry->acl_text_w);
786                 entry->acl_text_w = NULL;
787         }
788         entry->acl_p = NULL;
789         entry->acl_state = 0; /* Not counting. */
790 }
791
792 /*
793  * Add a single ACL entry to the internal list of ACL data.
794  */
795 void
796 archive_entry_acl_add_entry(struct archive_entry *entry,
797     int type, int permset, int tag, int id, const char *name)
798 {
799         struct ae_acl *ap;
800
801         if (acl_special(entry, type, permset, tag) == 0)
802                 return;
803         ap = acl_new_entry(entry, type, permset, tag, id);
804         if (ap == NULL) {
805                 /* XXX Error XXX */
806                 return;
807         }
808         if (name != NULL  &&  *name != '\0')
809                 aes_copy_mbs(&ap->name, name);
810         else
811                 aes_clean(&ap->name);
812 }
813
814 /*
815  * As above, but with a wide-character name.
816  */
817 void
818 archive_entry_acl_add_entry_w(struct archive_entry *entry,
819     int type, int permset, int tag, int id, const wchar_t *name)
820 {
821         struct ae_acl *ap;
822
823         if (acl_special(entry, type, permset, tag) == 0)
824                 return;
825         ap = acl_new_entry(entry, type, permset, tag, id);
826         if (ap == NULL) {
827                 /* XXX Error XXX */
828                 return;
829         }
830         if (name != NULL  &&  *name != L'\0')
831                 aes_copy_wcs(&ap->name, name);
832         else
833                 aes_clean(&ap->name);
834 }
835
836 /*
837  * If this ACL entry is part of the standard POSIX permissions set,
838  * store the permissions in the stat structure and return zero.
839  */
840 static int
841 acl_special(struct archive_entry *entry, int type, int permset, int tag)
842 {
843         if (type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS) {
844                 switch (tag) {
845                 case ARCHIVE_ENTRY_ACL_USER_OBJ:
846                         entry->ae_stat.st_mode &= ~0700;
847                         entry->ae_stat.st_mode |= (permset & 7) << 6;
848                         return (0);
849                 case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
850                         entry->ae_stat.st_mode &= ~0070;
851                         entry->ae_stat.st_mode |= (permset & 7) << 3;
852                         return (0);
853                 case ARCHIVE_ENTRY_ACL_OTHER:
854                         entry->ae_stat.st_mode &= ~0007;
855                         entry->ae_stat.st_mode |= permset & 7;
856                         return (0);
857                 }
858         }
859         return (1);
860 }
861
862 /*
863  * Allocate and populate a new ACL entry with everything but the
864  * name.
865  */
866 static struct ae_acl *
867 acl_new_entry(struct archive_entry *entry,
868     int type, int permset, int tag, int id)
869 {
870         struct ae_acl *ap;
871
872         if (type != ARCHIVE_ENTRY_ACL_TYPE_ACCESS &&
873             type != ARCHIVE_ENTRY_ACL_TYPE_DEFAULT)
874                 return (NULL);
875         if (entry->acl_text_w != NULL) {
876                 free(entry->acl_text_w);
877                 entry->acl_text_w = NULL;
878         }
879
880         /* XXX TODO: More sanity-checks on the arguments XXX */
881
882         /* If there's a matching entry already in the list, overwrite it. */
883         for (ap = entry->acl_head; ap != NULL; ap = ap->next) {
884                 if (ap->type == type && ap->tag == tag && ap->id == id) {
885                         ap->permset = permset;
886                         return (ap);
887                 }
888         }
889
890         /* Add a new entry to the list. */
891         ap = malloc(sizeof(*ap));
892         if (ap == NULL)
893                 return (NULL);
894         memset(ap, 0, sizeof(*ap));
895         ap->next = entry->acl_head;
896         entry->acl_head = ap;
897         ap->type = type;
898         ap->tag = tag;
899         ap->id = id;
900         ap->permset = permset;
901         return (ap);
902 }
903
904 /*
905  * Return a count of entries matching "want_type".
906  */
907 int
908 archive_entry_acl_count(struct archive_entry *entry, int want_type)
909 {
910         int count;
911         struct ae_acl *ap;
912
913         count = 0;
914         ap = entry->acl_head;
915         while (ap != NULL) {
916                 if ((ap->type & want_type) != 0)
917                         count++;
918                 ap = ap->next;
919         }
920
921         if (count > 0 && ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0))
922                 count += 3;
923         return (count);
924 }
925
926 /*
927  * Prepare for reading entries from the ACL data.  Returns a count
928  * of entries matching "want_type", or zero if there are no
929  * non-extended ACL entries of that type.
930  */
931 int
932 archive_entry_acl_reset(struct archive_entry *entry, int want_type)
933 {
934         int count, cutoff;
935
936         count = archive_entry_acl_count(entry, want_type);
937
938         /*
939          * If the only entries are the three standard ones,
940          * then don't return any ACL data.  (In this case,
941          * client can just use chmod(2) to set permissions.)
942          */
943         if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0)
944                 cutoff = 3;
945         else
946                 cutoff = 0;
947
948         if (count > cutoff)
949                 entry->acl_state = ARCHIVE_ENTRY_ACL_USER_OBJ;
950         else
951                 entry->acl_state = 0;
952         entry->acl_p = entry->acl_head;
953         return (count);
954 }
955
956 /*
957  * Return the next ACL entry in the list.  Fake entries for the
958  * standard permissions and include them in the returned list.
959  */
960
961 int
962 archive_entry_acl_next(struct archive_entry *entry, int want_type, int *type,
963     int *permset, int *tag, int *id, const char **name)
964 {
965         *name = NULL;
966         *id = -1;
967
968         /*
969          * The acl_state is either zero (no entries available), -1
970          * (reading from list), or an entry type (retrieve that type
971          * from ae_stat.st_mode).
972          */
973         if (entry->acl_state == 0)
974                 return (ARCHIVE_WARN);
975
976         /* The first three access entries are special. */
977         if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
978                 switch (entry->acl_state) {
979                 case ARCHIVE_ENTRY_ACL_USER_OBJ:
980                         *permset = (entry->ae_stat.st_mode >> 6) & 7;
981                         *type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
982                         *tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
983                         entry->acl_state = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
984                         return (ARCHIVE_OK);
985                 case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
986                         *permset = (entry->ae_stat.st_mode >> 3) & 7;
987                         *type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
988                         *tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
989                         entry->acl_state = ARCHIVE_ENTRY_ACL_OTHER;
990                         return (ARCHIVE_OK);
991                 case ARCHIVE_ENTRY_ACL_OTHER:
992                         *permset = entry->ae_stat.st_mode & 7;
993                         *type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
994                         *tag = ARCHIVE_ENTRY_ACL_OTHER;
995                         entry->acl_state = -1;
996                         entry->acl_p = entry->acl_head;
997                         return (ARCHIVE_OK);
998                 default:
999                         break;
1000                 }
1001         }
1002
1003         while (entry->acl_p != NULL && (entry->acl_p->type & want_type) == 0)
1004                 entry->acl_p = entry->acl_p->next;
1005         if (entry->acl_p == NULL) {
1006                 entry->acl_state = 0;
1007                 return (ARCHIVE_WARN);
1008         }
1009         *type = entry->acl_p->type;
1010         *permset = entry->acl_p->permset;
1011         *tag = entry->acl_p->tag;
1012         *id = entry->acl_p->id;
1013         *name = aes_get_mbs(&entry->acl_p->name);
1014         entry->acl_p = entry->acl_p->next;
1015         return (ARCHIVE_OK);
1016 }
1017
1018 /*
1019  * Generate a text version of the ACL.  The flags parameter controls
1020  * the style of the generated ACL.
1021  */
1022 const wchar_t *
1023 archive_entry_acl_text_w(struct archive_entry *entry, int flags)
1024 {
1025         int count;
1026         int length;
1027         const wchar_t *wname;
1028         const wchar_t *prefix;
1029         wchar_t separator;
1030         struct ae_acl *ap;
1031         int id;
1032         wchar_t *wp;
1033
1034         if (entry->acl_text_w != NULL) {
1035                 free (entry->acl_text_w);
1036                 entry->acl_text_w = NULL;
1037         }
1038
1039         separator = L',';
1040         count = 0;
1041         length = 0;
1042         ap = entry->acl_head;
1043         while (ap != NULL) {
1044                 if ((ap->type & flags) != 0) {
1045                         count++;
1046                         if ((flags & ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT) &&
1047                             (ap->type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT))
1048                                 length += 8; /* "default:" */
1049                         length += 5; /* tag name */
1050                         length += 1; /* colon */
1051                         wname = aes_get_wcs(&ap->name);
1052                         if (wname != NULL)
1053                                 length += wcslen(wname);
1054                         length ++; /* colon */
1055                         length += 3; /* rwx */
1056                         length += 1; /* colon */
1057                         length += max(sizeof(uid_t),sizeof(gid_t)) * 3 + 1;
1058                         length ++; /* newline */
1059                 }
1060                 ap = ap->next;
1061         }
1062
1063         if (count > 0 && ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0)) {
1064                 length += 10; /* "user::rwx\n" */
1065                 length += 11; /* "group::rwx\n" */
1066                 length += 11; /* "other::rwx\n" */
1067         }
1068
1069         if (count == 0)
1070                 return (NULL);
1071
1072         /* Now, allocate the string and actually populate it. */
1073         wp = entry->acl_text_w = malloc(length * sizeof(wchar_t));
1074         if (wp == NULL)
1075                 __archive_errx(1, "No memory to generate the text version of the ACL");
1076         count = 0;
1077         if ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
1078                 append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_USER_OBJ, NULL,
1079                     entry->ae_stat.st_mode & 0700, -1);
1080                 *wp++ = ',';
1081                 append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_GROUP_OBJ, NULL,
1082                     entry->ae_stat.st_mode & 0070, -1);
1083                 *wp++ = ',';
1084                 append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_OTHER, NULL,
1085                     entry->ae_stat.st_mode & 0007, -1);
1086                 count += 3;
1087
1088                 ap = entry->acl_head;
1089                 while (ap != NULL) {
1090                         if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
1091                                 wname = aes_get_wcs(&ap->name);
1092                                 *wp++ = separator;
1093                                 if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID)
1094                                         id = ap->id;
1095                                 else
1096                                         id = -1;
1097                                 append_entry_w(&wp, NULL, ap->tag, wname,
1098                                     ap->permset, id);
1099                                 count++;
1100                         }
1101                         ap = ap->next;
1102                 }
1103         }
1104
1105
1106         if ((flags & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) {
1107                 if (flags & ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT)
1108                         prefix = L"default:";
1109                 else
1110                         prefix = NULL;
1111                 ap = entry->acl_head;
1112                 count = 0;
1113                 while (ap != NULL) {
1114                         if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) {
1115                                 wname = aes_get_wcs(&ap->name);
1116                                 if (count > 0)
1117                                         *wp++ = separator;
1118                                 if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID)
1119                                         id = ap->id;
1120                                 else
1121                                         id = -1;
1122                                 append_entry_w(&wp, prefix, ap->tag,
1123                                     wname, ap->permset, id);
1124                                 count ++;
1125                         }
1126                         ap = ap->next;
1127                 }
1128         }
1129
1130         return (entry->acl_text_w);
1131 }
1132
1133 static void
1134 append_id_w(wchar_t **wp, int id)
1135 {
1136         if (id > 9)
1137                 append_id_w(wp, id / 10);
1138         *(*wp)++ = L"0123456789"[id % 10];
1139 }
1140
1141 static void
1142 append_entry_w(wchar_t **wp, const wchar_t *prefix, int tag,
1143     const wchar_t *wname, int perm, int id)
1144 {
1145         if (prefix != NULL) {
1146                 wcscpy(*wp, prefix);
1147                 *wp += wcslen(*wp);
1148         }
1149         switch (tag) {
1150         case ARCHIVE_ENTRY_ACL_USER_OBJ:
1151                 wname = NULL;
1152                 id = -1;
1153                 /* FALL THROUGH */
1154         case ARCHIVE_ENTRY_ACL_USER:
1155                 wcscpy(*wp, L"user");
1156                 break;
1157         case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
1158                 wname = NULL;
1159                 id = -1;
1160                 /* FALL THROUGH */
1161         case ARCHIVE_ENTRY_ACL_GROUP:
1162                 wcscpy(*wp, L"group");
1163                 break;
1164         case ARCHIVE_ENTRY_ACL_MASK:
1165                 wcscpy(*wp, L"mask");
1166                 wname = NULL;
1167                 id = -1;
1168                 break;
1169         case ARCHIVE_ENTRY_ACL_OTHER:
1170                 wcscpy(*wp, L"other");
1171                 wname = NULL;
1172                 id = -1;
1173                 break;
1174         }
1175         *wp += wcslen(*wp);
1176         *(*wp)++ = L':';
1177         if (wname != NULL) {
1178                 wcscpy(*wp, wname);
1179                 *wp += wcslen(*wp);
1180         }
1181         *(*wp)++ = L':';
1182         *(*wp)++ = (perm & 0444) ? L'r' : L'-';
1183         *(*wp)++ = (perm & 0222) ? L'w' : L'-';
1184         *(*wp)++ = (perm & 0111) ? L'x' : L'-';
1185         if (id != -1) {
1186                 *(*wp)++ = L':';
1187                 append_id_w(wp, id);
1188         }
1189         **wp = L'\0';
1190 }
1191
1192 /*
1193  * Parse a textual ACL.  This automatically recognizes and supports
1194  * extensions described above.  The 'type' argument is used to
1195  * indicate the type that should be used for any entries not
1196  * explicitly marked as "default:".
1197  */
1198 int
1199 __archive_entry_acl_parse_w(struct archive_entry *entry,
1200     const wchar_t *text, int default_type)
1201 {
1202         int type, tag, permset, id;
1203         const wchar_t *start, *end;
1204         const wchar_t *name_start, *name_end;
1205         wchar_t sep;
1206         wchar_t *namebuff;
1207         int namebuff_length;
1208
1209         name_start = name_end = NULL;
1210         namebuff = NULL;
1211         namebuff_length = 0;
1212
1213         while (text != NULL  &&  *text != L'\0') {
1214                 next_field_w(&text, &start, &end, &sep);
1215                 if (sep != L':')
1216                         goto fail;
1217
1218                 /*
1219                  * Solaris extension:  "defaultuser::rwx" is the
1220                  * default ACL corresponding to "user::rwx", etc.
1221                  */
1222                 if (end-start > 7  && wmemcmp(start, L"default", 7) == 0) {
1223                         type = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT;
1224                         start += 7;
1225                 } else
1226                         type = default_type;
1227
1228                 if (prefix_w(start, end, L"user")) {
1229                         next_field_w(&text, &start, &end, &sep);
1230                         if (sep != L':')
1231                                 goto fail;
1232                         if (end > start) {
1233                                 tag = ARCHIVE_ENTRY_ACL_USER;
1234                                 name_start = start;
1235                                 name_end = end;
1236                         } else
1237                                 tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
1238                 } else if (prefix_w(start, end, L"group")) {
1239                         next_field_w(&text, &start, &end, &sep);
1240                         if (sep != L':')
1241                                 goto fail;
1242                         if (end > start) {
1243                                 tag = ARCHIVE_ENTRY_ACL_GROUP;
1244                                 name_start = start;
1245                                 name_end = end;
1246                         } else
1247                                 tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
1248                 } else if (prefix_w(start, end, L"other")) {
1249                         next_field_w(&text, &start, &end, &sep);
1250                         if (sep != L':')
1251                                 goto fail;
1252                         if (end > start)
1253                                 goto fail;
1254                         tag = ARCHIVE_ENTRY_ACL_OTHER;
1255                 } else if (prefix_w(start, end, L"mask")) {
1256                         next_field_w(&text, &start, &end, &sep);
1257                         if (sep != L':')
1258                                 goto fail;
1259                         if (end > start)
1260                                 goto fail;
1261                         tag = ARCHIVE_ENTRY_ACL_MASK;
1262                 } else
1263                         goto fail;
1264
1265                 next_field_w(&text, &start, &end, &sep);
1266                 permset = 0;
1267                 while (start < end) {
1268                         switch (*start++) {
1269                         case 'r': case 'R':
1270                                 permset |= ARCHIVE_ENTRY_ACL_READ;
1271                                 break;
1272                         case 'w': case 'W':
1273                                 permset |= ARCHIVE_ENTRY_ACL_WRITE;
1274                                 break;
1275                         case 'x': case 'X':
1276                                 permset |= ARCHIVE_ENTRY_ACL_EXECUTE;
1277                                 break;
1278                         case '-':
1279                                 break;
1280                         default:
1281                                 goto fail;
1282                         }
1283                 }
1284
1285                 /*
1286                  * Support star-compatible numeric UID/GID extension.
1287                  * This extension adds a ":" followed by the numeric
1288                  * ID so that "group:groupname:rwx", for example,
1289                  * becomes "group:groupname:rwx:999", where 999 is the
1290                  * numeric GID.  This extension makes it possible, for
1291                  * example, to correctly restore ACLs on a system that
1292                  * might have a damaged passwd file or be disconnected
1293                  * from a central NIS server.  This extension is compatible
1294                  * with POSIX.1e draft 17.
1295                  */
1296                 if (sep == L':' && (tag == ARCHIVE_ENTRY_ACL_USER ||
1297                     tag == ARCHIVE_ENTRY_ACL_GROUP)) {
1298                         next_field_w(&text, &start, &end, &sep);
1299
1300                         id = 0;
1301                         while (start < end  && *start >= '0' && *start <= '9') {
1302                                 if (id > (INT_MAX / 10))
1303                                         id = INT_MAX;
1304                                 else {
1305                                         id *= 10;
1306                                         id += *start - '0';
1307                                         start++;
1308                                 }
1309                         }
1310                 } else
1311                         id = -1; /* No id specified. */
1312
1313                 /* Skip any additional entries. */
1314                 while (sep == L':') {
1315                         next_field_w(&text, &start, &end, &sep);
1316                 }
1317
1318                 /* Add entry to the internal list. */
1319                 if (name_end == name_start) {
1320                         archive_entry_acl_add_entry_w(entry, type, permset,
1321                             tag, id, NULL);
1322                 } else {
1323                         if (namebuff_length <= name_end - name_start) {
1324                                 if (namebuff != NULL)
1325                                         free(namebuff);
1326                                 namebuff_length = name_end - name_start + 256;
1327                                 namebuff =
1328                                     malloc(namebuff_length * sizeof(wchar_t));
1329                                 if (namebuff == NULL)
1330                                         goto fail;
1331                         }
1332                         wmemcpy(namebuff, name_start, name_end - name_start);
1333                         namebuff[name_end - name_start] = L'\0';
1334                         archive_entry_acl_add_entry_w(entry, type,
1335                             permset, tag, id, namebuff);
1336                 }
1337         }
1338         if (namebuff != NULL)
1339                 free(namebuff);
1340         return (ARCHIVE_OK);
1341
1342 fail:
1343         if (namebuff != NULL)
1344                 free(namebuff);
1345         return (ARCHIVE_WARN);
1346 }
1347
1348 /*
1349  * Match "[:whitespace:]*(.*)[:whitespace:]*[:,\n]".  *wp is updated
1350  * to point to just after the separator.  *start points to the first
1351  * character of the matched text and *end just after the last
1352  * character of the matched identifier.  In particular *end - *start
1353  * is the length of the field body, not including leading or trailing
1354  * whitespace.
1355  */
1356 static void
1357 next_field_w(const wchar_t **wp, const wchar_t **start,
1358     const wchar_t **end, wchar_t *sep)
1359 {
1360         /* Skip leading whitespace to find start of field. */
1361         while (**wp == L' ' || **wp == L'\t' || **wp == L'\n') {
1362                 (*wp)++;
1363         }
1364         *start = *wp;
1365
1366         /* Scan for the separator. */
1367         while (**wp != L'\0' && **wp != L',' && **wp != L':' &&
1368             **wp != L'\n') {
1369                 (*wp)++;
1370         }
1371         *sep = **wp;
1372
1373         /* Trim trailing whitespace to locate end of field. */
1374         *end = *wp - 1;
1375         while (**end == L' ' || **end == L'\t' || **end == L'\n') {
1376                 (*end)--;
1377         }
1378         (*end)++;
1379
1380         /* Adjust scanner location. */
1381         if (**wp != L'\0')
1382                 (*wp)++;
1383 }
1384
1385 static int
1386 prefix_w(const wchar_t *start, const wchar_t *end, const wchar_t *test)
1387 {
1388         if (start == end)
1389                 return (0);
1390
1391         if (*start++ != *test++)
1392                 return (0);
1393
1394         while (start < end  &&  *start++ == *test++)
1395                 ;
1396
1397         if (start < end)
1398                 return (0);
1399
1400         return (1);
1401 }
1402
1403
1404 /*
1405  * Following code is modified from UC Berkeley sources, and
1406  * is subject to the following copyright notice.
1407  */
1408
1409 /*-
1410  * Copyright (c) 1993
1411  *      The Regents of the University of California.  All rights reserved.
1412  *
1413  * Redistribution and use in source and binary forms, with or without
1414  * modification, are permitted provided that the following conditions
1415  * are met:
1416  * 1. Redistributions of source code must retain the above copyright
1417  *    notice, this list of conditions and the following disclaimer.
1418  * 2. Redistributions in binary form must reproduce the above copyright
1419  *    notice, this list of conditions and the following disclaimer in the
1420  *    documentation and/or other materials provided with the distribution.
1421  * 4. Neither the name of the University nor the names of its contributors
1422  *    may be used to endorse or promote products derived from this software
1423  *    without specific prior written permission.
1424  *
1425  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
1426  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1427  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1428  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
1429  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1430  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
1431  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
1432  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
1433  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
1434  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
1435  * SUCH DAMAGE.
1436  */
1437
1438 static struct flag {
1439         const char      *name;
1440         const wchar_t   *wname;
1441         unsigned long    set;
1442         unsigned long    clear;
1443 } flags[] = {
1444         /* Preferred (shorter) names per flag first, all prefixed by "no" */
1445 #ifdef SF_APPEND
1446         { "nosappnd",   L"nosappnd",            SF_APPEND,      0 },
1447         { "nosappend",  L"nosappend",           SF_APPEND,      0 },
1448 #endif
1449 #ifdef  EXT2_APPEND_FL                          /* 'a' */
1450         { "nosappnd",   L"nosappnd",            EXT2_APPEND_FL, 0 },
1451         { "nosappend",  L"nosappend",           EXT2_APPEND_FL, 0 },
1452 #endif
1453 #ifdef SF_ARCHIVED
1454         { "noarch",     L"noarch",              SF_ARCHIVED,    0 },
1455         { "noarchived", L"noarchived",          SF_ARCHIVED,    0 },
1456 #endif
1457 #ifdef SF_IMMUTABLE
1458         { "noschg",     L"noschg",              SF_IMMUTABLE,   0 },
1459         { "noschange",  L"noschange",           SF_IMMUTABLE,   0 },
1460         { "nosimmutable",       L"nosimmutable",        SF_IMMUTABLE,   0 },
1461 #endif
1462 #ifdef EXT2_IMMUTABLE_FL                        /* 'i' */
1463         { "noschg",     L"noschg",              EXT2_IMMUTABLE_FL,      0 },
1464         { "noschange",  L"noschange",           EXT2_IMMUTABLE_FL,      0 },
1465         { "nosimmutable",       L"nosimmutable",        EXT2_IMMUTABLE_FL,      0 },
1466 #endif
1467 #ifdef SF_NOUNLINK
1468         { "nosunlnk",   L"nosunlnk",            SF_NOUNLINK,    0 },
1469         { "nosunlink",  L"nosunlink",           SF_NOUNLINK,    0 },
1470 #endif
1471 #ifdef SF_SNAPSHOT
1472         { "nosnapshot", L"nosnapshot",  SF_SNAPSHOT,    0 },
1473 #endif
1474 #ifdef UF_APPEND
1475         { "nouappnd",   L"nouappnd",            UF_APPEND,      0 },
1476         { "nouappend",  L"nouappend",           UF_APPEND,      0 },
1477 #endif
1478 #ifdef UF_IMMUTABLE
1479         { "nouchg",     L"nouchg",              UF_IMMUTABLE,   0 },
1480         { "nouchange",  L"nouchange",           UF_IMMUTABLE,   0 },
1481         { "nouimmutable",       L"nouimmutable",        UF_IMMUTABLE,   0 },
1482 #endif
1483 #ifdef UF_NODUMP
1484         { "nodump",     L"nodump",              0,              UF_NODUMP},
1485 #endif
1486 #ifdef EXT2_NODUMP_FL                           /* 'd' */
1487         { "nodump",     L"nodump",              0,              EXT2_NODUMP_FL},
1488 #endif
1489 #ifdef UF_OPAQUE
1490         { "noopaque",   L"noopaque",            UF_OPAQUE,      0 },
1491 #endif
1492 #ifdef UF_NOUNLINK
1493         { "nouunlnk",   L"nouunlnk",            UF_NOUNLINK,    0 },
1494         { "nouunlink",  L"nouunlink",           UF_NOUNLINK,    0 },
1495 #endif
1496 #ifdef EXT2_COMPR_FL                            /* 'c' */
1497         { "nocompress", L"nocompress",          EXT2_COMPR_FL,  0 },
1498 #endif
1499
1500 #ifdef EXT2_NOATIME_FL                          /* 'A' */
1501         { "noatime",    L"noatime",             0,              EXT2_NOATIME_FL},
1502 #endif
1503         { NULL,         NULL,                   0,              0 }
1504 };
1505
1506 /*
1507  * fflagstostr --
1508  *      Convert file flags to a comma-separated string.  If no flags
1509  *      are set, return the empty string.
1510  */
1511 char *
1512 ae_fflagstostr(unsigned long bitset, unsigned long bitclear)
1513 {
1514         char *string, *dp;
1515         const char *sp;
1516         unsigned long bits;
1517         struct flag *flag;
1518         int     length;
1519
1520         bits = bitset | bitclear;
1521         length = 0;
1522         for (flag = flags; flag->name != NULL; flag++)
1523                 if (bits & (flag->set | flag->clear)) {
1524                         length += strlen(flag->name) + 1;
1525                         bits &= ~(flag->set | flag->clear);
1526                 }
1527
1528         if (length == 0)
1529                 return (NULL);
1530         string = malloc(length);
1531         if (string == NULL)
1532                 return (NULL);
1533
1534         dp = string;
1535         for (flag = flags; flag->name != NULL; flag++) {
1536                 if (bitset & flag->set || bitclear & flag->clear) {
1537                         sp = flag->name + 2;
1538                 } else if (bitset & flag->clear  ||  bitclear & flag->set) {
1539                         sp = flag->name;
1540                 } else
1541                         continue;
1542                 bitset &= ~(flag->set | flag->clear);
1543                 bitclear &= ~(flag->set | flag->clear);
1544                 if (dp > string)
1545                         *dp++ = ',';
1546                 while ((*dp++ = *sp++) != '\0')
1547                         ;
1548                 dp--;
1549         }
1550
1551         *dp = '\0';
1552         return (string);
1553 }
1554
1555 /*
1556  * wcstofflags --
1557  *      Take string of arguments and return file flags.  This
1558  *      version works a little differently than strtofflags(3).
1559  *      In particular, it always tests every token, skipping any
1560  *      unrecognized tokens.  It returns a pointer to the first
1561  *      unrecognized token, or NULL if every token was recognized.
1562  *      This version is also const-correct and does not modify the
1563  *      provided string.
1564  */
1565 const wchar_t *
1566 ae_wcstofflags(const wchar_t *s, unsigned long *setp, unsigned long *clrp)
1567 {
1568         const wchar_t *start, *end;
1569         struct flag *flag;
1570         unsigned long set, clear;
1571         const wchar_t *failed;
1572
1573         set = clear = 0;
1574         start = s;
1575         failed = NULL;
1576         /* Find start of first token. */
1577         while (*start == L'\t'  ||  *start == L' '  ||  *start == L',')
1578                 start++;
1579         while (*start != L'\0') {
1580                 /* Locate end of token. */
1581                 end = start;
1582                 while (*end != L'\0'  &&  *end != L'\t'  &&
1583                     *end != L' '  &&  *end != L',')
1584                         end++;
1585                 for (flag = flags; flag->wname != NULL; flag++) {
1586                         if (wmemcmp(start, flag->wname, end - start) == 0) {
1587                                 /* Matched "noXXXX", so reverse the sense. */
1588                                 clear |= flag->set;
1589                                 set |= flag->clear;
1590                                 break;
1591                         } else if (wmemcmp(start, flag->wname + 2, end - start)
1592                             == 0) {
1593                                 /* Matched "XXXX", so don't reverse. */
1594                                 set |= flag->set;
1595                                 clear |= flag->clear;
1596                                 break;
1597                         }
1598                 }
1599                 /* Ignore unknown flag names. */
1600                 if (flag->wname == NULL  &&  failed == NULL)
1601                         failed = start;
1602
1603                 /* Find start of next token. */
1604                 start = end;
1605                 while (*start == L'\t'  ||  *start == L' '  ||  *start == L',')
1606                         start++;
1607
1608         }
1609
1610         if (setp)
1611                 *setp = set;
1612         if (clrp)
1613                 *clrp = clear;
1614
1615         /* Return location of first failure. */
1616         return (failed);
1617 }
1618
1619
1620 #ifdef TEST
1621 #include <stdio.h>
1622 int
1623 main(int argc, char **argv)
1624 {
1625         struct archive_entry *entry = archive_entry_new();
1626         unsigned long set, clear;
1627         const wchar_t *remainder;
1628
1629         remainder = archive_entry_copy_fflags_text_w(entry, L"nosappnd dump archive,,,,,,,");
1630         archive_entry_fflags(entry, &set, &clear);
1631
1632         wprintf(L"set=0x%lX clear=0x%lX remainder='%ls'\n", set, clear, remainder);
1633
1634         wprintf(L"new flags='%s'\n", archive_entry_fflags_text(entry));
1635         return (0);
1636 }
1637 #endif