From fd5586a4154475548d79b9ce171bf52ec86eb546 Mon Sep 17 00:00:00 2001 From: Britney Fransen Date: Tue, 2 Dec 2014 22:40:06 +0000 Subject: libarchive: update to 3.1.2-8 --- ...1-Limit-write-requests-to-at-most-INT_MAX.patch | 32 ++ abs/core/libarchive/PKGBUILD | 24 +- .../libarchive/libarchive-3.1.2-sparce-mtree.patch | 478 +++++++++++++++++++++ 3 files changed, 529 insertions(+), 5 deletions(-) create mode 100644 abs/core/libarchive/0001-Limit-write-requests-to-at-most-INT_MAX.patch create mode 100644 abs/core/libarchive/libarchive-3.1.2-sparce-mtree.patch diff --git a/abs/core/libarchive/0001-Limit-write-requests-to-at-most-INT_MAX.patch b/abs/core/libarchive/0001-Limit-write-requests-to-at-most-INT_MAX.patch new file mode 100644 index 0000000..c805ce1 --- /dev/null +++ b/abs/core/libarchive/0001-Limit-write-requests-to-at-most-INT_MAX.patch @@ -0,0 +1,32 @@ +From 22531545514043e04633e1c015c7540b9de9dbe4 Mon Sep 17 00:00:00 2001 +From: Tim Kientzle +Date: Fri, 22 Mar 2013 23:48:41 -0700 +Subject: [PATCH] Limit write requests to at most INT_MAX. This prevents a + certain common programming error (passing -1 to write) from leading to other + problems deeper in the library. + +--- + libarchive/archive_write.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/libarchive/archive_write.c b/libarchive/archive_write.c +index eede5e0..be85621 100644 +--- a/libarchive/archive_write.c ++++ b/libarchive/archive_write.c +@@ -673,8 +673,13 @@ static ssize_t + _archive_write_data(struct archive *_a, const void *buff, size_t s) + { + struct archive_write *a = (struct archive_write *)_a; ++ const size_t max_write = INT_MAX; ++ + archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC, + ARCHIVE_STATE_DATA, "archive_write_data"); ++ /* In particular, this catches attempts to pass negative values. */ ++ if (s > max_write) ++ s = max_write; + archive_clear_error(&a->archive); + return ((a->format_write_data)(a, buff, s)); + } +-- +1.9.0 + diff --git a/abs/core/libarchive/PKGBUILD b/abs/core/libarchive/PKGBUILD index 182ea71..3b1540f 100644 --- a/abs/core/libarchive/PKGBUILD +++ b/abs/core/libarchive/PKGBUILD @@ -3,21 +3,26 @@ pkgname=libarchive pkgver=3.1.2 -pkgrel=3 +pkgrel=8 pkgdesc="library that can create and read several streaming archive formats" arch=('i686' 'x86_64') url="http://libarchive.org/" license=('BSD') -depends=('acl' 'attr' 'bzip2' 'expat' 'lzo2' 'openssl' 'xz' 'zlib' 'nettle') +depends=('acl' 'attr' 'bzip2' 'expat' 'lzo' 'nettle' 'openssl' 'xz' 'zlib') +options=('strip' 'debug' 'libtool') provides=('libarchive.so') source=("http://libarchive.org/downloads/$pkgname-$pkgver.tar.gz" '0001-mtree-fix-line-filename-length-calculation.patch' - 'libarchive-3.1.2-acl.patch') + '0001-Limit-write-requests-to-at-most-INT_MAX.patch' + 'libarchive-3.1.2-acl.patch' + 'libarchive-3.1.2-sparce-mtree.patch') md5sums=('efad5a503f66329bb9d2f4308b5de98a' 'fda89c145bbcd793a96b06b463ef6a72' - 'a5c995661c62429ceff2c23ea322393b') + '9bf80940bd3ce861137a0a8dcacf5705' + 'a5c995661c62429ceff2c23ea322393b' + 'cb344a879b3c4550fe3faf86c3826f23') -build() { +prepare() { cd "$pkgname-$pkgver" # https://code.google.com/p/libarchive/issues/detail?id=301 @@ -27,6 +32,15 @@ build() { # https://code.google.com/p/libarchive/issues/detail?id=329 patch -Np1 -i "$srcdir/libarchive-3.1.2-acl.patch" + # CVE-2013-0211 + patch -Np1 -i "$srcdir/0001-Limit-write-requests-to-at-most-INT_MAX.patch" + + # upstream commit 977bf2a4 - improved mtree support + patch -p1 -i $srcdir/libarchive-3.1.2-sparce-mtree.patch +} + +build() { + cd "$pkgname-$pkgver" ./configure --prefix=/usr --without-xml2 make } diff --git a/abs/core/libarchive/libarchive-3.1.2-sparce-mtree.patch b/abs/core/libarchive/libarchive-3.1.2-sparce-mtree.patch new file mode 100644 index 0000000..7b40277 --- /dev/null +++ b/abs/core/libarchive/libarchive-3.1.2-sparce-mtree.patch @@ -0,0 +1,478 @@ +From 977bf2a49484239f7a7b6ce08bfa9da413a27ead Mon Sep 17 00:00:00 2001 +From: Florian Pritz +Date: Sat, 1 Mar 2014 17:21:47 +0100 +Subject: [PATCH] mtree: Make reading additional information from the fs + optional + +This feature is not needed if users just want to read in the content of +an mtree file and do validation against the file system themselves. + +It is needed for `bsdtar cvf out.tar @input.mtree` which is why the +option is enabled in bsdtar. + +Since the mtree tests rely on this feature, this patch also enables it +there. + +Signed-off-by: Florian Pritz +--- + libarchive/archive_read_support_format_mtree.c | 290 ++++++++++++++----------- + libarchive/test/test_read_format_mtree.c | 20 ++ + tar/write.c | 1 + + 3 files changed, 179 insertions(+), 132 deletions(-) + +diff --git a/libarchive/archive_read_support_format_mtree.c b/libarchive/archive_read_support_format_mtree.c +index 44799df..d82d4c1 100644 +--- a/libarchive/archive_read_support_format_mtree.c ++++ b/libarchive/archive_read_support_format_mtree.c +@@ -104,6 +104,7 @@ struct mtree { + struct archive_entry_linkresolver *resolver; + + int64_t cur_size; ++ char checkfs; + }; + + static int bid_keycmp(const char *, const char *, ssize_t); +@@ -174,6 +175,29 @@ static int read_header(struct archive_read *, + #endif + } + ++static int ++archive_read_format_mtree_options(struct archive_read *a, ++ const char *key, const char *val) ++{ ++ struct mtree *mtree; ++ ++ mtree = (struct mtree *)(a->format->data); ++ if (strcmp(key, "checkfs") == 0) { ++ /* Allows to read information missing from the mtree from the file system */ ++ if (val == NULL || val[0] == 0) { ++ mtree->checkfs = 0; ++ } else { ++ mtree->checkfs = 1; ++ } ++ return (ARCHIVE_OK); ++ } ++ ++ /* Note: The "warn" return is just to inform the options ++ * supervisor that we didn't handle it. It will generate ++ * a suitable error if no one used this option. */ ++ return (ARCHIVE_WARN); ++} ++ + static void + free_options(struct mtree_option *head) + { +@@ -206,7 +230,7 @@ static int read_header(struct archive_read *, + mtree->fd = -1; + + r = __archive_read_register_format(a, mtree, "mtree", +- mtree_bid, NULL, read_header, read_data, skip, NULL, cleanup); ++ mtree_bid, archive_read_format_mtree_options, read_header, read_data, skip, NULL, cleanup); + + if (r != ARCHIVE_OK) + free(mtree); +@@ -1104,162 +1128,164 @@ static int read_header(struct archive_read *, + mtree->current_dir.length = n; + } + +- /* +- * Try to open and stat the file to get the real size +- * and other file info. It would be nice to avoid +- * this here so that getting a listing of an mtree +- * wouldn't require opening every referenced contents +- * file. But then we wouldn't know the actual +- * contents size, so I don't see a really viable way +- * around this. (Also, we may want to someday pull +- * other unspecified info from the contents file on +- * disk.) +- */ +- mtree->fd = -1; +- if (archive_strlen(&mtree->contents_name) > 0) +- path = mtree->contents_name.s; +- else +- path = archive_entry_pathname(entry); +- +- if (archive_entry_filetype(entry) == AE_IFREG || +- archive_entry_filetype(entry) == AE_IFDIR) { +- mtree->fd = open(path, O_RDONLY | O_BINARY | O_CLOEXEC); +- __archive_ensure_cloexec_flag(mtree->fd); +- if (mtree->fd == -1 && +- (errno != ENOENT || +- archive_strlen(&mtree->contents_name) > 0)) { +- archive_set_error(&a->archive, errno, +- "Can't open %s", path); +- r = ARCHIVE_WARN; ++ if (mtree->checkfs) { ++ /* ++ * Try to open and stat the file to get the real size ++ * and other file info. It would be nice to avoid ++ * this here so that getting a listing of an mtree ++ * wouldn't require opening every referenced contents ++ * file. But then we wouldn't know the actual ++ * contents size, so I don't see a really viable way ++ * around this. (Also, we may want to someday pull ++ * other unspecified info from the contents file on ++ * disk.) ++ */ ++ mtree->fd = -1; ++ if (archive_strlen(&mtree->contents_name) > 0) ++ path = mtree->contents_name.s; ++ else ++ path = archive_entry_pathname(entry); ++ ++ if (archive_entry_filetype(entry) == AE_IFREG || ++ archive_entry_filetype(entry) == AE_IFDIR) { ++ mtree->fd = open(path, O_RDONLY | O_BINARY | O_CLOEXEC); ++ __archive_ensure_cloexec_flag(mtree->fd); ++ if (mtree->fd == -1 && ++ (errno != ENOENT || ++ archive_strlen(&mtree->contents_name) > 0)) { ++ archive_set_error(&a->archive, errno, ++ "Can't open %s", path); ++ r = ARCHIVE_WARN; ++ } + } +- } + +- st = &st_storage; +- if (mtree->fd >= 0) { +- if (fstat(mtree->fd, st) == -1) { +- archive_set_error(&a->archive, errno, +- "Could not fstat %s", path); +- r = ARCHIVE_WARN; +- /* If we can't stat it, don't keep it open. */ +- close(mtree->fd); +- mtree->fd = -1; ++ st = &st_storage; ++ if (mtree->fd >= 0) { ++ if (fstat(mtree->fd, st) == -1) { ++ archive_set_error(&a->archive, errno, ++ "Could not fstat %s", path); ++ r = ARCHIVE_WARN; ++ /* If we can't stat it, don't keep it open. */ ++ close(mtree->fd); ++ mtree->fd = -1; ++ st = NULL; ++ } ++ } else if (lstat(path, st) == -1) { + st = NULL; + } +- } else if (lstat(path, st) == -1) { +- st = NULL; +- } + +- /* +- * Check for a mismatch between the type in the specification and +- * the type of the contents object on disk. +- */ +- if (st != NULL) { +- if ( +- ((st->st_mode & S_IFMT) == S_IFREG && +- archive_entry_filetype(entry) == AE_IFREG) ++ /* ++ * Check for a mismatch between the type in the specification and ++ * the type of the contents object on disk. ++ */ ++ if (st != NULL) { ++ 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) ++ || ((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) ++ || ((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) ++ || ((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) ++ || ((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) ++ || ((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) ++ || ((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; +- } +- return r; ++ ) { ++ /* 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; ++ } ++ return r; ++ } + } +- } + +- /* +- * If there is a contents file on disk, pick some of the metadata +- * from that file. For most of these, we only set it from the contents +- * if it wasn't already parsed from the specification. +- */ +- if (st != NULL) { +- if (((parsed_kws & MTREE_HAS_DEVICE) == 0 || +- (parsed_kws & MTREE_HAS_NOCHANGE) != 0) && +- (archive_entry_filetype(entry) == AE_IFCHR || +- archive_entry_filetype(entry) == AE_IFBLK)) +- archive_entry_set_rdev(entry, st->st_rdev); +- if ((parsed_kws & (MTREE_HAS_GID | MTREE_HAS_GNAME)) == 0 || +- (parsed_kws & MTREE_HAS_NOCHANGE) != 0) +- archive_entry_set_gid(entry, st->st_gid); +- if ((parsed_kws & (MTREE_HAS_UID | MTREE_HAS_UNAME)) == 0 || +- (parsed_kws & MTREE_HAS_NOCHANGE) != 0) +- archive_entry_set_uid(entry, st->st_uid); +- if ((parsed_kws & MTREE_HAS_MTIME) == 0 || +- (parsed_kws & MTREE_HAS_NOCHANGE) != 0) { ++ /* ++ * If there is a contents file on disk, pick some of the metadata ++ * from that file. For most of these, we only set it from the contents ++ * if it wasn't already parsed from the specification. ++ */ ++ if (st != NULL) { ++ if (((parsed_kws & MTREE_HAS_DEVICE) == 0 || ++ (parsed_kws & MTREE_HAS_NOCHANGE) != 0) && ++ (archive_entry_filetype(entry) == AE_IFCHR || ++ archive_entry_filetype(entry) == AE_IFBLK)) ++ archive_entry_set_rdev(entry, st->st_rdev); ++ if ((parsed_kws & (MTREE_HAS_GID | MTREE_HAS_GNAME)) == 0 || ++ (parsed_kws & MTREE_HAS_NOCHANGE) != 0) ++ archive_entry_set_gid(entry, st->st_gid); ++ if ((parsed_kws & (MTREE_HAS_UID | MTREE_HAS_UNAME)) == 0 || ++ (parsed_kws & MTREE_HAS_NOCHANGE) != 0) ++ archive_entry_set_uid(entry, st->st_uid); ++ if ((parsed_kws & MTREE_HAS_MTIME) == 0 || ++ (parsed_kws & MTREE_HAS_NOCHANGE) != 0) { + #if HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC +- archive_entry_set_mtime(entry, st->st_mtime, +- st->st_mtimespec.tv_nsec); ++ archive_entry_set_mtime(entry, st->st_mtime, ++ st->st_mtimespec.tv_nsec); + #elif HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC +- archive_entry_set_mtime(entry, st->st_mtime, +- st->st_mtim.tv_nsec); ++ archive_entry_set_mtime(entry, st->st_mtime, ++ st->st_mtim.tv_nsec); + #elif HAVE_STRUCT_STAT_ST_MTIME_N +- archive_entry_set_mtime(entry, st->st_mtime, +- st->st_mtime_n); ++ archive_entry_set_mtime(entry, st->st_mtime, ++ st->st_mtime_n); + #elif HAVE_STRUCT_STAT_ST_UMTIME +- archive_entry_set_mtime(entry, st->st_mtime, +- st->st_umtime*1000); ++ archive_entry_set_mtime(entry, st->st_mtime, ++ st->st_umtime*1000); + #elif HAVE_STRUCT_STAT_ST_MTIME_USEC +- archive_entry_set_mtime(entry, st->st_mtime, +- st->st_mtime_usec*1000); ++ archive_entry_set_mtime(entry, st->st_mtime, ++ st->st_mtime_usec*1000); + #else +- archive_entry_set_mtime(entry, st->st_mtime, 0); ++ archive_entry_set_mtime(entry, st->st_mtime, 0); + #endif ++ } ++ if ((parsed_kws & MTREE_HAS_NLINK) == 0 || ++ (parsed_kws & MTREE_HAS_NOCHANGE) != 0) ++ archive_entry_set_nlink(entry, st->st_nlink); ++ if ((parsed_kws & MTREE_HAS_PERM) == 0 || ++ (parsed_kws & MTREE_HAS_NOCHANGE) != 0) ++ archive_entry_set_perm(entry, st->st_mode); ++ if ((parsed_kws & MTREE_HAS_SIZE) == 0 || ++ (parsed_kws & MTREE_HAS_NOCHANGE) != 0) ++ archive_entry_set_size(entry, st->st_size); ++ archive_entry_set_ino(entry, st->st_ino); ++ archive_entry_set_dev(entry, st->st_dev); ++ ++ archive_entry_linkify(mtree->resolver, &entry, &sparse_entry); ++ } else if (parsed_kws & MTREE_HAS_OPTIONAL) { ++ /* ++ * Couldn't open the entry, stat it or the on-disk type ++ * didn't match. If this entry is optional, just ignore it ++ * and read the next header entry. ++ */ ++ *use_next = 1; ++ return ARCHIVE_OK; + } +- if ((parsed_kws & MTREE_HAS_NLINK) == 0 || +- (parsed_kws & MTREE_HAS_NOCHANGE) != 0) +- archive_entry_set_nlink(entry, st->st_nlink); +- if ((parsed_kws & MTREE_HAS_PERM) == 0 || +- (parsed_kws & MTREE_HAS_NOCHANGE) != 0) +- archive_entry_set_perm(entry, st->st_mode); +- if ((parsed_kws & MTREE_HAS_SIZE) == 0 || +- (parsed_kws & MTREE_HAS_NOCHANGE) != 0) +- archive_entry_set_size(entry, st->st_size); +- archive_entry_set_ino(entry, st->st_ino); +- archive_entry_set_dev(entry, st->st_dev); +- +- archive_entry_linkify(mtree->resolver, &entry, &sparse_entry); +- } else if (parsed_kws & MTREE_HAS_OPTIONAL) { +- /* +- * Couldn't open the entry, stat it or the on-disk type +- * didn't match. If this entry is optional, just ignore it +- * and read the next header entry. +- */ +- *use_next = 1; +- return ARCHIVE_OK; + } + + mtree->cur_size = archive_entry_size(entry); +diff --git a/libarchive/test/test_read_format_mtree.c b/libarchive/test/test_read_format_mtree.c +index 830fa0a..f96529d 100644 +--- a/libarchive/test/test_read_format_mtree.c ++++ b/libarchive/test/test_read_format_mtree.c +@@ -58,6 +58,8 @@ + assertEqualIntA(a, ARCHIVE_OK, + archive_read_support_format_all(a)); + assertEqualIntA(a, ARCHIVE_OK, ++ archive_read_set_options(a, "mtree:checkfs")); ++ assertEqualIntA(a, ARCHIVE_OK, + archive_read_open_filename(a, reffile, 11)); + + /* +@@ -209,6 +211,8 @@ + assertEqualIntA(a, ARCHIVE_OK, + archive_read_support_format_all(a)); + assertEqualIntA(a, ARCHIVE_OK, ++ archive_read_set_options(a, "mtree:checkfs")); ++ assertEqualIntA(a, ARCHIVE_OK, + archive_read_open_memory(a, archive, sizeof(archive))); + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); + assertEqualInt(archive_format(a), ARCHIVE_FORMAT_MTREE); +@@ -246,6 +250,8 @@ + assertEqualIntA(a, ARCHIVE_OK, + archive_read_support_format_all(a)); + assertEqualIntA(a, ARCHIVE_OK, ++ archive_read_set_options(a, "mtree:checkfs")); ++ assertEqualIntA(a, ARCHIVE_OK, + archive_read_open_memory(a, archive, sizeof(archive))); + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); + assertEqualString(archive_entry_pathname(ae), "a"); +@@ -299,6 +305,8 @@ + assertEqualIntA(a, ARCHIVE_OK, + archive_read_support_format_all(a)); + assertEqualIntA(a, ARCHIVE_OK, ++ archive_read_set_options(a, "mtree:checkfs")); ++ assertEqualIntA(a, ARCHIVE_OK, + archive_read_open_memory(a, archive, sizeof(archive))); + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); + assertEqualString(archive_entry_pathname(ae), "./a"); +@@ -365,6 +373,8 @@ + assertEqualIntA(a, ARCHIVE_OK, + archive_read_support_format_all(a)); + assertEqualIntA(a, ARCHIVE_OK, ++ archive_read_set_options(a, "mtree:checkfs")); ++ assertEqualIntA(a, ARCHIVE_OK, + archive_read_open_memory(a, archive, sizeof(archive))); + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); + assertEqualString(archive_entry_pathname(ae), "./a"); +@@ -402,6 +412,8 @@ + assertEqualIntA(a, ARCHIVE_OK, + archive_read_support_format_all(a)); + assertEqualIntA(a, ARCHIVE_OK, ++ archive_read_set_options(a, "mtree:checkfs")); ++ assertEqualIntA(a, ARCHIVE_OK, + archive_read_open_memory(a, archive2, sizeof(archive2))); + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); + assertEqualString(archive_entry_pathname(ae), "./a"); +@@ -449,6 +461,8 @@ + assertEqualIntA(a, ARCHIVE_OK, + archive_read_support_format_all(a)); + assertEqualIntA(a, ARCHIVE_OK, ++ archive_read_set_options(a, "mtree:checkfs")); ++ assertEqualIntA(a, ARCHIVE_OK, + archive_read_open_filename(a, reffile, 11)); + + /* +@@ -552,6 +566,8 @@ + assertEqualIntA(a, ARCHIVE_OK, + archive_read_support_format_all(a)); + assertEqualIntA(a, ARCHIVE_OK, ++ archive_read_set_options(a, "mtree:checkfs")); ++ assertEqualIntA(a, ARCHIVE_OK, + archive_read_open_filename(a, reffile, 11)); + + /* +@@ -617,6 +633,8 @@ + assertEqualIntA(a, ARCHIVE_OK, + archive_read_support_format_all(a)); + assertEqualIntA(a, ARCHIVE_OK, ++ archive_read_set_options(a, "mtree:checkfs")); ++ assertEqualIntA(a, ARCHIVE_OK, + archive_read_open_filename(a, reffile, 11)); + + /* +@@ -680,6 +698,8 @@ + assertEqualIntA(a, ARCHIVE_OK, + archive_read_support_format_all(a)); + assertEqualIntA(a, ARCHIVE_OK, ++ archive_read_set_options(a, "mtree:checkfs")); ++ assertEqualIntA(a, ARCHIVE_OK, + archive_read_open_memory(a, archive, sizeof(archive))); + assertEqualIntA(a, ARCHIVE_WARN, archive_read_next_header(a, &ae)); + assert(strlen(archive_error_string(a)) > 0); +diff --git a/tar/write.c b/tar/write.c +index 40d2fb0..7e8cb13 100644 +--- a/tar/write.c ++++ b/tar/write.c +@@ -648,6 +648,7 @@ static void write_hierarchy(struct bsdtar *, struct archive *, + archive_read_support_format_all(ina); + archive_read_support_filter_all(ina); + set_reader_options(bsdtar, a); ++ archive_read_set_options(ina, "mtree:checkfs"); + if (archive_read_open_filename(ina, filename, + bsdtar->bytes_per_block)) { + lafe_warnc(0, "%s", archive_error_string(ina)); +-- +1.8.5.5 + -- cgit v0.12