summaryrefslogtreecommitdiffstats
path: root/contrib/libarchive/libarchive/archive_read_support_format_mtree.c
diff options
context:
space:
mode:
authormm <mm@FreeBSD.org>2012-02-25 10:58:02 +0000
committermm <mm@FreeBSD.org>2012-02-25 10:58:02 +0000
commit6132589d7bb05bbf0c9033cc9f5cf79bafdc0b0f (patch)
tree117e869a99c6fa7f789c6d9a87cf7eac26ae69e3 /contrib/libarchive/libarchive/archive_read_support_format_mtree.c
parent87f7f0cfe8d3d17bc154ca2c0dcd51bca1444006 (diff)
parent2f6e434fe4c652da1969314fa57ae21936cec85d (diff)
downloadFreeBSD-src-6132589d7bb05bbf0c9033cc9f5cf79bafdc0b0f.zip
FreeBSD-src-6132589d7bb05bbf0c9033cc9f5cf79bafdc0b0f.tar.gz
Update libarchive to 3.0.3
Some of new features: - New readers: RAR, LHA/LZH, CAB reader, 7-Zip - New writers: ISO9660, XAR - Improvements to many formats, especially including ISO9660 and Zip - Stackable write filters to write, e.g., tar.gz.uu in a single pass - Exploit seekable input; new "seekable" Zip reader can exploit the Zip Central Directory when it's available; the old "streamable" Zip reader is still fully supported for cases where seeking is not possible. Full release notes available at: https://github.com/libarchive/libarchive/wiki/ReleaseNotes
Diffstat (limited to 'contrib/libarchive/libarchive/archive_read_support_format_mtree.c')
-rw-r--r--contrib/libarchive/libarchive/archive_read_support_format_mtree.c632
1 files changed, 534 insertions, 98 deletions
diff --git a/contrib/libarchive/libarchive/archive_read_support_format_mtree.c b/contrib/libarchive/libarchive/archive_read_support_format_mtree.c
index 7ae0b02..316bad6 100644
--- a/contrib/libarchive/libarchive/archive_read_support_format_mtree.c
+++ b/contrib/libarchive/libarchive/archive_read_support_format_mtree.c
@@ -1,6 +1,7 @@
/*-
* Copyright (c) 2003-2007 Tim Kientzle
* Copyright (c) 2008 Joerg Sonnenberger
+ * Copyright (c) 2011 Michihiro NAKAJIMA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -86,9 +87,8 @@ struct mtree {
struct archive_string line;
size_t buffsize;
char *buff;
- off_t offset;
+ int64_t offset;
int fd;
- int filetype;
int archive_format;
const char *archive_format_name;
struct mtree_entry *entries;
@@ -98,11 +98,12 @@ struct mtree {
struct archive_entry_linkresolver *resolver;
- off_t cur_size, cur_offset;
+ int64_t cur_size;
};
+static int bid_keycmp(const char *, const char *, ssize_t);
static int cleanup(struct archive_read *);
-static int mtree_bid(struct archive_read *);
+static int mtree_bid(struct archive_read *, int);
static int parse_file(struct archive_read *, struct archive_entry *,
struct mtree *, struct mtree_entry *, int *);
static void parse_escapes(char *, struct mtree_entry *);
@@ -111,7 +112,7 @@ static int parse_line(struct archive_read *, struct archive_entry *,
static int parse_keyword(struct archive_read *, struct mtree *,
struct archive_entry *, struct mtree_option *, int *);
static int read_data(struct archive_read *a,
- const void **buff, size_t *size, off_t *offset);
+ const void **buff, size_t *size, int64_t *offset);
static ssize_t readline(struct archive_read *, struct mtree *, char **, ssize_t);
static int skip(struct archive_read *a);
static int read_header(struct archive_read *,
@@ -120,6 +121,53 @@ static int64_t mtree_atol10(char **);
static int64_t mtree_atol8(char **);
static int64_t mtree_atol(char **);
+/*
+ * There's no standard for TIME_T_MAX/TIME_T_MIN. So we compute them
+ * here. TODO: Move this to configure time, but be careful
+ * about cross-compile environments.
+ */
+static int64_t
+get_time_t_max(void)
+{
+#if defined(TIME_T_MAX)
+ return TIME_T_MAX;
+#else
+ static time_t t;
+ time_t a;
+ if (t == 0) {
+ a = 1;
+ while (a > t) {
+ t = a;
+ a = a * 2 + 1;
+ }
+ }
+ return t;
+#endif
+}
+
+static int64_t
+get_time_t_min(void)
+{
+#if defined(TIME_T_MIN)
+ return TIME_T_MIN;
+#else
+ /* 't' will hold the minimum value, which will be zero (if
+ * time_t is unsigned) or -2^n (if time_t is signed). */
+ static int computed;
+ static time_t t;
+ time_t a;
+ if (computed == 0) {
+ a = (time_t)-1;
+ while (a < t) {
+ t = a;
+ a = a * 2;
+ }
+ computed = 1;
+ }
+ return t;
+#endif
+}
+
static void
free_options(struct mtree_option *head)
{
@@ -139,6 +187,9 @@ archive_read_support_format_mtree(struct archive *_a)
struct mtree *mtree;
int r;
+ archive_check_magic(_a, ARCHIVE_READ_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_read_support_format_mtree");
+
mtree = (struct mtree *)malloc(sizeof(*mtree));
if (mtree == NULL) {
archive_set_error(&a->archive, ENOMEM,
@@ -183,20 +234,389 @@ cleanup(struct archive_read *a)
return (ARCHIVE_OK);
}
+static ssize_t
+get_line_size(const char *b, ssize_t avail, ssize_t *nlsize)
+{
+ ssize_t len;
+
+ len = 0;
+ while (len < avail) {
+ switch (*b) {
+ case '\0':/* Non-ascii character or control character. */
+ if (nlsize != NULL)
+ *nlsize = 0;
+ return (-1);
+ case '\r':
+ if (avail-len > 1 && b[1] == '\n') {
+ if (nlsize != NULL)
+ *nlsize = 2;
+ return (len+2);
+ }
+ /* FALL THROUGH */
+ case '\n':
+ if (nlsize != NULL)
+ *nlsize = 1;
+ return (len+1);
+ default:
+ b++;
+ len++;
+ break;
+ }
+ }
+ if (nlsize != NULL)
+ *nlsize = 0;
+ return (avail);
+}
+
+static ssize_t
+next_line(struct archive_read *a,
+ const char **b, ssize_t *avail, ssize_t *ravail, ssize_t *nl)
+{
+ ssize_t len;
+ int quit;
+
+ quit = 0;
+ if (*avail == 0) {
+ *nl = 0;
+ len = 0;
+ } else
+ len = get_line_size(*b, *avail, nl);
+ /*
+ * Read bytes more while it does not reach the end of line.
+ */
+ while (*nl == 0 && len == *avail && !quit) {
+ ssize_t diff = *ravail - *avail;
+ size_t nbytes_req = (*ravail+1023) & ~1023U;
+ ssize_t tested;
+
+ /* Increase reading bytes if it is not enough to at least
+ * new two lines. */
+ if (nbytes_req < (size_t)*ravail + 160)
+ nbytes_req <<= 1;
+
+ *b = __archive_read_ahead(a, nbytes_req, avail);
+ if (*b == NULL) {
+ if (*ravail >= *avail)
+ return (0);
+ /* Reading bytes reaches the end of file. */
+ *b = __archive_read_ahead(a, *avail, avail);
+ quit = 1;
+ }
+ *ravail = *avail;
+ *b += diff;
+ *avail -= diff;
+ tested = len;/* Skip some bytes we already determinated. */
+ len = get_line_size(*b, *avail, nl);
+ if (len >= 0)
+ len += tested;
+ }
+ return (len);
+}
+/*
+ * Compare characters with a mtree keyword.
+ * Returns the length of a mtree keyword if matched.
+ * Returns 0 if not matched.
+ */
static int
-mtree_bid(struct archive_read *a)
+bid_keycmp(const char *p, const char *key, ssize_t len)
+{
+ int match_len = 0;
+
+ while (len > 0 && *p && *key) {
+ if (*p == *key) {
+ --len;
+ ++p;
+ ++key;
+ ++match_len;
+ continue;
+ }
+ return (0);/* Not match */
+ }
+ if (*key != '\0')
+ return (0);/* Not match */
+
+ /* A following character should be specified characters */
+ if (p[0] == '=' || p[0] == ' ' || p[0] == '\t' ||
+ p[0] == '\n' || p[0] == '\r' ||
+ (p[0] == '\\' && (p[1] == '\n' || p[1] == '\r')))
+ return (match_len);
+ return (0);/* Not match */
+}
+
+/*
+ * Test whether the characters 'p' has is mtree keyword.
+ * Returns the length of a detected keyword.
+ * Returns 0 if any keywords were not found.
+ */
+static ssize_t
+bid_keyword(const char *p, ssize_t len)
+{
+ static const char *keys_c[] = {
+ "content", "contents", "cksum", NULL
+ };
+ static const char *keys_df[] = {
+ "device", "flags", NULL
+ };
+ static const char *keys_g[] = {
+ "gid", "gname", NULL
+ };
+ static const char *keys_il[] = {
+ "ignore", "link", NULL
+ };
+ static const char *keys_m[] = {
+ "md5", "md5digest", "mode", NULL
+ };
+ static const char *keys_no[] = {
+ "nlink", "optional", NULL
+ };
+ static const char *keys_r[] = {
+ "rmd160", "rmd160digest", NULL
+ };
+ static const char *keys_s[] = {
+ "sha1", "sha1digest",
+ "sha256", "sha256digest",
+ "sha384", "sha384digest",
+ "sha512", "sha512digest",
+ "size", NULL
+ };
+ static const char *keys_t[] = {
+ "tags", "time", "type", NULL
+ };
+ static const char *keys_u[] = {
+ "uid", "uname", NULL
+ };
+ const char **keys;
+ int i;
+
+ switch (*p) {
+ case 'c': keys = keys_c; break;
+ case 'd': case 'f': keys = keys_df; break;
+ case 'g': keys = keys_g; break;
+ case 'i': case 'l': keys = keys_il; break;
+ case 'm': keys = keys_m; break;
+ case 'n': case 'o': keys = keys_no; break;
+ case 'r': keys = keys_r; break;
+ case 's': keys = keys_s; break;
+ case 't': keys = keys_t; break;
+ case 'u': keys = keys_u; break;
+ default: return (0);/* Unknown key */
+ }
+
+ for (i = 0; keys[i] != NULL; i++) {
+ int l = bid_keycmp(p, keys[i], len);
+ if (l > 0)
+ return (l);
+ }
+ return (0);/* Unknown key */
+}
+
+/*
+ * Test whether there is a set of mtree keywords.
+ * Returns the number of keyword.
+ * Returns -1 if we got incorrect sequence.
+ * This function expects a set of "<space characters>keyword=value".
+ * When "unset" is specified, expects a set of "<space characters>keyword".
+ */
+static int
+bid_keyword_list(const char *p, ssize_t len, int unset)
+{
+ int l;
+ int keycnt = 0;
+
+ while (len > 0 && *p) {
+ int blank = 0;
+
+ /* Test whether there are blank characters in the line. */
+ while (len >0 && (*p == ' ' || *p == '\t')) {
+ ++p;
+ --len;
+ blank = 1;
+ }
+ if (*p == '\n' || *p == '\r')
+ break;
+ if (p[0] == '\\' && (p[1] == '\n' || p[1] == '\r'))
+ break;
+ if (!blank) /* No blank character. */
+ return (-1);
+
+ if (unset) {
+ l = bid_keycmp(p, "all", len);
+ if (l > 0)
+ return (1);
+ }
+ /* Test whether there is a correct key in the line. */
+ l = bid_keyword(p, len);
+ if (l == 0)
+ return (-1);/* Unknown keyword was found. */
+ p += l;
+ len -= l;
+ keycnt++;
+
+ /* Skip value */
+ if (*p == '=') {
+ int value = 0;
+ ++p;
+ --len;
+ while (len > 0 && *p != ' ' && *p != '\t') {
+ ++p;
+ --len;
+ value = 1;
+ }
+ /* A keyword should have a its value unless
+ * "/unset" operation. */
+ if (!unset && value == 0)
+ return (-1);
+ }
+ }
+ return (keycnt);
+}
+
+static int
+bid_entry(const char *p, ssize_t len)
+{
+ int f = 0;
+ static const unsigned char safe_char[256] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 00 - 0F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 1F */
+ /* !"$%&'()*+,-./ EXCLUSION:( )(#) */
+ 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 20 - 2F */
+ /* 0123456789:;<>? EXCLUSION:(=) */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, /* 30 - 3F */
+ /* @ABCDEFGHIJKLMNO */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 - 4F */
+ /* PQRSTUVWXYZ[\]^_ */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 50 - 5F */
+ /* `abcdefghijklmno */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 - 6F */
+ /* pqrstuvwxyz{|}~ */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* 70 - 7F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A0 - AF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B0 - BF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C0 - CF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D0 - DF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F0 - FF */
+ };
+
+ /*
+ * Skip the path-name which is quoted.
+ */
+ while (len > 0 && *p != ' ' && *p != '\t') {
+ if (!safe_char[*(const unsigned char *)p])
+ return (-1);
+ ++p;
+ --len;
+ ++f;
+ }
+ /* If a path-name was not found, returns error. */
+ if (f == 0)
+ return (-1);
+
+ return (bid_keyword_list(p, len, 0));
+}
+
+#define MAX_BID_ENTRY 3
+
+static int
+mtree_bid(struct archive_read *a, int best_bid)
{
const char *signature = "#mtree";
const char *p;
+ ssize_t avail, ravail;
+ ssize_t len, nl;
+ int detected_bytes = 0, entry_cnt = 0, multiline = 0;
+
+ (void)best_bid; /* UNUSED */
/* Now let's look at the actual header and see if it matches. */
- p = __archive_read_ahead(a, strlen(signature), NULL);
+ p = __archive_read_ahead(a, strlen(signature), &avail);
if (p == NULL)
return (-1);
- if (strncmp(p, signature, strlen(signature)) == 0)
+ if (memcmp(p, signature, strlen(signature)) == 0)
return (8 * (int)strlen(signature));
+
+ /*
+ * There is not a mtree signature. Let's try to detect mtree format.
+ */
+ ravail = avail;
+ for (;;) {
+ len = next_line(a, &p, &avail, &ravail, &nl);
+ /* The terminal character of the line should be
+ * a new line character, '\r\n' or '\n'. */
+ if (len <= 0 || nl == 0)
+ break;
+ if (!multiline) {
+ /* Leading whitespace is never significant,
+ * ignore it. */
+ while (len > 0 && (*p == ' ' || *p == '\t')) {
+ ++p;
+ --avail;
+ --len;
+ }
+ /* Skip comment or empty line. */
+ if (p[0] == '#' || p[0] == '\n' || p[0] == '\r') {
+ p += len;
+ avail -= len;
+ continue;
+ }
+ } else {
+ /* A continuance line; the terminal
+ * character of previous line was '\' character. */
+ if (bid_keyword_list(p, len, 0) <= 0)
+ break;
+ if (multiline == 1)
+ detected_bytes += len;
+ if (p[len-nl-1] != '\\') {
+ if (multiline == 1 &&
+ ++entry_cnt >= MAX_BID_ENTRY)
+ break;
+ multiline = 0;
+ }
+ p += len;
+ avail -= len;
+ continue;
+ }
+ if (p[0] != '/') {
+ if (bid_entry(p, len) >= 0) {
+ detected_bytes += len;
+ if (p[len-nl-1] == '\\')
+ /* This line continues. */
+ multiline = 1;
+ else {
+ /* We've got plenty of correct lines
+ * to assume that this file is a mtree
+ * format. */
+ if (++entry_cnt >= MAX_BID_ENTRY)
+ break;
+ }
+ } else
+ break;
+ } else if (strncmp(p, "/set", 4) == 0) {
+ if (bid_keyword_list(p+4, len-4, 0) <= 0)
+ break;
+ /* This line continues. */
+ if (p[len-nl-1] == '\\')
+ multiline = 2;
+ } else if (strncmp(p, "/unset", 6) == 0) {
+ if (bid_keyword_list(p+6, len-6, 1) <= 0)
+ break;
+ /* This line continues. */
+ if (p[len-nl-1] == '\\')
+ multiline = 2;
+ } else
+ break;
+
+ /* Test next line. */
+ p += len;
+ avail -= len;
+ }
+ if (entry_cnt >= MAX_BID_ENTRY || (entry_cnt > 0 && len == 0))
+ return (32);
+
return (0);
}
@@ -215,21 +635,21 @@ static int
add_option(struct archive_read *a, struct mtree_option **global,
const char *value, size_t len)
{
- struct mtree_option *option;
+ struct mtree_option *opt;
- if ((option = malloc(sizeof(*option))) == NULL) {
+ if ((opt = malloc(sizeof(*opt))) == NULL) {
archive_set_error(&a->archive, errno, "Can't allocate memory");
return (ARCHIVE_FATAL);
}
- if ((option->value = malloc(len + 1)) == NULL) {
- free(option);
+ if ((opt->value = malloc(len + 1)) == NULL) {
+ free(opt);
archive_set_error(&a->archive, errno, "Can't allocate memory");
return (ARCHIVE_FATAL);
}
- memcpy(option->value, value, len);
- option->value[len] = '\0';
- option->next = *global;
- *global = option;
+ memcpy(opt->value, value, len);
+ opt->value[len] = '\0';
+ opt->next = *global;
+ *global = opt;
return (ARCHIVE_OK);
}
@@ -400,7 +820,7 @@ read_mtree(struct archive_read *a, struct mtree *mtree)
last_entry = NULL;
for (counter = 1; ; ++counter) {
- len = readline(a, mtree, &p, 256);
+ len = readline(a, mtree, &p, 65536);
if (len == 0) {
mtree->this_entry = mtree->entries;
free_options(global);
@@ -518,12 +938,12 @@ parse_file(struct archive_read *a, struct archive_entry *entry,
struct stat st_storage, *st;
struct mtree_entry *mp;
struct archive_entry *sparse_entry;
- int r = ARCHIVE_OK, r1, parsed_kws, mismatched_type;
+ int r = ARCHIVE_OK, r1, parsed_kws;
mentry->used = 1;
/* Initialize reasonable defaults. */
- mtree->filetype = AE_IFREG;
+ archive_entry_set_filetype(entry, AE_IFREG);
archive_entry_set_size(entry, 0);
archive_string_empty(&mtree->contents_name);
@@ -618,44 +1038,49 @@ parse_file(struct archive_read *a, struct archive_entry *entry,
* the type of the contents object on disk.
*/
if (st != NULL) {
- mismatched_type = 0;
- if ((st->st_mode & S_IFMT) == S_IFREG &&
- archive_entry_filetype(entry) != AE_IFREG)
- mismatched_type = 1;
- if ((st->st_mode & S_IFMT) == S_IFLNK &&
- archive_entry_filetype(entry) != AE_IFLNK)
- mismatched_type = 1;
- if ((st->st_mode & S_IFSOCK) == S_IFSOCK &&
- archive_entry_filetype(entry) != AE_IFSOCK)
- mismatched_type = 1;
- if ((st->st_mode & S_IFMT) == S_IFCHR &&
- archive_entry_filetype(entry) != AE_IFCHR)
- mismatched_type = 1;
- if ((st->st_mode & S_IFMT) == S_IFBLK &&
- archive_entry_filetype(entry) != AE_IFBLK)
- mismatched_type = 1;
- if ((st->st_mode & S_IFMT) == S_IFDIR &&
- archive_entry_filetype(entry) != AE_IFDIR)
- mismatched_type = 1;
- if ((st->st_mode & S_IFMT) == S_IFIFO &&
- archive_entry_filetype(entry) != AE_IFIFO)
- mismatched_type = 1;
-
- if (mismatched_type) {
- if ((parsed_kws & MTREE_HAS_OPTIONAL) == 0) {
+ if (
+ ((st->st_mode & S_IFMT) == S_IFREG &&
+ archive_entry_filetype(entry) == AE_IFREG)
+#ifdef S_IFLNK
+ || ((st->st_mode & S_IFMT) == S_IFLNK &&
+ archive_entry_filetype(entry) == AE_IFLNK)
+#endif
+#ifdef S_IFSOCK
+ || ((st->st_mode & S_IFSOCK) == S_IFSOCK &&
+ archive_entry_filetype(entry) == AE_IFSOCK)
+#endif
+#ifdef S_IFCHR
+ || ((st->st_mode & S_IFMT) == S_IFCHR &&
+ archive_entry_filetype(entry) == AE_IFCHR)
+#endif
+#ifdef S_IFBLK
+ || ((st->st_mode & S_IFMT) == S_IFBLK &&
+ archive_entry_filetype(entry) == AE_IFBLK)
+#endif
+ || ((st->st_mode & S_IFMT) == S_IFDIR &&
+ archive_entry_filetype(entry) == AE_IFDIR)
+#ifdef S_IFIFO
+ || ((st->st_mode & S_IFMT) == S_IFIFO &&
+ archive_entry_filetype(entry) == AE_IFIFO)
+#endif
+ ) {
+ /* Types match. */
+ } else {
+ /* Types don't match; bail out gracefully. */
+ if (mtree->fd >= 0)
+ close(mtree->fd);
+ mtree->fd = -1;
+ if (parsed_kws & MTREE_HAS_OPTIONAL) {
+ /* It's not an error for an optional entry
+ to not match disk. */
+ *use_next = 1;
+ } else if (r == ARCHIVE_OK) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
"mtree specification has different type for %s",
archive_entry_pathname(entry));
r = ARCHIVE_WARN;
- } else {
- *use_next = 1;
}
- /* Don't hold a non-regular file open. */
- if (mtree->fd >= 0)
- close(mtree->fd);
- mtree->fd = -1;
- st = NULL;
return r;
}
}
@@ -735,7 +1160,7 @@ parse_line(struct archive_read *a, struct archive_entry *entry,
if (r1 < r)
r = r1;
}
- if ((*parsed_kws & MTREE_HAS_TYPE) == 0) {
+ if (r == ARCHIVE_OK && (*parsed_kws & MTREE_HAS_TYPE) == 0) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Missing type keyword in mtree specification");
return (ARCHIVE_WARN);
@@ -779,11 +1204,11 @@ parse_device(struct archive *a, struct archive_entry *entry, char *val)
*/
static int
parse_keyword(struct archive_read *a, struct mtree *mtree,
- struct archive_entry *entry, struct mtree_option *option, int *parsed_kws)
+ struct archive_entry *entry, struct mtree_option *opt, int *parsed_kws)
{
char *val, *key;
- key = option->value;
+ key = opt->value;
if (*key == '\0')
return (ARCHIVE_OK);
@@ -900,58 +1325,67 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
break;
}
if (strcmp(key, "time") == 0) {
- time_t m;
+ int64_t m;
+ int64_t my_time_t_max = get_time_t_max();
+ int64_t my_time_t_min = get_time_t_min();
long ns;
*parsed_kws |= MTREE_HAS_MTIME;
- m = (time_t)mtree_atol10(&val);
+ m = mtree_atol10(&val);
+ /* Replicate an old mtree bug:
+ * 123456789.1 represents 123456789
+ * seconds and 1 nanosecond. */
if (*val == '.') {
++val;
ns = (long)mtree_atol10(&val);
} else
ns = 0;
- archive_entry_set_mtime(entry, m, ns);
+ if (m > my_time_t_max)
+ m = my_time_t_max;
+ else if (m < my_time_t_min)
+ m = my_time_t_min;
+ archive_entry_set_mtime(entry, (time_t)m, ns);
break;
}
if (strcmp(key, "type") == 0) {
- *parsed_kws |= MTREE_HAS_TYPE;
switch (val[0]) {
case 'b':
if (strcmp(val, "block") == 0) {
- mtree->filetype = AE_IFBLK;
+ archive_entry_set_filetype(entry, AE_IFBLK);
break;
}
case 'c':
if (strcmp(val, "char") == 0) {
- mtree->filetype = AE_IFCHR;
+ archive_entry_set_filetype(entry, AE_IFCHR);
break;
}
case 'd':
if (strcmp(val, "dir") == 0) {
- mtree->filetype = AE_IFDIR;
+ archive_entry_set_filetype(entry, AE_IFDIR);
break;
}
case 'f':
if (strcmp(val, "fifo") == 0) {
- mtree->filetype = AE_IFIFO;
+ archive_entry_set_filetype(entry, AE_IFIFO);
break;
}
if (strcmp(val, "file") == 0) {
- mtree->filetype = AE_IFREG;
+ archive_entry_set_filetype(entry, AE_IFREG);
break;
}
case 'l':
if (strcmp(val, "link") == 0) {
- mtree->filetype = AE_IFLNK;
+ archive_entry_set_filetype(entry, AE_IFLNK);
break;
}
default:
archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
- "Unrecognized file type \"%s\"", val);
+ "Unrecognized file type \"%s\"; assuming \"file\"", val);
+ archive_entry_set_filetype(entry, AE_IFREG);
return (ARCHIVE_WARN);
}
- archive_entry_set_filetype(entry, mtree->filetype);
+ *parsed_kws |= MTREE_HAS_TYPE;
break;
}
case 'u':
@@ -974,7 +1408,7 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
}
static int
-read_data(struct archive_read *a, const void **buff, size_t *size, off_t *offset)
+read_data(struct archive_read *a, const void **buff, size_t *size, int64_t *offset)
{
size_t bytes_to_read;
ssize_t bytes_read;
@@ -999,7 +1433,7 @@ read_data(struct archive_read *a, const void **buff, size_t *size, off_t *offset
*buff = mtree->buff;
*offset = mtree->offset;
- if ((off_t)mtree->buffsize > mtree->cur_size - mtree->offset)
+ if ((int64_t)mtree->buffsize > mtree->cur_size - mtree->offset)
bytes_to_read = mtree->cur_size - mtree->offset;
else
bytes_to_read = mtree->buffsize;
@@ -1147,28 +1581,43 @@ mtree_atol10(char **p)
int base, digit, sign;
base = 10;
- limit = INT64_MAX / base;
- last_digit_limit = INT64_MAX % base;
if (**p == '-') {
sign = -1;
+ limit = ((uint64_t)(INT64_MAX) + 1) / base;
+ last_digit_limit = ((uint64_t)(INT64_MAX) + 1) % base;
++(*p);
- } else
+ } else {
sign = 1;
+ limit = INT64_MAX / base;
+ last_digit_limit = INT64_MAX % base;
+ }
l = 0;
digit = **p - '0';
while (digit >= 0 && digit < base) {
- if (l > limit || (l == limit && digit > last_digit_limit)) {
- l = INT64_MAX; /* Truncate on overflow. */
- break;
- }
+ if (l > limit || (l == limit && digit > last_digit_limit))
+ return (sign < 0) ? INT64_MIN : INT64_MAX;
l = (l * base) + digit;
digit = *++(*p) - '0';
}
return (sign < 0) ? -l : l;
}
+/* Parse a hex digit. */
+static int
+parsehex(char c)
+{
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ else if (c >= 'a' && c <= 'f')
+ return c - 'a';
+ else if (c >= 'A' && c <= 'F')
+ return c - 'A';
+ else
+ return -1;
+}
+
/*
* Note that this implementation does not (and should not!) obey
* locale settings; you cannot simply substitute strtol here, since
@@ -1181,38 +1630,25 @@ mtree_atol16(char **p)
int base, digit, sign;
base = 16;
- limit = INT64_MAX / base;
- last_digit_limit = INT64_MAX % base;
if (**p == '-') {
sign = -1;
+ limit = ((uint64_t)(INT64_MAX) + 1) / base;
+ last_digit_limit = ((uint64_t)(INT64_MAX) + 1) % base;
++(*p);
- } else
+ } else {
sign = 1;
+ limit = INT64_MAX / base;
+ last_digit_limit = INT64_MAX % base;
+ }
l = 0;
- if (**p >= '0' && **p <= '9')
- digit = **p - '0';
- else if (**p >= 'a' && **p <= 'f')
- digit = **p - 'a' + 10;
- else if (**p >= 'A' && **p <= 'F')
- digit = **p - 'A' + 10;
- else
- digit = -1;
+ digit = parsehex(**p);
while (digit >= 0 && digit < base) {
- if (l > limit || (l == limit && digit > last_digit_limit)) {
- l = INT64_MAX; /* Truncate on overflow. */
- break;
- }
+ if (l > limit || (l == limit && digit > last_digit_limit))
+ return (sign < 0) ? INT64_MIN : INT64_MAX;
l = (l * base) + digit;
- if (**p >= '0' && **p <= '9')
- digit = **p - '0';
- else if (**p >= 'a' && **p <= 'f')
- digit = **p - 'a' + 10;
- else if (**p >= 'A' && **p <= 'F')
- digit = **p - 'A' + 10;
- else
- digit = -1;
+ digit = parsehex(*++(*p));
}
return (sign < 0) ? -l : l;
}
OpenPOWER on IntegriCloud