summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/libarchive/Makefile2
-rw-r--r--lib/libarchive/Makefile.freebsd2
-rw-r--r--lib/libarchive/archive_private.h9
-rw-r--r--lib/libarchive/archive_write_set_format_pax.c33
-rw-r--r--lib/libarchive/archive_write_set_format_ustar.c96
5 files changed, 117 insertions, 25 deletions
diff --git a/lib/libarchive/Makefile b/lib/libarchive/Makefile
index 406dded..7c72f95 100644
--- a/lib/libarchive/Makefile
+++ b/lib/libarchive/Makefile
@@ -2,7 +2,7 @@
LIB= archive
SHLIB_MAJOR= 1
-VERSION= 1.00.000
+VERSION= 1.00.002
CFLAGS+= -DPACKAGE_NAME=\"lib${LIB}\"
CFLAGS+= -DPACKAGE_VERSION=\"${VERSION}\"
diff --git a/lib/libarchive/Makefile.freebsd b/lib/libarchive/Makefile.freebsd
index 406dded..7c72f95 100644
--- a/lib/libarchive/Makefile.freebsd
+++ b/lib/libarchive/Makefile.freebsd
@@ -2,7 +2,7 @@
LIB= archive
SHLIB_MAJOR= 1
-VERSION= 1.00.000
+VERSION= 1.00.002
CFLAGS+= -DPACKAGE_NAME=\"lib${LIB}\"
CFLAGS+= -DPACKAGE_VERSION=\"${VERSION}\"
diff --git a/lib/libarchive/archive_private.h b/lib/libarchive/archive_private.h
index 730974c..5fb4d9b 100644
--- a/lib/libarchive/archive_private.h
+++ b/lib/libarchive/archive_private.h
@@ -198,10 +198,15 @@ struct archive {
};
-/* Utility function to format a USTAR header into a buffer. */
+/*
+ * Utility function to format a USTAR header into a buffer. If
+ * "strict" is set, this tries to create the absolutely most portable
+ * version of a ustar header. If "strict" is set to 0, then it will
+ * relax certain requirements.
+ */
int
__archive_write_format_header_ustar(struct archive *, char buff[512],
- struct archive_entry *, int tartype);
+ struct archive_entry *, int tartype, int strict);
#define ARCHIVE_STATE_ANY 0xFFFFU
#define ARCHIVE_STATE_NEW 1U
diff --git a/lib/libarchive/archive_write_set_format_pax.c b/lib/libarchive/archive_write_set_format_pax.c
index cc4b82e..a8e5be8 100644
--- a/lib/libarchive/archive_write_set_format_pax.c
+++ b/lib/libarchive/archive_write_set_format_pax.c
@@ -500,7 +500,6 @@ archive_write_pax_header(struct archive *a,
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)
@@ -595,9 +594,33 @@ archive_write_pax_header(struct archive *a,
if (hardlink != NULL)
archive_entry_set_size(entry_main, 0);
- /* Format 'ustar' header for main entry. */
- /* We don't care if this returns an error. */
- __archive_write_format_header_ustar(a, ustarbuff, entry_main, -1);
+ /* Format 'ustar' header for main entry.
+ *
+ * The trouble with file size: If the reader can't understand
+ * the file size, they may not be able to locate the next
+ * entry and the rest of the archive is toast. Pax-compliant
+ * readers are supposed to ignore the file size in the main
+ * header, so the question becomes how to maximize portability
+ * for readers that don't support pax attribute extensions.
+ * For maximum compatibility, I permit numeric extensions in
+ * the main header so that the file size stored will always be
+ * correct, even if it's in a format that only some
+ * implementations understand. The technique used here is:
+ *
+ * a) If possible, follow the standard exactly. This handles
+ * files up to 8 gigabytes minus 1.
+ *
+ * b) If that fails, try octal but omit the field terminator.
+ * That handles files up to 64 gigabytes minus 1.
+ *
+ * c) Otherwise, use base-256 extensions. That handles files
+ * up to 2^63 in this implementation, with the potential to
+ * go up to 2^94. That should hold us for a while. ;-)
+ *
+ * The non-strict formatter uses similar logic for other
+ * numeric fields, though they're less critical.
+ */
+ __archive_write_format_header_ustar(a, ustarbuff, entry_main, -1, 0);
/* If we built any extended attributes, write that entry first. */
ret = 0;
@@ -624,7 +647,7 @@ archive_write_pax_header(struct archive *a,
archive_entry_gname(entry_main));
ret = __archive_write_format_header_ustar(a, paxbuff,
- pax_attr_entry, 'x');
+ pax_attr_entry, 'x', 1);
archive_entry_free(pax_attr_entry);
archive_string_free(&pax_entry_name);
diff --git a/lib/libarchive/archive_write_set_format_ustar.c b/lib/libarchive/archive_write_set_format_ustar.c
index 68892eb..9e49596 100644
--- a/lib/libarchive/archive_write_set_format_ustar.c
+++ b/lib/libarchive/archive_write_set_format_ustar.c
@@ -102,6 +102,8 @@ static int archive_write_ustar_finish(struct archive *);
static int archive_write_ustar_finish_entry(struct archive *);
static int archive_write_ustar_header(struct archive *,
struct archive_entry *entry);
+static int format_256(int64_t, char *, int);
+static int format_number(int64_t, char *, int size, int max, int strict);
static int format_octal(int64_t, char *, int);
static int write_nulls(struct archive *a, size_t);
@@ -151,7 +153,7 @@ archive_write_ustar_header(struct archive *a, struct archive_entry *entry)
!S_ISREG(archive_entry_mode(entry)))
archive_entry_set_size(entry, 0);
- ret = __archive_write_format_header_ustar(a, buff, entry, -1);
+ ret = __archive_write_format_header_ustar(a, buff, entry, -1, 1);
if (ret != ARCHIVE_OK)
return (ret);
ret = (a->compression_write)(a, buff, 512);
@@ -168,12 +170,14 @@ archive_write_ustar_header(struct archive *a, struct archive_entry *entry)
*
* Returns -1 if format failed (due to field overflow).
* Note that this always formats as much of the header as possible.
+ * If "strict" is set to zero, it will extend numeric fields as
+ * necessary (overwriting terminators or using base-256 extensions).
*
* This is exported so that other 'tar' formats can use it.
*/
int
__archive_write_format_header_ustar(struct archive *a, char buff[512],
- struct archive_entry *entry, int tartype)
+ struct archive_entry *entry, int tartype, int strict)
{
unsigned int checksum;
struct archive_entry_header_ustar *h;
@@ -185,6 +189,11 @@ __archive_write_format_header_ustar(struct archive *a, char buff[512],
ret = 0;
mytartype = -1;
+ /*
+ * The "template header" already includes the "ustar"
+ * signature, various end-of-field markers and other required
+ * elements.
+ */
memcpy(buff, &template_header, 512);
h = (struct archive_entry_header_ustar *)buff;
@@ -262,42 +271,42 @@ __archive_write_format_header_ustar(struct archive *a, char buff[512],
st = archive_entry_stat(entry);
- if (format_octal(st->st_mode & 07777, h->mode, sizeof(h->mode))) {
+ if (format_number(st->st_mode & 07777, h->mode, sizeof(h->mode), 8, strict)) {
archive_set_error(a, ERANGE, "Numeric mode too large");
ret = ARCHIVE_WARN;
}
- if (format_octal(st->st_uid, h->uid, sizeof(h->uid))) {
+ if (format_number(st->st_uid, h->uid, sizeof(h->uid), 8, strict)) {
archive_set_error(a, ERANGE, "Numeric user ID too large");
ret = ARCHIVE_WARN;
}
- if (format_octal(st->st_gid, h->gid, sizeof(h->gid))) {
+ if (format_number(st->st_gid, h->gid, sizeof(h->gid), 8, strict)) {
archive_set_error(a, ERANGE, "Numeric group ID too large");
ret = ARCHIVE_WARN;
}
- if (format_octal(st->st_size, h->size, sizeof(h->size))) {
- archive_set_error(a, ERANGE, "File size too large");
+ if (format_number(st->st_size, h->size, sizeof(h->size), 12, strict)) {
+ archive_set_error(a, ERANGE, "File size out of range");
ret = ARCHIVE_WARN;
}
- if (format_octal(st->st_mtime, h->mtime, sizeof(h->mtime))) {
+ if (format_number(st->st_mtime, h->mtime, sizeof(h->mtime), 12, strict)) {
archive_set_error(a, ERANGE,
"File modification time too large");
ret = ARCHIVE_WARN;
}
if (S_ISBLK(st->st_mode) || S_ISCHR(st->st_mode)) {
- if (format_octal(major(st->st_rdev), h->rdevmajor,
- sizeof(h->rdevmajor))) {
+ if (format_number(major(st->st_rdev), h->rdevmajor,
+ sizeof(h->rdevmajor), 8, strict)) {
archive_set_error(a, ERANGE,
"Major device number too large");
ret = ARCHIVE_WARN;
}
- if (format_octal(minor(st->st_rdev), h->rdevminor,
- sizeof(h->rdevminor))) {
+ if (format_number(minor(st->st_rdev), h->rdevminor,
+ sizeof(h->rdevminor), 8, strict)) {
archive_set_error(a, ERANGE,
"Minor device number too large");
ret = ARCHIVE_WARN;
@@ -331,13 +340,61 @@ __archive_write_format_header_ustar(struct archive *a, char buff[512],
checksum = 0;
for (i = 0; i < 512; i++)
checksum += 255 & (unsigned int)buff[i];
- h->checksum[6] = '\0';
- h->checksum[7] = ' ';
+ h->checksum[6] = '\0'; /* Can't be pre-set in the template. */
+ /* h->checksum[7] = ' '; */ /* This is pre-set in the template. */
format_octal(checksum, h->checksum, 6);
return (ret);
}
/*
+ * Format a number into a field, with some intelligence.
+ */
+static int
+format_number(int64_t v, char *p, int s, int maxsize, int strict)
+{
+ int64_t limit;
+
+ limit = ((int64_t)1 << (s*3));
+
+ /* "Strict" only permits octal values with proper termination. */
+ if (strict)
+ return (format_octal(v, p, s));
+
+ /*
+ * In non-strict mode, we allow the number to overwrite one or
+ * more bytes of the field termination. Even old tar
+ * implementations should be able to handle this with no
+ * problem.
+ */
+ if (v >= 0) {
+ while (s <= maxsize) {
+ if (v < limit)
+ return (format_octal(v, p, s));
+ s++;
+ limit <<= 3;
+ }
+ }
+
+ /* Base-256 can handle any number, positive or negative. */
+ return (format_256(v, p, maxsize));
+}
+
+/*
+ * Format a number into the specified field using base-256.
+ */
+static int
+format_256(int64_t v, char *p, int s)
+{
+ p += s;
+ while (s-- > 0) {
+ *--p = (char)(v & 0xff);
+ v >>= 8;
+ }
+ *p |= 0x80; /* Set the base-256 marker bit. */
+ return (0);
+}
+
+/*
* Format a number into the specified field.
*/
static int
@@ -345,9 +402,16 @@ format_octal(int64_t v, char *p, int s)
{
int len;
- p += s; /* Start at the end and work backwards. */
-
len = s;
+
+ /* Octal values can't be negative, so use 0. */
+ if (v < 0) {
+ while (len-- > 0)
+ *p++ = '0';
+ return (-1);
+ }
+
+ p += s; /* Start at the end and work backwards. */
while (s-- > 0) {
*--p = '0' + (v & 7);
v >>= 3;
OpenPOWER on IntegriCloud