]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Ignore ustar size when pax size is present (#2405)
authorTim Kientzle <kientzle@acm.org>
Wed, 6 Nov 2024 21:21:54 +0000 (13:21 -0800)
committerGitHub <noreply@github.com>
Wed, 6 Nov 2024 21:21:54 +0000 (22:21 +0100)
When the pax `size` field is present, we should ignore the size value in
the ustar header. In particular, this fixes reading pax archives created
by GNU tar with entries larger than 8GB.

Note: This doesn't impact reading pax archives created by libarchive
because libarchive uses tar extensions to store an accurate large size
field in the ustar header. GNU tar instead strictly follows ustar in
this case, which prevents it from storing accurate sizes in the ustar
header.

Resolves #2404

Makefile.am
libarchive/archive_read_support_format_tar.c
libarchive/test/CMakeLists.txt
libarchive/test/test_compat_gtar_large.c [new file with mode: 0644]

index 8f175f68fb8b17ad725a0b5dd75c2da8713bea07..46a3c0e7f0d84f1183c1090df6aa8002d2c339bc 100644 (file)
@@ -411,6 +411,7 @@ libarchive_test_SOURCES= \
        libarchive/test/test_compat_bzip2.c \
        libarchive/test/test_compat_cpio.c \
        libarchive/test/test_compat_gtar.c \
+       libarchive/test/test_compat_gtar_large.c \
        libarchive/test/test_compat_gzip.c \
        libarchive/test/test_compat_lz4.c \
        libarchive/test/test_compat_lzip.c \
index ecaf6c392d9a2ecd81e2858d159233003eb3b329..14c157345fa47eb96728831594912fd4bca98ef1 100644 (file)
@@ -750,7 +750,7 @@ tar_read_header(struct archive_read *a, struct tar *tar,
                                         * if there's no regular header, then this is
                                         * a premature EOF. */
                                        archive_set_error(&a->archive, EINVAL,
-                                                         "Damaged tar archive");
+                                                         "Damaged tar archive (end-of-archive within a sequence of headers)");
                                        return (ARCHIVE_FATAL);
                                } else {
                                        return (ARCHIVE_EOF);
@@ -787,7 +787,8 @@ tar_read_header(struct archive_read *a, struct tar *tar,
                        /* This is NOT a null block, so it must be a valid header. */
                        if (!checksum(a, h)) {
                                tar_flush_unconsumed(a, unconsumed);
-                               archive_set_error(&a->archive, EINVAL, "Damaged tar archive");
+                               archive_set_error(&a->archive, EINVAL,
+                                                 "Damaged tar archive (bad header checksum)");
                                /* If we've read some critical information (pax headers, etc)
                                 * and _then_ see a bad header, we can't really recover. */
                                if (eof_fatal) {
@@ -1308,35 +1309,42 @@ header_common(struct archive_read *a, struct tar *tar,
                archive_entry_set_perm(entry,
                        (mode_t)tar_atol(header->mode, sizeof(header->mode)));
        }
+
+       /* Set uid, gid, mtime if not already set */
        if (!archive_entry_uid_is_set(entry)) {
                archive_entry_set_uid(entry, tar_atol(header->uid, sizeof(header->uid)));
        }
        if (!archive_entry_gid_is_set(entry)) {
                archive_entry_set_gid(entry, tar_atol(header->gid, sizeof(header->gid)));
        }
-
-       tar->entry_bytes_remaining = tar_atol(header->size, sizeof(header->size));
-       if (tar->entry_bytes_remaining < 0) {
-               tar->entry_bytes_remaining = 0;
-               archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-                   "Tar entry has negative size");
-               return (ARCHIVE_FATAL);
-       }
-       if (tar->entry_bytes_remaining > entry_limit) {
-               tar->entry_bytes_remaining = 0;
-               archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-                   "Tar entry size overflow");
-               return (ARCHIVE_FATAL);
-       }
-       if (!tar->realsize_override) {
-               tar->realsize = tar->entry_bytes_remaining;
-       }
-       archive_entry_set_size(entry, tar->realsize);
-
        if (!archive_entry_mtime_is_set(entry)) {
                archive_entry_set_mtime(entry, tar_atol(header->mtime, sizeof(header->mtime)), 0);
        }
 
+       /* Update size information as appropriate */
+       if (!archive_entry_size_is_set(entry)) {
+               tar->entry_bytes_remaining = tar_atol(header->size, sizeof(header->size));
+               if (tar->entry_bytes_remaining < 0) {
+                       tar->entry_bytes_remaining = 0;
+                       archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+                                         "Tar entry has negative size");
+                       return (ARCHIVE_FATAL);
+               }
+               if (tar->entry_bytes_remaining > entry_limit) {
+                       tar->entry_bytes_remaining = 0;
+                       archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+                                         "Tar entry size overflow");
+                       return (ARCHIVE_FATAL);
+               }
+               if (!tar->realsize_override) {
+                       tar->realsize = tar->entry_bytes_remaining;
+               }
+               archive_entry_set_size(entry, tar->realsize);
+       } else if (tar->realsize_override) {
+               tar->entry_bytes_remaining = tar->realsize;
+               archive_entry_set_size(entry, tar->realsize);
+       }
+
        /* Handle the tar type flag appropriately. */
        tar->filetype = header->typeflag[0];
 
index e11f1a147a30b51f8c1e43116a88fcef14fe6bf9..c8133e65ff04803105a217e0e96ac9ab741629d4 100644 (file)
@@ -55,6 +55,7 @@ IF(ENABLE_TEST)
     test_compat_bzip2.c
     test_compat_cpio.c
     test_compat_gtar.c
+    test_compat_gtar_large.c
     test_compat_gzip.c
     test_compat_lz4.c
     test_compat_lzip.c
diff --git a/libarchive/test/test_compat_gtar_large.c b/libarchive/test/test_compat_gtar_large.c
new file mode 100644 (file)
index 0000000..633b20c
--- /dev/null
@@ -0,0 +1,224 @@
+/*-
+ * Copyright (c) 2003-2024 Tim Kientzle
+ * 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"
+
+/*
+ * Verify reading a GNU tar pax format archive with >8GB entry.
+ *
+ * Sample data created with GNU tar 1.35:
+ * $ dd if=/dev/zero of=test.bin bs=1048576 count=8192
+ * $ gnutar --format=posix -cvf test.tar test.bin
+ * $ hexdump -C -v test.tar | head -n 96
+ */
+
+static const unsigned char test_compat_gtar_large_data[] = {
+  /* 00000000 */   0x2e, 0x2f, 0x50, 0x61, 0x78, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2f, 0x74, 0x65, 0x73,  /* |./PaxHeaders/tes| */
+  /* 00000010 */   0x74, 0x2e, 0x62, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |t.bin...........| */
+  /* 00000020 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 00000030 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 00000040 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 00000050 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 00000060 */   0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x36, 0x34, 0x34, 0x00, 0x30, 0x30, 0x30, 0x30,  /* |....0000644.0000| */
+  /* 00000070 */   0x30, 0x30, 0x30, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x30, 0x30, 0x30, 0x30,  /* |000.0000000.0000| */
+  /* 00000080 */   0x30, 0x30, 0x30, 0x30, 0x31, 0x35, 0x35, 0x00, 0x31, 0x34, 0x37, 0x31, 0x31, 0x35, 0x36, 0x36,  /* |0000155.14711566| */
+  /* 00000090 */   0x30, 0x31, 0x33, 0x00, 0x30, 0x31, 0x31, 0x37, 0x35, 0x33, 0x00, 0x20, 0x78, 0x00, 0x00, 0x00,  /* |013.011753. x...| */
+  /* 000000a0 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 000000b0 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 000000c0 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 000000d0 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 000000e0 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 000000f0 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 00000100 */   0x00, 0x75, 0x73, 0x74, 0x61, 0x72, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |.ustar.00.......| */
+  /* 00000110 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 00000120 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 00000130 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 00000140 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 00000150 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 00000160 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 00000170 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 00000180 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 00000190 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 000001a0 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 000001b0 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 000001c0 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 000001d0 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 000001e0 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 000001f0 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 00000200 */   0x31, 0x39, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x3d, 0x38, 0x35, 0x38, 0x39, 0x39, 0x33, 0x34, 0x35,  /* |19 size=85899345| */
+  /* 00000210 */   0x39, 0x32, 0x0a, 0x33, 0x30, 0x20, 0x6d, 0x74, 0x69, 0x6d, 0x65, 0x3d, 0x31, 0x37, 0x33, 0x30,  /* |92.30 mtime=1730| */
+  /* 00000220 */   0x36, 0x30, 0x34, 0x30, 0x34, 0x33, 0x2e, 0x30, 0x34, 0x36, 0x38, 0x33, 0x33, 0x30, 0x31, 0x31,  /* |604043.046833011| */
+  /* 00000230 */   0x0a, 0x33, 0x30, 0x20, 0x61, 0x74, 0x69, 0x6d, 0x65, 0x3d, 0x31, 0x37, 0x33, 0x30, 0x36, 0x30,  /* |.30 atime=173060| */
+  /* 00000240 */   0x34, 0x30, 0x33, 0x39, 0x2e, 0x38, 0x30, 0x37, 0x30, 0x38, 0x31, 0x33, 0x31, 0x39, 0x0a, 0x33,  /* |4039.807081319.3| */
+  /* 00000250 */   0x30, 0x20, 0x63, 0x74, 0x69, 0x6d, 0x65, 0x3d, 0x31, 0x37, 0x33, 0x30, 0x36, 0x30, 0x34, 0x30,  /* |0 ctime=17306040| */
+  /* 00000260 */   0x34, 0x33, 0x2e, 0x30, 0x34, 0x36, 0x38, 0x33, 0x33, 0x30, 0x31, 0x31, 0x0a, 0x00, 0x00, 0x00,  /* |43.046833011....| */
+  /* 00000270 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 00000280 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 00000290 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 000002a0 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 000002b0 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 000002c0 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 000002d0 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 000002e0 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 000002f0 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 00000300 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 00000310 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 00000320 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 00000330 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 00000340 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 00000350 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 00000360 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 00000370 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 00000380 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 00000390 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 000003a0 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 000003b0 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 000003c0 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 000003d0 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 000003e0 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 000003f0 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 00000400 */   0x74, 0x65, 0x73, 0x74, 0x2e, 0x62, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |test.bin........| */
+  /* 00000410 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 00000420 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 00000430 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 00000440 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 00000450 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 00000460 */   0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x36, 0x34, 0x34, 0x00, 0x30, 0x30, 0x30, 0x30,  /* |....0000644.0000| */
+  /* 00000470 */   0x37, 0x36, 0x35, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0x32, 0x34, 0x00, 0x30, 0x30, 0x30, 0x30,  /* |765.0000024.0000| */
+  /* 00000480 */   0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x31, 0x34, 0x37, 0x31, 0x31, 0x35, 0x36, 0x36,  /* |0000000.14711566| */
+  /* 00000490 */   0x30, 0x31, 0x33, 0x00, 0x30, 0x31, 0x31, 0x32, 0x33, 0x35, 0x00, 0x20, 0x30, 0x00, 0x00, 0x00,  /* |013.011235. 0...| */
+  /* 000004a0 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 000004b0 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 000004c0 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 000004d0 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 000004e0 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 000004f0 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 00000500 */   0x00, 0x75, 0x73, 0x74, 0x61, 0x72, 0x00, 0x30, 0x30, 0x74, 0x69, 0x6d, 0x00, 0x00, 0x00, 0x00,  /* |.ustar.00tim....| */
+  /* 00000510 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 00000520 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x74, 0x61, 0x66, 0x66, 0x00, 0x00,  /* |.........staff..| */
+  /* 00000530 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 00000540 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 00000550 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 00000560 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 00000570 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 00000580 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 00000590 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 000005a0 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 000005b0 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 000005c0 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 000005d0 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 000005e0 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+  /* 000005f0 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* |................| */
+};
+
+/*
+ * Followed by 16777218 blocks, each consisting of 512 zeros:
+ * Entry is 8GB = 2^24 = 16777216 blocks
+ * Plus 2 zero blocks for end-of-archive
+ */
+
+struct my_reader {
+       const void *prefix;
+       int prefix_length;
+       int zero_blocks_remaining;
+       void *zero_block;
+};
+
+/*
+ * Custom reader returns first the prefix, then
+ * the expected number of zero blocks, then EOF.
+ */
+static ssize_t
+myread(struct archive *a, void *client_data, const void **buff)
+{
+  struct my_reader *reader = client_data;
+  (void)a; /* UNUSED */
+
+  if (reader->prefix != NULL) {
+         *buff = reader->prefix;
+         reader->prefix = NULL;
+         return reader->prefix_length;
+  } else if (reader->zero_blocks_remaining > 0) {
+         *buff = reader->zero_block;
+         reader->zero_blocks_remaining -= 1;
+         return 512;
+  } else {
+         return 0;
+  }
+}
+
+/*
+ * test_compat_gtar_large verifies that we can read
+ * the archive encoded above.
+ */
+DEFINE_TEST(test_compat_gtar_large)
+{
+       struct archive *a;
+       struct archive_entry *ae;
+       struct my_reader reader = {
+               test_compat_gtar_large_data,
+               sizeof(test_compat_gtar_large_data),
+               16777218, /* 2^24 + 2 ; See above */
+               NULL
+       };
+       int r;
+
+       reader.zero_block = calloc(1, 512);
+
+       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));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_open(a, &reader, NULL, myread, NULL));
+
+       /* Read first entry. */
+       assertEqualIntA(a, ARCHIVE_OK, r = archive_read_next_header(a, &ae));
+       if (r != ARCHIVE_OK) {
+               archive_read_free(a);
+               return;
+       }
+       assertEqualString("test.bin", archive_entry_pathname(ae));
+       assertEqualInt(1730604043, archive_entry_mtime(ae));
+       assertEqualInt(501, archive_entry_uid(ae));
+       assertEqualString("tim", archive_entry_uname(ae));
+       assertEqualInt(20, archive_entry_gid(ae));
+       assertEqualString("staff", archive_entry_gname(ae));
+       assertEqualInt(0100644, archive_entry_mode(ae));
+       assertEqualInt(8589934592LL, archive_entry_size(ae));
+
+       /* TODO: Read and verify contents: 8GB of zeros */
+
+       /* Verify the end-of-archive. */
+       assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
+
+       /* Verify that the format detection worked. */
+       assertEqualInt(archive_filter_code(a, 0), ARCHIVE_FILTER_NONE);
+       assertEqualInt(archive_format(a), ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE);
+
+       /* Verify that the reader actually read to the end of data */
+       assertEqualInt(reader.zero_blocks_remaining, 0);
+
+       assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+       assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+       free(reader.zero_block);
+}