summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/libarchive/Makefile14
-rw-r--r--lib/libarchive/Makefile.freebsd14
-rw-r--r--lib/libarchive/archive_entry.3128
-rw-r--r--lib/libarchive/archive_entry.c327
-rw-r--r--lib/libarchive/archive_entry.h14
-rw-r--r--lib/libarchive/archive_read_extract.c79
-rw-r--r--lib/libarchive/archive_read_support_format_tar.c2
-rw-r--r--lib/libarchive/archive_write_set_format_pax.c8
-rw-r--r--lib/libarchive/archive_write_set_format_shar.c2
9 files changed, 506 insertions, 82 deletions
diff --git a/lib/libarchive/Makefile b/lib/libarchive/Makefile
index 676b1e3..6a72f01 100644
--- a/lib/libarchive/Makefile
+++ b/lib/libarchive/Makefile
@@ -51,13 +51,23 @@ MAN= archive_entry.3 \
MLINKS+= archive_entry.3 archive_entry_clear.3
MLINKS+= archive_entry.3 archive_entry_clone.3
+MLINKS+= archive_entry.3 archive_entry_copy_fflags_text_w.3
+MLINKS+= archive_entry.3 archive_entry_copy_gname_w.3
+MLINKS+= archive_entry.3 archive_entry_copy_hardlink_w.3
+MLINKS+= archive_entry.3 archive_entry_copy_pathname_w.3
MLINKS+= archive_entry.3 archive_entry_copy_stat.3
-MLINKS+= archive_entry.3 archive_entry_dup.3
+MLINKS+= archive_entry.3 archive_entry_copy_symlink_w.3
+MLINKS+= archive_entry.3 archive_entry_copy_uname_w.3
+MLINKS+= archive_entry.3 archive_entry_fflags.3
+MLINKS+= archive_entry.3 archive_entry_fflags_text.3
MLINKS+= archive_entry.3 archive_entry_free.3
MLINKS+= archive_entry.3 archive_entry_gname.3
+MLINKS+= archive_entry.3 archive_entry_gname_w.3
MLINKS+= archive_entry.3 archive_entry_hardlink.3
+MLINKS+= archive_entry.3 archive_entry_hardlink_w.3
MLINKS+= archive_entry.3 archive_entry_new.3
MLINKS+= archive_entry.3 archive_entry_pathname.3
+MLINKS+= archive_entry.3 archive_entry_pathname_w.3
MLINKS+= archive_entry.3 archive_entry_set_devmajor.3
MLINKS+= archive_entry.3 archive_entry_set_devminor.3
MLINKS+= archive_entry.3 archive_entry_set_gid.3
@@ -72,7 +82,9 @@ MLINKS+= archive_entry.3 archive_entry_set_uname.3
MLINKS+= archive_entry.3 archive_entry_size.3
MLINKS+= archive_entry.3 archive_entry_stat.3
MLINKS+= archive_entry.3 archive_entry_symlink.3
+MLINKS+= archive_entry.3 archive_entry_symlink_w.3
MLINKS+= archive_entry.3 archive_entry_uname.3
+MLINKS+= archive_entry.3 archive_entry_uname_w.3
MLINKS+= archive_read.3 archive_read_data.3
MLINKS+= archive_read.3 archive_read_data_into_buffer.3
MLINKS+= archive_read.3 archive_read_data_into_file.3
diff --git a/lib/libarchive/Makefile.freebsd b/lib/libarchive/Makefile.freebsd
index 676b1e3..6a72f01 100644
--- a/lib/libarchive/Makefile.freebsd
+++ b/lib/libarchive/Makefile.freebsd
@@ -51,13 +51,23 @@ MAN= archive_entry.3 \
MLINKS+= archive_entry.3 archive_entry_clear.3
MLINKS+= archive_entry.3 archive_entry_clone.3
+MLINKS+= archive_entry.3 archive_entry_copy_fflags_text_w.3
+MLINKS+= archive_entry.3 archive_entry_copy_gname_w.3
+MLINKS+= archive_entry.3 archive_entry_copy_hardlink_w.3
+MLINKS+= archive_entry.3 archive_entry_copy_pathname_w.3
MLINKS+= archive_entry.3 archive_entry_copy_stat.3
-MLINKS+= archive_entry.3 archive_entry_dup.3
+MLINKS+= archive_entry.3 archive_entry_copy_symlink_w.3
+MLINKS+= archive_entry.3 archive_entry_copy_uname_w.3
+MLINKS+= archive_entry.3 archive_entry_fflags.3
+MLINKS+= archive_entry.3 archive_entry_fflags_text.3
MLINKS+= archive_entry.3 archive_entry_free.3
MLINKS+= archive_entry.3 archive_entry_gname.3
+MLINKS+= archive_entry.3 archive_entry_gname_w.3
MLINKS+= archive_entry.3 archive_entry_hardlink.3
+MLINKS+= archive_entry.3 archive_entry_hardlink_w.3
MLINKS+= archive_entry.3 archive_entry_new.3
MLINKS+= archive_entry.3 archive_entry_pathname.3
+MLINKS+= archive_entry.3 archive_entry_pathname_w.3
MLINKS+= archive_entry.3 archive_entry_set_devmajor.3
MLINKS+= archive_entry.3 archive_entry_set_devminor.3
MLINKS+= archive_entry.3 archive_entry_set_gid.3
@@ -72,7 +82,9 @@ MLINKS+= archive_entry.3 archive_entry_set_uname.3
MLINKS+= archive_entry.3 archive_entry_size.3
MLINKS+= archive_entry.3 archive_entry_stat.3
MLINKS+= archive_entry.3 archive_entry_symlink.3
+MLINKS+= archive_entry.3 archive_entry_symlink_w.3
MLINKS+= archive_entry.3 archive_entry_uname.3
+MLINKS+= archive_entry.3 archive_entry_uname_w.3
MLINKS+= archive_read.3 archive_read_data.3
MLINKS+= archive_read.3 archive_read_data_into_buffer.3
MLINKS+= archive_read.3 archive_read_data_into_file.3
diff --git a/lib/libarchive/archive_entry.3 b/lib/libarchive/archive_entry.3
index 94ed5ea..e128b6c 100644
--- a/lib/libarchive/archive_entry.3
+++ b/lib/libarchive/archive_entry.3
@@ -30,12 +30,15 @@
.Sh NAME
.Nm archive_entry_clear
.Nm archive_entry_clone
+.Nm archive_entry_copy_fflags_text_w
.Nm archive_entry_copy_gname_w
.Nm archive_entry_copy_hardlink_w
.Nm archive_entry_copy_pathname_w
.Nm archive_entry_copy_stat
.Nm archive_entry_copy_symlink_w
.Nm archive_entry_copy_uname_w
+.Nm archive_entry_fflags
+.Nm archive_entry_fflags_text
.Nm archive_entry_free
.Nm archive_entry_gname
.Nm archive_entry_gname_w
@@ -46,9 +49,11 @@
.Nm archive_entry_pathname_w
.Nm archive_entry_set_devmajor
.Nm archive_entry_set_devminor
+.Nm archive_entry_set_fflags
.Nm archive_entry_set_gid
.Nm archive_entry_set_gname
.Nm archive_entry_set_hardlink
+.Nm archive_entry_set_link
.Nm archive_entry_set_mode
.Nm archive_entry_set_pathname
.Nm archive_entry_set_symlink
@@ -67,6 +72,8 @@
.Fn archive_entry_clear "struct archive_entry *"
.Ft struct archive_entry *
.Fn archive_entry_clone "struct archive_entry *"
+.Ft const wchar_t *
+.Fn archive_entry_copy_fflags_text_w "struct archive_entry *" "const wchar_t *"
.Ft void
.Fn archive_entry_copy_gname_w "struct archive_entry *" "const wchar_t *"
.Ft void
@@ -80,6 +87,10 @@
.Ft void
.Fn archive_entry_copy_uname_w "struct archive_entry *" "const wchar_t *"
.Ft void
+.Fn archive_entry_fflags "struct archive_entry *" "unsigned long *set" "unsigned long *clear"
+.Ft const char *
+.Fn archive_entry_fflags_text "struct archive_entry *"
+.Ft void
.Fn archive_entry_free "struct archive_entry *"
.Ft const char *
.Fn archive_entry_gname "struct archive_entry *"
@@ -100,6 +111,8 @@
.Ft void
.Fn archive_entry_set_devminor "struct archive_entry *" "dev_t"
.Ft void
+.Fn archive_entry_set_fflags "struct archive_entry *" "unsigned long set" "unsigned long clear"
+.Ft void
.Fn archive_entry_set_gid "struct archive_entry *" "gid_t"
.Ft void
.Fn archive_entry_set_gname "struct archive_entry *" "const char *"
@@ -141,10 +154,30 @@ These objects are used by
.Xr libarchive 3
to represent the metadata associated with a particular
entry in an archive.
-.Pp
-Most of the functions here set or read entries
-in an object. Such functions have one of the
-following forms:
+.Ss Create and Destroy
+There are functions to allocate, destroy, clear, and copy
+.Va archive_entry
+objects:
+.Bl -tag -compact -width indent
+.It Fn archive_entry_clear
+Erases the object, resetting all internal fields to the
+same state as a newly-created object.
+This is provided to allow you to quickly recycle objects
+without thrashing the heap.
+.It Fn archive_entry_clone
+A deep copy operation; all text fields are duplicated.
+.It Fn archive_entry_free
+Releases the
+.Tn struct archive_entry
+object.
+.It Fn archive_entry_new
+Allocate and return a blank
+.Tn struct archive_entry
+object.
+.El
+.Ss Set and Get Functions
+Most of the functions here set or read entries in an object.
+Such functions have one of the following forms:
.Bl -tag -compact -width indent
.It Fn archive_entry_set_XXXX
Stores the provided data in the object.
@@ -158,14 +191,13 @@ Returns the specified data.
In the case of strings, a const-qualified pointer to
the string is returned.
.El
-The string data can be accessed as wide character strings
-(which are suffixed with
-.Cm _w )
+String data can be set or accessed as wide character strings
or normal
.Va char
strings.
-Note that these are different representations of the same
-data:
+The funtions that use wide character strings are suffixed with
+.Cm _w .
+Note that these are different representations of the same data:
For example, if you store a narrow string and read the corresponding
wide string, the object will transparently convert formats
using the current locale.
@@ -173,27 +205,67 @@ Similarly, if you store a wide string and then store a
narrow string for the same data, the previously-set wide string will
be discarded in favor of the new data.
.Pp
-The remaining functions allocate, destroy, clear, and copy
-.Va archive_entry
-objects.
-These functions are described below:
+There are a few set/get functions that merit additional description:
.Bl -tag -compact -width indent
-.It Fn archive_entry_clear
-Erases the object, resetting all internal fields to the
-same state as a newly-created object.
-This is provided to allow you to quickly recycle objects
-without thrashing the heap.
-.It Fn archive_entry_clone
-A deep copy operation; all text fields are duplicated.
-.It Fn archive_entry_free
-Releases the
-.Tn struct archive_entry
-object.
-.It Fn archive_entry_new
-Allocate and return a blank
-.Tn struct archive_entry
-object.
+.It Fn archive_entry_set_link
+This function sets the symlink field if it is already set.
+Otherwise, it sets the hardlink field.
.El
+.Ss File Flags
+File flags are transparently converted between a bitmap
+representation and a textual format.
+For example, if you set the bitmap and ask for text, the library
+will build a canonical text format.
+However, if you set a text format and request a text format,
+you will get back the same text, even if it is ill-formed.
+If you need to canonicalize a textual flags string, you should first set the
+text form, then request the bitmap form, then use that to set the bitmap form.
+Setting the bitmap format will clear the internal text representation
+and force it to be reconstructed when you next request the text form.
+.Pp
+The bitmap format consists of two integers, one containing bits
+that should be set, the other specifying bits that should be
+cleared.
+Bits not mentioned in either bitmap will be ignored.
+Usually, the bitmap of bits to be cleared will be set to zero.
+In unusual circumstances, you can force a fully-specified set
+of file flags by setting the bitmap of flags to clear to the complement
+of the bitmap of flags to set.
+(This differs from
+.Xr fflagstostr 3 ,
+which only includes names for set bits.)
+Converting a bitmap to a textual string is a platform-specific
+operation; bits that are not meaningful on the current platform
+will be ignored.
+.Pp
+The canonical text format is a comma-separated list of flag names.
+The
+.Fn archive_entry_copy_fflags_text_w
+function parses the provided text and sets the internal bitmap values.
+This is a platform-specific operation; names that are not meaningful
+on the current platform will be ignored.
+The function returns a pointer to the start of the first name that was not
+recognized, or NULL if every name was recognized.
+Note that every name--including names that follow an unrecognized name--will
+be evaluated, and the bitmaps will be set to reflect every name that is
+recognized.
+(In particular, this differs from
+.Xr strtofflags 3 ,
+which stops parsing at the first unrecognized name.)
+.Ss ACL Handling
+XXX This needs serious help. XXX
+.Pp
+An
+.Dq Access Control List
+(ACL) is a list of permissions that grant access to particular users or
+groups beyond what would normally be provided by standard POSIX mode bits.
+The ACL handling here addresses some deficiencies in the POSIX.1e draft 17 ACL
+specification.
+In particular, POSIX.1e draft 17 specifies several different formats, but
+none of those formats include both textual user/group names and numeric
+UIDs/GIDs.
+.Pp
+XXX explain ACL stuff XXX
.\" .Sh EXAMPLE
.\" .Sh RETURN VALUES
.\" .Sh ERRORS
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
diff --git a/lib/libarchive/archive_entry.h b/lib/libarchive/archive_entry.h
index 733a60d..42c1fca 100644
--- a/lib/libarchive/archive_entry.h
+++ b/lib/libarchive/archive_entry.h
@@ -68,7 +68,9 @@ struct archive_entry *archive_entry_new(void);
dev_t archive_entry_devmajor(struct archive_entry *);
dev_t archive_entry_devminor(struct archive_entry *);
-const char *archive_entry_fflags(struct archive_entry *);
+const char *archive_entry_fflags_text(struct archive_entry *);
+void archive_entry_fflags(struct archive_entry *,
+ unsigned long *set, unsigned long *clear);
const char *archive_entry_gname(struct archive_entry *);
const char *archive_entry_hardlink(struct archive_entry *);
mode_t archive_entry_mode(struct archive_entry *);
@@ -85,14 +87,18 @@ const char *archive_entry_uname(struct archive_entry *);
* Set fields in an archive_entry.
*
* Note that string 'set' functions do not copy the string, only the pointer.
- * In contrast, 'copy_stat' does copy the full structure.
+ * In contrast, 'copy' functions do copy the object pointed to.
*/
void archive_entry_copy_stat(struct archive_entry *, const struct stat *);
-void archive_entry_set_fflags(struct archive_entry *, const char *);
-void archive_entry_copy_fflags_w(struct archive_entry *, const wchar_t *);
void archive_entry_set_devmajor(struct archive_entry *, dev_t);
void archive_entry_set_devminor(struct archive_entry *, dev_t);
+void archive_entry_set_fflags(struct archive_entry *,
+ unsigned long set, unsigned long clear);
+/* Returns pointer to start of first invalid token, or NULL if none. */
+/* Note that all recognized tokens are processed, regardless. */
+const wchar_t *archive_entry_copy_fflags_text_w(struct archive_entry *,
+ const wchar_t *);
void archive_entry_set_gid(struct archive_entry *, gid_t);
void archive_entry_set_gname(struct archive_entry *, const char *);
void archive_entry_copy_gname_w(struct archive_entry *, const wchar_t *);
diff --git a/lib/libarchive/archive_read_extract.c b/lib/libarchive/archive_read_extract.c
index 6155c52..77d6bb0 100644
--- a/lib/libarchive/archive_read_extract.c
+++ b/lib/libarchive/archive_read_extract.c
@@ -44,6 +44,10 @@ __FBSDID("$FreeBSD$");
#include <string.h>
#include <tar.h>
#include <unistd.h>
+#ifdef LINUX
+#include <ext2fs/ext2_fs.h>
+#include <sys/ioctl.h>
+#endif
#include "archive.h"
#include "archive_string.h"
@@ -440,7 +444,11 @@ archive_read_extract_dir_create(struct archive *a, const char *name, int mode,
return (ARCHIVE_OK);
/* Unlink failed. It's okay if it failed because it's already a dir. */
- if (errno != EPERM) {
+ /*
+ * BSD returns EPERM for unlink on an dir,
+ * Linux returns EISDIR
+ */
+ if (errno != EPERM && errno != EISDIR) {
archive_set_error(a, errno, "Couldn't create dir");
return (ARCHIVE_WARN);
}
@@ -782,29 +790,31 @@ set_extended_perm(struct archive *a, struct archive_entry *entry, int flags)
static int
set_fflags(struct archive *a, struct archive_entry *entry)
{
- char *fflags;
- const char *fflagsc;
- char *fflags_p;
const char *name;
int ret;
unsigned long set, clear;
struct stat st;
+#ifdef LINUX
+ struct stat *stp;
+ int fd;
+ int err;
+ unsigned long newflags, oldflags;
+#endif
name = archive_entry_pathname(entry);
-
ret = ARCHIVE_OK;
- fflagsc = archive_entry_fflags(entry);
- if (fflagsc == NULL)
- return (ARCHIVE_OK);
-
- fflags = strdup(fflagsc);
- if (fflags == NULL)
- return (ARCHIVE_WARN);
+ archive_entry_fflags(entry, &set, &clear);
+ if (set == 0 && clear == 0)
+ return (ret);
#ifdef HAVE_CHFLAGS
- fflags_p = fflags;
- if (strtofflags(&fflags_p, &set, &clear) == 0 &&
- stat(name, &st) == 0) {
+ /*
+ * XXX Is the stat here really necessary? Or can I just use
+ * the 'set' flags directly? In particular, I'm not sure
+ * about the correct approach if we're overwriting an existing
+ * file that already has flags on it. XXX
+ */
+ if (stat(name, &st) == 0) {
st.st_flags &= ~clear;
st.st_flags |= set;
if (chflags(name, st.st_flags) != 0) {
@@ -814,8 +824,45 @@ set_fflags(struct archive *a, struct archive_entry *entry)
}
}
#endif
+ /* Linux has flags too, but no chflags syscall */
+#ifdef LINUX
+ /*
+ * Linux has no define for the flags that are only settable
+ * by the root user...
+ */
+#define SF_MASK (EXT2_IMMUTABLE_FL|EXT2_APPEND_FL)
+
+ /*
+ * XXX As above, this would be way simpler if we didn't have
+ * to read the current flags from disk. XXX
+ */
+ stp = archive_entry_stat(entry);
+ if ((S_ISREG(stp->st_mode) || S_ISDIR(stp->st_mode)) &&
+ ((fd = open(name, O_RDONLY|O_NONBLOCK)) >= 0)) {
+ err = 1;
+ if (fd >= 0 && (ioctl(fd, EXT2_IOC_GETFLAGS, &oldflags) >= 0)) {
+ newflags = (oldflags & ~clear) | set;
+ if (ioctl(fd, EXT2_IOC_SETFLAGS, &newflags) >= 0) {
+ err = 0;
+ } else if (errno == EPERM) {
+ if (ioctl(fd, EXT2_IOC_GETFLAGS, &oldflags) >= 0) {
+ newflags &= ~SF_MASK;
+ oldflags &= SF_MASK;
+ newflags |= oldflags;
+ if (ioctl(fd, EXT2_IOC_SETFLAGS, &newflags) >= 0)
+ err = 0;
+ }
+ }
+ }
+ close(fd);
+ if (err) {
+ archive_set_error(a, errno,
+ "Failed to set file flags");
+ ret = ARCHIVE_WARN;
+ }
+ }
+#endif
- free(fflags);
return (ret);
}
diff --git a/lib/libarchive/archive_read_support_format_tar.c b/lib/libarchive/archive_read_support_format_tar.c
index e2f6242..f41e37d 100644
--- a/lib/libarchive/archive_read_support_format_tar.c
+++ b/lib/libarchive/archive_read_support_format_tar.c
@@ -911,7 +911,7 @@ pax_attribute(struct archive_entry *entry, struct stat *st,
st->st_rdev = makedev(major(st->st_dev),
tar_atol10(value, wcslen(value)));
else if (wcscmp(key, L"SCHILY.fflags")==0)
- archive_entry_copy_fflags_w(entry, value);
+ archive_entry_copy_fflags_text_w(entry, value);
else if (wcscmp(key, L"SCHILY.nlink")==0)
st->st_nlink = tar_atol10(value, wcslen(value));
break;
diff --git a/lib/libarchive/archive_write_set_format_pax.c b/lib/libarchive/archive_write_set_format_pax.c
index 19317df..950cd4d 100644
--- a/lib/libarchive/archive_write_set_format_pax.c
+++ b/lib/libarchive/archive_write_set_format_pax.c
@@ -493,6 +493,12 @@ archive_write_pax_header(struct archive *a,
((st_main->st_mtime < 0) || (st_main->st_mtime >= 0x7fffffff)))
need_extension = 1;
+ /* I use a star-compatible file flag attribute. */
+ p = archive_entry_fflags_text(entry_main);
+ if (!need_extension && p != NULL && *p != '\0')
+ need_extension = 1;
+
+
/* If there are non-trivial ACL entries, we need an extension. */
if (!need_extension && archive_entry_acl_count(entry_original,
ARCHIVE_ENTRY_ACL_TYPE_ACCESS) > 0)
@@ -533,7 +539,7 @@ archive_write_pax_header(struct archive *a,
ARCHIVE_STAT_ATIME_NANOS(st_main));
/* I use a star-compatible file flag attribute. */
- p = archive_entry_fflags(entry_main);
+ p = archive_entry_fflags_text(entry_main);
if (p != NULL && *p != '\0')
add_pax_attr(&(pax->pax_header), "SCHILY.fflags", p);
diff --git a/lib/libarchive/archive_write_set_format_shar.c b/lib/libarchive/archive_write_set_format_shar.c
index f9082c6..5944e0f 100644
--- a/lib/libarchive/archive_write_set_format_shar.c
+++ b/lib/libarchive/archive_write_set_format_shar.c
@@ -423,7 +423,7 @@ archive_write_shar_finish_entry(struct archive *a)
archive_entry_pathname(shar->entry));
}
- if ((p = archive_entry_fflags(shar->entry)) != NULL) {
+ if ((p = archive_entry_fflags_text(shar->entry)) != NULL) {
shar_printf(a, "chflags %s %s\n", p,
archive_entry_pathname(shar->entry));
}
OpenPOWER on IntegriCloud