summaryrefslogtreecommitdiffstats
path: root/lib/libarchive/archive_entry.c
diff options
context:
space:
mode:
authorkientzle <kientzle@FreeBSD.org>2004-04-26 23:37:54 +0000
committerkientzle <kientzle@FreeBSD.org>2004-04-26 23:37:54 +0000
commit736725bcabf6c72ac5bfda301f3aa3b447ac4c6b (patch)
treef0f5a81c35118c56a6a3ac1a5d72fd50e2cdf842 /lib/libarchive/archive_entry.c
parentf5f7c88a25b2bbf11fbacb20c1194ad48018294b (diff)
downloadFreeBSD-src-736725bcabf6c72ac5bfda301f3aa3b447ac4c6b.zip
FreeBSD-src-736725bcabf6c72ac5bfda301f3aa3b447ac4c6b.tar.gz
Update file flag handling.
The new fflags support in archive_entry supports Linux and FreeBSD file flags and is a bit more gracious about unrecognized flag names than strtofflags(3). This involves some minor API breakage. The default tar format ("restricted pax") now enables pax extensions when archiving files that have flags. In particular, copying dir heirarchies with 'bsdtar cf - -C src . | bsdtar xpf - -C dest' now preserves file flags. (Note the "p" on extract!) While I'm here, fill in some additional explanation in the archive_entry.3 manpage, fill in some missing MLINKS, mark some overlooked internal functions 'static', and make a few minor style fixes.
Diffstat (limited to 'lib/libarchive/archive_entry.c')
-rw-r--r--lib/libarchive/archive_entry.c327
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
OpenPOWER on IntegriCloud