aboutsummaryrefslogtreecommitdiff
path: root/libarchive
diff options
context:
space:
mode:
authorMartin Matuska <mm@FreeBSD.org>2016-12-01 15:39:33 +0000
committerMartin Matuska <mm@FreeBSD.org>2016-12-01 15:39:33 +0000
commit181b8217c998bcd403ea399ee7cac80e2a6a1eaa (patch)
treed00665effd90684768decb688bdb54062d252245 /libarchive
parent35837ea989bc77db98fdb46127d63e0f9c857ec6 (diff)
downloadsrc-181b8217c998bcd403ea399ee7cac80e2a6a1eaa.tar.gz
src-181b8217c998bcd403ea399ee7cac80e2a6a1eaa.zip
Notes
Diffstat (limited to 'libarchive')
-rw-r--r--libarchive/archive.h10
-rw-r--r--libarchive/archive_read_support_format_mtree.c42
-rw-r--r--libarchive/archive_read_support_format_tar.c53
-rw-r--r--libarchive/test/CMakeLists.txt1
-rw-r--r--libarchive/test/test_compat_perl_archive_tar.c66
-rw-r--r--libarchive/test/test_compat_perl_archive_tar.tar.uu49
6 files changed, 198 insertions, 23 deletions
diff --git a/libarchive/archive.h b/libarchive/archive.h
index ff401e94fa66..3a9369084d47 100644
--- a/libarchive/archive.h
+++ b/libarchive/archive.h
@@ -562,7 +562,7 @@ __LA_DECL la_int64_t archive_read_header_position(struct archive *);
* we cannot say whether there are encrypted entries, then
* ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW is returned.
* In general, this function will return values below zero when the
- * reader is uncertain or totally uncapable of encryption support.
+ * reader is uncertain or totally incapable of encryption support.
* When this function returns 0 you can be sure that the reader
* supports encryption detection but no encrypted entries have
* been found yet.
@@ -984,12 +984,12 @@ __LA_DECL int archive_read_disk_can_descend(struct archive *);
__LA_DECL int archive_read_disk_current_filesystem(struct archive *);
__LA_DECL int archive_read_disk_current_filesystem_is_synthetic(struct archive *);
__LA_DECL int archive_read_disk_current_filesystem_is_remote(struct archive *);
-/* Request that the access time of the entry visited by travesal be restored. */
+/* Request that the access time of the entry visited by traversal be restored. */
__LA_DECL int archive_read_disk_set_atime_restored(struct archive *);
/*
* Set behavior. The "flags" argument selects optional behavior.
*/
-/* Request that the access time of the entry visited by travesal be restored.
+/* Request that the access time of the entry visited by traversal be restored.
* This is the same as archive_read_disk_set_atime_restored. */
#define ARCHIVE_READDISK_RESTORE_ATIME (0x0001)
/* Default: Do not skip an entry which has nodump flags. */
@@ -1124,7 +1124,7 @@ __LA_DECL int archive_match_time_excluded(struct archive *,
/*
* Flags to tell a matching type of time stamps. These are used for
- * following functinos.
+ * following functions.
*/
/* Time flag: mtime to be tested. */
#define ARCHIVE_MATCH_MTIME (0x0100)
@@ -1144,7 +1144,7 @@ __LA_DECL int archive_match_include_date(struct archive *, int _flag,
const char *_datestr);
__LA_DECL int archive_match_include_date_w(struct archive *, int _flag,
const wchar_t *_datestr);
-/* Set inclusion time by a particluar file. */
+/* Set inclusion time by a particular file. */
__LA_DECL int archive_match_include_file_time(struct archive *,
int _flag, const char *_pathname);
__LA_DECL int archive_match_include_file_time_w(struct archive *,
diff --git a/libarchive/archive_read_support_format_mtree.c b/libarchive/archive_read_support_format_mtree.c
index ae58e8750534..85c655fbbbc6 100644
--- a/libarchive/archive_read_support_format_mtree.c
+++ b/libarchive/archive_read_support_format_mtree.c
@@ -75,6 +75,8 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_support_format_mtree.c 2011
#define MTREE_HAS_OPTIONAL 0x0800
#define MTREE_HAS_NOCHANGE 0x1000 /* FreeBSD specific */
+#define MTREE_HASHTABLE_SIZE 1024
+
struct mtree_option {
struct mtree_option *next;
char *value;
@@ -86,6 +88,8 @@ struct mtree_entry {
char *name;
char full;
char used;
+ unsigned int name_hash;
+ struct mtree_entry *hashtable_next;
};
struct mtree {
@@ -98,6 +102,7 @@ struct mtree {
const char *archive_format_name;
struct mtree_entry *entries;
struct mtree_entry *this_entry;
+ struct mtree_entry *entry_hashtable[MTREE_HASHTABLE_SIZE];
struct archive_string current_dir;
struct archive_string contents_name;
@@ -110,6 +115,7 @@ struct mtree {
static int bid_keycmp(const char *, const char *, ssize_t);
static int cleanup(struct archive_read *);
static int detect_form(struct archive_read *, int *);
+static unsigned int hash(const char *);
static int mtree_bid(struct archive_read *, int);
static int parse_file(struct archive_read *, struct archive_entry *,
struct mtree *, struct mtree_entry *, int *);
@@ -862,11 +868,12 @@ process_add_entry(struct archive_read *a, struct mtree *mtree,
struct mtree_option **global, const char *line, ssize_t line_len,
struct mtree_entry **last_entry, int is_form_d)
{
- struct mtree_entry *entry;
+ struct mtree_entry *entry, *ht_iter;
struct mtree_option *iter;
const char *next, *eq, *name, *end;
size_t name_len, len;
int r, i;
+ unsigned int ht_idx;
if ((entry = malloc(sizeof(*entry))) == NULL) {
archive_set_error(&a->archive, errno, "Can't allocate memory");
@@ -877,6 +884,8 @@ process_add_entry(struct archive_read *a, struct mtree *mtree,
entry->name = NULL;
entry->used = 0;
entry->full = 0;
+ entry->name_hash = 0;
+ entry->hashtable_next = NULL;
/* Add this entry to list. */
if (*last_entry == NULL)
@@ -929,6 +938,16 @@ process_add_entry(struct archive_read *a, struct mtree *mtree,
memcpy(entry->name, name, name_len);
entry->name[name_len] = '\0';
parse_escapes(entry->name, entry);
+ entry->name_hash = hash(entry->name);
+
+ ht_idx = entry->name_hash % MTREE_HASHTABLE_SIZE;
+ if ((ht_iter = mtree->entry_hashtable[ht_idx]) != NULL) {
+ while (ht_iter->hashtable_next)
+ ht_iter = ht_iter->hashtable_next;
+ ht_iter->hashtable_next = entry;
+ } else {
+ mtree->entry_hashtable[ht_idx] = entry;
+ }
for (iter = *global; iter != NULL; iter = iter->next) {
r = add_option(a, &entry->options, iter->value,
@@ -1122,9 +1141,10 @@ parse_file(struct archive_read *a, struct archive_entry *entry,
* with pathname canonicalization, which is a very
* tricky subject.)
*/
- for (mp = mentry->next; mp != NULL; mp = mp->next) {
+ for (mp = mentry->hashtable_next; mp != NULL; mp = mp->hashtable_next) {
if (mp->full && !mp->used
- && strcmp(mentry->name, mp->name) == 0) {
+ && mentry->name_hash == mp->name_hash
+ && strcmp(mentry->name, mp->name) == 0) {
/* Later lines override earlier ones. */
mp->used = 1;
r1 = parse_line(a, entry, mtree, mp,
@@ -2000,3 +2020,19 @@ readline(struct archive_read *a, struct mtree *mtree, char **start,
find_off = u - mtree->line.s;
}
}
+
+static unsigned int
+hash(const char *p)
+{
+ /* A 32-bit version of Peter Weinberger's (PJW) hash algorithm,
+ as used by ELF for hashing function names. */
+ unsigned g, h = 0;
+ while (*p != '\0') {
+ h = (h << 4) + *p++;
+ if ((g = h & 0xF0000000) != 0) {
+ h ^= g >> 24;
+ h &= 0x0FFFFFFF;
+ }
+ }
+ return h;
+}
diff --git a/libarchive/archive_read_support_format_tar.c b/libarchive/archive_read_support_format_tar.c
index 0ee511ea1ae8..b977cb7400fb 100644
--- a/libarchive/archive_read_support_format_tar.c
+++ b/libarchive/archive_read_support_format_tar.c
@@ -294,8 +294,14 @@ archive_read_format_tar_cleanup(struct archive_read *a)
return (ARCHIVE_OK);
}
+/*
+ * Validate number field
+ *
+ * Flags:
+ * 1 - allow double \0 at field end
+ */
static int
-validate_number_field(const char* p_field, size_t i_size)
+validate_number_field(const char* p_field, size_t i_size, int flags)
{
unsigned char marker = (unsigned char)p_field[0];
/* octal? */
@@ -305,14 +311,24 @@ validate_number_field(const char* p_field, size_t i_size)
for (i = 0; i < i_size; ++i) {
switch (p_field[i])
{
- case ' ': /* skip any leading spaces and trailing space*/
+ case ' ':
+ /* skip any leading spaces and trailing space */
if (octal_found == 0 || i == i_size - 1) {
continue;
}
break;
- case '\0': /* null is allowed only at the end */
+ case '\0':
+ /*
+ * null should be allowed only at the end
+ *
+ * Perl Archive::Tar terminates some fields
+ * with two nulls. We must allow this to stay
+ * compatible.
+ */
if (i != i_size - 1) {
- return 0;
+ if (((flags & 1) == 0)
+ || i != i_size - 2)
+ return 0;
}
break;
/* rest must be octal digits */
@@ -390,18 +406,25 @@ archive_read_format_tar_bid(struct archive_read *a, int best_bid)
* Check format of mode/uid/gid/mtime/size/rdevmajor/rdevminor fields.
* These are usually octal numbers but GNU tar encodes "big" values as
* base256 and leading zeroes are sometimes replaced by spaces.
- * Even the null terminator is sometimes omitted. Anyway, must be checked
- * to avoid false positives.
+ * Even the null terminator is sometimes omitted. Anyway, must be
+ * checked to avoid false positives.
+ *
+ * Perl Archive::Tar does not follow the spec and terminates mode, uid,
+ * gid, rdevmajor and rdevminor with a double \0. For compatibility
+ * reasons we allow this deviation.
*/
- if (bid > 0 &&
- (validate_number_field(header->mode, sizeof(header->mode)) == 0 ||
- validate_number_field(header->uid, sizeof(header->uid)) == 0 ||
- validate_number_field(header->gid, sizeof(header->gid)) == 0 ||
- validate_number_field(header->mtime, sizeof(header->mtime)) == 0 ||
- validate_number_field(header->size, sizeof(header->size)) == 0 ||
- validate_number_field(header->rdevmajor, sizeof(header->rdevmajor)) == 0 ||
- validate_number_field(header->rdevminor, sizeof(header->rdevminor)) == 0)) {
- bid = 0;
+ if (bid > 0 && (
+ validate_number_field(header->mode, sizeof(header->mode), 1) == 0
+ || validate_number_field(header->uid, sizeof(header->uid), 1) == 0
+ || validate_number_field(header->gid, sizeof(header->gid), 1) == 0
+ || validate_number_field(header->mtime, sizeof(header->mtime),
+ 0) == 0
+ || validate_number_field(header->size, sizeof(header->size), 0) == 0
+ || validate_number_field(header->rdevmajor,
+ sizeof(header->rdevmajor), 1) == 0
+ || validate_number_field(header->rdevminor,
+ sizeof(header->rdevminor), 1) == 0)) {
+ bid = 0;
}
return (bid);
diff --git a/libarchive/test/CMakeLists.txt b/libarchive/test/CMakeLists.txt
index 9d2622b0cda5..5dad2191021d 100644
--- a/libarchive/test/CMakeLists.txt
+++ b/libarchive/test/CMakeLists.txt
@@ -58,6 +58,7 @@ IF(ENABLE_TEST)
test_compat_lzop.c
test_compat_mac.c
test_compat_pax_libarchive_2x.c
+ test_compat_perl_archive_tar.c
test_compat_solaris_pax_sparse.c
test_compat_solaris_tar_acl.c
test_compat_star_acl_posix1e.c
diff --git a/libarchive/test/test_compat_perl_archive_tar.c b/libarchive/test/test_compat_perl_archive_tar.c
new file mode 100644
index 000000000000..165a519a3432
--- /dev/null
+++ b/libarchive/test/test_compat_perl_archive_tar.c
@@ -0,0 +1,66 @@
+/*-
+ * Copyright (c) 2016 Martin Matuska
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``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 AUTHOR(S) 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.
+ */
+#include "test.h"
+__FBSDID("$FreeBSD");
+
+/*
+ * Verify our ability to read sample files created by Perl module Archive::Tar
+ */
+
+DEFINE_TEST(test_compat_perl_archive_tar)
+{
+ char name[] = "test_compat_perl_archive_tar.tar";
+ struct archive_entry *ae;
+ struct archive *a;
+ int r;
+
+ assert((a = archive_read_new()) != NULL);
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+ extract_reference_file(name);
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, name,
+ 10240));
+
+ /* Read first entry. */
+ assertEqualIntA(a, ARCHIVE_OK, r = archive_read_next_header(a, &ae));
+ if (r != ARCHIVE_OK) {
+ archive_read_free(a);
+ return;
+ }
+ assertEqualString("file1", archive_entry_pathname(ae));
+ assertEqualInt(1480603099, archive_entry_mtime(ae));
+ assertEqualInt(1000, archive_entry_uid(ae));
+ assertEqualString("john", archive_entry_uname(ae));
+ assertEqualInt(1000, archive_entry_gid(ae));
+ assertEqualString("john", archive_entry_gname(ae));
+ assertEqualInt(0100644, archive_entry_mode(ae));
+
+ /* Verify that the format detection worked. */
+ assertEqualInt(archive_filter_code(a, 0), ARCHIVE_FILTER_NONE);
+ assertEqualInt(archive_format(a), ARCHIVE_FORMAT_TAR_USTAR);
+
+ assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+}
diff --git a/libarchive/test/test_compat_perl_archive_tar.tar.uu b/libarchive/test/test_compat_perl_archive_tar.tar.uu
new file mode 100644
index 000000000000..ca7bc2a9764f
--- /dev/null
+++ b/libarchive/test/test_compat_perl_archive_tar.tar.uu
@@ -0,0 +1,49 @@
+begin 644 test_compat_perl_archive_tar.tar
+M9FEL93$`````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````#`P,#8T-```,#`Q-S4P```P,#$W-3```"`@("`@("`@("`U
+M`#$S,#(P,#,R-S,S`"`Q,3$R,P`@,```````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````````````!U<W1A<@`P,&IO:&X`
+M````````````````````````````````````:F]H;@``````````````````
+M```````````````````P,#`P,#```#`P,#`P,```````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````!A8F-D"@``````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+7````````````````````````````````
+`
+end