|
@@ -51,6 +51,7 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_support_format_mtree.c 2011
|
|
|
|
|
|
|
|
#include "archive.h"
|
|
#include "archive.h"
|
|
|
#include "archive_entry.h"
|
|
#include "archive_entry.h"
|
|
|
|
|
+#include "archive_entry_private.h"
|
|
|
#include "archive_private.h"
|
|
#include "archive_private.h"
|
|
|
#include "archive_rb.h"
|
|
#include "archive_rb.h"
|
|
|
#include "archive_read_private.h"
|
|
#include "archive_read_private.h"
|
|
@@ -135,6 +136,9 @@ static int skip(struct archive_read *a);
|
|
|
static int read_header(struct archive_read *,
|
|
static int read_header(struct archive_read *,
|
|
|
struct archive_entry *);
|
|
struct archive_entry *);
|
|
|
static int64_t mtree_atol(char **, int base);
|
|
static int64_t mtree_atol(char **, int base);
|
|
|
|
|
+#ifndef HAVE_STRNLEN
|
|
|
|
|
+static size_t mtree_strnlen(const char *, size_t);
|
|
|
|
|
+#endif
|
|
|
|
|
|
|
|
/*
|
|
/*
|
|
|
* There's no standard for TIME_T_MAX/TIME_T_MIN. So we compute them
|
|
* There's no standard for TIME_T_MAX/TIME_T_MIN. So we compute them
|
|
@@ -186,6 +190,24 @@ get_time_t_min(void)
|
|
|
#endif
|
|
#endif
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+#ifdef HAVE_STRNLEN
|
|
|
|
|
+#define mtree_strnlen(a,b) strnlen(a,b)
|
|
|
|
|
+#else
|
|
|
|
|
+static size_t
|
|
|
|
|
+mtree_strnlen(const char *p, size_t maxlen)
|
|
|
|
|
+{
|
|
|
|
|
+ size_t i;
|
|
|
|
|
+
|
|
|
|
|
+ for (i = 0; i <= maxlen; i++) {
|
|
|
|
|
+ if (p[i] == 0)
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (i > maxlen)
|
|
|
|
|
+ return (-1);/* invalid */
|
|
|
|
|
+ return (i);
|
|
|
|
|
+}
|
|
|
|
|
+#endif
|
|
|
|
|
+
|
|
|
static int
|
|
static int
|
|
|
archive_read_format_mtree_options(struct archive_read *a,
|
|
archive_read_format_mtree_options(struct archive_read *a,
|
|
|
const char *key, const char *val)
|
|
const char *key, const char *val)
|
|
@@ -1482,6 +1504,84 @@ parse_device(dev_t *pdev, struct archive *a, char *val)
|
|
|
#undef MAX_PACK_ARGS
|
|
#undef MAX_PACK_ARGS
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+static int
|
|
|
|
|
+parse_hex_nibble(char c)
|
|
|
|
|
+{
|
|
|
|
|
+ if (c >= '0' && c <= '9')
|
|
|
|
|
+ return c - '0';
|
|
|
|
|
+ if (c >= 'a' && c <= 'f')
|
|
|
|
|
+ return 10 + c - 'a';
|
|
|
|
|
+#if 0
|
|
|
|
|
+ /* XXX: Is uppercase something we should support? */
|
|
|
|
|
+ if (c >= 'A' && c <= 'F')
|
|
|
|
|
+ return 10 + c - 'A';
|
|
|
|
|
+#endif
|
|
|
|
|
+
|
|
|
|
|
+ return -1;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int
|
|
|
|
|
+parse_digest(struct archive_read *a, struct archive_entry *entry,
|
|
|
|
|
+ const char *digest, int type)
|
|
|
|
|
+{
|
|
|
|
|
+ unsigned char digest_buf[64];
|
|
|
|
|
+ int high, low;
|
|
|
|
|
+ size_t i, j, len;
|
|
|
|
|
+
|
|
|
|
|
+ switch (type) {
|
|
|
|
|
+ case ARCHIVE_ENTRY_DIGEST_MD5:
|
|
|
|
|
+ len = sizeof(entry->digest.md5);
|
|
|
|
|
+ break;
|
|
|
|
|
+ case ARCHIVE_ENTRY_DIGEST_RMD160:
|
|
|
|
|
+ len = sizeof(entry->digest.rmd160);
|
|
|
|
|
+ break;
|
|
|
|
|
+ case ARCHIVE_ENTRY_DIGEST_SHA1:
|
|
|
|
|
+ len = sizeof(entry->digest.sha1);
|
|
|
|
|
+ break;
|
|
|
|
|
+ case ARCHIVE_ENTRY_DIGEST_SHA256:
|
|
|
|
|
+ len = sizeof(entry->digest.sha256);
|
|
|
|
|
+ break;
|
|
|
|
|
+ case ARCHIVE_ENTRY_DIGEST_SHA384:
|
|
|
|
|
+ len = sizeof(entry->digest.sha384);
|
|
|
|
|
+ break;
|
|
|
|
|
+ case ARCHIVE_ENTRY_DIGEST_SHA512:
|
|
|
|
|
+ len = sizeof(entry->digest.sha512);
|
|
|
|
|
+ break;
|
|
|
|
|
+ default:
|
|
|
|
|
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
|
|
|
|
|
+ "Internal error: Unknown digest type");
|
|
|
|
|
+ return ARCHIVE_FATAL;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (len > sizeof(digest_buf)) {
|
|
|
|
|
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
|
|
|
|
|
+ "Internal error: Digest storage too large");
|
|
|
|
|
+ return ARCHIVE_FATAL;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ len *= 2;
|
|
|
|
|
+
|
|
|
|
|
+ if (mtree_strnlen(digest, len+1) != len) {
|
|
|
|
|
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
|
|
|
|
+ "incorrect digest length, ignoring");
|
|
|
|
|
+ return ARCHIVE_WARN;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ for (i = 0, j = 0; i < len; i += 2, j++) {
|
|
|
|
|
+ high = parse_hex_nibble(digest[i]);
|
|
|
|
|
+ low = parse_hex_nibble(digest[i+1]);
|
|
|
|
|
+ if (high == -1 || low == -1) {
|
|
|
|
|
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
|
|
|
|
+ "invalid digest data, ignoring");
|
|
|
|
|
+ return ARCHIVE_WARN;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ digest_buf[j] = high << 4 | low;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return archive_entry_set_digest(entry, type, digest_buf);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
/*
|
|
/*
|
|
|
* Parse a single keyword and its value.
|
|
* Parse a single keyword and its value.
|
|
|
*/
|
|
*/
|
|
@@ -1580,8 +1680,10 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
|
|
|
}
|
|
}
|
|
|
__LA_FALLTHROUGH;
|
|
__LA_FALLTHROUGH;
|
|
|
case 'm':
|
|
case 'm':
|
|
|
- if (strcmp(key, "md5") == 0 || strcmp(key, "md5digest") == 0)
|
|
|
|
|
- break;
|
|
|
|
|
|
|
+ if (strcmp(key, "md5") == 0 || strcmp(key, "md5digest") == 0) {
|
|
|
|
|
+ return parse_digest(a, entry, val,
|
|
|
|
|
+ ARCHIVE_ENTRY_DIGEST_MD5);
|
|
|
|
|
+ }
|
|
|
if (strcmp(key, "mode") == 0) {
|
|
if (strcmp(key, "mode") == 0) {
|
|
|
if (val[0] >= '0' && val[0] <= '7') {
|
|
if (val[0] >= '0' && val[0] <= '7') {
|
|
|
*parsed_kws |= MTREE_HAS_PERM;
|
|
*parsed_kws |= MTREE_HAS_PERM;
|
|
@@ -1617,21 +1719,32 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
|
|
|
return r;
|
|
return r;
|
|
|
}
|
|
}
|
|
|
if (strcmp(key, "rmd160") == 0 ||
|
|
if (strcmp(key, "rmd160") == 0 ||
|
|
|
- strcmp(key, "rmd160digest") == 0)
|
|
|
|
|
- break;
|
|
|
|
|
|
|
+ strcmp(key, "rmd160digest") == 0) {
|
|
|
|
|
+ return parse_digest(a, entry, val,
|
|
|
|
|
+ ARCHIVE_ENTRY_DIGEST_RMD160);
|
|
|
|
|
+ }
|
|
|
__LA_FALLTHROUGH;
|
|
__LA_FALLTHROUGH;
|
|
|
case 's':
|
|
case 's':
|
|
|
- if (strcmp(key, "sha1") == 0 || strcmp(key, "sha1digest") == 0)
|
|
|
|
|
- break;
|
|
|
|
|
|
|
+ if (strcmp(key, "sha1") == 0 ||
|
|
|
|
|
+ strcmp(key, "sha1digest") == 0) {
|
|
|
|
|
+ return parse_digest(a, entry, val,
|
|
|
|
|
+ ARCHIVE_ENTRY_DIGEST_SHA1);
|
|
|
|
|
+ }
|
|
|
if (strcmp(key, "sha256") == 0 ||
|
|
if (strcmp(key, "sha256") == 0 ||
|
|
|
- strcmp(key, "sha256digest") == 0)
|
|
|
|
|
- break;
|
|
|
|
|
|
|
+ strcmp(key, "sha256digest") == 0) {
|
|
|
|
|
+ return parse_digest(a, entry, val,
|
|
|
|
|
+ ARCHIVE_ENTRY_DIGEST_SHA256);
|
|
|
|
|
+ }
|
|
|
if (strcmp(key, "sha384") == 0 ||
|
|
if (strcmp(key, "sha384") == 0 ||
|
|
|
- strcmp(key, "sha384digest") == 0)
|
|
|
|
|
- break;
|
|
|
|
|
|
|
+ strcmp(key, "sha384digest") == 0) {
|
|
|
|
|
+ return parse_digest(a, entry, val,
|
|
|
|
|
+ ARCHIVE_ENTRY_DIGEST_SHA384);
|
|
|
|
|
+ }
|
|
|
if (strcmp(key, "sha512") == 0 ||
|
|
if (strcmp(key, "sha512") == 0 ||
|
|
|
- strcmp(key, "sha512digest") == 0)
|
|
|
|
|
- break;
|
|
|
|
|
|
|
+ strcmp(key, "sha512digest") == 0) {
|
|
|
|
|
+ return parse_digest(a, entry, val,
|
|
|
|
|
+ ARCHIVE_ENTRY_DIGEST_SHA512);
|
|
|
|
|
+ }
|
|
|
if (strcmp(key, "size") == 0) {
|
|
if (strcmp(key, "size") == 0) {
|
|
|
archive_entry_set_size(entry, mtree_atol(&val, 10));
|
|
archive_entry_set_size(entry, mtree_atol(&val, 10));
|
|
|
break;
|
|
break;
|