2 * Copyright (c) 2003-2004 Tim Kientzle
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
27 #include "archive_platform.h"
28 __FBSDID("$FreeBSD: src/lib/libarchive/archive_entry.c,v 1.35 2006/05/01 00:55:44 kientzle Exp $");
31 #include <sys/types.h>
33 #include <sys/mkdev.h>
35 #ifdef MAJOR_IN_SYSMACROS
36 #include <sys/sysmacros.h>
39 #ifdef HAVE_EXT2FS_EXT2_FS_H
40 #include <ext2fs/ext2_fs.h> /* for Linux file flags */
48 /* Obtain suitable wide-character manipulation functions. */
52 static size_t wcslen(const wchar_t *s
)
59 static wchar_t * wcscpy(wchar_t *s1
, const wchar_t *s2
)
62 while ((*s1
= *s2
) != L
'\0')
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))
72 #include "archive_entry.h"
73 #include "archive_private.h"
76 #define max(a, b) ((a)>(b)?(a):(b))
79 * Handle wide character (i.e., Unicode) and non-wide character
80 * strings transparently.
87 const wchar_t *aes_wcs
;
88 wchar_t *aes_wcs_alloc
;
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 */
101 struct ae_xattr
*next
;
108 static void aes_clean(struct aes
*);
109 static void aes_copy(struct aes
*dest
, struct aes
*src
);
110 static const char * aes_get_mbs(struct aes
*);
111 static const wchar_t * aes_get_wcs(struct aes
*);
112 static void aes_set_mbs(struct aes
*, const char *mbs
);
113 static void aes_copy_mbs(struct aes
*, const char *mbs
);
114 /* static void aes_set_wcs(struct aes *, const wchar_t *wcs); */
115 static void aes_copy_wcs(struct aes
*, const wchar_t *wcs
);
117 static char * ae_fflagstostr(unsigned long bitset
, unsigned long bitclear
);
118 static const wchar_t *ae_wcstofflags(const wchar_t *stringp
,
119 unsigned long *setp
, unsigned long *clrp
);
120 static void append_entry_w(wchar_t **wp
, const wchar_t *prefix
, int tag
,
121 const wchar_t *wname
, int perm
, int id
);
122 static void append_id_w(wchar_t **wp
, int id
);
124 static int acl_special(struct archive_entry
*entry
,
125 int type
, int permset
, int tag
);
126 static struct ae_acl
*acl_new_entry(struct archive_entry
*entry
,
127 int type
, int permset
, int tag
, int id
);
128 static void next_field_w(const wchar_t **wp
, const wchar_t **start
,
129 const wchar_t **end
, wchar_t *sep
);
130 static int prefix_w(const wchar_t *start
, const wchar_t *end
,
131 const wchar_t *test
);
135 * Description of an archive entry.
137 * Basically, this is a "struct stat" with a few text fields added in.
139 * TODO: Add "comment", "charset", and possibly other entries
140 * that are supported by "pax interchange" format. However, GNU, ustar,
141 * cpio, and other variants don't support these features, so they're not an
142 * excruciatingly high priority right now.
144 * TODO: "pax interchange" format allows essentially arbitrary
145 * key/value attributes to be attached to any entry. Supporting
146 * such extensions may make this library useful for special
147 * applications (e.g., a package manager could attach special
148 * package-management attributes to each entry). There are tricky
149 * API issues involved, so this is not going to happen until
150 * there's a real demand for it.
152 * TODO: Design a good API for handling sparse files.
154 struct archive_entry
{
156 * Note that ae_stat.st_mode & S_IFMT can be 0!
158 * This occurs when the actual file type of the object is not
159 * in the archive. For example, 'tar' archives store
160 * hardlinks without marking the type of the underlying
166 * Use aes here so that we get transparent mbs<->wcs conversions.
168 struct aes ae_fflags_text
; /* Text fflags per fflagstostr(3) */
169 unsigned long ae_fflags_set
; /* Bitmap fflags */
170 unsigned long ae_fflags_clear
;
171 struct aes ae_gname
; /* Name of owning group */
172 struct aes ae_hardlink
; /* Name of target for hardlink */
173 struct aes ae_pathname
; /* Name of entry */
174 struct aes ae_symlink
; /* symlink contents */
175 struct aes ae_uname
; /* Name of owner */
177 struct ae_acl
*acl_head
;
178 struct ae_acl
*acl_p
;
179 int acl_state
; /* See acl_next for details. */
182 struct ae_xattr
*xattr_head
;
183 struct ae_xattr
*xattr_p
;
187 aes_clean(struct aes
*aes
)
189 if (aes
->aes_mbs_alloc
) {
190 free(aes
->aes_mbs_alloc
);
191 aes
->aes_mbs_alloc
= NULL
;
193 if (aes
->aes_wcs_alloc
) {
194 free(aes
->aes_wcs_alloc
);
195 aes
->aes_wcs_alloc
= NULL
;
197 memset(aes
, 0, sizeof(*aes
));
201 aes_copy(struct aes
*dest
, struct aes
*src
)
204 if (src
->aes_mbs
!= NULL
) {
205 dest
->aes_mbs_alloc
= strdup(src
->aes_mbs
);
206 dest
->aes_mbs
= dest
->aes_mbs_alloc
;
207 if (dest
->aes_mbs
== NULL
)
208 __archive_errx(1, "No memory for aes_copy()");
211 if (src
->aes_wcs
!= NULL
) {
212 dest
->aes_wcs_alloc
= malloc((wcslen(src
->aes_wcs
) + 1)
214 dest
->aes_wcs
= dest
->aes_wcs_alloc
;
215 if (dest
->aes_wcs
== NULL
)
216 __archive_errx(1, "No memory for aes_copy()");
217 wcscpy(dest
->aes_wcs_alloc
, src
->aes_wcs
);
222 aes_get_mbs(struct aes
*aes
)
224 if (aes
->aes_mbs
== NULL
&& aes
->aes_wcs
== NULL
)
226 if (aes
->aes_mbs
== NULL
&& aes
->aes_wcs
!= NULL
) {
228 * XXX Need to estimate the number of byte in the
229 * multi-byte form. Assume that, on average, wcs
230 * chars encode to no more than 3 bytes. There must
231 * be a better way... XXX
233 int mbs_length
= wcslen(aes
->aes_wcs
) * 3 + 64;
234 aes
->aes_mbs_alloc
= malloc(mbs_length
);
235 aes
->aes_mbs
= aes
->aes_mbs_alloc
;
236 if (aes
->aes_mbs
== NULL
)
237 __archive_errx(1, "No memory for aes_get_mbs()");
238 wcstombs(aes
->aes_mbs_alloc
, aes
->aes_wcs
, mbs_length
- 1);
239 aes
->aes_mbs_alloc
[mbs_length
- 1] = 0;
241 return (aes
->aes_mbs
);
244 static const wchar_t *
245 aes_get_wcs(struct aes
*aes
)
247 if (aes
->aes_wcs
== NULL
&& aes
->aes_mbs
== NULL
)
249 if (aes
->aes_wcs
== NULL
&& aes
->aes_mbs
!= NULL
) {
251 * No single byte will be more than one wide character,
252 * so this length estimate will always be big enough.
254 int wcs_length
= strlen(aes
->aes_mbs
);
256 = malloc((wcs_length
+ 1) * sizeof(wchar_t));
257 aes
->aes_wcs
= aes
->aes_wcs_alloc
;
258 if (aes
->aes_wcs
== NULL
)
259 __archive_errx(1, "No memory for aes_get_wcs()");
260 mbstowcs(aes
->aes_wcs_alloc
, aes
->aes_mbs
, wcs_length
);
261 aes
->aes_wcs_alloc
[wcs_length
] = 0;
263 return (aes
->aes_wcs
);
267 aes_set_mbs(struct aes
*aes
, const char *mbs
)
269 if (aes
->aes_mbs_alloc
) {
270 free(aes
->aes_mbs_alloc
);
271 aes
->aes_mbs_alloc
= NULL
;
273 if (aes
->aes_wcs_alloc
) {
274 free(aes
->aes_wcs_alloc
);
275 aes
->aes_wcs_alloc
= NULL
;
282 aes_copy_mbs(struct aes
*aes
, const char *mbs
)
284 if (aes
->aes_mbs_alloc
) {
285 free(aes
->aes_mbs_alloc
);
286 aes
->aes_mbs_alloc
= NULL
;
288 if (aes
->aes_wcs_alloc
) {
289 free(aes
->aes_wcs_alloc
);
290 aes
->aes_wcs_alloc
= NULL
;
292 aes
->aes_mbs_alloc
= malloc((strlen(mbs
) + 1) * sizeof(char));
293 if (aes
->aes_mbs_alloc
== NULL
)
294 __archive_errx(1, "No memory for aes_copy_mbs()");
295 strcpy(aes
->aes_mbs_alloc
, mbs
);
296 aes
->aes_mbs
= aes
->aes_mbs_alloc
;
302 aes_set_wcs(struct aes
*aes
, const wchar_t *wcs
)
304 if (aes
->aes_mbs_alloc
) {
305 free(aes
->aes_mbs_alloc
);
306 aes
->aes_mbs_alloc
= NULL
;
308 if (aes
->aes_wcs_alloc
) {
309 free(aes
->aes_wcs_alloc
);
310 aes
->aes_wcs_alloc
= NULL
;
318 aes_copy_wcs(struct aes
*aes
, const wchar_t *wcs
)
320 if (aes
->aes_mbs_alloc
) {
321 free(aes
->aes_mbs_alloc
);
322 aes
->aes_mbs_alloc
= NULL
;
324 if (aes
->aes_wcs_alloc
) {
325 free(aes
->aes_wcs_alloc
);
326 aes
->aes_wcs_alloc
= NULL
;
329 aes
->aes_wcs_alloc
= malloc((wcslen(wcs
) + 1) * sizeof(wchar_t));
330 if (aes
->aes_wcs_alloc
== NULL
)
331 __archive_errx(1, "No memory for aes_copy_wcs()");
332 wcscpy(aes
->aes_wcs_alloc
, wcs
);
333 aes
->aes_wcs
= aes
->aes_wcs_alloc
;
336 struct archive_entry
*
337 archive_entry_clear(struct archive_entry
*entry
)
339 aes_clean(&entry
->ae_fflags_text
);
340 aes_clean(&entry
->ae_gname
);
341 aes_clean(&entry
->ae_hardlink
);
342 aes_clean(&entry
->ae_pathname
);
343 aes_clean(&entry
->ae_symlink
);
344 aes_clean(&entry
->ae_uname
);
345 archive_entry_acl_clear(entry
);
346 archive_entry_xattr_clear(entry
);
347 memset(entry
, 0, sizeof(*entry
));
351 struct archive_entry
*
352 archive_entry_clone(struct archive_entry
*entry
)
354 struct archive_entry
*entry2
;
356 /* Allocate new structure and copy over all of the fields. */
357 entry2
= malloc(sizeof(*entry2
));
360 memset(entry2
, 0, sizeof(*entry2
));
361 entry2
->ae_stat
= entry
->ae_stat
;
362 entry2
->ae_fflags_set
= entry
->ae_fflags_set
;
363 entry2
->ae_fflags_clear
= entry
->ae_fflags_clear
;
365 aes_copy(&entry2
->ae_fflags_text
, &entry
->ae_fflags_text
);
366 aes_copy(&entry2
->ae_gname
, &entry
->ae_gname
);
367 aes_copy(&entry2
->ae_hardlink
, &entry
->ae_hardlink
);
368 aes_copy(&entry2
->ae_pathname
, &entry
->ae_pathname
);
369 aes_copy(&entry2
->ae_symlink
, &entry
->ae_symlink
);
370 aes_copy(&entry2
->ae_uname
, &entry
->ae_uname
);
372 /* XXX TODO: Copy ACL data over as well. XXX */
373 /* XXX TODO: Copy xattr data over as well. XXX */
378 archive_entry_free(struct archive_entry
*entry
)
380 archive_entry_clear(entry
);
384 struct archive_entry
*
385 archive_entry_new(void)
387 struct archive_entry
*entry
;
389 entry
= malloc(sizeof(*entry
));
392 memset(entry
, 0, sizeof(*entry
));
397 * Functions for reading fields from an archive_entry.
401 archive_entry_atime(struct archive_entry
*entry
)
403 return (entry
->ae_stat
.st_atime
);
407 archive_entry_atime_nsec(struct archive_entry
*entry
)
409 (void)entry
; /* entry can be unused here. */
410 return (ARCHIVE_STAT_ATIME_NANOS(&entry
->ae_stat
));
414 archive_entry_ctime(struct archive_entry
*entry
)
416 return (entry
->ae_stat
.st_ctime
);
420 archive_entry_ctime_nsec(struct archive_entry
*entry
)
422 (void)entry
; /* entry can be unused here. */
423 return (ARCHIVE_STAT_CTIME_NANOS(&entry
->ae_stat
));
427 archive_entry_dev(struct archive_entry
*entry
)
429 return (entry
->ae_stat
.st_dev
);
433 archive_entry_fflags(struct archive_entry
*entry
,
434 unsigned long *set
, unsigned long *clear
)
436 *set
= entry
->ae_fflags_set
;
437 *clear
= entry
->ae_fflags_clear
;
441 * Note: if text was provided, this just returns that text. If you
442 * really need the text to be rebuilt in a canonical form, set the
443 * text, ask for the bitmaps, then set the bitmaps. (Setting the
444 * bitmaps clears any stored text.) This design is deliberate: if
445 * we're editing archives, we don't want to discard flags just because
446 * they aren't supported on the current system. The bitmap<->text
447 * conversions are platform-specific (see below).
450 archive_entry_fflags_text(struct archive_entry
*entry
)
455 f
= aes_get_mbs(&entry
->ae_fflags_text
);
459 if (entry
->ae_fflags_set
== 0 && entry
->ae_fflags_clear
== 0)
462 p
= ae_fflagstostr(entry
->ae_fflags_set
, entry
->ae_fflags_clear
);
466 aes_copy_mbs(&entry
->ae_fflags_text
, p
);
468 f
= aes_get_mbs(&entry
->ae_fflags_text
);
473 archive_entry_gid(struct archive_entry
*entry
)
475 return (entry
->ae_stat
.st_gid
);
479 archive_entry_gname(struct archive_entry
*entry
)
481 return (aes_get_mbs(&entry
->ae_gname
));
485 archive_entry_gname_w(struct archive_entry
*entry
)
487 return (aes_get_wcs(&entry
->ae_gname
));
491 archive_entry_hardlink(struct archive_entry
*entry
)
493 return (aes_get_mbs(&entry
->ae_hardlink
));
497 archive_entry_hardlink_w(struct archive_entry
*entry
)
499 return (aes_get_wcs(&entry
->ae_hardlink
));
503 archive_entry_ino(struct archive_entry
*entry
)
505 return (entry
->ae_stat
.st_ino
);
509 archive_entry_mode(struct archive_entry
*entry
)
511 return (entry
->ae_stat
.st_mode
);
515 archive_entry_mtime(struct archive_entry
*entry
)
517 return (entry
->ae_stat
.st_mtime
);
521 archive_entry_mtime_nsec(struct archive_entry
*entry
)
523 (void)entry
; /* entry can be unused here. */
524 return (ARCHIVE_STAT_MTIME_NANOS(&entry
->ae_stat
));
528 archive_entry_pathname(struct archive_entry
*entry
)
530 return (aes_get_mbs(&entry
->ae_pathname
));
534 archive_entry_pathname_w(struct archive_entry
*entry
)
536 return (aes_get_wcs(&entry
->ae_pathname
));
540 archive_entry_rdev(struct archive_entry
*entry
)
542 return (entry
->ae_stat
.st_rdev
);
546 archive_entry_rdevmajor(struct archive_entry
*entry
)
548 return (major(entry
->ae_stat
.st_rdev
));
552 archive_entry_rdevminor(struct archive_entry
*entry
)
554 return (minor(entry
->ae_stat
.st_rdev
));
558 archive_entry_size(struct archive_entry
*entry
)
560 return (entry
->ae_stat
.st_size
);
564 archive_entry_stat(struct archive_entry
*entry
)
566 return (&entry
->ae_stat
);
570 archive_entry_symlink(struct archive_entry
*entry
)
572 return (aes_get_mbs(&entry
->ae_symlink
));
576 archive_entry_symlink_w(struct archive_entry
*entry
)
578 return (aes_get_wcs(&entry
->ae_symlink
));
582 archive_entry_uid(struct archive_entry
*entry
)
584 return (entry
->ae_stat
.st_uid
);
588 archive_entry_uname(struct archive_entry
*entry
)
590 return (aes_get_mbs(&entry
->ae_uname
));
594 archive_entry_uname_w(struct archive_entry
*entry
)
596 return (aes_get_wcs(&entry
->ae_uname
));
600 * Functions to set archive_entry properties.
604 * Note "copy" not "set" here. The "set" functions that accept a pointer
605 * only store the pointer; they don't copy the underlying object.
608 archive_entry_copy_stat(struct archive_entry
*entry
, const struct stat
*st
)
610 entry
->ae_stat
= *st
;
614 archive_entry_set_fflags(struct archive_entry
*entry
,
615 unsigned long set
, unsigned long clear
)
617 aes_clean(&entry
->ae_fflags_text
);
618 entry
->ae_fflags_set
= set
;
619 entry
->ae_fflags_clear
= clear
;
623 archive_entry_copy_fflags_text_w(struct archive_entry
*entry
,
624 const wchar_t *flags
)
626 aes_copy_wcs(&entry
->ae_fflags_text
, flags
);
627 return (ae_wcstofflags(flags
,
628 &entry
->ae_fflags_set
, &entry
->ae_fflags_clear
));
632 archive_entry_set_gid(struct archive_entry
*entry
, gid_t g
)
634 entry
->ae_stat
.st_gid
= g
;
638 archive_entry_set_gname(struct archive_entry
*entry
, const char *name
)
640 aes_set_mbs(&entry
->ae_gname
, name
);
644 archive_entry_copy_gname_w(struct archive_entry
*entry
, const wchar_t *name
)
646 aes_copy_wcs(&entry
->ae_gname
, name
);
650 archive_entry_set_hardlink(struct archive_entry
*entry
, const char *target
)
652 aes_set_mbs(&entry
->ae_hardlink
, target
);
656 archive_entry_copy_hardlink(struct archive_entry
*entry
, const char *target
)
658 aes_copy_mbs(&entry
->ae_hardlink
, target
);
662 archive_entry_copy_hardlink_w(struct archive_entry
*entry
, const wchar_t *target
)
664 aes_copy_wcs(&entry
->ae_hardlink
, target
);
668 archive_entry_set_atime(struct archive_entry
*entry
, time_t t
, long ns
)
670 entry
->ae_stat
.st_atime
= t
;
671 ARCHIVE_STAT_SET_ATIME_NANOS(&entry
->ae_stat
, ns
);
675 archive_entry_set_ctime(struct archive_entry
*entry
, time_t t
, long ns
)
677 entry
->ae_stat
.st_ctime
= t
;
678 ARCHIVE_STAT_SET_CTIME_NANOS(&entry
->ae_stat
, ns
);
681 /* Set symlink if symlink is already set, else set hardlink. */
683 archive_entry_set_link(struct archive_entry
*entry
, const char *target
)
685 if (entry
->ae_symlink
.aes_mbs
!= NULL
||
686 entry
->ae_symlink
.aes_wcs
!= NULL
)
687 aes_set_mbs(&entry
->ae_symlink
, target
);
689 aes_set_mbs(&entry
->ae_hardlink
, target
);
693 archive_entry_set_mode(struct archive_entry
*entry
, mode_t m
)
695 entry
->ae_stat
.st_mode
= m
;
699 archive_entry_set_mtime(struct archive_entry
*entry
, time_t m
, long ns
)
701 entry
->ae_stat
.st_mtime
= m
;
702 ARCHIVE_STAT_SET_MTIME_NANOS(&entry
->ae_stat
, ns
);
706 archive_entry_set_pathname(struct archive_entry
*entry
, const char *name
)
708 aes_set_mbs(&entry
->ae_pathname
, name
);
712 archive_entry_copy_pathname(struct archive_entry
*entry
, const char *name
)
714 aes_copy_mbs(&entry
->ae_pathname
, name
);
718 archive_entry_copy_pathname_w(struct archive_entry
*entry
, const wchar_t *name
)
720 aes_copy_wcs(&entry
->ae_pathname
, name
);
724 archive_entry_set_rdevmajor(struct archive_entry
*entry
, dev_t m
)
728 d
= entry
->ae_stat
.st_rdev
;
729 entry
->ae_stat
.st_rdev
= makedev(major(m
), minor(d
));
733 archive_entry_set_rdevminor(struct archive_entry
*entry
, dev_t m
)
737 d
= entry
->ae_stat
.st_rdev
;
738 entry
->ae_stat
.st_rdev
= makedev(major(d
), minor(m
));
742 archive_entry_set_size(struct archive_entry
*entry
, int64_t s
)
744 entry
->ae_stat
.st_size
= s
;
748 archive_entry_set_symlink(struct archive_entry
*entry
, const char *linkname
)
750 aes_set_mbs(&entry
->ae_symlink
, linkname
);
754 archive_entry_copy_symlink_w(struct archive_entry
*entry
, const wchar_t *linkname
)
756 aes_copy_wcs(&entry
->ae_symlink
, linkname
);
760 archive_entry_set_uid(struct archive_entry
*entry
, uid_t u
)
762 entry
->ae_stat
.st_uid
= u
;
766 archive_entry_set_uname(struct archive_entry
*entry
, const char *name
)
768 aes_set_mbs(&entry
->ae_uname
, name
);
772 archive_entry_copy_uname_w(struct archive_entry
*entry
, const wchar_t *name
)
774 aes_copy_wcs(&entry
->ae_uname
, name
);
778 * ACL management. The following would, of course, be a lot simpler
779 * if: 1) the last draft of POSIX.1e were a really thorough and
780 * complete standard that addressed the needs of ACL archiving and 2)
781 * everyone followed it faithfully. Alas, neither is true, so the
782 * following is a lot more complex than might seem necessary to the
787 archive_entry_acl_clear(struct archive_entry
*entry
)
791 while (entry
->acl_head
!= NULL
) {
792 ap
= entry
->acl_head
->next
;
793 aes_clean(&entry
->acl_head
->name
);
794 free(entry
->acl_head
);
795 entry
->acl_head
= ap
;
797 if (entry
->acl_text_w
!= NULL
) {
798 free(entry
->acl_text_w
);
799 entry
->acl_text_w
= NULL
;
802 entry
->acl_state
= 0; /* Not counting. */
806 * Add a single ACL entry to the internal list of ACL data.
809 archive_entry_acl_add_entry(struct archive_entry
*entry
,
810 int type
, int permset
, int tag
, int id
, const char *name
)
814 if (acl_special(entry
, type
, permset
, tag
) == 0)
816 ap
= acl_new_entry(entry
, type
, permset
, tag
, id
);
821 if (name
!= NULL
&& *name
!= '\0')
822 aes_copy_mbs(&ap
->name
, name
);
824 aes_clean(&ap
->name
);
828 * As above, but with a wide-character name.
831 archive_entry_acl_add_entry_w(struct archive_entry
*entry
,
832 int type
, int permset
, int tag
, int id
, const wchar_t *name
)
836 if (acl_special(entry
, type
, permset
, tag
) == 0)
838 ap
= acl_new_entry(entry
, type
, permset
, tag
, id
);
843 if (name
!= NULL
&& *name
!= L
'\0')
844 aes_copy_wcs(&ap
->name
, name
);
846 aes_clean(&ap
->name
);
850 * If this ACL entry is part of the standard POSIX permissions set,
851 * store the permissions in the stat structure and return zero.
854 acl_special(struct archive_entry
*entry
, int type
, int permset
, int tag
)
856 if (type
== ARCHIVE_ENTRY_ACL_TYPE_ACCESS
) {
858 case ARCHIVE_ENTRY_ACL_USER_OBJ
:
859 entry
->ae_stat
.st_mode
&= ~0700;
860 entry
->ae_stat
.st_mode
|= (permset
& 7) << 6;
862 case ARCHIVE_ENTRY_ACL_GROUP_OBJ
:
863 entry
->ae_stat
.st_mode
&= ~0070;
864 entry
->ae_stat
.st_mode
|= (permset
& 7) << 3;
866 case ARCHIVE_ENTRY_ACL_OTHER
:
867 entry
->ae_stat
.st_mode
&= ~0007;
868 entry
->ae_stat
.st_mode
|= permset
& 7;
876 * Allocate and populate a new ACL entry with everything but the
879 static struct ae_acl
*
880 acl_new_entry(struct archive_entry
*entry
,
881 int type
, int permset
, int tag
, int id
)
885 if (type
!= ARCHIVE_ENTRY_ACL_TYPE_ACCESS
&&
886 type
!= ARCHIVE_ENTRY_ACL_TYPE_DEFAULT
)
888 if (entry
->acl_text_w
!= NULL
) {
889 free(entry
->acl_text_w
);
890 entry
->acl_text_w
= NULL
;
893 /* XXX TODO: More sanity-checks on the arguments XXX */
895 /* If there's a matching entry already in the list, overwrite it. */
896 for (ap
= entry
->acl_head
; ap
!= NULL
; ap
= ap
->next
) {
897 if (ap
->type
== type
&& ap
->tag
== tag
&& ap
->id
== id
) {
898 ap
->permset
= permset
;
903 /* Add a new entry to the list. */
904 ap
= malloc(sizeof(*ap
));
907 memset(ap
, 0, sizeof(*ap
));
908 ap
->next
= entry
->acl_head
;
909 entry
->acl_head
= ap
;
913 ap
->permset
= permset
;
918 * Return a count of entries matching "want_type".
921 archive_entry_acl_count(struct archive_entry
*entry
, int want_type
)
927 ap
= entry
->acl_head
;
929 if ((ap
->type
& want_type
) != 0)
934 if (count
> 0 && ((want_type
& ARCHIVE_ENTRY_ACL_TYPE_ACCESS
) != 0))
940 * Prepare for reading entries from the ACL data. Returns a count
941 * of entries matching "want_type", or zero if there are no
942 * non-extended ACL entries of that type.
945 archive_entry_acl_reset(struct archive_entry
*entry
, int want_type
)
949 count
= archive_entry_acl_count(entry
, want_type
);
952 * If the only entries are the three standard ones,
953 * then don't return any ACL data. (In this case,
954 * client can just use chmod(2) to set permissions.)
956 if ((want_type
& ARCHIVE_ENTRY_ACL_TYPE_ACCESS
) != 0)
962 entry
->acl_state
= ARCHIVE_ENTRY_ACL_USER_OBJ
;
964 entry
->acl_state
= 0;
965 entry
->acl_p
= entry
->acl_head
;
970 * Return the next ACL entry in the list. Fake entries for the
971 * standard permissions and include them in the returned list.
975 archive_entry_acl_next(struct archive_entry
*entry
, int want_type
, int *type
,
976 int *permset
, int *tag
, int *id
, const char **name
)
982 * The acl_state is either zero (no entries available), -1
983 * (reading from list), or an entry type (retrieve that type
984 * from ae_stat.st_mode).
986 if (entry
->acl_state
== 0)
987 return (ARCHIVE_WARN
);
989 /* The first three access entries are special. */
990 if ((want_type
& ARCHIVE_ENTRY_ACL_TYPE_ACCESS
) != 0) {
991 switch (entry
->acl_state
) {
992 case ARCHIVE_ENTRY_ACL_USER_OBJ
:
993 *permset
= (entry
->ae_stat
.st_mode
>> 6) & 7;
994 *type
= ARCHIVE_ENTRY_ACL_TYPE_ACCESS
;
995 *tag
= ARCHIVE_ENTRY_ACL_USER_OBJ
;
996 entry
->acl_state
= ARCHIVE_ENTRY_ACL_GROUP_OBJ
;
998 case ARCHIVE_ENTRY_ACL_GROUP_OBJ
:
999 *permset
= (entry
->ae_stat
.st_mode
>> 3) & 7;
1000 *type
= ARCHIVE_ENTRY_ACL_TYPE_ACCESS
;
1001 *tag
= ARCHIVE_ENTRY_ACL_GROUP_OBJ
;
1002 entry
->acl_state
= ARCHIVE_ENTRY_ACL_OTHER
;
1003 return (ARCHIVE_OK
);
1004 case ARCHIVE_ENTRY_ACL_OTHER
:
1005 *permset
= entry
->ae_stat
.st_mode
& 7;
1006 *type
= ARCHIVE_ENTRY_ACL_TYPE_ACCESS
;
1007 *tag
= ARCHIVE_ENTRY_ACL_OTHER
;
1008 entry
->acl_state
= -1;
1009 entry
->acl_p
= entry
->acl_head
;
1010 return (ARCHIVE_OK
);
1016 while (entry
->acl_p
!= NULL
&& (entry
->acl_p
->type
& want_type
) == 0)
1017 entry
->acl_p
= entry
->acl_p
->next
;
1018 if (entry
->acl_p
== NULL
) {
1019 entry
->acl_state
= 0;
1020 return (ARCHIVE_WARN
);
1022 *type
= entry
->acl_p
->type
;
1023 *permset
= entry
->acl_p
->permset
;
1024 *tag
= entry
->acl_p
->tag
;
1025 *id
= entry
->acl_p
->id
;
1026 *name
= aes_get_mbs(&entry
->acl_p
->name
);
1027 entry
->acl_p
= entry
->acl_p
->next
;
1028 return (ARCHIVE_OK
);
1032 * Generate a text version of the ACL. The flags parameter controls
1033 * the style of the generated ACL.
1036 archive_entry_acl_text_w(struct archive_entry
*entry
, int flags
)
1040 const wchar_t *wname
;
1041 const wchar_t *prefix
;
1047 if (entry
->acl_text_w
!= NULL
) {
1048 free (entry
->acl_text_w
);
1049 entry
->acl_text_w
= NULL
;
1055 ap
= entry
->acl_head
;
1056 while (ap
!= NULL
) {
1057 if ((ap
->type
& flags
) != 0) {
1059 if ((flags
& ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT
) &&
1060 (ap
->type
& ARCHIVE_ENTRY_ACL_TYPE_DEFAULT
))
1061 length
+= 8; /* "default:" */
1062 length
+= 5; /* tag name */
1063 length
+= 1; /* colon */
1064 wname
= aes_get_wcs(&ap
->name
);
1066 length
+= wcslen(wname
);
1067 length
++; /* colon */
1068 length
+= 3; /* rwx */
1069 length
+= 1; /* colon */
1070 length
+= max(sizeof(uid_t
), sizeof(gid_t
)) * 3 + 1;
1071 length
++; /* newline */
1076 if (count
> 0 && ((flags
& ARCHIVE_ENTRY_ACL_TYPE_ACCESS
) != 0)) {
1077 length
+= 10; /* "user::rwx\n" */
1078 length
+= 11; /* "group::rwx\n" */
1079 length
+= 11; /* "other::rwx\n" */
1085 /* Now, allocate the string and actually populate it. */
1086 wp
= entry
->acl_text_w
= malloc(length
* sizeof(wchar_t));
1088 __archive_errx(1, "No memory to generate the text version of the ACL");
1090 if ((flags
& ARCHIVE_ENTRY_ACL_TYPE_ACCESS
) != 0) {
1091 append_entry_w(&wp
, NULL
, ARCHIVE_ENTRY_ACL_USER_OBJ
, NULL
,
1092 entry
->ae_stat
.st_mode
& 0700, -1);
1094 append_entry_w(&wp
, NULL
, ARCHIVE_ENTRY_ACL_GROUP_OBJ
, NULL
,
1095 entry
->ae_stat
.st_mode
& 0070, -1);
1097 append_entry_w(&wp
, NULL
, ARCHIVE_ENTRY_ACL_OTHER
, NULL
,
1098 entry
->ae_stat
.st_mode
& 0007, -1);
1101 ap
= entry
->acl_head
;
1102 while (ap
!= NULL
) {
1103 if ((ap
->type
& ARCHIVE_ENTRY_ACL_TYPE_ACCESS
) != 0) {
1104 wname
= aes_get_wcs(&ap
->name
);
1106 if (flags
& ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID
)
1110 append_entry_w(&wp
, NULL
, ap
->tag
, wname
,
1119 if ((flags
& ARCHIVE_ENTRY_ACL_TYPE_DEFAULT
) != 0) {
1120 if (flags
& ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT
)
1121 prefix
= L
"default:";
1124 ap
= entry
->acl_head
;
1126 while (ap
!= NULL
) {
1127 if ((ap
->type
& ARCHIVE_ENTRY_ACL_TYPE_DEFAULT
) != 0) {
1128 wname
= aes_get_wcs(&ap
->name
);
1131 if (flags
& ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID
)
1135 append_entry_w(&wp
, prefix
, ap
->tag
,
1136 wname
, ap
->permset
, id
);
1143 return (entry
->acl_text_w
);
1147 append_id_w(wchar_t **wp
, int id
)
1150 append_id_w(wp
, id
/ 10);
1151 *(*wp
)++ = L
"0123456789"[id
% 10];
1155 append_entry_w(wchar_t **wp
, const wchar_t *prefix
, int tag
,
1156 const wchar_t *wname
, int perm
, int id
)
1158 if (prefix
!= NULL
) {
1159 wcscpy(*wp
, prefix
);
1163 case ARCHIVE_ENTRY_ACL_USER_OBJ
:
1167 case ARCHIVE_ENTRY_ACL_USER
:
1168 wcscpy(*wp
, L
"user");
1170 case ARCHIVE_ENTRY_ACL_GROUP_OBJ
:
1174 case ARCHIVE_ENTRY_ACL_GROUP
:
1175 wcscpy(*wp
, L
"group");
1177 case ARCHIVE_ENTRY_ACL_MASK
:
1178 wcscpy(*wp
, L
"mask");
1182 case ARCHIVE_ENTRY_ACL_OTHER
:
1183 wcscpy(*wp
, L
"other");
1190 if (wname
!= NULL
) {
1195 *(*wp
)++ = (perm
& 0444) ? L
'r' : L
'-';
1196 *(*wp
)++ = (perm
& 0222) ? L
'w' : L
'-';
1197 *(*wp
)++ = (perm
& 0111) ? L
'x' : L
'-';
1200 append_id_w(wp
, id
);
1206 * Parse a textual ACL. This automatically recognizes and supports
1207 * extensions described above. The 'type' argument is used to
1208 * indicate the type that should be used for any entries not
1209 * explicitly marked as "default:".
1212 __archive_entry_acl_parse_w(struct archive_entry
*entry
,
1213 const wchar_t *text
, int default_type
)
1215 int type
, tag
, permset
, id
;
1216 const wchar_t *start
, *end
;
1217 const wchar_t *name_start
, *name_end
;
1220 int namebuff_length
;
1222 name_start
= name_end
= NULL
;
1224 namebuff_length
= 0;
1226 while (text
!= NULL
&& *text
!= L
'\0') {
1227 next_field_w(&text
, &start
, &end
, &sep
);
1232 * Solaris extension: "defaultuser::rwx" is the
1233 * default ACL corresponding to "user::rwx", etc.
1235 if (end
-start
> 7 && wmemcmp(start
, L
"default", 7) == 0) {
1236 type
= ARCHIVE_ENTRY_ACL_TYPE_DEFAULT
;
1239 type
= default_type
;
1241 if (prefix_w(start
, end
, L
"user")) {
1242 next_field_w(&text
, &start
, &end
, &sep
);
1246 tag
= ARCHIVE_ENTRY_ACL_USER
;
1250 tag
= ARCHIVE_ENTRY_ACL_USER_OBJ
;
1251 } else if (prefix_w(start
, end
, L
"group")) {
1252 next_field_w(&text
, &start
, &end
, &sep
);
1256 tag
= ARCHIVE_ENTRY_ACL_GROUP
;
1260 tag
= ARCHIVE_ENTRY_ACL_GROUP_OBJ
;
1261 } else if (prefix_w(start
, end
, L
"other")) {
1262 next_field_w(&text
, &start
, &end
, &sep
);
1267 tag
= ARCHIVE_ENTRY_ACL_OTHER
;
1268 } else if (prefix_w(start
, end
, L
"mask")) {
1269 next_field_w(&text
, &start
, &end
, &sep
);
1274 tag
= ARCHIVE_ENTRY_ACL_MASK
;
1278 next_field_w(&text
, &start
, &end
, &sep
);
1280 while (start
< end
) {
1283 permset
|= ARCHIVE_ENTRY_ACL_READ
;
1286 permset
|= ARCHIVE_ENTRY_ACL_WRITE
;
1289 permset
|= ARCHIVE_ENTRY_ACL_EXECUTE
;
1299 * Support star-compatible numeric UID/GID extension.
1300 * This extension adds a ":" followed by the numeric
1301 * ID so that "group:groupname:rwx", for example,
1302 * becomes "group:groupname:rwx:999", where 999 is the
1303 * numeric GID. This extension makes it possible, for
1304 * example, to correctly restore ACLs on a system that
1305 * might have a damaged passwd file or be disconnected
1306 * from a central NIS server. This extension is compatible
1307 * with POSIX.1e draft 17.
1309 if (sep
== L
':' && (tag
== ARCHIVE_ENTRY_ACL_USER
||
1310 tag
== ARCHIVE_ENTRY_ACL_GROUP
)) {
1311 next_field_w(&text
, &start
, &end
, &sep
);
1314 while (start
< end
&& *start
>= '0' && *start
<= '9') {
1315 if (id
> (INT_MAX
/ 10))
1324 id
= -1; /* No id specified. */
1326 /* Skip any additional entries. */
1327 while (sep
== L
':') {
1328 next_field_w(&text
, &start
, &end
, &sep
);
1331 /* Add entry to the internal list. */
1332 if (name_end
== name_start
) {
1333 archive_entry_acl_add_entry_w(entry
, type
, permset
,
1336 if (namebuff_length
<= name_end
- name_start
) {
1337 if (namebuff
!= NULL
)
1339 namebuff_length
= name_end
- name_start
+ 256;
1341 malloc(namebuff_length
* sizeof(wchar_t));
1342 if (namebuff
== NULL
)
1345 wmemcpy(namebuff
, name_start
, name_end
- name_start
);
1346 namebuff
[name_end
- name_start
] = L
'\0';
1347 archive_entry_acl_add_entry_w(entry
, type
,
1348 permset
, tag
, id
, namebuff
);
1351 if (namebuff
!= NULL
)
1353 return (ARCHIVE_OK
);
1356 if (namebuff
!= NULL
)
1358 return (ARCHIVE_WARN
);
1362 * extended attribute handling
1366 archive_entry_xattr_clear(struct archive_entry
*entry
)
1368 struct ae_xattr
*xp
;
1370 while (entry
->xattr_head
!= NULL
) {
1371 xp
= entry
->xattr_head
->next
;
1372 free(entry
->xattr_head
->name
);
1373 free(entry
->xattr_head
->value
);
1374 free(entry
->xattr_head
);
1375 entry
->xattr_head
= xp
;
1378 entry
->xattr_head
= NULL
;
1382 archive_entry_xattr_add_entry(struct archive_entry
*entry
,
1383 const char *name
, const void *value
, size_t size
)
1385 struct ae_xattr
*xp
;
1387 for (xp
= entry
->xattr_head
; xp
!= NULL
; xp
= xp
->next
)
1390 if ((xp
= malloc(sizeof(struct ae_xattr
))) == NULL
)
1394 xp
->name
= strdup(name
);
1395 if ((xp
-> value
= malloc(size
)) != NULL
) {
1396 memcpy(xp
-> value
, value
, size
);
1401 xp
->next
= entry
->xattr_head
;
1402 entry
->xattr_head
= xp
;
1407 * returns number of the extended attribute entries
1410 archive_entry_xattr_count(struct archive_entry
*entry
)
1412 struct ae_xattr
*xp
;
1415 for (xp
= entry
->xattr_head
; xp
!= NULL
; xp
= xp
->next
)
1422 archive_entry_xattr_reset(struct archive_entry
* entry
)
1424 entry
->xattr_p
= entry
->xattr_head
;
1426 return archive_entry_xattr_count(entry
);
1430 archive_entry_xattr_next(struct archive_entry
* entry
,
1431 const char **name
, const void **value
, size_t *size
)
1433 if (entry
->xattr_p
) {
1434 *name
= entry
->xattr_p
->name
;
1435 *value
= entry
->xattr_p
->value
;
1436 *size
= entry
->xattr_p
->size
;
1438 entry
->xattr_p
= entry
->xattr_p
->next
;
1440 return (ARCHIVE_OK
);
1445 return (ARCHIVE_WARN
);
1450 * end of xattr handling
1454 * Match "[:whitespace:]*(.*)[:whitespace:]*[:,\n]". *wp is updated
1455 * to point to just after the separator. *start points to the first
1456 * character of the matched text and *end just after the last
1457 * character of the matched identifier. In particular *end - *start
1458 * is the length of the field body, not including leading or trailing
1462 next_field_w(const wchar_t **wp
, const wchar_t **start
,
1463 const wchar_t **end
, wchar_t *sep
)
1465 /* Skip leading whitespace to find start of field. */
1466 while (**wp
== L
' ' || **wp
== L
'\t' || **wp
== L
'\n') {
1471 /* Scan for the separator. */
1472 while (**wp
!= L
'\0' && **wp
!= L
',' && **wp
!= L
':' &&
1478 /* Trim trailing whitespace to locate end of field. */
1480 while (**end
== L
' ' || **end
== L
'\t' || **end
== L
'\n') {
1485 /* Adjust scanner location. */
1491 prefix_w(const wchar_t *start
, const wchar_t *end
, const wchar_t *test
)
1496 if (*start
++ != *test
++)
1499 while (start
< end
&& *start
++ == *test
++)
1510 * Following code is modified from UC Berkeley sources, and
1511 * is subject to the following copyright notice.
1515 * Copyright (c) 1993
1516 * The Regents of the University of California. All rights reserved.
1518 * Redistribution and use in source and binary forms, with or without
1519 * modification, are permitted provided that the following conditions
1521 * 1. Redistributions of source code must retain the above copyright
1522 * notice, this list of conditions and the following disclaimer.
1523 * 2. Redistributions in binary form must reproduce the above copyright
1524 * notice, this list of conditions and the following disclaimer in the
1525 * documentation and/or other materials provided with the distribution.
1526 * 4. Neither the name of the University nor the names of its contributors
1527 * may be used to endorse or promote products derived from this software
1528 * without specific prior written permission.
1530 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
1531 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1532 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1533 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
1534 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1535 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
1536 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
1537 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
1538 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
1539 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
1543 static struct flag
{
1545 const wchar_t *wname
;
1547 unsigned long clear
;
1549 /* Preferred (shorter) names per flag first, all prefixed by "no" */
1551 { "nosappnd", L
"nosappnd", SF_APPEND
, 0 },
1552 { "nosappend", L
"nosappend", SF_APPEND
, 0 },
1554 #ifdef EXT2_APPEND_FL /* 'a' */
1555 { "nosappnd", L
"nosappnd", EXT2_APPEND_FL
, 0 },
1556 { "nosappend", L
"nosappend", EXT2_APPEND_FL
, 0 },
1559 { "noarch", L
"noarch", SF_ARCHIVED
, 0 },
1560 { "noarchived", L
"noarchived", SF_ARCHIVED
, 0 },
1563 { "noschg", L
"noschg", SF_IMMUTABLE
, 0 },
1564 { "noschange", L
"noschange", SF_IMMUTABLE
, 0 },
1565 { "nosimmutable", L
"nosimmutable", SF_IMMUTABLE
, 0 },
1567 #ifdef EXT2_IMMUTABLE_FL /* 'i' */
1568 { "noschg", L
"noschg", EXT2_IMMUTABLE_FL
, 0 },
1569 { "noschange", L
"noschange", EXT2_IMMUTABLE_FL
, 0 },
1570 { "nosimmutable", L
"nosimmutable", EXT2_IMMUTABLE_FL
, 0 },
1573 { "nosunlnk", L
"nosunlnk", SF_NOUNLINK
, 0 },
1574 { "nosunlink", L
"nosunlink", SF_NOUNLINK
, 0 },
1577 { "nosnapshot", L
"nosnapshot", SF_SNAPSHOT
, 0 },
1580 { "nouappnd", L
"nouappnd", UF_APPEND
, 0 },
1581 { "nouappend", L
"nouappend", UF_APPEND
, 0 },
1584 { "nouchg", L
"nouchg", UF_IMMUTABLE
, 0 },
1585 { "nouchange", L
"nouchange", UF_IMMUTABLE
, 0 },
1586 { "nouimmutable", L
"nouimmutable", UF_IMMUTABLE
, 0 },
1589 { "nodump", L
"nodump", 0, UF_NODUMP
},
1591 #ifdef EXT2_NODUMP_FL /* 'd' */
1592 { "nodump", L
"nodump", 0, EXT2_NODUMP_FL
},
1595 { "noopaque", L
"noopaque", UF_OPAQUE
, 0 },
1598 { "nouunlnk", L
"nouunlnk", UF_NOUNLINK
, 0 },
1599 { "nouunlink", L
"nouunlink", UF_NOUNLINK
, 0 },
1601 #ifdef EXT2_COMPR_FL /* 'c' */
1602 { "nocompress", L
"nocompress", EXT2_COMPR_FL
, 0 },
1605 #ifdef EXT2_NOATIME_FL /* 'A' */
1606 { "noatime", L
"noatime", 0, EXT2_NOATIME_FL
},
1608 { NULL
, NULL
, 0, 0 }
1613 * Convert file flags to a comma-separated string. If no flags
1614 * are set, return the empty string.
1617 ae_fflagstostr(unsigned long bitset
, unsigned long bitclear
)
1625 bits
= bitset
| bitclear
;
1627 for (flag
= flags
; flag
->name
!= NULL
; flag
++)
1628 if (bits
& (flag
->set
| flag
->clear
)) {
1629 length
+= strlen(flag
->name
) + 1;
1630 bits
&= ~(flag
->set
| flag
->clear
);
1635 string
= malloc(length
);
1640 for (flag
= flags
; flag
->name
!= NULL
; flag
++) {
1641 if (bitset
& flag
->set
|| bitclear
& flag
->clear
) {
1642 sp
= flag
->name
+ 2;
1643 } else if (bitset
& flag
->clear
|| bitclear
& flag
->set
) {
1647 bitset
&= ~(flag
->set
| flag
->clear
);
1648 bitclear
&= ~(flag
->set
| flag
->clear
);
1651 while ((*dp
++ = *sp
++) != '\0')
1662 * Take string of arguments and return file flags. This
1663 * version works a little differently than strtofflags(3).
1664 * In particular, it always tests every token, skipping any
1665 * unrecognized tokens. It returns a pointer to the first
1666 * unrecognized token, or NULL if every token was recognized.
1667 * This version is also const-correct and does not modify the
1671 ae_wcstofflags(const wchar_t *s
, unsigned long *setp
, unsigned long *clrp
)
1673 const wchar_t *start
, *end
;
1675 unsigned long set
, clear
;
1676 const wchar_t *failed
;
1681 /* Find start of first token. */
1682 while (*start
== L
'\t' || *start
== L
' ' || *start
== L
',')
1684 while (*start
!= L
'\0') {
1685 /* Locate end of token. */
1687 while (*end
!= L
'\0' && *end
!= L
'\t' &&
1688 *end
!= L
' ' && *end
!= L
',')
1690 for (flag
= flags
; flag
->wname
!= NULL
; flag
++) {
1691 if (wmemcmp(start
, flag
->wname
, end
- start
) == 0) {
1692 /* Matched "noXXXX", so reverse the sense. */
1696 } else if (wmemcmp(start
, flag
->wname
+ 2, end
- start
)
1698 /* Matched "XXXX", so don't reverse. */
1700 clear
|= flag
->clear
;
1704 /* Ignore unknown flag names. */
1705 if (flag
->wname
== NULL
&& failed
== NULL
)
1708 /* Find start of next token. */
1710 while (*start
== L
'\t' || *start
== L
' ' || *start
== L
',')
1720 /* Return location of first failure. */
1728 main(int argc
, char **argv
)
1730 struct archive_entry
*entry
= archive_entry_new();
1731 unsigned long set
, clear
;
1732 const wchar_t *remainder
;
1734 remainder
= archive_entry_copy_fflags_text_w(entry
, L
"nosappnd dump archive,,,,,,,");
1735 archive_entry_fflags(entry
, &set
, &clear
);
1737 wprintf(L
"set=0x%lX clear=0x%lX remainder='%ls'\n", set
, clear
, remainder
);
1739 wprintf(L
"new flags='%s'\n", archive_entry_fflags_text(entry
));