diff options
Diffstat (limited to 'lib/libarchive/archive_entry.c')
-rw-r--r-- | lib/libarchive/archive_entry.c | 327 |
1 files changed, 298 insertions, 29 deletions
diff --git a/lib/libarchive/archive_entry.c b/lib/libarchive/archive_entry.c index 1f85e59..0aedaeb 100644 --- a/lib/libarchive/archive_entry.c +++ b/lib/libarchive/archive_entry.c @@ -37,7 +37,6 @@ __FBSDID("$FreeBSD$"); #include "archive.h" #include "archive_entry.h" -#include "archive_private.h" #undef max #define max(a, b) ((a)>(b)?(a):(b)) @@ -73,6 +72,9 @@ static void aes_copy_mbs(struct aes *, const char *mbs); /* static void aes_set_wcs(struct aes *, const wchar_t *wcs); */ static void aes_copy_wcs(struct aes *, const wchar_t *wcs); +static char * ae_fflagstostr(unsigned long bitset, unsigned long bitclear); +static const wchar_t *ae_wcstofflags(const wchar_t *stringp, + unsigned long *setp, unsigned long *clrp); static void append_entry_w(wchar_t **wp, const wchar_t *prefix, int tag, const wchar_t *wname, int perm, int id); static void append_id_w(wchar_t **wp, int id); @@ -110,16 +112,20 @@ static int prefix_w(const wchar_t *start, const wchar_t *end, struct archive_entry { /* * Note that ae_stat.st_mode & S_IFMT can be 0! - * This occurs when the actual file type of the underlying object is - * not in the archive. For example, 'tar' archives store hardlinks - * without marking the type of the underlying object. + * + * This occurs when the actual file type of the object is not + * in the archive. For example, 'tar' archives store + * hardlinks without marking the type of the underlying + * object. */ struct stat ae_stat; /* * Use aes here so that we get transparent mbs<->wcs conversions. */ - struct aes ae_fflags; /* Text fflags per fflagstostr(3) */ + struct aes ae_fflags_text; /* Text fflags per fflagstostr(3) */ + unsigned long ae_fflags_set; /* Bitmap fflags */ + unsigned long ae_fflags_clear; struct aes ae_gname; /* Name of owning group */ struct aes ae_hardlink; /* Name of target for hardlink */ struct aes ae_pathname; /* Name of entry */ @@ -132,7 +138,7 @@ struct archive_entry { wchar_t *acl_text_w; }; -void +static void aes_clean(struct aes *aes) { if (aes->aes_mbs_alloc) { @@ -146,7 +152,7 @@ aes_clean(struct aes *aes) memset(aes, 0, sizeof(*aes)); } -void +static void aes_copy(struct aes *dest, struct aes *src) { *dest = *src; @@ -163,7 +169,7 @@ aes_copy(struct aes *dest, struct aes *src) } } -const char * +static const char * aes_get_mbs(struct aes *aes) { if (aes->aes_mbs == NULL && aes->aes_wcs != NULL) { @@ -182,7 +188,7 @@ aes_get_mbs(struct aes *aes) return (aes->aes_mbs); } -const wchar_t * +static const wchar_t * aes_get_wcs(struct aes *aes) { if (aes->aes_wcs == NULL && aes->aes_mbs != NULL) { @@ -200,7 +206,7 @@ aes_get_wcs(struct aes *aes) return (aes->aes_wcs); } -void +static void aes_set_mbs(struct aes *aes, const char *mbs) { if (aes->aes_mbs_alloc) { @@ -215,7 +221,7 @@ aes_set_mbs(struct aes *aes, const char *mbs) aes->aes_wcs = NULL; } -void +static void aes_copy_mbs(struct aes *aes, const char *mbs) { if (aes->aes_mbs_alloc) { @@ -233,7 +239,7 @@ aes_copy_mbs(struct aes *aes, const char *mbs) } #if 0 -void +static void aes_set_wcs(struct aes *aes, const wchar_t *wcs) { if (aes->aes_mbs_alloc) { @@ -249,7 +255,7 @@ aes_set_wcs(struct aes *aes, const wchar_t *wcs) } #endif -void +static void aes_copy_wcs(struct aes *aes, const wchar_t *wcs) { if (aes->aes_mbs_alloc) { @@ -269,7 +275,7 @@ aes_copy_wcs(struct aes *aes, const wchar_t *wcs) struct archive_entry * archive_entry_clear(struct archive_entry *entry) { - aes_clean(&entry->ae_fflags); + aes_clean(&entry->ae_fflags_text); aes_clean(&entry->ae_gname); aes_clean(&entry->ae_hardlink); aes_clean(&entry->ae_pathname); @@ -291,14 +297,17 @@ archive_entry_clone(struct archive_entry *entry) return (NULL); memset(entry2, 0, sizeof(*entry2)); entry2->ae_stat = entry->ae_stat; + entry2->ae_fflags_set = entry->ae_fflags_set; + entry2->ae_fflags_clear = entry->ae_fflags_clear; - aes_copy(&entry2->ae_fflags, &entry->ae_fflags); + aes_copy(&entry2->ae_fflags_text, &entry->ae_fflags_text); aes_copy(&entry2->ae_gname, &entry->ae_gname); aes_copy(&entry2->ae_hardlink, &entry->ae_hardlink); aes_copy(&entry2->ae_pathname, &entry->ae_pathname); aes_copy(&entry2->ae_symlink, &entry->ae_symlink); aes_copy(&entry2->ae_uname, &entry->ae_uname); + /* XXX TODO: Copy ACL data over as well. XXX */ return (entry2); } @@ -338,10 +347,44 @@ archive_entry_devminor(struct archive_entry *entry) return (minor(entry->ae_stat.st_rdev)); } +void +archive_entry_fflags(struct archive_entry *entry, + unsigned long *set, unsigned long *clear) +{ + *set = entry->ae_fflags_set; + *clear = entry->ae_fflags_clear; +} + +/* + * Note: if text was provided, this just returns that text. If you + * really need the text to be rebuilt in a canonical form, set the + * text, ask for the bitmaps, then set the bitmaps. (Setting the + * bitmaps clears any stored text.) This design is deliberate: if + * we're editing archives, we don't want to discard flags just because + * they aren't supported on the current system. The bitmap<->text + * conversions are platform-specific (see below). + */ const char * -archive_entry_fflags(struct archive_entry *entry) +archive_entry_fflags_text(struct archive_entry *entry) { - return (aes_get_mbs(&entry->ae_fflags)); + const char *f; + char *p; + + f = aes_get_mbs(&entry->ae_fflags_text); + if (f != NULL) + return (f); + + if (entry->ae_fflags_set == 0 && entry->ae_fflags_clear == 0) + return (NULL); + + p = ae_fflagstostr(entry->ae_fflags_set, entry->ae_fflags_clear); + if (p == NULL) + return (NULL); + + aes_copy_mbs(&entry->ae_fflags_text, p); + free(p); + f = aes_get_mbs(&entry->ae_fflags_text); + return (f); } const char * @@ -444,15 +487,21 @@ archive_entry_set_devminor(struct archive_entry *entry, dev_t m) } void -archive_entry_set_fflags(struct archive_entry *entry, const char *flags) +archive_entry_set_fflags(struct archive_entry *entry, + unsigned long set, unsigned long clear) { - aes_set_mbs(&entry->ae_fflags, flags); + aes_clean(&entry->ae_fflags_text); + entry->ae_fflags_set = set; + entry->ae_fflags_clear = clear; } -void -archive_entry_copy_fflags_w(struct archive_entry *entry, const wchar_t *flags) +const wchar_t * +archive_entry_copy_fflags_text_w(struct archive_entry *entry, + const wchar_t *flags) { - aes_copy_wcs(&entry->ae_fflags, flags); + aes_copy_wcs(&entry->ae_fflags_text, flags); + return (ae_wcstofflags(flags, + &entry->ae_fflags_set, &entry->ae_fflags_clear)); } void @@ -1187,17 +1236,237 @@ prefix_w(const wchar_t *start, const wchar_t *end, const wchar_t *test) } -#if TEST +/* + * Following code is modified from UC Berkeley sources, and + * is subject to the following copyright notice. + */ + +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +static struct flag { + const char *name; + const wchar_t *wname; + unsigned long set; + unsigned long clear; +} flags[] = { + /* Preferred (shorter) names per flag first, all prefixed by "no" */ +#ifdef SF_APPEND + { "nosappnd", L"nosappnd", SF_APPEND, 0 }, + { "nosappend", L"nosappend", SF_APPEND, 0 }, +#endif +#ifdef EXT2_APPEND_FL /* 'a' */ + { "nosappnd", L"nosappnd", EXT2_APPEND_FL, 0 }, + { "nosappend", L"nosappend", EXT2_APPEND_FL, 0 }, +#endif +#ifdef SF_ARCHIVED + { "noarch", L"noarch", SF_ARCHIVED, 0 }, + { "noarchived", L"noarchived", SF_ARCHIVED, 0 }, +#endif +#ifdef SF_IMMUTABLE + { "noschg", L"noschg", SF_IMMUTABLE, 0 }, + { "noschange", L"noschange", SF_IMMUTABLE, 0 }, + { "nosimmutable", L"nosimmutable", SF_IMMUTABLE, 0 }, +#endif +#ifdef EXT2_IMMUTABLE_FL /* 'i' */ + { "noschg", L"noschg", EXT2_IMMUTABLE_FL, 0 }, + { "noschange", L"noschange", EXT2_IMMUTABLE_FL, 0 }, + { "nosimmutable", L"nosimmutable", EXT2_IMMUTABLE_FL, 0 }, +#endif +#ifdef SF_NOUNLINK + { "nosunlnk", L"nosunlnk", SF_NOUNLINK, 0 }, + { "nosunlink", L"nosunlink", SF_NOUNLINK, 0 }, +#endif +#ifdef SF_SNAPSHOT + { "nosnapshot", L"nosnapshot", SF_SNAPSHOT, 0 }, +#endif +#ifdef UF_APPEND + { "nouappnd", L"nouappnd", UF_APPEND, 0 }, + { "nouappend", L"nouappend", UF_APPEND, 0 }, +#endif +#ifdef UF_IMMUTABLE + { "nouchg", L"nouchg", UF_IMMUTABLE, 0 }, + { "nouchange", L"nouchange", UF_IMMUTABLE, 0 }, + { "nouimmutable", L"nouimmutable", UF_IMMUTABLE, 0 }, +#endif +#ifdef UF_NODUMP + { "nodump", L"nodump", 0, UF_NODUMP}, +#endif +#ifdef EXT2_NODUMP_FL /* 'd' */ + { "nodump", L"nodump", 0, EXT2_NODUMP_FL}, +#endif +#ifdef UF_OPAQUE + { "noopaque", L"noopaque", UF_OPAQUE, 0 }, +#endif +#ifdef UF_NOUNLINK + { "nouunlnk", L"nouunlnk", UF_NOUNLINK, 0 }, + { "nouunlink", L"nouunlink", UF_NOUNLINK, 0 }, +#endif +#ifdef EXT2_COMPR_FL /* 'c' */ + { "nocompress", L"nocompress", EXT2_COMPR_FL, 0 }, +#endif + +#ifdef EXT2_NOATIME_FL /* 'A' */ + { "noatime", L"noatime", 0, EXT2_NOATIME_FL}, +#endif + { NULL, NULL, 0, 0 } +}; +#define longestflaglen 12 +#define nmappings (sizeof(mapping) / sizeof(mapping[0])) + +/* + * fflagstostr -- + * Convert file flags to a comma-separated string. If no flags + * are set, return the empty string. + */ +char * +ae_fflagstostr(unsigned long bitset, unsigned long bitclear) +{ + char *string, *dp; + const char *sp; + unsigned long bits; + struct flag *flag; + int length; + + bits = bitset | bitclear; + length = 0; + for (flag = flags; flag->name != NULL; flag++) + if (bits & (flag->set | flag->clear)) { + length += strlen(flag->name) + 1; + bits &= ~(flag->set | flag->clear); + } + + string = malloc(length); + if (string == NULL) + return (NULL); + + dp = string; + for (flag = flags; flag->name != NULL; flag++) { + if (bitset & flag->set || bitclear & flag->clear) { + sp = flag->name + 2; + } else if (bitset & flag->clear || bitclear & flag->set) { + sp = flag->name; + } else + continue; + bitset &= ~(flag->set | flag->clear); + bitclear &= ~(flag->set | flag->clear); + if (dp > string) + *dp++ = ','; + while ((*dp++ = *sp++) != '\0') + ; + dp--; + } + + *dp = '\0'; + return (string); +} + +/* + * wcstofflags -- + * Take string of arguments and return file flags. This + * version works a little differently than strtofflags(3). + * In particular, it always tests every token, skipping any + * unrecognized tokens. It returns a pointer to the first + * unrecognized token, or NULL if every token was recognized. + * This version is also const-correct and does not modify the + * provided string. + */ +const wchar_t * +ae_wcstofflags(const wchar_t *s, unsigned long *setp, unsigned long *clrp) +{ + const wchar_t *start, *end; + struct flag *flag; + unsigned long set, clear; + const wchar_t *failed; + + set = clear = 0; + start = s; + failed = NULL; + /* Find start of first token. */ + while (*start == L'\t' || *start == L' ' || *start == L',') + start++; + while (*start != L'\0') { + /* Locate end of token. */ + end = start; + while (*end != L'\0' && *end != L'\t' && + *end != L' ' && *end != L',') + end++; + for (flag = flags; flag->wname != NULL; flag++) { + if (wmemcmp(start, flag->wname, end - start) == 0) { + /* Matched "noXXXX", so reverse the sense. */ + clear |= flag->set; + set |= flag->clear; + break; + } else if (wmemcmp(start, flag->wname + 2, end - start) + == 0) { + /* Matched "XXXX", so don't reverse. */ + set |= flag->set; + clear |= flag->clear; + break; + } + } + /* Ignore unknown flag names. */ + if (flag->wname == NULL && failed == NULL) + failed = start; + + /* Find start of next token. */ + start = end; + while (*start == L'\t' || *start == L' ' || *start == L',') + start++; + + } + + if (setp) + *setp = set; + if (clrp) + *clrp = clear; + + /* Return location of first failure. */ + return (failed); +} + + +#ifdef TEST +#include <stdio.h> int main(int argc, char **argv) { - struct aes aes; + struct archive_entry *entry = archive_entry_new(); + unsigned long set, clear; + const wchar_t *remainder; + + remainder = archive_entry_copy_fflags_text_w(entry, L"nosappnd dump archive,,,,,,,"); + archive_entry_fflags(entry, &set, &clear); + + wprintf(L"set=0x%lX clear=0x%lX remainder='%ls'\n", set, clear, remainder); - memset(&aes, 0, sizeof(aes)); - aes_clean(&aes); - aes_set_mbs(&aes, "ÈÈÈabc"); - wprintf("%S\n", L"abcdef"); - wprintf("%S\n",aes_get_wcs(&aes)); + wprintf(L"new flags='%s'\n", archive_entry_fflags_text(entry)); return (0); } #endif |