summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--abs/core/libarchive/0001-Limit-write-requests-to-at-most-INT_MAX.patch32
-rw-r--r--abs/core/libarchive/PKGBUILD24
-rw-r--r--abs/core/libarchive/libarchive-3.1.2-sparce-mtree.patch478
3 files changed, 529 insertions, 5 deletions
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 <kientzle@acm.org>
+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 <bluewind@xinu.at>
+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 <bluewind@xinu.at>
+---
+ 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
+