summaryrefslogtreecommitdiff
path: root/archivers/libarchive/files/libarchive
diff options
context:
space:
mode:
Diffstat (limited to 'archivers/libarchive/files/libarchive')
-rw-r--r--archivers/libarchive/files/libarchive/archive.h.in54
-rw-r--r--archivers/libarchive/files/libarchive/archive_entry.h34
-rw-r--r--archivers/libarchive/files/libarchive/archive_entry_link_resolver.c222
-rw-r--r--archivers/libarchive/files/libarchive/archive_entry_private.h2
-rw-r--r--archivers/libarchive/files/libarchive/archive_entry_strmode.c83
-rw-r--r--archivers/libarchive/files/libarchive/archive_platform.h3
-rw-r--r--archivers/libarchive/files/libarchive/archive_read.34
-rw-r--r--archivers/libarchive/files/libarchive/archive_read.c18
-rw-r--r--archivers/libarchive/files/libarchive/archive_read_support_compression_none.c109
-rw-r--r--archivers/libarchive/files/libarchive/archive_read_support_format_ar.c8
-rw-r--r--archivers/libarchive/files/libarchive/archive_read_support_format_cpio.c179
-rw-r--r--archivers/libarchive/files/libarchive/archive_read_support_format_iso9660.c17
-rw-r--r--archivers/libarchive/files/libarchive/archive_read_support_format_mtree.c19
-rw-r--r--archivers/libarchive/files/libarchive/archive_read_support_format_tar.c89
-rw-r--r--archivers/libarchive/files/libarchive/archive_read_support_format_zip.c30
-rw-r--r--archivers/libarchive/files/libarchive/archive_util.c2
-rw-r--r--archivers/libarchive/files/libarchive/archive_write_disk.c21
-rw-r--r--archivers/libarchive/files/libarchive/archive_write_set_compression_none.c43
-rw-r--r--archivers/libarchive/files/libarchive/archive_write_set_format_cpio.c10
-rw-r--r--archivers/libarchive/files/libarchive/archive_write_set_format_cpio_newc.c9
-rw-r--r--archivers/libarchive/files/libarchive/archive_write_set_format_pax.c13
-rw-r--r--archivers/libarchive/files/libarchive/archive_write_set_format_ustar.c13
-rw-r--r--archivers/libarchive/files/libarchive/config_windows.h3
-rw-r--r--archivers/libarchive/files/libarchive/cpio.5325
-rw-r--r--archivers/libarchive/files/libarchive/libarchive-formats.532
-rw-r--r--archivers/libarchive/files/libarchive/libarchive_internals.322
-rw-r--r--archivers/libarchive/files/libarchive/mtree.5270
-rw-r--r--archivers/libarchive/files/libarchive/test/list.h4
-rw-r--r--archivers/libarchive/files/libarchive/test/main.c288
-rw-r--r--archivers/libarchive/files/libarchive/test/read_open_memory.c2
-rw-r--r--archivers/libarchive/files/libarchive/test/test.h90
-rw-r--r--archivers/libarchive/files/libarchive/test/test_entry_strmode.c48
-rw-r--r--archivers/libarchive/files/libarchive/test/test_read_format_cpio_odc.c2
-rw-r--r--archivers/libarchive/files/libarchive/test/test_read_format_gtar_sparse.c57
-rw-r--r--archivers/libarchive/files/libarchive/test/test_read_format_isorr_bz2.c3
-rw-r--r--archivers/libarchive/files/libarchive/test/test_read_format_zip.c6
-rw-r--r--archivers/libarchive/files/libarchive/test/test_read_pax_truncated.c4
-rw-r--r--archivers/libarchive/files/libarchive/test/test_tar_filenames.c2
-rw-r--r--archivers/libarchive/files/libarchive/test/test_tar_large.c307
-rw-r--r--archivers/libarchive/files/libarchive/test/test_write_disk.c79
-rw-r--r--archivers/libarchive/files/libarchive/test/test_write_format_cpio.c96
-rw-r--r--archivers/libarchive/files/libarchive/test/test_write_format_cpio_newc.c172
-rw-r--r--archivers/libarchive/files/libarchive/test/test_write_format_cpio_odc.c224
43 files changed, 2624 insertions, 394 deletions
diff --git a/archivers/libarchive/files/libarchive/archive.h.in b/archivers/libarchive/files/libarchive/archive.h.in
index eb374437d13..e21a7105e7c 100644
--- a/archivers/libarchive/files/libarchive/archive.h.in
+++ b/archivers/libarchive/files/libarchive/archive.h.in
@@ -60,40 +60,10 @@ extern "C" {
/*
* Textual name/version of the library, useful for version displays.
*/
-#define ARCHIVE_LIBRARY_VERSION "libarchive @ARCHIVE_VERSION@"
+#define ARCHIVE_LIBRARY_VERSION "libarchive @LIBARCHIVE_VERSION_STRING@"
const char * archive_version(void);
/*
- * Major version number: If ARCHIVE_API_VERSION !=
- * archive_api_version(), then the library you were linked with is
- * using an incompatible API to the one you were compiled with. This
- * is almost certainly a fatal problem.
- */
-#define ARCHIVE_API_VERSION @ARCHIVE_API_MAJOR@
-int archive_api_version(void);
-
-/*
- * Minor version number: ARCHIVE_API_FEATURE is incremented with each
- * significant feature addition, so you can test (at compile or run
- * time) if a particular feature is implemented. It's no big deal if
- * ARCHIVE_API_FEATURE != archive_api_feature(), as long as both are
- * high enough to include the features you're relying on. Specific
- * values of FEATURE are documented here:
- *
- * 1 - Version tests are available.
- * 2 - archive_{read,write}_close available separately from _finish.
- * 3 - open_memory, open_memory2, open_FILE, open_fd available
- * 5 - archive_write_disk interface available
- *
- * Unfortunately, this count resets whenever ARCHIVE_API_VERSION changes,
- * making it awkward to use in practice. For that reason, it is deprecated
- * in favor of the more-accurate version stamp below. It will eventually
- * be removed.
- */
-#define ARCHIVE_API_FEATURE @ARCHIVE_API_MINOR@
-int archive_api_feature(void);
-
-/*
* The "version stamp" is a single integer that makes it easy to check
* the exact version: for version a.b.c, the version stamp is
* printf("%d%03d%03d",a,b,c). For example, version 2.12.108 has
@@ -102,16 +72,34 @@ int archive_api_feature(void);
* This was introduced with libarchive 1.9.0 in the libarchive 1.x family
* and libarchive 2.2.4 in the libarchive 2.x family. The following
* may be useful if you really want to do feature detection for earlier
- * libarchive versions:
+ * libarchive versions (which defined API_VERSION and API_FEATURE):
*
* #ifndef ARCHIVE_VERSION_STAMP
* #define ARCHIVE_VERSION_STAMP \
* (ARCHIVE_API_VERSION * 1000000 + ARCHIVE_API_FEATURE * 1000)
* #endif
*/
-#define ARCHIVE_VERSION_STAMP @ARCHIVE_VERSION_STAMP@
+#define ARCHIVE_VERSION_STAMP @LIBARCHIVE_VERSION@
int archive_version_stamp(void);
+/*
+ * Major version number: If ARCHIVE_API_VERSION !=
+ * archive_api_version(), then the library you were linked with is
+ * using an incompatible API to the one you were compiled with. This
+ * is almost certainly a fatal problem.
+ * This is deprecated and will be removed; use ARCHIVE_VERSION_STAMP
+ * instead.
+ */
+#define ARCHIVE_API_VERSION (ARCHIVE_VERSION_STAMP / 1000000)
+int archive_api_version(void);
+
+/*
+ * Minor version number. This is deprecated and will be removed.
+ * Use ARCHIVE_VERSION_STAMP to adapt to libarchive API variations.
+ */
+#define ARCHIVE_API_FEATURE ((ARCHIVE_VERSION_STAMP / 1000) % 1000)
+int archive_api_feature(void);
+
#define ARCHIVE_BYTES_PER_RECORD 512
#define ARCHIVE_DEFAULT_BYTES_PER_BLOCK 10240
diff --git a/archivers/libarchive/files/libarchive/archive_entry.h b/archivers/libarchive/files/libarchive/archive_entry.h
index 95fe8c61c75..33c5649a9f1 100644
--- a/archivers/libarchive/files/libarchive/archive_entry.h
+++ b/archivers/libarchive/files/libarchive/archive_entry.h
@@ -62,6 +62,7 @@ struct archive_entry;
#define AE_IFMT 0170000
#define AE_IFREG 0100000
#define AE_IFLNK 0120000
+#define AE_IFSOCK 0140000
#define AE_IFCHR 0020000
#define AE_IFBLK 0060000
#define AE_IFDIR 0040000
@@ -108,6 +109,7 @@ dev_t archive_entry_rdev(struct archive_entry *);
dev_t archive_entry_rdevmajor(struct archive_entry *);
dev_t archive_entry_rdevminor(struct archive_entry *);
int64_t archive_entry_size(struct archive_entry *);
+const char *archive_entry_strmode(struct archive_entry *);
const char *archive_entry_symlink(struct archive_entry *);
const wchar_t *archive_entry_symlink_w(struct archive_entry *);
uid_t archive_entry_uid(struct archive_entry *);
@@ -261,11 +263,6 @@ int archive_entry_acl_count(struct archive_entry *, int want_type);
int __archive_entry_acl_parse_w(struct archive_entry *,
const wchar_t *, int type);
-
-#ifdef __cplusplus
-}
-#endif
-
/*
* extended attributes
*/
@@ -284,5 +281,32 @@ int archive_entry_xattr_reset(struct archive_entry *);
int archive_entry_xattr_next(struct archive_entry *,
const char **name, const void **value, size_t *);
+/*
+ * Utility to detect hardlinks.
+ *
+ * The 'struct archive_hardlink_lookup' is a cache of entry
+ * names and dev/ino numbers. Here's how to use it:
+ * 1. Create a lookup object with archive_hardlink_lookup_new()
+ * 2. Hand each archive_entry to archive_hardlink_lookup().
+ * That function will return NULL (this is not a hardlink to
+ * a previous entry) or the pathname of the first entry
+ * that matched this.
+ * 3. Use archive_hardlink_lookup_free() to release the cache.
+ *
+ * To make things more efficient, be sure that each entry has a valid
+ * nlinks value. The hardlink cache uses this to track when all links
+ * have been found. If the nlinks value is zero, it will keep every
+ * name in the cache indefinitely, which can use a lot of memory.
+ */
+struct archive_entry_linkresolver;
+
+struct archive_entry_linkresolver *archive_entry_linkresolver_new(void);
+void archive_entry_linkresolver_free(struct archive_entry_linkresolver *);
+const char *archive_entry_linkresolve(struct archive_entry_linkresolver *,
+ struct archive_entry *);
+
+#ifdef __cplusplus
+}
+#endif
#endif /* !ARCHIVE_ENTRY_H_INCLUDED */
diff --git a/archivers/libarchive/files/libarchive/archive_entry_link_resolver.c b/archivers/libarchive/files/libarchive/archive_entry_link_resolver.c
new file mode 100644
index 00000000000..0f07e068e07
--- /dev/null
+++ b/archivers/libarchive/files/libarchive/archive_entry_link_resolver.c
@@ -0,0 +1,222 @@
+/*-
+ * Copyright (c) 2003-2007 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 "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#include "archive_entry.h"
+
+/* Initial size of link cache. */
+#define links_cache_initial_size 1024
+
+struct archive_entry_linkresolver {
+ char *last_name;
+ unsigned long number_entries;
+ size_t number_buckets;
+ struct links_entry **buckets;
+};
+
+struct links_entry {
+ struct links_entry *next;
+ struct links_entry *previous;
+ int links;
+ dev_t dev;
+ ino_t ino;
+ char *name;
+};
+
+struct archive_entry_linkresolver *
+archive_entry_linkresolver_new(void)
+{
+ struct archive_entry_linkresolver *links_cache;
+ size_t i;
+
+ links_cache = malloc(sizeof(struct archive_entry_linkresolver));
+ if (links_cache == NULL)
+ return (NULL);
+ memset(links_cache, 0, sizeof(struct archive_entry_linkresolver));
+ links_cache->number_buckets = links_cache_initial_size;
+ links_cache->buckets = malloc(links_cache->number_buckets *
+ sizeof(links_cache->buckets[0]));
+ if (links_cache->buckets == NULL) {
+ free(links_cache);
+ return (NULL);
+ }
+ for (i = 0; i < links_cache->number_buckets; i++)
+ links_cache->buckets[i] = NULL;
+ return (links_cache);
+}
+
+void
+archive_entry_linkresolver_free(struct archive_entry_linkresolver *links_cache)
+{
+ size_t i;
+
+ if (links_cache->buckets == NULL)
+ return;
+
+ for (i = 0; i < links_cache->number_buckets; i++) {
+ while (links_cache->buckets[i] != NULL) {
+ struct links_entry *lp = links_cache->buckets[i]->next;
+ if (links_cache->buckets[i]->name != NULL)
+ free(links_cache->buckets[i]->name);
+ free(links_cache->buckets[i]);
+ links_cache->buckets[i] = lp;
+ }
+ }
+ free(links_cache->buckets);
+ links_cache->buckets = NULL;
+}
+
+const char *
+archive_entry_linkresolve(struct archive_entry_linkresolver *links_cache,
+ struct archive_entry *entry)
+{
+ struct links_entry *le, **new_buckets;
+ int hash;
+ size_t i, new_size;
+ dev_t dev;
+ ino_t ino;
+ int nlinks;
+
+
+ /* Free a held name. */
+ free(links_cache->last_name);
+ links_cache->last_name = NULL;
+
+ /* If the links cache overflowed and got flushed, don't bother. */
+ if (links_cache->buckets == NULL)
+ return (NULL);
+
+ dev = archive_entry_dev(entry);
+ ino = archive_entry_ino(entry);
+ nlinks = archive_entry_nlink(entry);
+
+ /* An entry with one link can't be a hard link. */
+ if (nlinks == 1)
+ return (NULL);
+
+ /* If the links cache is getting too full, enlarge the hash table. */
+ if (links_cache->number_entries > links_cache->number_buckets * 2)
+ {
+ /* Try to enlarge the bucket list. */
+ new_size = links_cache->number_buckets * 2;
+ new_buckets = malloc(new_size * sizeof(struct links_entry *));
+
+ if (new_buckets != NULL) {
+ memset(new_buckets, 0,
+ new_size * sizeof(struct links_entry *));
+ for (i = 0; i < links_cache->number_buckets; i++) {
+ while (links_cache->buckets[i] != NULL) {
+ /* Remove entry from old bucket. */
+ le = links_cache->buckets[i];
+ links_cache->buckets[i] = le->next;
+
+ /* Add entry to new bucket. */
+ hash = (le->dev ^ le->ino) % new_size;
+
+ if (new_buckets[hash] != NULL)
+ new_buckets[hash]->previous =
+ le;
+ le->next = new_buckets[hash];
+ le->previous = NULL;
+ new_buckets[hash] = le;
+ }
+ }
+ free(links_cache->buckets);
+ links_cache->buckets = new_buckets;
+ links_cache->number_buckets = new_size;
+ }
+ }
+
+ /* Try to locate this entry in the links cache. */
+ hash = ( dev ^ ino ) % links_cache->number_buckets;
+ for (le = links_cache->buckets[hash]; le != NULL; le = le->next) {
+ if (le->dev == dev && le->ino == ino) {
+ /*
+ * Decrement link count each time and release
+ * the entry if it hits zero. This saves
+ * memory and is necessary for detecting
+ * missed links.
+ */
+ --le->links;
+ if (le->links > 0)
+ return (le->name);
+ /*
+ * When we release the entry, save the name
+ * until the next call.
+ */
+ links_cache->last_name = le->name;
+ /*
+ * Release the entry.
+ */
+ if (le->previous != NULL)
+ le->previous->next = le->next;
+ if (le->next != NULL)
+ le->next->previous = le->previous;
+ if (links_cache->buckets[hash] == le)
+ links_cache->buckets[hash] = le->next;
+ links_cache->number_entries--;
+ free(le);
+ return (links_cache->last_name);
+ }
+ }
+
+ /* Add this entry to the links cache. */
+ le = malloc(sizeof(struct links_entry));
+ if (le == NULL)
+ return (NULL);
+ le->name = strdup(archive_entry_pathname(entry));
+ if (le->name == NULL) {
+ free(le);
+ return (NULL);
+ }
+
+ /* If we could allocate the entry, record it. */
+ if (links_cache->buckets[hash] != NULL)
+ links_cache->buckets[hash]->previous = le;
+ links_cache->number_entries++;
+ le->next = links_cache->buckets[hash];
+ le->previous = NULL;
+ links_cache->buckets[hash] = le;
+ le->dev = dev;
+ le->ino = ino;
+ le->links = nlinks - 1;
+ return (NULL);
+}
diff --git a/archivers/libarchive/files/libarchive/archive_entry_private.h b/archivers/libarchive/files/libarchive/archive_entry_private.h
index 234ba47e844..50ad7b9064b 100644
--- a/archivers/libarchive/files/libarchive/archive_entry_private.h
+++ b/archivers/libarchive/files/libarchive/archive_entry_private.h
@@ -149,6 +149,8 @@ struct archive_entry {
struct ae_xattr *xattr_head;
struct ae_xattr *xattr_p;
+
+ char strmode[11];
};
diff --git a/archivers/libarchive/files/libarchive/archive_entry_strmode.c b/archivers/libarchive/files/libarchive/archive_entry_strmode.c
new file mode 100644
index 00000000000..1a018734bce
--- /dev/null
+++ b/archivers/libarchive/files/libarchive/archive_entry_strmode.c
@@ -0,0 +1,83 @@
+/*-
+ * Copyright (c) 2003-2007 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 "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#include "archive_entry.h"
+#include "archive_entry_private.h"
+
+const char *
+archive_entry_strmode(struct archive_entry *entry)
+{
+ static const char *perms = "?rwxrwxrwx ";
+ static const mode_t permbits[] =
+ { 0400, 0200, 0100, 0040, 0020, 0010, 0004, 0002, 0001 };
+ char *bp = entry->strmode;
+ mode_t mode;
+ int i;
+
+ /* Fill in a default string, then selectively override. */
+ strcpy(bp, perms);
+
+ mode = archive_entry_mode(entry);
+ switch (archive_entry_filetype(entry)) {
+ case AE_IFREG: bp[0] = '-'; break;
+ case AE_IFBLK: bp[0] = 'b'; break;
+ case AE_IFCHR: bp[0] = 'c'; break;
+ case AE_IFDIR: bp[0] = 'd'; break;
+ case AE_IFLNK: bp[0] = 'l'; break;
+ case AE_IFSOCK: bp[0] = 's'; break;
+ case AE_IFIFO: bp[0] = 'p'; break;
+ }
+
+ for (i = 0; i < 9; i++)
+ if (!(mode & permbits[i]))
+ bp[i+1] = '-';
+
+ if (mode & S_ISUID) {
+ if (mode & S_IXUSR) bp[3] = 's';
+ else bp[3] = 'S';
+ }
+ if (mode & S_ISGID) {
+ if (mode & S_IXGRP) bp[6] = 's';
+ else bp[6] = 'S';
+ }
+ if (mode & S_ISVTX) {
+ if (mode & S_IXOTH) bp[9] = 't';
+ else bp[9] = 'T';
+ }
+ if (archive_entry_acl_count(entry, ARCHIVE_ENTRY_ACL_TYPE_ACCESS))
+ bp[10] = '+';
+
+ return (bp);
+}
diff --git a/archivers/libarchive/files/libarchive/archive_platform.h b/archivers/libarchive/files/libarchive/archive_platform.h
index 70cc037c3ac..193a52cc674 100644
--- a/archivers/libarchive/files/libarchive/archive_platform.h
+++ b/archivers/libarchive/files/libarchive/archive_platform.h
@@ -57,7 +57,8 @@
#ifdef __FreeBSD__
#include <sys/cdefs.h> /* For __FBSDID */
#else
-#define __FBSDID(a) /* null */
+/* Just leaving this macro replacement empty leads to a dangling semicolon. */
+#define __FBSDID(a) struct _undefined_hack
#endif
/* Try to get standard C99-style integer type definitions. */
diff --git a/archivers/libarchive/files/libarchive/archive_read.3 b/archivers/libarchive/files/libarchive/archive_read.3
index 9e4f878dc10..6daba3f3d11 100644
--- a/archivers/libarchive/files/libarchive/archive_read.3
+++ b/archivers/libarchive/files/libarchive/archive_read.3
@@ -22,7 +22,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.\" $FreeBSD: src/lib/libarchive/archive_read.3,v 1.34 2007/05/29 01:00:18 kientzle Exp $
+.\" $FreeBSD: src/lib/libarchive/archive_read.3,v 1.35 2007/09/19 16:37:45 kientzle Exp $
.\"
.Dd August 19, 2006
.Dt archive_read 3
@@ -267,7 +267,7 @@ to create the entry on disk and copy data into it.
The
.Va flags
argument is passed unmodified to
-.Xr archiv_write_disk_set_options 3 .
+.Xr archive_write_disk_set_options 3 .
.It Fn archive_read_extract_set_progress_callback
Sets a pointer to a user-defined callback that can be used
for updating progress displays during extraction.
diff --git a/archivers/libarchive/files/libarchive/archive_read.c b/archivers/libarchive/files/libarchive/archive_read.c
index 54330971200..7803fd2f9fe 100644
--- a/archivers/libarchive/files/libarchive/archive_read.c
+++ b/archivers/libarchive/files/libarchive/archive_read.c
@@ -307,6 +307,18 @@ archive_read_next_header(struct archive *_a, struct archive_entry **entryp)
archive_clear_error(&a->archive);
/*
+ * If no format has yet been chosen, choose one.
+ */
+ if (a->format == NULL) {
+ slot = choose_format(a);
+ if (slot < 0) {
+ a->archive.state = ARCHIVE_STATE_FATAL;
+ return (ARCHIVE_FATAL);
+ }
+ a->format = &(a->formats[slot]);
+ }
+
+ /*
* If client didn't consume entire data, skip any remainder
* (This is especially important for GNU incremental directories.)
*/
@@ -324,12 +336,6 @@ archive_read_next_header(struct archive *_a, struct archive_entry **entryp)
/* Record start-of-header. */
a->header_position = a->archive.file_position;
- slot = choose_format(a);
- if (slot < 0) {
- a->archive.state = ARCHIVE_STATE_FATAL;
- return (ARCHIVE_FATAL);
- }
- a->format = &(a->formats[slot]);
ret = (a->format->read_header)(a, entry);
/*
diff --git a/archivers/libarchive/files/libarchive/archive_read_support_compression_none.c b/archivers/libarchive/files/libarchive/archive_read_support_compression_none.c
index 58a5559167f..1cafd8385a5 100644
--- a/archivers/libarchive/files/libarchive/archive_read_support_compression_none.c
+++ b/archivers/libarchive/files/libarchive/archive_read_support_compression_none.c
@@ -24,7 +24,7 @@
*/
#include "archive_platform.h"
-__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_compression_none.c,v 1.17 2007/05/29 01:00:19 kientzle Exp $");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_compression_none.c,v 1.18 2007/10/27 22:45:40 kientzle Exp $");
#ifdef HAVE_ERRNO_H
#include <errno.h>
@@ -170,56 +170,45 @@ archive_decompressor_none_read_ahead(struct archive_read *a, const void **buff,
min = state->buffer_size;
/*
- * Try to satisfy the request directly from the client
- * buffer. We can do this if all of the data in the copy
- * buffer was copied from the current client buffer. This
- * also covers the case where the copy buffer is empty and
- * the client buffer has all the data we need.
+ * Keep pulling more data until we can satisfy the request.
*/
- if (state->client_total >= state->client_avail + state->avail
- && state->client_avail + state->avail >= min) {
- state->client_avail += state->avail;
- state->client_next -= state->avail;
- state->avail = 0;
- state->next = state->buffer;
- *buff = state->client_next;
- return (state->client_avail);
- }
+ for (;;) {
- /*
- * If we can't use client buffer, we'll have to use copy buffer.
- */
+ /*
+ * If we can satisfy from the copy buffer, we're done.
+ */
+ if (state->avail >= min) {
+ *buff = state->next;
+ return (state->avail);
+ }
- /* Move data forward in copy buffer if necessary. */
- if (state->next > state->buffer &&
- state->next + min > state->buffer + state->buffer_size) {
- if (state->avail > 0)
- memmove(state->buffer, state->next, state->avail);
- state->next = state->buffer;
- }
+ /*
+ * We can satisfy directly from client buffer if everything
+ * currently in the copy buffer is still in the client buffer.
+ */
+ if (state->client_total >= state->client_avail + state->avail
+ && state->client_avail + state->avail >= min) {
+ /* "Roll back" to client buffer. */
+ state->client_avail += state->avail;
+ state->client_next -= state->avail;
+ /* Copy buffer is now empty. */
+ state->avail = 0;
+ state->next = state->buffer;
+ /* Return data from client buffer. */
+ *buff = state->client_next;
+ return (state->client_avail);
+ }
- /* Collect data in copy buffer to fulfill request. */
- while (state->avail < min) {
- /* Copy data from client buffer to our copy buffer. */
- if (state->client_avail > 0) {
- /* First estimate: copy to fill rest of buffer. */
- size_t tocopy = (state->buffer + state->buffer_size)
- - (state->next + state->avail);
- /* Don't copy more than is available. */
- if (tocopy > state->client_avail)
- tocopy = state->client_avail;
- memcpy(state->next + state->avail, state->client_next,
- tocopy);
- state->client_next += tocopy;
- state->client_avail -= tocopy;
- state->avail += tocopy;
- } else {
- /* There is no more client data: fetch more. */
- /*
- * It seems to me that const void ** and const
- * char ** should be compatible, but they
- * aren't, hence the cast.
- */
+ /* Move data forward in copy buffer if necessary. */
+ if (state->next > state->buffer &&
+ state->next + min > state->buffer + state->buffer_size) {
+ if (state->avail > 0)
+ memmove(state->buffer, state->next, state->avail);
+ state->next = state->buffer;
+ }
+
+ /* If we've used up the client data, get more. */
+ if (state->client_avail <= 0) {
bytes_read = (a->client_reader)(&a->archive,
a->client_data, &state->client_buff);
if (bytes_read < 0) { /* Read error. */
@@ -232,17 +221,33 @@ archive_decompressor_none_read_ahead(struct archive_read *a, const void **buff,
state->client_total = state->client_avail = 0;
state->client_next = state->client_buff = NULL;
state->end_of_file = 1;
- break;
+ /* Return whatever we do have. */
+ *buff = state->next;
+ return (state->avail);
}
a->archive.raw_position += bytes_read;
state->client_total = bytes_read;
state->client_avail = state->client_total;
state->client_next = state->client_buff;
}
+ else
+ {
+ /* We can add client data to copy buffer. */
+ /* First estimate: copy to fill rest of buffer. */
+ size_t tocopy = (state->buffer + state->buffer_size)
+ - (state->next + state->avail);
+ /* Don't copy more than is available. */
+ if (tocopy > state->client_avail)
+ tocopy = state->client_avail;
+ memcpy(state->next + state->avail, state->client_next,
+ tocopy);
+ /* Remove this data from client buffer. */
+ state->client_next += tocopy;
+ state->client_avail -= tocopy;
+ /* add it to copy buffer. */
+ state->avail += tocopy;
+ }
}
-
- *buff = state->next;
- return (state->avail);
}
/*
@@ -334,7 +339,7 @@ archive_decompressor_none_skip(struct archive_read *a, off_t request)
const void* dummy_buffer;
ssize_t bytes_read;
bytes_read = archive_decompressor_none_read_ahead(a,
- &dummy_buffer, request);
+ &dummy_buffer, 1);
if (bytes_read < 0)
return (bytes_read);
if (bytes_read == 0) {
diff --git a/archivers/libarchive/files/libarchive/archive_read_support_format_ar.c b/archivers/libarchive/files/libarchive/archive_read_support_format_ar.c
index 97ed28af1fa..5fad4aea038 100644
--- a/archivers/libarchive/files/libarchive/archive_read_support_format_ar.c
+++ b/archivers/libarchive/files/libarchive/archive_read_support_format_ar.c
@@ -47,7 +47,6 @@ __FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_ar.c,v 1.6 20
#include "archive_read_private.h"
struct ar {
- int bid;
off_t entry_bytes_remaining;
off_t entry_offset;
off_t entry_padding;
@@ -103,7 +102,6 @@ archive_read_support_format_ar(struct archive *_a)
return (ARCHIVE_FATAL);
}
memset(ar, 0, sizeof(*ar));
- ar->bid = -1;
ar->strtab = NULL;
r = __archive_read_register_format(a,
@@ -148,9 +146,6 @@ archive_read_format_ar_bid(struct archive_read *a)
ar = (struct ar *)(a->format->data);
- if (ar->bid > 0)
- return (ar->bid);
-
/*
* Verify the 8-byte file signature.
* TODO: Do we need to check more than this?
@@ -159,8 +154,7 @@ archive_read_format_ar_bid(struct archive_read *a)
if (bytes_read < 8)
return (-1);
if (strncmp((const char*)h, "!<arch>\n", 8) == 0) {
- ar->bid = 64;
- return (ar->bid);
+ return (64);
}
return (-1);
}
diff --git a/archivers/libarchive/files/libarchive/archive_read_support_format_cpio.c b/archivers/libarchive/files/libarchive/archive_read_support_format_cpio.c
index 7a056b9f439..1ede8b622b2 100644
--- a/archivers/libarchive/files/libarchive/archive_read_support_format_cpio.c
+++ b/archivers/libarchive/files/libarchive/archive_read_support_format_cpio.c
@@ -118,6 +118,8 @@ static int archive_read_format_cpio_read_data(struct archive_read *,
static int archive_read_format_cpio_read_header(struct archive_read *,
struct archive_entry *);
static int be4(const unsigned char *);
+static int find_odc_header(struct archive_read *);
+static int find_newc_header(struct archive_read *);
static int header_bin_be(struct archive_read *, struct cpio *,
struct archive_entry *, size_t *, size_t *);
static int header_bin_le(struct archive_read *, struct cpio *,
@@ -126,6 +128,8 @@ static int header_newc(struct archive_read *, struct cpio *,
struct archive_entry *, size_t *, size_t *);
static int header_odc(struct archive_read *, struct cpio *,
struct archive_entry *, size_t *, size_t *);
+static int is_octal(const char *, size_t);
+static int is_hex(const char *, size_t);
static int le4(const unsigned char *);
static void record_hardlink(struct cpio *cpio, struct archive_entry *entry);
@@ -161,13 +165,14 @@ archive_read_support_format_cpio(struct archive *_a)
static int
archive_read_format_cpio_bid(struct archive_read *a)
{
- int bid, bytes_read;
+ int bytes_read;
const void *h;
const unsigned char *p;
struct cpio *cpio;
+ int bid;
cpio = (struct cpio *)(a->format->data);
- bid = 0;
+
bytes_read = (a->decompressor->read_ahead)(a, &h, 6);
/* Convert error code into error return. */
if (bytes_read < 0)
@@ -176,6 +181,7 @@ archive_read_format_cpio_bid(struct archive_read *a)
return (-1);
p = (const unsigned char *)h;
+ bid = 0;
if (memcmp(p, "070707", 6) == 0) {
/* ASCII cpio archive (odc, POSIX.1) */
cpio->read_header = header_odc;
@@ -231,7 +237,7 @@ archive_read_format_cpio_read_header(struct archive_read *a,
cpio = (struct cpio *)(a->format->data);
r = (cpio->read_header(a, cpio, entry, &namelength, &name_pad));
- if (r != ARCHIVE_OK)
+ if (r < ARCHIVE_WARN)
return (r);
/* Read name from buffer. */
@@ -266,7 +272,7 @@ archive_read_format_cpio_read_header(struct archive_read *a,
/* Detect and record hardlinks to previously-extracted entries. */
record_hardlink(cpio, entry);
- return (ARCHIVE_OK);
+ return (r);
}
static int
@@ -306,6 +312,82 @@ archive_read_format_cpio_read_data(struct archive_read *a,
}
}
+/*
+ * Skip forward to the next cpio newc header by searching for the
+ * 07070[12] string. This should be generalized and merged with
+ * find_odc_header below.
+ */
+static int
+is_hex(const char *p, size_t len)
+{
+ while (len-- > 0) {
+ if (*p < '0' || (*p > '9' && *p < 'a') || *p > 'f') {
+ return (0);
+ }
+ ++p;
+ }
+ return (1);
+}
+
+static int
+find_newc_header(struct archive_read *a)
+{
+ const void *h;
+ const char *p, *q;
+ size_t skip, bytes, skipped = 0;
+
+ for (;;) {
+ bytes = (a->decompressor->read_ahead)(a, &h, 2048);
+ if (bytes < sizeof(struct cpio_newc_header))
+ return (ARCHIVE_FATAL);
+ p = h;
+ q = p + bytes;
+
+ /* Try the typical case first, then go into the slow search.*/
+ if (memcmp("07070", p, 5) == 0
+ && (p[5] == '1' || p[5] == '2')
+ && is_hex(p, sizeof(struct cpio_newc_header)))
+ return (ARCHIVE_OK);
+
+ /*
+ * Scan ahead until we find something that looks
+ * like an odc header.
+ */
+ while (p + sizeof(struct cpio_newc_header) < q) {
+ switch (p[5]) {
+ case '1':
+ case '2':
+ if (memcmp("07070", p, 5) == 0
+ && is_hex(p, sizeof(struct cpio_newc_header))) {
+ skip = p - (const char *)h;
+ (a->decompressor->consume)(a, skip);
+ skipped += skip;
+ if (skipped > 0) {
+ archive_set_error(&a->archive,
+ 0,
+ "Skipped %d bytes before "
+ "finding valid header",
+ (int)skipped);
+ return (ARCHIVE_WARN);
+ }
+ return (ARCHIVE_OK);
+ }
+ p += 2;
+ break;
+ case '0':
+ p++;
+ break;
+ default:
+ p += 6;
+ break;
+ }
+ }
+ skip = p - (const char *)h;
+ (a->decompressor->consume)(a, skip);
+ skipped += skip;
+ }
+}
+
static int
header_newc(struct archive_read *a, struct cpio *cpio,
struct archive_entry *entry, size_t *namelength, size_t *name_pad)
@@ -313,6 +395,11 @@ header_newc(struct archive_read *a, struct cpio *cpio,
const void *h;
const struct cpio_newc_header *header;
size_t bytes;
+ int r;
+
+ r = find_newc_header(a);
+ if (r < ARCHIVE_WARN)
+ return (r);
/* Read fixed-size portion of header. */
bytes = (a->decompressor->read_ahead)(a, &h, sizeof(struct cpio_newc_header));
@@ -357,7 +444,81 @@ header_newc(struct archive_read *a, struct cpio *cpio,
archive_entry_set_size(entry, cpio->entry_bytes_remaining);
/* Pad file contents to a multiple of 4. */
cpio->entry_padding = 3 & -cpio->entry_bytes_remaining;
- return (ARCHIVE_OK);
+ return (r);
+}
+
+/*
+ * Skip forward to the next cpio odc header by searching for the
+ * 070707 string. This is a hand-optimized search that could
+ * probably be easily generalized to handle all character-based
+ * cpio variants.
+ */
+static int
+is_octal(const char *p, size_t len)
+{
+ while (len-- > 0) {
+ if (*p < '0' || *p > '7')
+ return (0);
+ ++p;
+ }
+ return (1);
+}
+
+static int
+find_odc_header(struct archive_read *a)
+{
+ const void *h;
+ const char *p, *q;
+ size_t skip, bytes, skipped = 0;
+
+ for (;;) {
+ bytes = (a->decompressor->read_ahead)(a, &h, 512);
+ if (bytes < sizeof(struct cpio_odc_header))
+ return (ARCHIVE_FATAL);
+ p = h;
+ q = p + bytes;
+
+ /* Try the typical case first, then go into the slow search.*/
+ if (memcmp("070707", p, 6) == 0
+ && is_octal(p, sizeof(struct cpio_odc_header)))
+ return (ARCHIVE_OK);
+
+ /*
+ * Scan ahead until we find something that looks
+ * like an odc header.
+ */
+ while (p + sizeof(struct cpio_odc_header) < q) {
+ switch (p[5]) {
+ case '7':
+ if (memcmp("070707", p, 6) == 0
+ && is_octal(p, sizeof(struct cpio_odc_header))) {
+ skip = p - (const char *)h;
+ (a->decompressor->consume)(a, skip);
+ skipped += skip;
+ if (skipped > 0) {
+ archive_set_error(&a->archive,
+ 0,
+ "Skipped %d bytes before "
+ "finding valid header",
+ (int)skipped);
+ return (ARCHIVE_WARN);
+ }
+ return (ARCHIVE_OK);
+ }
+ p += 2;
+ break;
+ case '0':
+ p++;
+ break;
+ default:
+ p += 6;
+ break;
+ }
+ }
+ skip = p - (const char *)h;
+ (a->decompressor->consume)(a, skip);
+ skipped += skip;
+ }
}
static int
@@ -365,12 +526,18 @@ header_odc(struct archive_read *a, struct cpio *cpio,
struct archive_entry *entry, size_t *namelength, size_t *name_pad)
{
const void *h;
+ int r;
const struct cpio_odc_header *header;
size_t bytes;
a->archive.archive_format = ARCHIVE_FORMAT_CPIO_POSIX;
a->archive.archive_format_name = "POSIX octet-oriented cpio";
+ /* Find the start of the next header. */
+ r = find_odc_header(a);
+ if (r < ARCHIVE_WARN)
+ return (r);
+
/* Read fixed-size portion of header. */
bytes = (a->decompressor->read_ahead)(a, &h, sizeof(struct cpio_odc_header));
if (bytes < sizeof(struct cpio_odc_header))
@@ -400,7 +567,7 @@ header_odc(struct archive_read *a, struct cpio *cpio,
atol8(header->c_filesize, sizeof(header->c_filesize));
archive_entry_set_size(entry, cpio->entry_bytes_remaining);
cpio->entry_padding = 0;
- return (ARCHIVE_OK);
+ return (r);
}
static int
diff --git a/archivers/libarchive/files/libarchive/archive_read_support_format_iso9660.c b/archivers/libarchive/files/libarchive/archive_read_support_format_iso9660.c
index d77bd871c0e..d2419eac66f 100644
--- a/archivers/libarchive/files/libarchive/archive_read_support_format_iso9660.c
+++ b/archivers/libarchive/files/libarchive/archive_read_support_format_iso9660.c
@@ -194,7 +194,6 @@ struct file_info {
struct iso9660 {
int magic;
#define ISO9660_MAGIC 0x96609660
- int bid; /* If non-zero, return this as our bid. */
struct archive_string pathname;
char seenRockridge; /* Set true if RR extensions are used. */
unsigned char suspOffset;
@@ -255,7 +254,6 @@ archive_read_support_format_iso9660(struct archive *_a)
}
memset(iso9660, 0, sizeof(*iso9660));
iso9660->magic = ISO9660_MAGIC;
- iso9660->bid = -1; /* We haven't yet bid. */
r = __archive_read_register_format(a,
iso9660,
@@ -280,12 +278,10 @@ archive_read_format_iso9660_bid(struct archive_read *a)
ssize_t bytes_read;
const void *h;
const unsigned char *p;
+ int bid;
iso9660 = (struct iso9660 *)(a->format->data);
- if (iso9660->bid >= 0)
- return (iso9660->bid);
-
/*
* Skip the first 32k (reserved area) and get the first
* 8 sectors of the volume descriptor table. Of course,
@@ -293,7 +289,7 @@ archive_read_format_iso9660_bid(struct archive_read *a)
*/
bytes_read = (a->decompressor->read_ahead)(a, &h, 32768 + 8*2048);
if (bytes_read < 32768 + 8*2048)
- return (iso9660->bid = -1);
+ return (-1);
p = (const unsigned char *)h;
/* Skip the reserved area. */
@@ -302,16 +298,15 @@ archive_read_format_iso9660_bid(struct archive_read *a)
/* Check each volume descriptor to locate the PVD. */
for (; bytes_read > 2048; bytes_read -= 2048, p += 2048) {
- iso9660->bid = isPVD(iso9660, p);
- if (iso9660->bid > 0)
- return (iso9660->bid);
+ bid = isPVD(iso9660, p);
+ if (bid > 0)
+ return (bid);
if (*p == '\177') /* End-of-volume-descriptor marker. */
break;
}
/* We didn't find a valid PVD; return a bid of zero. */
- iso9660->bid = 0;
- return (iso9660->bid);
+ return (0);
}
static int
diff --git a/archivers/libarchive/files/libarchive/archive_read_support_format_mtree.c b/archivers/libarchive/files/libarchive/archive_read_support_format_mtree.c
index 6b6ca925930..e6ac99f6bfb 100644
--- a/archivers/libarchive/files/libarchive/archive_read_support_format_mtree.c
+++ b/archivers/libarchive/files/libarchive/archive_read_support_format_mtree.c
@@ -65,7 +65,6 @@ struct mtree {
char *buff;
off_t offset;
int fd;
- int bid;
int filetype;
int archive_format;
const char *archive_format_name;
@@ -75,8 +74,8 @@ struct mtree {
struct archive_string contents_name;
};
-static int bid(struct archive_read *);
static int cleanup(struct archive_read *);
+static int mtree_bid(struct archive_read *);
static void parse_escapes(char *, struct mtree_entry *);
static int parse_setting(struct archive_read *, struct mtree *,
struct archive_entry *, char *, char *);
@@ -103,11 +102,10 @@ archive_read_support_format_mtree(struct archive *_a)
return (ARCHIVE_FATAL);
}
memset(mtree, 0, sizeof(*mtree));
- mtree->bid = -1;
mtree->fd = -1;
r = __archive_read_register_format(a, mtree,
- bid, read_header, read_data, skip, cleanup);
+ mtree_bid, read_header, read_data, skip, cleanup);
if (r != ARCHIVE_OK)
free(mtree);
@@ -144,17 +142,16 @@ cleanup(struct archive_read *a)
static int
-bid(struct archive_read *a)
+mtree_bid(struct archive_read *a)
{
struct mtree *mtree;
ssize_t bytes_read;
const void *h;
const char *signature = "#mtree";
const char *p;
+ int bid;
mtree = (struct mtree *)(a->format->data);
- if (mtree->bid != -1)
- return (mtree->bid);
/* Now let's look at the actual header and see if it matches. */
bytes_read = (a->decompressor->read_ahead)(a, &h, strlen(signature));
@@ -163,16 +160,16 @@ bid(struct archive_read *a)
return (bytes_read);
p = h;
- mtree->bid = 0;
+ bid = 0;
while (bytes_read > 0 && *signature != '\0') {
if (*p != *signature)
- return (mtree->bid = 0);
- mtree->bid += 8;
+ return (bid = 0);
+ bid += 8;
p++;
signature++;
bytes_read--;
}
- return (mtree->bid);
+ return (bid);
}
/*
diff --git a/archivers/libarchive/files/libarchive/archive_read_support_format_tar.c b/archivers/libarchive/files/libarchive/archive_read_support_format_tar.c
index 5e7748eb1b4..6d6ee309571 100644
--- a/archivers/libarchive/files/libarchive/archive_read_support_format_tar.c
+++ b/archivers/libarchive/files/libarchive/archive_read_support_format_tar.c
@@ -24,7 +24,7 @@
*/
#include "archive_platform.h"
-__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_tar.c,v 1.61 2007/08/18 21:53:25 kientzle Exp $");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_tar.c,v 1.62 2007/10/24 04:01:31 kientzle Exp $");
#ifdef HAVE_ERRNO_H
#include <errno.h>
@@ -128,8 +128,8 @@ struct archive_entry_header_gnutar {
char isextended[1];
char realsize[12];
/*
- * GNU doesn't use POSIX 'prefix' field; they use the 'L' (longname)
- * entry instead.
+ * Old GNU format doesn't use POSIX 'prefix' field; they use
+ * the 'L' (longname) entry instead.
*/
};
@@ -318,23 +318,8 @@ archive_read_format_tar_bid(struct archive_read *a)
bytes_read = 0; /* Empty file. */
if (bytes_read < 0)
return (ARCHIVE_FATAL);
- if (bytes_read == 0 && bid > 0) {
- /* An archive without a proper end-of-archive marker. */
- /* Hold our nose and bid 1 anyway. */
- return (1);
- }
- if (bytes_read < 512) {
- /* If it's a new archive, then just return a zero bid. */
- if (bid == 0)
- return (0);
- /*
- * If we already know this is a tar archive,
- * then we have a problem.
- */
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Truncated tar archive");
- return (ARCHIVE_FATAL);
- }
+ if (bytes_read < 512)
+ return (0);
/* If it's an end-of-archive mark, we can handle it. */
if ((*(const char *)h) == 0 && archive_block_is_null((const unsigned char *)h)) {
@@ -440,6 +425,7 @@ archive_read_format_tar_read_header(struct archive_read *a,
free(sp);
}
tar->sparse_last = NULL;
+ tar->realsize = -1; /* Mark this as "unset" */
r = tar_read_header(a, tar, entry);
@@ -450,8 +436,6 @@ archive_read_format_tar_read_header(struct archive_read *a,
if (tar->sparse_list == NULL)
gnu_add_sparse_entry(tar, 0, tar->entry_bytes_remaining);
- tar->realsize = archive_entry_size(entry);
-
if (r == ARCHIVE_OK) {
/*
* "Regular" entry with trailing '/' is really
@@ -579,16 +563,24 @@ tar_read_header(struct archive_read *a, struct tar *tar,
/* Read 512-byte header record */
bytes = (a->decompressor->read_ahead)(a, &h, 512);
- if (bytes < 512) {
+ if (bytes < 0)
+ return (bytes);
+ if (bytes == 0) {
/*
- * If we're here, it's becase the _bid function accepted
- * this file. So just call a short read end-of-archive
- * and be done with it.
+ * An archive that just ends without a proper
+ * end-of-archive marker. Yes, there are tar programs
+ * that do this; hold our nose and accept it.
*/
return (ARCHIVE_EOF);
}
+ if (bytes < 512) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Truncated tar archive");
+ return (ARCHIVE_FATAL);
+ }
(a->decompressor->consume)(a, 512);
+
/* Check for end-of-archive mark. */
if (((*(const char *)h)==0) && archive_block_is_null((const unsigned char *)h)) {
/* Try to consume a second all-null record, as well. */
@@ -934,6 +926,7 @@ header_common(struct archive_read *a, struct tar *tar,
archive_entry_set_uid(entry, tar_atol(header->uid, sizeof(header->uid)));
archive_entry_set_gid(entry, tar_atol(header->gid, sizeof(header->gid)));
tar->entry_bytes_remaining = tar_atol(header->size, sizeof(header->size));
+ tar->realsize = tar->entry_bytes_remaining;
archive_entry_set_size(entry, tar->entry_bytes_remaining);
archive_entry_set_mtime(entry, tar_atol(header->mtime, sizeof(header->mtime)), 0);
@@ -1365,9 +1358,10 @@ pax_attribute(struct tar *tar, struct archive_entry *entry,
tar->sparse_numbytes = -1;
}
}
- if (wcscmp(key, L"GNU.sparse.size") == 0)
- archive_entry_set_size(entry,
- tar_atol10(value, wcslen(value)));
+ if (wcscmp(key, L"GNU.sparse.size") == 0) {
+ tar->realsize = tar_atol10(value, wcslen(value));
+ archive_entry_set_size(entry, tar->realsize);
+ }
/* GNU "0.1" sparse pax format. */
if (wcscmp(key, L"GNU.sparse.map") == 0) {
@@ -1388,9 +1382,10 @@ pax_attribute(struct tar *tar, struct archive_entry *entry,
}
if (wcscmp(key, L"GNU.sparse.name") == 0)
archive_entry_copy_pathname_w(entry, value);
- if (wcscmp(key, L"GNU.sparse.realsize") == 0)
- archive_entry_set_size(entry,
- tar_atol10(value, wcslen(value)));
+ if (wcscmp(key, L"GNU.sparse.realsize") == 0) {
+ tar->realsize = tar_atol10(value, wcslen(value));
+ archive_entry_set_size(entry, tar->realsize);
+ }
break;
case 'L':
/* Our extensions */
@@ -1422,6 +1417,10 @@ pax_attribute(struct tar *tar, struct archive_entry *entry,
archive_entry_set_ino(entry, tar_atol10(value, wcslen(value)));
else if (wcscmp(key, L"SCHILY.nlink")==0)
archive_entry_set_nlink(entry, tar_atol10(value, wcslen(value)));
+ else if (wcscmp(key, L"SCHILY.realsize")==0) {
+ tar->realsize = tar_atol10(value, wcslen(value));
+ archive_entry_set_size(entry, tar->realsize);
+ }
break;
case 'a':
if (wcscmp(key, L"atime")==0) {
@@ -1471,11 +1470,24 @@ pax_attribute(struct tar *tar, struct archive_entry *entry,
/* POSIX has reserved 'security.*' */
/* Someday: if (wcscmp(key, L"security.acl")==0) { ... } */
if (wcscmp(key, L"size")==0) {
- tar->entry_bytes_remaining = tar_atol10(value, wcslen(value));
- archive_entry_set_size(entry, tar->entry_bytes_remaining);
+ /* "size" is the size of the data in the entry. */
+ tar->entry_bytes_remaining
+ = tar_atol10(value, wcslen(value));
+ /*
+ * But, "size" is not necessarily the size of
+ * the file on disk; if this is a sparse file,
+ * the disk size may have already been set from
+ * GNU.sparse.realsize or GNU.sparse.size or
+ * an old GNU header field or SCHILY.realsize
+ * or ....
+ */
+ if (tar->realsize < 0) {
+ archive_entry_set_size(entry,
+ tar->entry_bytes_remaining);
+ tar->realsize
+ = tar->entry_bytes_remaining;
+ }
}
- tar->entry_bytes_remaining = 0;
-
break;
case 'u':
if (wcscmp(key, L"uid")==0)
@@ -1594,8 +1606,9 @@ header_gnutar(struct archive_read *a, struct tar *tar,
archive_entry_set_ctime(entry,
tar_atol(header->ctime, sizeof(header->ctime)), 0);
if (header->realsize[0] != 0) {
- archive_entry_set_size(entry,
- tar_atol(header->realsize, sizeof(header->realsize)));
+ tar->realsize
+ = tar_atol(header->realsize, sizeof(header->realsize));
+ archive_entry_set_size(entry, tar->realsize);
}
if (header->sparse[0].offset[0] != 0) {
diff --git a/archivers/libarchive/files/libarchive/archive_read_support_format_zip.c b/archivers/libarchive/files/libarchive/archive_read_support_format_zip.c
index 0d8df370e35..f5d97adb064 100644
--- a/archivers/libarchive/files/libarchive/archive_read_support_format_zip.c
+++ b/archivers/libarchive/files/libarchive/archive_read_support_format_zip.c
@@ -24,7 +24,7 @@
*/
#include "archive_platform.h"
-__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_zip.c,v 1.14 2007/07/15 19:13:59 kientzle Exp $");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_zip.c,v 1.15 2007/10/12 04:08:28 kientzle Exp $");
#ifdef HAVE_ERRNO_H
#include <errno.h>
@@ -179,18 +179,19 @@ archive_read_format_zip_bid(struct archive_read *a)
return (-1);
p = (const char *)h;
+ /*
+ * Bid of 30 here is: 16 bits for "PK",
+ * next 16-bit field has four options (-2 bits).
+ * 16 + 16-2 = 30.
+ */
if (p[0] == 'P' && p[1] == 'K') {
- bid += 16;
- if (p[2] == '\001' && p[3] == '\002')
- bid += 16;
- else if (p[2] == '\003' && p[3] == '\004')
- bid += 16;
- else if (p[2] == '\005' && p[3] == '\006')
- bid += 16;
- else if (p[2] == '\007' && p[3] == '\010')
- bid += 16;
+ if ((p[2] == '\001' && p[3] == '\002')
+ || (p[2] == '\003' && p[3] == '\004')
+ || (p[2] == '\005' && p[3] == '\006')
+ || (p[2] == '\007' && p[3] == '\010'))
+ return (30);
}
- return (bid);
+ return (0);
}
static int
@@ -335,6 +336,10 @@ zip_read_file_header(struct archive_read *a, struct archive_entry *entry,
zip->entry_bytes_remaining = zip->compressed_size;
zip->entry_offset = 0;
+ /* If there's no body, force read_data() to return EOF immediately. */
+ if (zip->entry_bytes_remaining < 1)
+ zip->end_of_entry = 1;
+
/* Set up a more descriptive format name. */
sprintf(zip->format_name, "ZIP %d.%d (%s)",
zip->version / 10, zip->version % 10,
@@ -422,6 +427,9 @@ archive_read_format_zip_read_data(struct archive_read *a,
/* End-of-entry cleanup done. */
zip->end_of_entry_cleanup = 1;
}
+ *offset = zip->entry_uncompressed_bytes_read;
+ *size = 0;
+ *buff = NULL;
return (ARCHIVE_EOF);
}
diff --git a/archivers/libarchive/files/libarchive/archive_util.c b/archivers/libarchive/files/libarchive/archive_util.c
index d73366357d0..2bc2844abcb 100644
--- a/archivers/libarchive/files/libarchive/archive_util.c
+++ b/archivers/libarchive/files/libarchive/archive_util.c
@@ -60,7 +60,7 @@ archive_version_stamp(void)
const char *
archive_version(void)
{
- return (PACKAGE_NAME " " PACKAGE_VERSION);
+ return (ARCHIVE_LIBRARY_VERSION);
}
int
diff --git a/archivers/libarchive/files/libarchive/archive_write_disk.c b/archivers/libarchive/files/libarchive/archive_write_disk.c
index e3b3a328cc6..ec220869074 100644
--- a/archivers/libarchive/files/libarchive/archive_write_disk.c
+++ b/archivers/libarchive/files/libarchive/archive_write_disk.c
@@ -25,7 +25,7 @@
*/
#include "archive_platform.h"
-__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_disk.c,v 1.14 2007/08/12 17:35:05 kientzle Exp $");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_disk.c,v 1.17 2007/09/21 04:52:42 kientzle Exp $");
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
@@ -421,6 +421,12 @@ _archive_write_header(struct archive *_a, struct archive_entry *entry)
/* We've created the object and are ready to pour data into it. */
if (ret == ARCHIVE_OK)
a->archive.state = ARCHIVE_STATE_DATA;
+ /*
+ * If it's not open, tell our client not to try writing.
+ * In particular, dirs, links, etc, don't get written to.
+ */
+ if (a->fd < 0)
+ archive_entry_set_size(entry, 0);
done:
/* Restore the user's umask before returning. */
umask(a->user_umask);
@@ -448,8 +454,10 @@ _archive_write_data_block(struct archive *_a,
__archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
ARCHIVE_STATE_DATA, "archive_write_disk_block");
- if (a->fd < 0)
- return (ARCHIVE_OK);
+ if (a->fd < 0) {
+ archive_set_error(&a->archive, 0, "File not open");
+ return (ARCHIVE_WARN);
+ }
archive_clear_error(&a->archive);
/* Seek if necessary to the specified offset. */
@@ -478,12 +486,17 @@ static ssize_t
_archive_write_data(struct archive *_a, const void *buff, size_t size)
{
struct archive_write_disk *a = (struct archive_write_disk *)_a;
+ int r;
+
__archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
ARCHIVE_STATE_DATA, "archive_write_data");
if (a->fd < 0)
return (ARCHIVE_OK);
- return (_archive_write_data_block(_a, buff, size, a->offset));
+ r = _archive_write_data_block(_a, buff, size, a->offset);
+ if (r < ARCHIVE_OK)
+ return (r);
+ return (size);
}
static int
diff --git a/archivers/libarchive/files/libarchive/archive_write_set_compression_none.c b/archivers/libarchive/files/libarchive/archive_write_set_compression_none.c
index 0ad962a5007..bb8555ef4eb 100644
--- a/archivers/libarchive/files/libarchive/archive_write_set_compression_none.c
+++ b/archivers/libarchive/files/libarchive/archive_write_set_compression_none.c
@@ -151,11 +151,18 @@ archive_compressor_none_write(struct archive_write *a, const void *vbuff,
return (ARCHIVE_OK);
}
- while ((remaining > 0) || (state->avail == 0)) {
- /*
- * If we have a full output block, write it and reset the
- * output buffer.
- */
+ /* If the copy buffer isn't empty, try to fill it. */
+ if (state->avail < state->buffer_size) {
+ /* If buffer is not empty... */
+ /* ... copy data into buffer ... */
+ to_copy = (remaining > state->avail) ?
+ state->avail : remaining;
+ memcpy(state->next, buff, to_copy);
+ state->next += to_copy;
+ state->avail -= to_copy;
+ buff += to_copy;
+ remaining -= to_copy;
+ /* ... if it's full, write it out. */
if (state->avail == 0) {
bytes_written = (a->client_writer)(&a->archive,
a->client_data, state->buffer, state->buffer_size);
@@ -166,16 +173,26 @@ archive_compressor_none_write(struct archive_write *a, const void *vbuff,
state->next = state->buffer;
state->avail = state->buffer_size;
}
+ }
- /* Now we have space in the buffer; copy new data into it. */
- to_copy = (remaining > state->avail) ?
- state->avail : remaining;
- memcpy(state->next, buff, to_copy);
- state->next += to_copy;
- state->avail -= to_copy;
- buff += to_copy;
- remaining -= to_copy;
+ while (remaining > state->buffer_size) {
+ /* Write out full blocks directly to client. */
+ bytes_written = (a->client_writer)(&a->archive,
+ a->client_data, buff, state->buffer_size);
+ if (bytes_written <= 0)
+ return (ARCHIVE_FATAL);
+ a->archive.raw_position += bytes_written;
+ buff += bytes_written;
+ remaining -= bytes_written;
}
+
+ if (remaining > 0) {
+ /* Copy last bit into copy buffer. */
+ memcpy(state->next, buff, remaining);
+ state->next += remaining;
+ state->avail -= remaining;
+ }
+
a->archive.file_position += length;
return (ARCHIVE_OK);
}
diff --git a/archivers/libarchive/files/libarchive/archive_write_set_format_cpio.c b/archivers/libarchive/files/libarchive/archive_write_set_format_cpio.c
index 6459477e420..c8a6a7ac5ec 100644
--- a/archivers/libarchive/files/libarchive/archive_write_set_format_cpio.c
+++ b/archivers/libarchive/files/libarchive/archive_write_set_format_cpio.c
@@ -24,7 +24,7 @@
*/
#include "archive_platform.h"
-__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_format_cpio.c,v 1.11 2007/05/29 01:00:19 kientzle Exp $");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_format_cpio.c,v 1.12 2007/10/12 04:11:31 kientzle Exp $");
#ifdef HAVE_ERRNO_H
#include <errno.h>
@@ -142,12 +142,17 @@ archive_write_cpio_header(struct archive_write *a, struct archive_entry *entry)
format_octal(archive_entry_mtime(entry), &h.c_mtime, sizeof(h.c_mtime));
format_octal(pathlength, &h.c_namesize, sizeof(h.c_namesize));
+ /* Non-regular files don't store bodies. */
+ if (archive_entry_filetype(entry) != AE_IFREG)
+ archive_entry_set_size(entry, 0);
+
/* Symlinks get the link written as the body of the entry. */
p = archive_entry_symlink(entry);
if (p != NULL && *p != '\0')
format_octal(strlen(p), &h.c_filesize, sizeof(h.c_filesize));
else
- format_octal(archive_entry_size(entry), &h.c_filesize, sizeof(h.c_filesize));
+ format_octal(archive_entry_size(entry),
+ &h.c_filesize, sizeof(h.c_filesize));
ret = (a->compressor.write)(a, &h, sizeof(h));
if (ret != ARCHIVE_OK)
@@ -223,6 +228,7 @@ archive_write_cpio_finish(struct archive_write *a)
cpio = (struct cpio *)a->format_data;
trailer = archive_entry_new();
+ /* nlink = 1 here for GNU cpio compat. */
archive_entry_set_nlink(trailer, 1);
archive_entry_set_pathname(trailer, "TRAILER!!!");
er = archive_write_cpio_header(a, trailer);
diff --git a/archivers/libarchive/files/libarchive/archive_write_set_format_cpio_newc.c b/archivers/libarchive/files/libarchive/archive_write_set_format_cpio_newc.c
index ab48d380043..e50544b45f3 100644
--- a/archivers/libarchive/files/libarchive/archive_write_set_format_cpio_newc.c
+++ b/archivers/libarchive/files/libarchive/archive_write_set_format_cpio_newc.c
@@ -25,7 +25,7 @@
*/
#include "archive_platform.h"
-__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_format_cpio_newc.c,v 1.1 2007/06/22 05:47:00 kientzle Exp $");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_format_cpio_newc.c,v 1.2 2007/10/12 04:11:31 kientzle Exp $");
#ifdef HAVE_ERRNO_H
#include <errno.h>
@@ -148,12 +148,17 @@ archive_write_newc_header(struct archive_write *a, struct archive_entry *entry)
format_hex(pathlength, &h.c_namesize, sizeof(h.c_namesize));
format_hex(0, &h.c_checksum, sizeof(h.c_checksum));
+ /* Non-regular files don't store bodies. */
+ if (archive_entry_filetype(entry) != AE_IFREG)
+ archive_entry_set_size(entry, 0);
+
/* Symlinks get the link written as the body of the entry. */
p = archive_entry_symlink(entry);
if (p != NULL && *p != '\0')
format_hex(strlen(p), &h.c_filesize, sizeof(h.c_filesize));
else
- format_hex(archive_entry_size(entry), &h.c_filesize, sizeof(h.c_filesize));
+ format_hex(archive_entry_size(entry),
+ &h.c_filesize, sizeof(h.c_filesize));
ret = (a->compressor.write)(a, &h, sizeof(h));
if (ret != ARCHIVE_OK)
diff --git a/archivers/libarchive/files/libarchive/archive_write_set_format_pax.c b/archivers/libarchive/files/libarchive/archive_write_set_format_pax.c
index 471feb8307e..cedbfd75c96 100644
--- a/archivers/libarchive/files/libarchive/archive_write_set_format_pax.c
+++ b/archivers/libarchive/files/libarchive/archive_write_set_format_pax.c
@@ -418,12 +418,15 @@ archive_write_pax_header(struct archive_write *a,
p = archive_entry_pathname(entry_original);
if (p[strlen(p) - 1] != '/') {
t = (char *)malloc(strlen(p) + 2);
- if (t != NULL) {
- strcpy(t, p);
- strcat(t, "/");
- archive_entry_copy_pathname(entry_original, t);
- free(t);
+ if (t == NULL) {
+ archive_set_error(&a->archive, ENOMEM,
+ "Can't allocate pax data");
+ return(ARCHIVE_FATAL);
}
+ strcpy(t, p);
+ strcat(t, "/");
+ archive_entry_copy_pathname(entry_original, t);
+ free(t);
}
break;
default:
diff --git a/archivers/libarchive/files/libarchive/archive_write_set_format_ustar.c b/archivers/libarchive/files/libarchive/archive_write_set_format_ustar.c
index 61c90d50415..287afe0657c 100644
--- a/archivers/libarchive/files/libarchive/archive_write_set_format_ustar.c
+++ b/archivers/libarchive/files/libarchive/archive_write_set_format_ustar.c
@@ -216,12 +216,15 @@ archive_write_ustar_header(struct archive_write *a, struct archive_entry *entry)
p = archive_entry_pathname(entry);
if (p[strlen(p) - 1] != '/') {
t = (char *)malloc(strlen(p) + 2);
- if (t != NULL) {
- strcpy(t, p);
- strcat(t, "/");
- archive_entry_copy_pathname(entry, t);
- free(t);
+ if (t == NULL) {
+ archive_set_error(&a->archive, ENOMEM,
+ "Can't allocate ustar data");
+ return(ARCHIVE_FATAL);
}
+ strcpy(t, p);
+ strcat(t, "/");
+ archive_entry_copy_pathname(entry, t);
+ free(t);
}
}
diff --git a/archivers/libarchive/files/libarchive/config_windows.h b/archivers/libarchive/files/libarchive/config_windows.h
index 074bb3bdf85..fa55c8e306d 100644
--- a/archivers/libarchive/files/libarchive/config_windows.h
+++ b/archivers/libarchive/files/libarchive/config_windows.h
@@ -159,9 +159,6 @@ typedef _int64 intmax_t;
#define mkdir _mkdir
#define close _close
-#define PACKAGE_NAME "libarchive"
-#define PACKAGE_VERSION "2.0experimental"
-
/* TODO: Fix the code, don't suppress the warnings. */
#pragma warning(disable:4996)
#pragma warning(disable:4244)
diff --git a/archivers/libarchive/files/libarchive/cpio.5 b/archivers/libarchive/files/libarchive/cpio.5
new file mode 100644
index 00000000000..2f298332d18
--- /dev/null
+++ b/archivers/libarchive/files/libarchive/cpio.5
@@ -0,0 +1,325 @@
+.\" Copyright (c) 2007 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd October 5, 2007
+.Dt CPIO 5
+.Os
+.Sh NAME
+.Nm cpio
+.Nd format of cpio archive files
+.Sh DESCRIPTION
+The
+.Nm
+archive format collects any number of files, directories, and other
+file system objects (symbolic links, device nodes, etc.) into a single
+stream of bytes.
+.Ss General Format
+Each file system object in a
+.Nm
+archive comprises a header record with basic numeric metadata
+followed by the full pathname of the entry and the file data.
+The header record stores a series of integer values that generally
+follow the fields in
+.Va struct stat .
+(See
+.Xr stat 2
+for details.)
+The variants differ primarily in how they store those integers
+(binary, octal, or hexadecimal).
+The header is followed by the pathname of the
+entry (the length of the pathname is stored in the header)
+and any file data.
+The end of the archive is indicated by a special record with
+the pathname
+.Dq TRAILER!!! .
+.Ss PWB format
+XXX Any documentation of the original PWB/UNIX 1.0 format? XXX
+.Ss Old Binary Format
+The old binary
+.Nm
+format stores numbers as 2-byte and 4-byte binary values.
+Each entry begins with a header in the following format:
+.Bd -literal -offset indent
+struct header_old_cpio {
+ unsigned short c_magic;
+ unsigned short c_dev;
+ unsigned short c_ino;
+ unsigned short c_mode;
+ unsigned short c_uid;
+ unsigned short c_gid;
+ unsigned short c_nlink;
+ unsigned short c_rdev;
+ unsigned short c_mtime[2];
+ unsigned short c_namesize;
+ unsigned short c_filesize[2];
+};
+.Ed
+.Pp
+The
+.Va unsigned short
+fields here are 16-bit integer values; the
+.Va unsigned int
+fields are 32-bit integer values.
+The fields are as follows
+.Bl -tag -width indent
+.It Va magic
+The integer value octal 070707.
+This value can be used to determine whether this archive is
+written with little-endian or big-endian integers.
+.It Va dev , Va ino
+The device and inode numbers from the disk.
+These are used by programs that read
+.Nm
+archives to determine when two entries refer to the same file.
+Programs that synthesize
+.Nm
+archives should be careful to set these to distinct values for each entry.
+.It Va mode
+The mode specifies both the regular permissions and the file type.
+It consists of several bit fields as follows:
+.Bl -tag -width "MMMMMMM" -compact
+.It 0170000
+This masks the file type bits.
+.It 0140000
+File type value for sockets.
+.It 0120000
+File type value for symbolic links.
+For symbolic links, the link body is stored as file data.
+.It 0100000
+File type value for regular files.
+.It 0060000
+File type value for block special devices.
+.It 0040000
+File type value for directories.
+.It 0020000
+File type value for character special devices.
+.It 0010000
+File type value for named pipes or FIFOs.
+.It 0004000
+SUID bit.
+.It 0002000
+SGID bit.
+.It 0001000
+Sticky bit.
+On some systems, this modifies the behavior of executables and/or directories.
+.It 0000777
+The lower 9 bits specify read/write/execute permissions
+for world, group, and user following standard POSIX conventions.
+.El
+.It Va uid , Va gid
+The numeric user id and group id of the owner.
+.It Va nlink
+The number of links to this file.
+Directories always have a value of at least two here.
+Note that hardlinked files include file data with every copy in the archive.
+.It Va rdev
+For block special and character special entries,
+this field contains the associated device number.
+For all other entry types, it should be set to zero by writers
+and ignored by readers.
+.It Va mtime
+Modification time of the file, indicated as the number
+of seconds since the start of the epoch,
+00:00:00 UTC January 1, 1970.
+The four-byte integer is stored with the most-significant 16 bits first
+followed by the least-significant 16 bits.
+Each of the two 16 bit values are stored in machine-native byte order.
+.It Va namesize
+The number of bytes in the pathname that follows the header.
+This count includes the trailing NULL byte.
+.It Va filesize
+The size of the file.
+Note that this archive format is limited to
+four gigabyte file sizes.
+See
+.Va mtime
+above for a description of the storage of four-byte integers.
+.El
+.Pp
+The pathname immediately follows the fixed header.
+If the
+.Cm namesize
+is odd, an additional NULL byte is added after the pathname.
+The file data is then appended, padded with NULL
+bytes to an even length.
+.Pp
+Hardlinked files are not given special treatment;
+the full file contents are included with each copy of the
+file.
+.Ss Portable ASCII Format
+.St -susv2
+standardized an ASCII variant that is portable across all
+platforms.
+It is commonly known as the
+.Dq old character
+format or as the
+.Dq odc
+format.
+It stores the same numeric fields as the old binary format, but
+represents them as 6-character or 11-character octal values.
+.Bd -literal -offset indent
+struct cpio_odc_header {
+ char c_magic[6];
+ char c_dev[6];
+ char c_ino[6];
+ char c_mode[6];
+ char c_uid[6];
+ char c_gid[6];
+ char c_nlink[6];
+ char c_rdev[6];
+ char c_mtime[11];
+ char c_namesize[6];
+ char c_filesize[11];
+};
+.Ed
+.Pp
+The fields are identical to those in the old binary format.
+The name and file body follow the fixed header.
+Unlike the old binary format, there is no additional padding
+after the pathname or file contents.
+If the files being archived are themselves entirely ASCII, then
+the resulting archive will be entirely ASCII, except for the
+NULL byte that terminates the name field.
+.Ss New ASCII Format
+The "new" ASCII format uses 8-byte hexadecimal fields for
+all numbers and separates device numbers into separate fields
+for major and minor numbers.
+.Bd -literal -offset indent
+struct cpio_newc_header {
+ char c_magic[6];
+ char c_ino[8];
+ char c_mode[8];
+ char c_uid[8];
+ char c_gid[8];
+ char c_nlink[8];
+ char c_mtime[8];
+ char c_filesize[8];
+ char c_devmajor[8];
+ char c_devminor[8];
+ char c_rdevmajor[8];
+ char c_rdevminor[8];
+ char c_namesize[8];
+ char c_check[8];
+};
+.Ed
+.Pp
+Except as specified below, the fields here match those specified
+for the old binary format above.
+.Bl -tag -width indent
+.It Va magic
+The string
+.Dq 070701 .
+.It Va check
+This field is always set to zero by writers and ignored by readers.
+See the next section for more details.
+.El
+.Pp
+The pathname is followed by NULL bytes so that the total size
+of the fixed header plus pathname is a multiple of four.
+Likewise, the file data is padded to a multiple of four bytes.
+Note that this format supports only 4 gigabyte files (unlike the
+older ASCII format, which supports 8 gigabyte files).
+.Pp
+In this format, hardlinked files are handled by setting the
+filesize to zero for each entry except the last one that
+appears in the archive.
+.Ss New CRC Format
+The CRC format is identical to the new ASCII format described
+in the previous section except that the magic field is set
+to
+.Dq 070702
+and the
+.Va check
+field is set to the sum of all bytes in the file data.
+This sum is computed treating all bytes as unsigned values
+and using unsigned arithmetic.
+Only the least-significant 32 bits of the sum are stored.
+.Ss HP variants
+The
+.Nm cpio
+implementation distributed with HPUX used XXXX but stored
+device numbers differently XXX.
+.Ss Other Extensions and Variants
+Sun Solaris uses additional file types to store extended file
+data, including ACLs and extended attributes, as special
+entries in cpio archives.
+.Pp
+XXX Others? XXX
+.Sh BUGS
+The
+.Dq CRC
+format is mis-named, as it uses a simple checksum and
+not a cyclic redundancy check.
+.Pp
+The old binary format is limited to 16 bits for user id,
+group id, device, and inode numbers.
+It is limited to 4 gigabyte file sizes.
+.Pp
+The old ASCII format is limited to 18 bits for
+the user id, group id, device, and inode numbers.
+It is limited to 8 gigabyte file sizes.
+.Pp
+The new ASCII format is limited to 4 gigabyte file sizes.
+.Pp
+None of the cpio formats store user or group names,
+which are essential when moving files between systems with
+dissimilar user or group numbering.
+.Pp
+Especially when writing older cpio variants, it may be necessary
+to map actual device/inode values to synthesized values that
+fit the available fields.
+With very large filesystems, this may be necessary even for
+the newer formats.
+.Sh SEE ALSO
+.Xr cpio 1 ,
+.Xr tar 5
+.Sh STANDARDS
+The
+.Nm cpio
+utility is no longer a part of POSIX or the Single Unix Standard.
+It last appeared in
+.St -susv2 .
+It has been supplanted in subsequent standards by
+.Xr pax 1 .
+The portable ASCII format is currently part of the specification for the
+.Xr pax 1
+utility.
+.Sh HISTORY
+The original cpio utility was written by Dick Haight
+while working in AT&T's Unix Support Group.
+It appeared in 1977 as part of PWB/UNIX 1.0, the
+.Dq Programmer's Work Bench
+derived from
+.At v6
+that was used internally at AT&T.
+Both the old binary and old character formats were in use
+by 1980, according to the System III source released
+by SCO under their
+.Dq Ancient Unix
+license.
+The character format was adopted as part of
+.St -p1003.1-88 .
+XXX when did "newc" appear? Who invented it? When did HP come out with their variant? When did Sun introduce ACLs and extended attributes? XXX \ No newline at end of file
diff --git a/archivers/libarchive/files/libarchive/libarchive-formats.5 b/archivers/libarchive/files/libarchive/libarchive-formats.5
index cd34622b2c5..0606a5ba1d0 100644
--- a/archivers/libarchive/files/libarchive/libarchive-formats.5
+++ b/archivers/libarchive/files/libarchive/libarchive-formats.5
@@ -74,6 +74,8 @@ It currently supports the most popular GNU extensions, including
modern long filename and linkname support, as well as atime and ctime data.
The libarchive library does not support multi-volume
archives, nor the old GNU long filename format.
+It can read GNU sparse file entries, including the new POSIX-based
+formats, but cannot write GNU sparse file entries.
.It Cm pax
The
.Xr libarchive 3
@@ -93,7 +95,7 @@ defined by Joerg Schilling's
.Dq star
archiver.
The libarchive library can read most of the SCHILY keys.
-It ignores any keywords that it does not understand.
+It silently ignores any keywords that it does not understand.
.It Cm restricted pax
The libarchive library can also write pax archives in which it
attempts to suppress the extended attributes entry whenever
@@ -139,19 +141,18 @@ In particular, it supports base-256 values in certain numeric fields.
This essentially removes the limitations on file size, modification time,
and device numbers.
.Pp
-The first tar program appeared in Sixth Edition Unix (circa 1976).
-This makes the tar format one of the oldest and most widely-supported
-archive formats.
+The first tar program appeared in Seventh Edition Unix in 1979.
The first official standard for the tar file format was the
.Dq ustar
(Unix Standard Tar) format defined by POSIX in 1988.
POSIX.1-2001 extended the ustar format to create the
.Dq pax interchange
format.
-There have also been many custom variations.
.Ss Cpio Formats
The libarchive library can read a number of common cpio variants and can write
.Dq odc
+and
+.Dq newc
format archives.
A cpio archive stores each entry as a fixed-size header followed
by a variable-length filename and variable-length data.
@@ -184,15 +185,26 @@ The SVR4 format can optionally include a CRC of the file
contents, although libarchive does not currently verify this CRC.
.El
.Pp
-Cpio is an old format that was widely used because of its simplicity
-and its support for very long filenames.
-Unfortunately, it has many limitations that make it unsuitable
+Cpio first appeared in PWB/UNIX 1.0, which was released within
+AT&T in 1977.
+PWB/UNIX 1.0 formed the basis of System III Unix, released outside
+of AT&T in 1981.
+This makes cpio older than tar, although cpio was not included
+in Version 7 AT&T Unix.
+As a result, the tar command became much better known in universities
+and research groups that used Version 7.
+The combination of the
+.Nm find
+and
+.Nm cpio
+utilities provided very precise control over file selection.
+Unfortunately, the format has many limitations that make it unsuitable
for widespread use.
Only the POSIX format permits files over 4GB, and its 18-bit
limit for most other fields makes it unsuitable for modern systems.
In addition, cpio formats only store numeric UID/GID values (not
usernames and group names), which can make it very difficult to correctly
-transfer archives across systems.
+transfer archives across systems with dissimilar user numbering.
.Ss Shar Formats
A
.Dq shell archive
@@ -255,4 +267,6 @@ Libarchive provides read and write support for both variants.
.Xr tar 1 ,
.Xr zip 1 ,
.Xr zlib 3 ,
+.Xr cpio 5 ,
+.Xr mtree 5 ,
.Xr tar 5
diff --git a/archivers/libarchive/files/libarchive/libarchive_internals.3 b/archivers/libarchive/files/libarchive/libarchive_internals.3
index 1161f65fb4e..a84c9406d34 100644
--- a/archivers/libarchive/files/libarchive/libarchive_internals.3
+++ b/archivers/libarchive/files/libarchive/libarchive_internals.3
@@ -96,12 +96,9 @@ When opening the archive, it reads an initial block of data
and offers it to each registered compression handler.
The one with the highest bid is initialized with the first block.
Similarly, the format handlers are polled to see which handler
-is the best for each header request.
-(Note that a single file can have entries handled by different
-format handlers;
-this allows a simple handler for a generic version of a format
-with more complex handlers implemented independently for
-extended sub-formats.)
+is the best for each archive.
+(Prior to 2.4.0, the format bidders were invoked for each
+entry, but this design hindered error recovery.)
.Ss I/O Layer and Client Callbacks
The read API goes to some lengths to be nice to clients.
As a result, there are few restrictions on the behavior of
@@ -116,6 +113,8 @@ In particular, blocks may be of different sizes.
The client skip callback returns the number of bytes actually
skipped, which may be much smaller than the skip requested.
The only requirement is that the skip not be larger.
+In particular, clients are allowed to return zero for any
+skip that they don't want to handle.
The skip callback must never be invoked with a negative value.
.Pp
Keep in mind that not all clients are reading from disk:
@@ -242,21 +241,12 @@ decompression method but not calling the
method.
This allows each bidder to look ahead in the input stream.
Bidders should not look further ahead than necessary, as long
-look aheads put pressure on the compression layer to buffer
+look aheads put pressure on the decompression layer to buffer
lots of data.
Most formats only require a few hundred bytes of look ahead;
look aheads of a few kilobytes are reasonable.
(The ISO9660 reader sometimes looks ahead by 48k, which
should be considered an upper limit.)
-Note that the bidder is invoked for every entry.
-For many formats, this is inappropriate; if you can only bid at
-the beginning of the file, store your bid value and check that
-each time your bid function is called.
-For example, the ISO9660 reader initializes a
-.Va bid
-value to -1 at registration time;
-each time the bid function is called, the bid value is returned
-immediately if it is zero or larger.
.It Read header
The header read is usually the most complex part of any format.
There are a few strategies worth mentioning:
diff --git a/archivers/libarchive/files/libarchive/mtree.5 b/archivers/libarchive/files/libarchive/mtree.5
new file mode 100644
index 00000000000..613de6a5dae
--- /dev/null
+++ b/archivers/libarchive/files/libarchive/mtree.5
@@ -0,0 +1,270 @@
+.\" Copyright (c) 1989, 1990, 1993
+.\" The Regents of the University of California. 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.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+.\"
+.\" From: @(#)mtree.8 8.2 (Berkeley) 12/11/93
+.\" $FreeBSD$
+.\"
+.Dd August 20, 2007
+.Dt MTREE 5
+.Os
+.Sh NAME
+.Nm mtree
+.Nd format of mtree dir heirarchy files
+.Sh DESCRIPTION
+The
+.Nm
+format is a textual format that describes a collection of filesystem objects.
+Such files are typically used to create or verify directory heirarchies.
+.Ss General Format
+An
+.Nm
+file consists of a series of lines, each providing information
+about a single filesystem object.
+Leading whitespace is always ignored.
+.Pp
+When encoding file or pathnames, any backslash character or
+character outside of the 95 printable ASCII characters must be
+encoded as a a backslash followed by three
+octal digits.
+When reading mtree files, any appearance of a backslash
+followed by three octal digits should be converted into the
+corresponding character.
+.Pp
+Each line is interpreted independently as one of the following types:
+.Bl -tag -width Cm
+.It Signature
+The first line of any mtree file must begin with
+.Dq #mtree .
+If a file contains any full path entries, the first line should
+begin with
+.Dq #mtree v2.0 ,
+otherwise, the first line should begin with
+.Dq #mtree v1.0 .
+.It Blank
+Blank lines are ignored.
+.It Comment
+Lines beginning with
+.Cm #
+are ignored.
+.It Special
+Lines beginning with
+.Cm /
+are special commands that influence
+the interpretation of later lines.
+.It Relative
+If the first whitespace-delimited word has no
+.Cm /
+characters,
+it is the name of a file in the current directory.
+Any relative entry that describes a directory changes the
+current directory.
+.It dot-dot
+As a special case, a relative entry with the filename
+.Pa ..
+changes the current directory to the parent directory.
+Options on dot-dot entries are always ignored.
+.It Full
+If the first whitespace-delimited word has a
+.Cm /
+character after
+the first character, it is the pathname of a file relative to the
+starting directory.
+There can be multiple full entries describing the same file.
+.El
+.Pp
+Some tools that process
+.Nm
+files may require that multiple lines describing the same file
+occur consecutively.
+It is not permitted for the same file to be mentioned using
+both a relative and a full file specification.
+.Ss Special commands
+Two special commands are currently defined:
+.Bl -tag -width Cm
+.It Cm /set
+This command defines default values for one or more keywords.
+It is followed on the same line by one or more whitespace-separated
+keyword definitions.
+These definitions apply to all following files that do not specify
+a value for that keyword.
+.It Cm /unset
+This command removes any default value set by a previous
+.Cm /set
+command.
+It is followed on the same line by one or more keywords
+separated by whitespace.
+.El
+.Ss Keywords
+After the filename, a full or relative entry consists of zero
+or more whitespace-separated keyword definitions.
+Each such definitions consists of a key from the following
+list immediately followed by an '=' sign
+and a value.
+Software programs reading mtree files should warn about
+unrecognized keywords.
+.Pp
+Currently supported keywords are as follows:
+.Bl -tag -width Cm
+.It Cm cksum
+The checksum of the file using the default algorithm specified by
+the
+.Xr cksum 1
+utility.
+.It Cm contents
+The full pathname of a file whose contents should be
+compared to the contents of this file.
+.It Cm flags
+The file flags as a symbolic name.
+See
+.Xr chflags 1
+for information on these names.
+If no flags are to be set the string
+.Dq none
+may be used to override the current default.
+.It Cm ignore
+Ignore any file hierarchy below this file.
+.It Cm gid
+The file group as a numeric value.
+.It Cm gname
+The file group as a symbolic name.
+.It Cm md5
+The MD5 message digest of the file.
+.It Cm md5digest
+A synonym for
+.Cm md5 .
+.It Cm sha1
+The
+.Tn FIPS
+160-1
+.Pq Dq Tn SHA-1
+message digest of the file.
+.It Cm sha1digest
+A synonym for
+.Cm sha1 .
+.It Cm sha256
+The
+.Tn FIPS
+180-2
+.Pq Dq Tn SHA-256
+message digest of the file.
+.It Cm sha256digest
+A synonym for
+.Cm sha256 .
+.It Cm ripemd160digest
+The
+.Tn RIPEMD160
+message digest of the file.
+.It Cm rmd160
+A synonym for
+.Cm ripemd160digest .
+.It Cm rmd160digest
+A synonym for
+.Cm ripemd160digest .
+.It Cm mode
+The current file's permissions as a numeric (octal) or symbolic
+value.
+.It Cm nlink
+The number of hard links the file is expected to have.
+.It Cm nochange
+Make sure this file or directory exists but otherwise ignore all attributes.
+.It Cm uid
+The file owner as a numeric value.
+.It Cm uname
+The file owner as a symbolic name.
+.It Cm size
+The size, in bytes, of the file.
+.It Cm link
+The file the symbolic link is expected to reference.
+.It Cm time
+The last modification time of the file.
+.It Cm type
+The type of the file; may be set to any one of the following:
+.Pp
+.Bl -tag -width Cm -compact
+.It Cm block
+block special device
+.It Cm char
+character special device
+.It Cm dir
+directory
+.It Cm fifo
+fifo
+.It Cm file
+regular file
+.It Cm link
+symbolic link
+.It Cm socket
+socket
+.El
+.El
+.Pp
+.Sh SEE ALSO
+.Xr cksum 1 ,
+.Xr find 1 ,
+.Xr mtree 8
+.Sh BUGS
+The
+.Fx
+implementation of mtree does not currently support
+the
+.Nm
+2.0
+format.
+The requirement for a
+.Dq #mtree
+signature line is new and not yet widely implemented.
+.Sh HISTORY
+The
+.Nm
+utility appeared in
+.Bx 4.3 Reno .
+The
+.Tn MD5
+digest capability was added in
+.Fx 2.1 ,
+in response to the widespread use of programs which can spoof
+.Xr cksum 1 .
+The
+.Tn SHA-1
+and
+.Tn RIPEMD160
+digests were added in
+.Fx 4.0 ,
+as new attacks have demonstrated weaknesses in
+.Tn MD5 .
+The
+.Tn SHA-256
+digest was added in
+.Fx 6.0 .
+Support for file flags was added in
+.Fx 4.0 ,
+and mostly comes from
+.Nx .
+The
+.Dq full
+entry format was added by
+.Nx .
diff --git a/archivers/libarchive/files/libarchive/test/list.h b/archivers/libarchive/files/libarchive/test/list.h
index 252651f2c09..0b221fcec97 100644
--- a/archivers/libarchive/files/libarchive/test/list.h
+++ b/archivers/libarchive/files/libarchive/test/list.h
@@ -3,6 +3,7 @@ DEFINE_TEST(test_acl_pax)
DEFINE_TEST(test_archive_api_feature)
DEFINE_TEST(test_bad_fd)
DEFINE_TEST(test_entry)
+DEFINE_TEST(test_entry_strmode)
DEFINE_TEST(test_read_compress_program)
DEFINE_TEST(test_read_data_large)
DEFINE_TEST(test_read_extract)
@@ -31,6 +32,7 @@ DEFINE_TEST(test_read_pax_truncated)
DEFINE_TEST(test_read_position)
DEFINE_TEST(test_read_truncated)
DEFINE_TEST(test_tar_filenames)
+DEFINE_TEST(test_tar_large)
DEFINE_TEST(test_write_compress_program)
DEFINE_TEST(test_write_disk)
DEFINE_TEST(test_write_disk_perms)
@@ -38,6 +40,8 @@ DEFINE_TEST(test_write_disk_secure)
DEFINE_TEST(test_write_format_ar)
DEFINE_TEST(test_write_format_cpio)
DEFINE_TEST(test_write_format_cpio_empty)
+DEFINE_TEST(test_write_format_cpio_newc)
+DEFINE_TEST(test_write_format_cpio_odc)
DEFINE_TEST(test_write_format_shar_empty)
DEFINE_TEST(test_write_format_tar)
DEFINE_TEST(test_write_format_tar_empty)
diff --git a/archivers/libarchive/files/libarchive/test/main.c b/archivers/libarchive/files/libarchive/test/main.c
index 9dd852ffa75..4585c2631db 100644
--- a/archivers/libarchive/files/libarchive/test/main.c
+++ b/archivers/libarchive/files/libarchive/test/main.c
@@ -34,6 +34,18 @@
#include "test.h"
__FBSDID("$FreeBSD: src/lib/libarchive/test/main.c,v 1.8 2007/07/31 05:03:27 kientzle Exp $");
+/*
+ * "list.h" is simply created by "grep DEFINE_TEST"; it has
+ * a line like
+ * DEFINE_TEST(test_function)
+ * for each test.
+ * Include it here with a suitable DEFINE_TEST to declare all of the
+ * test functions.
+ */
+#undef DEFINE_TEST
+#define DEFINE_TEST(name) void name(void);
+#include "list.h"
+
/* Interix doesn't define these in a standard header. */
#if __INTERIX__
extern char *optarg;
@@ -57,12 +69,10 @@ static int skips = 0;
* Emacs. ;-)
*
* It also supports a few special features specifically to simplify
- * libarchive test harnesses:
+ * test harnesses:
* failure(fmt, args) -- Stores a text string that gets
* printed if the following assertion fails, good for
* explaining subtle tests.
- * assertA(a, cond) -- If the test fails, also prints out any error
- * message stored in archive object 'a'.
*/
static char msg[4096];
@@ -77,11 +87,13 @@ static struct line {
} failed_lines[1000];
-/* Count this failure; return the number of previous failures. */
+/*
+ * Count this failure; return the number of previous failures.
+ */
static int
previous_failures(const char *filename, int line)
{
- int i;
+ unsigned int i;
int count;
if (failed_filename == NULL || strcmp(failed_filename, filename) != 0)
@@ -100,9 +112,12 @@ previous_failures(const char *filename, int line)
return (0);
}
}
+ return (0);
}
-/* Inform user that we're skipping a test. */
+/*
+ * Inform user that we're skipping a test.
+ */
static const char *skipped_filename;
static int skipped_line;
void skipping_setup(const char *filename, int line)
@@ -113,8 +128,6 @@ void skipping_setup(const char *filename, int line)
void
test_skipping(const char *fmt, ...)
{
- int i;
- int line = skipped_line;
va_list ap;
if (previous_failures(skipped_filename, skipped_line))
@@ -130,29 +143,30 @@ test_skipping(const char *fmt, ...)
/* Common handling of failed tests. */
static void
-test_failed(struct archive *a, int line)
+report_failure(void *extra)
{
- int i;
-
- failures ++;
-
if (msg[0] != '\0') {
fprintf(stderr, " Description: %s\n", msg);
msg[0] = '\0';
}
- if (a != NULL) {
- fprintf(stderr, " archive error: %s\n", archive_error_string(a));
+ if (extra != NULL) {
+ fprintf(stderr, " archive error: %s\n", archive_error_string((struct archive *)extra));
}
if (dump_on_failure) {
- fprintf(stderr, " *** forcing core dump so failure can be debugged ***\n");
+ fprintf(stderr,
+ " *** forcing core dump so failure can be debugged ***\n");
*(char *)(NULL) = 0;
exit(1);
}
}
-/* Summarize repeated failures in the just-completed test file. */
-int
+/*
+ * Summarize repeated failures in the just-completed test file.
+ * The reports above suppress multiple failures from the same source
+ * line; this reports on any tests that did fail multiple times.
+ */
+static int
summarize_comparator(const void *a0, const void *b0)
{
const struct line *a = a0, *b = b0;
@@ -165,10 +179,10 @@ summarize_comparator(const void *a0, const void *b0)
return (a->line - b->line);
}
-void
-summarize(const char *filename)
+static void
+summarize(void)
{
- int i;
+ unsigned int i;
qsort(failed_lines, sizeof(failed_lines)/sizeof(failed_lines[0]),
sizeof(failed_lines[0]), summarize_comparator);
@@ -196,35 +210,37 @@ failure(const char *fmt, ...)
/* Generic assert() just displays the failed condition. */
void
-test_assert(const char *file, int line, int value, const char *condition, struct archive *a)
+test_assert(const char *file, int line, int value, const char *condition, void *extra)
{
if (value) {
msg[0] = '\0';
return;
}
+ failures ++;
if (previous_failures(file, line))
return;
fprintf(stderr, "%s:%d: Assertion failed\n", file, line);
fprintf(stderr, " Condition: %s\n", condition);
- test_failed(a, line);
+ report_failure(extra);
}
/* assertEqualInt() displays the values of the two integers. */
void
test_assert_equal_int(const char *file, int line,
- int v1, const char *e1, int v2, const char *e2, struct archive *a)
+ int v1, const char *e1, int v2, const char *e2, void *extra)
{
if (v1 == v2) {
msg[0] = '\0';
return;
}
+ failures ++;
if (previous_failures(file, line))
return;
fprintf(stderr, "%s:%d: Assertion failed: Ints not equal\n",
file, line);
fprintf(stderr, " %s=%d\n", e1, v1);
fprintf(stderr, " %s=%d\n", e2, v2);
- test_failed(a, line);
+ report_failure(extra);
}
/* assertEqualString() displays the values of the two strings. */
@@ -232,7 +248,7 @@ void
test_assert_equal_string(const char *file, int line,
const char *v1, const char *e1,
const char *v2, const char *e2,
- struct archive *a)
+ void *extra)
{
if (v1 == NULL || v2 == NULL) {
if (v1 == v2) {
@@ -243,13 +259,14 @@ test_assert_equal_string(const char *file, int line,
msg[0] = '\0';
return;
}
+ failures ++;
if (previous_failures(file, line))
return;
fprintf(stderr, "%s:%d: Assertion failed: Strings not equal\n",
file, line);
fprintf(stderr, " %s = \"%s\"\n", e1, v1);
fprintf(stderr, " %s = \"%s\"\n", e2, v2);
- test_failed(a, line);
+ report_failure(extra);
}
/* assertEqualWString() displays the values of the two strings. */
@@ -257,19 +274,139 @@ void
test_assert_equal_wstring(const char *file, int line,
const wchar_t *v1, const char *e1,
const wchar_t *v2, const char *e2,
- struct archive *a)
+ void *extra)
{
if (wcscmp(v1, v2) == 0) {
msg[0] = '\0';
return;
}
+ failures ++;
if (previous_failures(file, line))
return;
fprintf(stderr, "%s:%d: Assertion failed: Unicode strings not equal\n",
file, line);
fwprintf(stderr, L" %s = \"%ls\"\n", e1, v1);
fwprintf(stderr, L" %s = \"%ls\"\n", e2, v2);
- test_failed(a, line);
+ report_failure(extra);
+}
+
+/* assertEqualMem() displays the values of the two strings. */
+void
+test_assert_equal_mem(const char *file, int line,
+ const char *v1, const char *e1,
+ const char *v2, const char *e2,
+ size_t l, const char *ld, void *extra)
+{
+ unsigned int i;
+
+ if (v1 == NULL || v2 == NULL) {
+ if (v1 == v2) {
+ msg[0] = '\0';
+ return;
+ }
+ } else if (memcmp(v1, v2, l) == 0) {
+ msg[0] = '\0';
+ return;
+ }
+ failures ++;
+ if (previous_failures(file, line))
+ return;
+ fprintf(stderr, "%s:%d: Assertion failed: memory not equal\n",
+ file, line);
+ fprintf(stderr, " size %s = %d\n", ld, (int)l);
+ fprintf(stderr, " %s = ", e1);
+ for(i=0; i < 32 && i < l; i++) {
+ int c = v1[i];
+ if (c >= ' ' && c <= 126)
+ fprintf(stderr, "'%c'", c);
+ else
+ fprintf(stderr, "0x%02x", c);
+ if (i < l)
+ fprintf(stderr, ", ");
+ }
+ fprintf(stderr, "\n");
+ fprintf(stderr, " %s = ", e2);
+ for(i=0; i < 32 && i < l; i++) {
+ int c = v2[i];
+ if (c >= ' ' && c <= 126)
+ fprintf(stderr, "'%c'", c);
+ else
+ fprintf(stderr, "0x%02x", c);
+ if (i < l)
+ fprintf(stderr, ", ");
+ }
+ fprintf(stderr, "\n");
+ report_failure(extra);
+}
+
+
+/*
+ * Call standard system() call, but build up the command line using
+ * sprintf() conventions.
+ */
+int
+systemf(const char *fmt, ...)
+{
+ char buff[8192];
+ va_list ap;
+ int r;
+
+ va_start(ap, fmt);
+ vsprintf(buff, fmt, ap);
+ r = system(buff);
+ va_end(ap);
+ return (r);
+}
+
+/*
+ * Slurp a file into memory for ease of comparison and testing.
+ * Returns size of file in 'sizep' if non-NULL, null-terminates
+ * data in memory for ease of use.
+ */
+char *
+slurpfile(size_t * sizep, const char *fmt, ...)
+{
+ char filename[8192];
+ struct stat st;
+ va_list ap;
+ char *p;
+ ssize_t bytes_read;
+ int fd;
+ int r;
+
+ va_start(ap, fmt);
+ vsprintf(filename, fmt, ap);
+ va_end(ap);
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0) {
+ /* Note: No error; non-existent file is okay here. */
+ return (NULL);
+ }
+ r = fstat(fd, &st);
+ if (r != 0) {
+ fprintf(stderr, "Can't stat file %s\n", filename);
+ close(fd);
+ return (NULL);
+ }
+ p = malloc(st.st_size + 1);
+ if (p == NULL) {
+ fprintf(stderr, "Can't allocate %ld bytes of memory to read file %s\n", (long int)st.st_size, filename);
+ close(fd);
+ return (NULL);
+ }
+ bytes_read = read(fd, p, st.st_size);
+ if (bytes_read < st.st_size) {
+ fprintf(stderr, "Can't read file %s\n", filename);
+ close(fd);
+ free(p);
+ return (NULL);
+ }
+ p[st.st_size] = '\0';
+ if (sizep != NULL)
+ *sizep = (size_t)st.st_size;
+ close(fd);
+ return (p);
}
/*
@@ -284,6 +421,12 @@ struct { void (*func)(void); const char *name; } tests[] = {
#include "list.h"
};
+/*
+ * Each test is run in a private work dir. Those work dirs
+ * do have consistent and predictable names, in case a group
+ * of tests need to collaborate. However, there is no provision
+ * for requiring that tests run in a certain order.
+ */
static int test_run(int i, const char *tmpdir)
{
int failures_before = failures;
@@ -307,29 +450,35 @@ static int test_run(int i, const char *tmpdir)
tests[i].name);
exit(1);
}
+ /* Chdir() to that work directory. */
if (chdir(tests[i].name)) {
fprintf(stderr,
"ERROR: Couldn't chdir to temp dir ``%s''\n",
tests[i].name);
exit(1);
}
+ /* Run the actual test. */
(*tests[i].func)();
- summarize(tests[i].name);
+ /* Summarize the results of this test. */
+ summarize();
+ /* Return appropriate status. */
return (failures == failures_before ? 0 : 1);
}
-static void usage(void)
+static void usage(const char *program)
{
static const int limit = sizeof(tests) / sizeof(tests[0]);
int i;
- printf("Usage: libarchive_test [options] <test> <test> ...\n");
+ printf("Usage: %s [options] <test> <test> ...\n", program);
printf("Default is to run all tests.\n");
printf("Otherwise, specify the numbers of the tests you wish to run.\n");
printf("Options:\n");
printf(" -k Keep running after failures.\n");
printf(" Default: Core dump after any failure.\n");
printf(" -q Quiet.\n");
+ printf(" -r <dir> Path to dir containing reference files.\n");
+ printf(" Default: Current directory.\n");
printf("Available tests:\n");
for (i = 0; i < limit; i++)
printf(" %d: %s\n", i, tests[i].name);
@@ -341,19 +490,41 @@ int main(int argc, char **argv)
static const int limit = sizeof(tests) / sizeof(tests[0]);
int i, tests_run = 0, tests_failed = 0, opt;
time_t now;
+ char *progname, *p;
char tmpdir[256];
+ char tmpdir_timestamp[256];
+
+ /*
+ * Name of this program, used to build root of our temp directory
+ * tree.
+ */
+ progname = p = argv[0];
+ while (*p != '\0') {
+ if (*p == '/')
+ progname = p + 1;
+ ++p;
+ }
- while ((opt = getopt(argc, argv, "kq")) != -1) {
+ /* Get the directory holding test files from environment. */
+ refdir = getenv("LIBARCHIVE_TEST_FILES");
+
+ /*
+ * Parse options.
+ */
+ while ((opt = getopt(argc, argv, "kqr:")) != -1) {
switch (opt) {
case 'k':
dump_on_failure = 0;
break;
case 'q':
- quiet_flag = 1;
+ quiet_flag++;
+ break;
+ case 'r':
+ refdir = optarg;
break;
case '?':
default:
- usage();
+ usage(progname);
}
}
argc -= optind;
@@ -366,10 +537,10 @@ int main(int argc, char **argv)
*/
now = time(NULL);
for (i = 0; i < 1000; i++) {
- strftime(tmpdir, sizeof(tmpdir),
- "/tmp/libarchive_test.%Y-%m-%dT%H.%M.%S",
+ strftime(tmpdir_timestamp, sizeof(tmpdir_timestamp),
+ "%Y-%m-%dT%H.%M.%S",
localtime(&now));
- sprintf(tmpdir + strlen(tmpdir), "-%03d", i);
+ sprintf(tmpdir, "/tmp/%s.%s-%03d", progname, tmpdir_timestamp, i);
if (mkdir(tmpdir,0755) == 0)
break;
if (errno == EEXIST)
@@ -379,11 +550,32 @@ int main(int argc, char **argv)
exit(1);
}
+ /*
+ * If the user didn't specify a directory for locating
+ * reference files, use the current directory for that.
+ */
+ if (refdir == NULL) {
+ systemf("/bin/pwd > %s/refdir", tmpdir);
+ refdir = slurpfile(NULL, "%s/refdir", tmpdir);
+ p = refdir + strlen(refdir);
+ while (p[-1] == '\n') {
+ --p;
+ *p = '\0';
+ }
+ }
+
+ /*
+ * Banner with basic information.
+ */
if (!quiet_flag) {
- printf("Running libarchive tests in: %s\n", tmpdir);
+ printf("Running tests in: %s\n", tmpdir);
+ printf("Reference files will be read from: %s\n", refdir);
printf("Exercising %s\n", archive_version());
}
+ /*
+ * Run some or all of the individual tests.
+ */
if (argc == 0) {
/* Default: Run all tests. */
for (i = 0; i < limit; i++) {
@@ -396,7 +588,7 @@ int main(int argc, char **argv)
i = atoi(*argv);
if (**argv < '0' || **argv > '9' || i < 0 || i >= limit) {
printf("*** INVALID Test %s\n", *argv);
- usage();
+ usage(progname);
} else {
if (test_run(i, tmpdir))
tests_failed++;
@@ -405,10 +597,16 @@ int main(int argc, char **argv)
argv++;
}
}
- printf("\n");
- printf("%d of %d test groups reported failures\n",
- tests_failed, tests_run);
- printf(" Total of %d individual tests failed.\n", failures);
- printf(" Total of %d individual tests were skipped.\n", skips);
+
+ /*
+ * Report summary statistics.
+ */
+ if (!quiet_flag) {
+ printf("\n");
+ printf("%d of %d test groups reported failures\n",
+ tests_failed, tests_run);
+ printf(" Total of %d individual tests failed.\n", failures);
+ printf(" Total of %d individual tests were skipped.\n", skips);
+ }
return (tests_failed);
}
diff --git a/archivers/libarchive/files/libarchive/test/read_open_memory.c b/archivers/libarchive/files/libarchive/test/read_open_memory.c
index 2729e1fdaaf..8be3d63eaef 100644
--- a/archivers/libarchive/files/libarchive/test/read_open_memory.c
+++ b/archivers/libarchive/files/libarchive/test/read_open_memory.c
@@ -96,7 +96,7 @@ static ssize_t
memory_read(struct archive *a, void *client_data, const void **buff)
{
struct read_memory_data *mine = (struct read_memory_data *)client_data;
- ssize_t size;
+ size_t size;
(void)a; /* UNUSED */
size = mine->end - mine->buffer;
diff --git a/archivers/libarchive/files/libarchive/test/test.h b/archivers/libarchive/files/libarchive/test/test.h
index c4a110c7199..940b0274bf5 100644
--- a/archivers/libarchive/files/libarchive/test/test.h
+++ b/archivers/libarchive/files/libarchive/test/test.h
@@ -34,13 +34,13 @@
#define _FILE_OFFSET_BITS 64
-#include <archive.h>
-#include <archive_entry.h>
+#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
+#include <unistd.h>
#include <wchar.h>
#ifdef USE_DMALLOC
@@ -69,52 +69,27 @@
#endif
/*
- * ARCHIVE_VERSION_STAMP first appeared in 1.9 and libarchive 2.2.4.
- * We can approximate it for earlier versions, though.
- * This is used to disable tests of features not present in the current
- * version.
- */
-#ifndef ARCHIVE_VERSION_STAMP
-#define ARCHIVE_VERSION_STAMP \
- (ARCHIVE_API_VERSION * 1000000 + ARCHIVE_API_FEATURE * 1000)
-#endif
-
-
-/*
- * "list.h" is simply created by "grep DEFINE_TEST"; it has
- * a line like
- * DEFINE_TEST(test_function)
- * for each test.
- * Include it here with a suitable DEFINE_TEST to declare all of the
- * test functions.
- */
-#define DEFINE_TEST(name) void name(void);
-#include "list.h"
-/*
* Redefine DEFINE_TEST for use in defining the test functions.
*/
#undef DEFINE_TEST
-#define DEFINE_TEST(name) void name(void)
+#define DEFINE_TEST(name) void name(void); void name(void)
/* An implementation of the standard assert() macro */
#define assert(e) test_assert(__FILE__, __LINE__, (e), #e, NULL)
-/* As above, but reports any archive_error found in variable 'a' */
-#define assertA(e) test_assert(__FILE__, __LINE__, (e), #e, (a))
-/* Asserts that two integers are the same. Reports value of each one if not. */
-#define assertEqualIntA(a,v1,v2) \
- test_assert_equal_int(__FILE__, __LINE__, (v1), #v1, (v2), #v2, (a))
+/* Assert two integers are the same. Reports value of each one if not. */
#define assertEqualInt(v1,v2) \
test_assert_equal_int(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL)
-/* Asserts that two strings are the same. Reports value of each one if not. */
-#define assertEqualStringA(a,v1,v2) \
- test_assert_equal_string(__FILE__, __LINE__, (v1), #v1, (v2), #v2, (a))
+/* Assert two strings are the same. Reports value of each one if not. */
#define assertEqualString(v1,v2) \
test_assert_equal_string(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL)
/* As above, but v1 and v2 are wchar_t * */
#define assertEqualWString(v1,v2) \
test_assert_equal_wstring(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL)
+/* As above, but raw blocks of bytes. */
+#define assertEqualMem(v1, v2, l) \
+ test_assert_equal_mem(__FILE__, __LINE__, (v1), #v1, (v2), #v2, (l), #l, NULL)
/*
* This would be simple with C99 variadic macros, but I don't want to
@@ -129,11 +104,50 @@
void failure(const char *fmt, ...);
void skipping_setup(const char *, int);
void test_skipping(const char *fmt, ...);
-void test_assert(const char *, int, int, const char *, struct archive *);
-void test_assert_equal_int(const char *, int, int, const char *, int, const char *, struct archive *);
-void test_assert_equal_string(const char *, int, const char *v1, const char *, const char *v2, const char *, struct archive *);
-void test_assert_equal_wstring(const char *, int, const wchar_t *v1, const char *, const wchar_t *v2, const char *, struct archive *);
+void test_assert(const char *, int, int, const char *, void *);
+void test_assert_equal_int(const char *, int, int, const char *, int, const char *, void *);
+void test_assert_equal_string(const char *, int, const char *v1, const char *, const char *v2, const char *, void *);
+void test_assert_equal_wstring(const char *, int, const wchar_t *v1, const char *, const wchar_t *v2, const char *, void *);
+void test_assert_equal_mem(const char *, int, const char *, const char *, const char *, const char *, size_t, const char *, void *);
+
+/* Like sprintf, then system() */
+int systemf(const char * fmt, ...);
+
+/* Suck file into string allocated via malloc(). Call free() when done. */
+/* Supports printf-style args: slurpfile(NULL, "%s/myfile", refdir); */
+char *slurpfile(size_t *, const char *fmt, ...);
+
+/*
+ * Global vars
+ */
+
+/* Directory holding reference files. */
+char *refdir;
+
+/*
+ * Special interfaces for libarchive test harness.
+ */
+
+#include "archive.h"
+#include "archive_entry.h"
/* Special customized read-from-memory interface. */
int read_open_memory(struct archive *, void *, size_t, size_t);
-int read_open_memory(struct archive *, void *, size_t, size_t);
+
+/*
+ * ARCHIVE_VERSION_STAMP first appeared in 1.9 and libarchive 2.2.4.
+ * We can approximate it for earlier versions, though.
+ * This is used to disable tests of features not present in the current
+ * version.
+ */
+#ifndef ARCHIVE_VERSION_STAMP
+#define ARCHIVE_VERSION_STAMP \
+ (ARCHIVE_API_VERSION * 1000000 + ARCHIVE_API_FEATURE * 1000)
+#endif
+
+/* Versions of above that accept an archive argument for additional info. */
+#define assertA(e) test_assert(__FILE__, __LINE__, (e), #e, (a))
+#define assertEqualIntA(a,v1,v2) \
+ test_assert_equal_int(__FILE__, __LINE__, (v1), #v1, (v2), #v2, (a))
+#define assertEqualStringA(a,v1,v2) \
+ test_assert_equal_string(__FILE__, __LINE__, (v1), #v1, (v2), #v2, (a))
diff --git a/archivers/libarchive/files/libarchive/test/test_entry_strmode.c b/archivers/libarchive/files/libarchive/test/test_entry_strmode.c
new file mode 100644
index 00000000000..43b01b42232
--- /dev/null
+++ b/archivers/libarchive/files/libarchive/test/test_entry_strmode.c
@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 2003-2007 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"
+__FBSDID("$FreeBSD$");
+
+DEFINE_TEST(test_entry_strmode)
+{
+ struct archive_entry *entry;
+
+ assert((entry = archive_entry_new()) != NULL);
+
+ archive_entry_set_mode(entry, S_IFREG | 0642);
+ assertEqualString(archive_entry_strmode(entry), "-rw-r---w- ");
+
+ archive_entry_set_mode(entry, S_IFBLK | 03642);
+ assertEqualString(archive_entry_strmode(entry), "brw-r-S-wT ");
+
+ archive_entry_set_mode(entry, S_IFCHR | 05777);
+ assertEqualString(archive_entry_strmode(entry), "crwsrwxrwt ");
+
+ archive_entry_set_mode(entry, S_IFLNK | 04000);
+ assertEqualString(archive_entry_strmode(entry), "l--S------ ");
+
+ /* Release the experimental entry. */
+ archive_entry_free(entry);
+}
diff --git a/archivers/libarchive/files/libarchive/test/test_read_format_cpio_odc.c b/archivers/libarchive/files/libarchive/test/test_read_format_cpio_odc.c
index d722c5eb930..c6eb8312165 100644
--- a/archivers/libarchive/files/libarchive/test/test_read_format_cpio_odc.c
+++ b/archivers/libarchive/files/libarchive/test/test_read_format_cpio_odc.c
@@ -54,7 +54,7 @@ DEFINE_TEST(test_read_format_cpio_odc)
assertA(0 == archive_read_support_compression_all(a));
assertA(0 == archive_read_support_format_all(a));
assertA(0 == archive_read_open_memory(a, archive, sizeof(archive)));
- assertA(0 == archive_read_next_header(a, &ae));
+ assertEqualIntA(a, 0, archive_read_next_header(a, &ae));
assertA(archive_compression(a) == ARCHIVE_COMPRESSION_NONE);
assertA(archive_format(a) == ARCHIVE_FORMAT_CPIO_POSIX);
assert(0 == archive_read_close(a));
diff --git a/archivers/libarchive/files/libarchive/test/test_read_format_gtar_sparse.c b/archivers/libarchive/files/libarchive/test/test_read_format_gtar_sparse.c
index 7f8e01eba9d..60ad5ba64cd 100644
--- a/archivers/libarchive/files/libarchive/test/test_read_format_gtar_sparse.c
+++ b/archivers/libarchive/files/libarchive/test/test_read_format_gtar_sparse.c
@@ -29,7 +29,7 @@ __FBSDID("$FreeBSD: src/lib/libarchive/test/test_read_format_gtar_sparse.c,v 1.6
struct contents {
off_t o;
size_t s;
- char *d;
+ const char *d;
};
struct contents archive_contents_sparse[] = {
@@ -226,59 +226,6 @@ static unsigned char archive_old_gtar_1_13[] = {
235,237,249,250,'t',185,'l',207,31,'?','=','|',221,207,254,14,0,0,0,0,0,0,
0,255,'1',255,0,178,'s',140,'2',0,240,0,0};
-/* Old GNU tar sparse format, as created by gtar 1.17 */
-static unsigned char archive_old_gtar_1_17[] = {
-31,139,8,0,30,'%',193,'F',0,3,237,215,']','r',19,'G',20,134,'a','e','\'',
-218,'@',170,186,'O',255,'-','$','+',208,5,23,'\\','@','(',203,236,'?','g',
-134,216,'8',232,139,160,248,'P','M',170,242,'>',20,'%',211,'6',214,153,158,
-'W','#',205,245,211,229,233,250,238,244,'P','%',205,222,183,199,186,'F','y',
-251,184,137,252,'{',170,'e',206,18,17,189,205,'S','~','w',197,'<',157,255,
-'x',236,'X','_','|',190,'>','_',158,206,231,211,243,251,15,'w',127,238,'{',
-223,255,'i',219,22,180,217,235,182,11,127,239,200,235,215,185,'K','!',214,
-'k',255,242,239,151,245,253,235,'{','O',240,250,31,'~',185,203,175,255,149,
-248,31,161,159,'c',']',247,235,127,'<',244,'9',238,'^',255,'k',143,'V',234,
-'?',175,255,17,'5',127,156,235,255,191,'^',255,'[',235,'M',173,175,'(',253,
-219,245,223,'J',25,171,142,186,182,'m','V',207,158,251,223,135,248,'m','1',
-'W',153,'b',189,197,232,'K',173,231,'A',168,163,232,17,'C',29,'E',159,181,
-170,163,200,'Q',199,205,'Q','l',235,'c','V','5',231,172,'}',168,'9',231,'h',
-'U',205,185,'j',157,'E',173,231,'f',139,'9',243,'a','N','1','g',205,']',11,
-'1','g',238,'A',155,'b',206,154,165,135,152,179,230,'s','N','1','g',141,182,
-154,152,179,198,202,243,')',214,183,'(',212,156,'m',197,186,173,226,245,252,
-215,222,'j','S',243,246,185,150,154,'w',196,'l','j',222,177,31,245,237,250,
-140,166,234,174,'s',134,170,'{',143,'X',237,'k',30,'v',17,'s','F','>','s',
-23,'s','F',201,138,196,156,'Q','k',12,'1','g',228,'k','D',245,155,'M',',',
-213,'o','^',171,166,234,'w',127,'9',169,'9',243,244,'T','5','g',207,3,'P',
-'s',230,'&',132,154,179,175,'9',213,156,163,13,213,'o',140,213,'n',251,253,
-'z',254,243,'l',134,234,'x',127,249,171,'y',215,246,'G',173,207,253,'0',190,
-']','o','9','q',19,243,182,'2',243,23,137,245,26,'U','u',220,'r',151,'n',
-';',222,'.','G','u',170,'~',247,203,148,152,179,'e',238,']',205,153,219,'W',
-212,156,25,'o','W','s',246,188,10,170,'9','G',134,167,230,220,'V',213,156,
-249,190,167,250,'}',185,156,222,174,175,'5',212,156,'y',154,171,154,'3','w',
-'m',220,'9',255,'}',219,17,'1','o',190,'x',170,234,184,'g',244,170,227,158,
-'/','h',213,241,'~',249,23,243,246,12,'o',138,'y','{',230,24,'b','_',243,
-147,'A','~',138,16,235,'=',175,24,'j',206,'|',21,170,'~',251,200,11,177,154,
-'s',140,'P',253,238,'o','S','j',206,153,'y',169,'9',243,'e',211,212,156,'+',
-131,17,'s',142,'-','=','1',231,200,29,'U',253,'n',231,'^',245,';',242,'B',
-175,250,221,223,'N',239,156,255,145,23,166,219,'O',13,219,250,10,245,185,
-'`','d','.',234,'s',193,200,'0',213,231,130,145,'\'','Z','u',156,23,237,174,
-':',206,211,208,'T',199,251,219,191,154,'s','n',239,0,'j','}',251,'#',214,
-247,15,'C','o',214,139,252,'`',132,31,194,253,27,28,244,3,7,253,192,'A','?',
-'p',208,15,28,244,3,135,219,15,253,193,'A','?','p',208,15,28,244,3,7,253,
-192,'A','?','p',208,15,28,220,255,227,'H',244,3,7,253,192,'A','?','p',208,
-15,28,244,3,7,253,192,193,253,'?',142,'D','?','p',208,15,28,244,3,7,253,192,
-'A','?','p',208,15,28,220,255,227,'H',244,3,7,253,192,'A','?','p',208,15,
-28,244,3,7,253,192,193,253,'?',142,'D','?','p',208,15,28,244,3,7,253,192,
-'A','?','p',208,15,28,220,255,227,'H',244,3,7,253,192,'A','?','p',208,15,
-28,244,3,7,253,192,193,253,'?',142,'D','?','p',208,15,28,244,3,7,253,192,
-'A','?','p',208,15,28,220,255,227,'H',244,3,7,253,192,'A','?','p',208,15,
-28,244,3,7,253,192,193,253,'?',142,'D','?','p',208,15,28,244,3,7,253,192,
-'A','?','p',208,15,28,220,255,227,'H',244,3,7,253,192,'A','?','p',208,15,
-28,244,3,7,253,192,193,253,'?',142,'D','?','p',208,15,28,244,3,7,253,192,
-'A','?','p',208,15,28,220,255,227,'H',244,3,7,253,192,'A','?',158,143,127,
-'~',252,253,250,233,242,'t','}',247,184,231,'(','i',246,190,'=',214,'5',202,
-219,199,23,167,'Z',230,',',17,209,219,'<',149,'Z','#',234,233,'\\',30,'7',
-210,'W',159,175,207,151,167,243,249,244,252,254,195,221,159,251,222,247,1,
-0,0,0,0,0,0,0,248,15,249,11,162,'$',218,227,0,240,0,0};
#if ARCHIVE_VERSION_STAMP >= 1009000
/* libarchive < 1.9 does not support this. */
@@ -831,7 +778,7 @@ _verify_archive(void *buffer, size_t length, const char *name,
(const void **)&actual.d,
&actual.s, &actual.o))) {
while (actual.s > 0) {
- char c = *(char *)actual.d;
+ char c = *(const char *)actual.d;
if(actual.o < expect.o) {
/*
* Any byte before the expected
diff --git a/archivers/libarchive/files/libarchive/test/test_read_format_isorr_bz2.c b/archivers/libarchive/files/libarchive/test/test_read_format_isorr_bz2.c
index f9a70768471..2a888af3586 100644
--- a/archivers/libarchive/files/libarchive/test/test_read_format_isorr_bz2.c
+++ b/archivers/libarchive/files/libarchive/test/test_read_format_isorr_bz2.c
@@ -110,6 +110,9 @@ DEFINE_TEST(test_read_format_isorr_bz2)
assertEqualInt(1, archive_entry_ctime(ae));
assertEqualInt(0, archive_entry_stat(ae)->st_nlink);
assertEqualInt(0, archive_entry_uid(ae));
+ assertEqualIntA(a, ARCHIVE_EOF,
+ archive_read_data_block(a, &p, &size, &offset));
+ assertEqualInt(size, 0);
/* A directory. */
assert(0 == archive_read_next_header(a, &ae));
diff --git a/archivers/libarchive/files/libarchive/test/test_read_format_zip.c b/archivers/libarchive/files/libarchive/test/test_read_format_zip.c
index 08a4d6f5529..ce065097e42 100644
--- a/archivers/libarchive/files/libarchive/test/test_read_format_zip.c
+++ b/archivers/libarchive/files/libarchive/test/test_read_format_zip.c
@@ -48,6 +48,9 @@ DEFINE_TEST(test_read_format_zip)
struct archive_entry *ae;
struct archive *a;
char *buff[128];
+ const void *pv;
+ size_t s;
+ off_t o;
assert((a = archive_read_new()) != NULL);
assertA(0 == archive_read_support_compression_all(a));
@@ -57,6 +60,9 @@ DEFINE_TEST(test_read_format_zip)
assertEqualString("dir/", archive_entry_pathname(ae));
assertEqualInt(1179604249, archive_entry_mtime(ae));
assertEqualInt(0, archive_entry_size(ae));
+ assertEqualIntA(a, ARCHIVE_EOF,
+ archive_read_data_block(a, &pv, &s, &o));
+ assertEqualInt(s, 0);
assertA(0 == archive_read_next_header(a, &ae));
assertEqualString("file1", archive_entry_pathname(ae));
assertEqualInt(1179604289, archive_entry_mtime(ae));
diff --git a/archivers/libarchive/files/libarchive/test/test_read_pax_truncated.c b/archivers/libarchive/files/libarchive/test/test_read_pax_truncated.c
index c8873d84372..2b169c83900 100644
--- a/archivers/libarchive/files/libarchive/test/test_read_pax_truncated.c
+++ b/archivers/libarchive/files/libarchive/test/test_read_pax_truncated.c
@@ -29,9 +29,9 @@ DEFINE_TEST(test_read_pax_truncated)
{
struct archive_entry *ae;
struct archive *a;
- size_t used, i;
+ ssize_t used, i;
size_t buff_size = 1000000;
- size_t filedata_size = 100000;
+ ssize_t filedata_size = 100000;
char *buff = malloc(buff_size);
char *buff2 = malloc(buff_size);
char *filedata = malloc(filedata_size);
diff --git a/archivers/libarchive/files/libarchive/test/test_tar_filenames.c b/archivers/libarchive/files/libarchive/test/test_tar_filenames.c
index b75ac7f0cae..de0b1d0351e 100644
--- a/archivers/libarchive/files/libarchive/test/test_tar_filenames.c
+++ b/archivers/libarchive/files/libarchive/test/test_tar_filenames.c
@@ -41,7 +41,7 @@ test_filename(const char *prefix, int dlen, int flen)
struct archive *a;
size_t used;
size_t prefix_length = 0;
- int i = 0;
+ unsigned i = 0;
if (prefix) {
strcpy(filename, prefix);
diff --git a/archivers/libarchive/files/libarchive/test/test_tar_large.c b/archivers/libarchive/files/libarchive/test/test_tar_large.c
new file mode 100644
index 00000000000..29e0c833562
--- /dev/null
+++ b/archivers/libarchive/files/libarchive/test/test_tar_large.c
@@ -0,0 +1,307 @@
+/*-
+ * Copyright (c) 2003-2007 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"
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * This is a somewhat tricky test that verifies the ability to
+ * write and read very large entries to tar archives. It
+ * writes entries from 2GB up to 1TB to an archive in memory.
+ * The memory storage here carefully avoids actually storing
+ * any part of the file bodies, so it runs very quickly and requires
+ * very little memory. If you're willing to wait a few minutes,
+ * you should be able to exercise petabyte entries with this code.
+ */
+
+/*
+ * Each file is built up by duplicating the following block.
+ */
+static size_t filedatasize;
+static void *filedata;
+
+/*
+ * We store the archive as blocks of data generated by libarchive,
+ * each possibly followed by bytes of file data.
+ */
+struct memblock {
+ struct memblock *next;
+ size_t size;
+ void *buff;
+ off_t filebytes;
+};
+
+/*
+ * The total memory store is just a list of memblocks plus
+ * some accounting overhead.
+ */
+struct memdata {
+ off_t filebytes;
+ void *buff;
+ struct memblock *first;
+ struct memblock *last;
+};
+
+/* The following size definitions simplify things below. */
+#define KB ((off_t)1024)
+#define MB ((off_t)1024 * KB)
+#define GB ((off_t)1024 * MB)
+#define TB ((off_t)1024 * GB)
+
+#if ARCHIVE_API_VERSION < 2
+static ssize_t memory_read_skip(struct archive *, void *, size_t request);
+#else
+static off_t memory_read_skip(struct archive *, void *, off_t request);
+#endif
+static ssize_t memory_read(struct archive *, void *, const void **buff);
+static ssize_t memory_write(struct archive *, void *, const void *, size_t);
+
+
+static ssize_t
+memory_write(struct archive *a, void *_private, const void *buff, size_t size)
+{
+ struct memdata *private = _private;
+ struct memblock *block;
+
+ (void)a;
+
+ /*
+ * Since libarchive has zero-copy behavior, if you give a pointer
+ * to filedata to the library, a pointer into that data will
+ * pop out here. This way, we can tell the difference between
+ * filedata and library header and metadata.
+ */
+ if ((const char *)filedata <= (const char *)buff
+ && (const char *)buff < (const char *)filedata + filedatasize) {
+ /* We don't need to store a block of file data. */
+ private->last->filebytes += size;
+ } else {
+ /* Yes, we're assuming the very first write is metadata. */
+ /* It's header or metadata, copy and save it. */
+ block = (struct memblock *)malloc(sizeof(*block));
+ memset(block, 0, sizeof(*block));
+ block->size = size;
+ block->buff = malloc(size);
+ memcpy(block->buff, buff, size);
+ if (private->last == NULL) {
+ private->first = private->last = block;
+ } else {
+ private->last->next = block;
+ private->last = block;
+ }
+ block->next = NULL;
+ }
+ return (size);
+}
+
+static ssize_t
+memory_read(struct archive *a, void *_private, const void **buff)
+{
+ struct memdata *private = _private;
+ struct memblock *block;
+ ssize_t size;
+
+ (void)a;
+
+ free(private->buff);
+ private->buff = NULL;
+ if (private->first == NULL) {
+ private->last = NULL;
+ return (ARCHIVE_EOF);
+ }
+ if (private->filebytes > 0) {
+ /*
+ * We're returning file bytes, simulate it by
+ * passing blocks from the template data.
+ */
+ if (private->filebytes > (off_t)filedatasize)
+ size = filedatasize;
+ else
+ size = (ssize_t)private->filebytes;
+ private->filebytes -= size;
+ *buff = filedata;
+ } else {
+ /*
+ * We need to get some real data to return.
+ */
+ block = private->first;
+ private->first = block->next;
+ size = block->size;
+ if (block->buff != NULL) {
+ private->buff = block->buff;
+ *buff = block->buff;
+ } else {
+ private->buff = NULL;
+ *buff = filedata;
+ }
+ private->filebytes = block->filebytes;
+ free(block);
+ }
+ return (size);
+}
+
+
+#if ARCHIVE_API_VERSION < 2
+static ssize_t
+memory_read_skip(struct archive *a, void *private, size_t skip)
+{
+ (void)a; /* UNUSED */
+ (void)private; /* UNUSED */
+ (void)skip; /* UNUSED */
+ return (0);
+}
+#else
+static off_t
+memory_read_skip(struct archive *a, void *_private, off_t skip)
+#endif
+{
+ struct memdata *private = _private;
+
+ (void)a;
+
+ if (private->first == NULL) {
+ private->last = NULL;
+ return (0);
+ }
+ if (private->filebytes > 0) {
+ if (private->filebytes < skip)
+ skip = private->filebytes;
+ private->filebytes -= skip;
+ } else {
+ skip = 0;
+ }
+ return (skip);
+}
+
+DEFINE_TEST(test_tar_large)
+{
+ /* The sizes of the entries we're going to generate. */
+ static off_t tests[] = {
+ /* Test for 32-bit signed overflow. */
+ 2 * GB - 1, 2 * GB, 2 * GB + 1,
+ /* Test for 32-bit unsigned overflow. */
+ 4 * GB - 1, 4 * GB, 4 * GB + 1,
+ /* 8GB is the "official" max for ustar. */
+ 8 * GB - 1, 8 * GB, 8 * GB + 1,
+ /* Bend ustar a tad and you can get 64GB (12 octal digits). */
+ 64 * GB - 1, 64 * GB,
+ /* And larger entries that require non-ustar extensions. */
+ 256 * GB, 1 * TB, 0 };
+ int i;
+ char namebuff[64];
+ struct memdata memdata;
+ struct archive_entry *ae;
+ struct archive *a;
+ off_t filesize, writesize;
+
+ filedatasize = 1 * MB;
+ filedata = malloc(filedatasize);
+ memset(filedata, 0xAA, filedatasize);
+ memset(&memdata, 0, sizeof(memdata));
+
+ /*
+ * Open an archive for writing.
+ */
+ a = archive_write_new();
+ archive_write_set_format_pax_restricted(a);
+ archive_write_set_bytes_per_block(a, 0); /* No buffering. */
+ archive_write_open(a, &memdata, NULL, memory_write, NULL);
+
+ /*
+ * Write a series of large files to it.
+ */
+ for (i = 0; tests[i] > 0; i++) {
+ assert((ae = archive_entry_new()) != NULL);
+ sprintf(namebuff, "file_%d", i);
+ archive_entry_copy_pathname(ae, namebuff);
+ archive_entry_set_mode(ae, S_IFREG | 0755);
+ filesize = tests[i];
+ archive_entry_set_size(ae, filesize);
+
+ assertA(0 == archive_write_header(a, ae));
+ archive_entry_free(ae);
+
+ /*
+ * Write the actual data to the archive.
+ */
+ while (filesize > 0) {
+ writesize = filedatasize;
+ if (writesize > filesize)
+ writesize = filesize;
+ assertA(writesize == archive_write_data(a, filedata, writesize));
+ filesize -= writesize;
+ }
+ }
+
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_copy_pathname(ae, "lastfile");
+ archive_entry_set_mode(ae, S_IFREG | 0755);
+ assertA(0 == archive_write_header(a, ae));
+ archive_entry_free(ae);
+
+
+ /* Close out the archive. */
+ assertA(0 == archive_write_close(a));
+#if ARCHIVE_API_VERSION > 1
+ assertA(0 == archive_write_finish(a));
+#else
+ archive_write_finish(a);
+#endif
+
+ /*
+ * Open the same archive for reading.
+ */
+ a = archive_read_new();
+ archive_read_support_format_tar(a);
+ archive_read_open2(a, &memdata, NULL,
+ memory_read, memory_read_skip, NULL);
+
+ /*
+ * Read entries back.
+ */
+ for (i = 0; tests[i] > 0; i++) {
+ assertEqualIntA(a, 0, archive_read_next_header(a, &ae));
+ sprintf(namebuff, "file_%d", i);
+ assertEqualString(namebuff, archive_entry_pathname(ae));
+ assert(tests[i] == archive_entry_size(ae));
+ }
+ assertEqualIntA(a, 0, archive_read_next_header(a, &ae));
+ assertEqualString("lastfile", archive_entry_pathname(ae));
+
+ assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
+
+ /* Close out the archive. */
+ assertA(0 == archive_read_close(a));
+#if ARCHIVE_API_VERSION > 1
+ assertA(0 == archive_read_finish(a));
+#else
+ archive_read_finish(a);
+#endif
+
+ free(filedata);
+}
diff --git a/archivers/libarchive/files/libarchive/test/test_write_disk.c b/archivers/libarchive/files/libarchive/test/test_write_disk.c
index 1d8f32e0adf..4cac97681a7 100644
--- a/archivers/libarchive/files/libarchive/test/test_write_disk.c
+++ b/archivers/libarchive/files/libarchive/test/test_write_disk.c
@@ -23,7 +23,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test.h"
-__FBSDID("$FreeBSD: src/lib/libarchive/test/test_write_disk.c,v 1.3 2007/07/06 15:43:11 kientzle Exp $");
+__FBSDID("$FreeBSD: src/lib/libarchive/test/test_write_disk.c,v 1.6 2007/09/21 04:52:43 kientzle Exp $");
#if ARCHIVE_VERSION_STAMP >= 1009000
@@ -50,6 +50,74 @@ static void create(struct archive_entry *ae, const char *msg)
st.st_mode, archive_entry_mode(ae));
assert(st.st_mode == (archive_entry_mode(ae) & ~UMASK));
}
+
+static void create_reg_file(struct archive_entry *ae, const char *msg)
+{
+ static const char data[]="abcdefghijklmnopqrstuvwxyz";
+ struct archive *ad;
+ struct stat st;
+
+ /* Write the entry to disk. */
+ assert((ad = archive_write_disk_new()) != NULL);
+ failure("%s", msg);
+ assertEqualIntA(ad, 0, archive_write_header(ad, ae));
+ assertEqualInt(sizeof(data), archive_write_data(ad, data, sizeof(data)));
+ assertEqualIntA(ad, 0, archive_write_finish_entry(ad));
+#if ARCHIVE_API_VERSION > 1
+ assertEqualInt(0, archive_write_finish(ad));
+#else
+ archive_write_finish(ad);
+#endif
+ /* Test the entries on disk. */
+ assert(0 == stat(archive_entry_pathname(ae), &st));
+ failure("st.st_mode=%o archive_entry_mode(ae)=%o",
+ st.st_mode, archive_entry_mode(ae));
+ assertEqualInt(st.st_mode, (archive_entry_mode(ae) & ~UMASK));
+ assertEqualInt(st.st_size, sizeof(data));
+}
+
+static void create_reg_file2(struct archive_entry *ae, const char *msg)
+{
+ const int datasize = 100000;
+ char *data;
+ char *compare;
+ struct archive *ad;
+ struct stat st;
+ int i, fd;
+
+ data = malloc(datasize);
+ for (i = 0; i < datasize; i++)
+ data[i] = (char)(i % 256);
+
+ /* Write the entry to disk. */
+ assert((ad = archive_write_disk_new()) != NULL);
+ failure("%s", msg);
+ assertEqualIntA(ad, 0, archive_write_header(ad, ae));
+ for (i = 0; i < datasize - 999; i += 1000) {
+ assertEqualIntA(ad, ARCHIVE_OK,
+ archive_write_data_block(ad, data + i, 1000, i));
+ }
+ assertEqualIntA(ad, 0, archive_write_finish_entry(ad));
+#if ARCHIVE_API_VERSION > 1
+ assertEqualInt(0, archive_write_finish(ad));
+#else
+ archive_write_finish(ad);
+#endif
+ /* Test the entries on disk. */
+ assert(0 == stat(archive_entry_pathname(ae), &st));
+ failure("st.st_mode=%o archive_entry_mode(ae)=%o",
+ st.st_mode, archive_entry_mode(ae));
+ assertEqualInt(st.st_mode, (archive_entry_mode(ae) & ~UMASK));
+ assertEqualInt(st.st_size, i);
+
+ compare = malloc(datasize);
+ fd = open(archive_entry_pathname(ae), O_RDONLY);
+ assertEqualInt(datasize, read(fd, compare, datasize));
+ close(fd);
+ assert(memcmp(compare, data, datasize) == 0);
+ free(compare);
+ free(data);
+}
#endif
DEFINE_TEST(test_write_disk)
@@ -66,7 +134,14 @@ DEFINE_TEST(test_write_disk)
assert((ae = archive_entry_new()) != NULL);
archive_entry_copy_pathname(ae, "file");
archive_entry_set_mode(ae, S_IFREG | 0755);
- create(ae, "Test creating a regular file");
+ create_reg_file(ae, "Test creating a regular file");
+ archive_entry_free(ae);
+
+ /* Another regular file. */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_copy_pathname(ae, "file2");
+ archive_entry_set_mode(ae, S_IFREG | 0755);
+ create_reg_file2(ae, "Test creating another regular file");
archive_entry_free(ae);
/* A regular file over an existing file */
diff --git a/archivers/libarchive/files/libarchive/test/test_write_format_cpio.c b/archivers/libarchive/files/libarchive/test/test_write_format_cpio.c
index 6677b5e1b57..7319d0c3cec 100644
--- a/archivers/libarchive/files/libarchive/test/test_write_format_cpio.c
+++ b/archivers/libarchive/files/libarchive/test/test_write_format_cpio.c
@@ -23,7 +23,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test.h"
-__FBSDID("$FreeBSD: src/lib/libarchive/test/test_write_format_cpio.c,v 1.2 2007/07/06 15:43:11 kientzle Exp $");
+__FBSDID("$FreeBSD: src/lib/libarchive/test/test_write_format_cpio.c,v 1.3 2007/10/12 04:11:31 kientzle Exp $");
/* The version stamp macro was introduced after cpio write support. */
#if ARCHIVE_VERSION_STAMP >= 1009000
@@ -37,6 +37,7 @@ test_format(int (*set_format)(struct archive *))
size_t used;
size_t buffsize = 1000000;
char *buff;
+ int damaged = 0;
buff = malloc(buffsize);
@@ -66,6 +67,41 @@ test_format(int (*set_format)(struct archive *))
archive_entry_free(ae);
assertA(8 == archive_write_data(a, "12345678", 9));
+ /*
+ * Write another file to it.
+ */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_set_mtime(ae, 1, 10);
+ assert(1 == archive_entry_mtime(ae));
+ assert(10 == archive_entry_mtime_nsec(ae));
+ p = strdup("file2");
+ archive_entry_copy_pathname(ae, p);
+ strcpy(p, "XXXX");
+ free(p);
+ assertEqualString("file2", archive_entry_pathname(ae));
+ archive_entry_set_mode(ae, S_IFREG | 0755);
+ assert((S_IFREG | 0755) == archive_entry_mode(ae));
+ archive_entry_set_size(ae, 4);
+
+ assertA(0 == archive_write_header(a, ae));
+ archive_entry_free(ae);
+ assertA(4 == archive_write_data(a, "1234", 5));
+
+ /*
+ * Write a directory to it.
+ */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_set_mtime(ae, 11, 110);
+ archive_entry_copy_pathname(ae, "dir");
+ archive_entry_set_mode(ae, S_IFDIR | 0755);
+ archive_entry_set_size(ae, 512);
+
+ assertA(0 == archive_write_header(a, ae));
+ assertEqualInt(0, archive_entry_size(ae));
+ archive_entry_free(ae);
+ assertEqualIntA(a, 0, archive_write_data(a, "12345678", 9));
+
+
/* Close out the archive. */
assertA(0 == archive_write_close(a));
#if ARCHIVE_API_VERSION > 1
@@ -75,6 +111,22 @@ test_format(int (*set_format)(struct archive *))
#endif
/*
+ * Damage the second entry to test the search-ahead recovery.
+ */
+ {
+ int i;
+ for (i = 80; i < 150; i++) {
+ if (memcmp(buff + i, "07070", 5) == 0) {
+ damaged = 1;
+ buff[i] = 'X';
+ break;
+ }
+ }
+ }
+ failure("Unable to locate the second header for damage-recovery test.");
+ assert(damaged = 1);
+
+ /*
* Now, read the data back.
*/
assert((a = archive_read_new()) != NULL);
@@ -82,21 +134,53 @@ test_format(int (*set_format)(struct archive *))
assertA(0 == archive_read_support_compression_all(a));
assertA(0 == archive_read_open_memory(a, buff, used));
- assertA(0 == archive_read_next_header(a, &ae));
+ assertEqualIntA(a, 0, archive_read_next_header(a, &ae));
- assert(1 == archive_entry_mtime(ae));
+ assertEqualInt(1, archive_entry_mtime(ae));
/* Not the same as above: cpio doesn't store hi-res times. */
assert(0 == archive_entry_mtime_nsec(ae));
assert(0 == archive_entry_atime(ae));
assert(0 == archive_entry_ctime(ae));
assertEqualString("file", archive_entry_pathname(ae));
- assert((S_IFREG | 0755) == archive_entry_mode(ae));
- assert(8 == archive_entry_size(ae));
+ assertEqualInt((S_IFREG | 0755), archive_entry_mode(ae));
+ assertEqualInt(8, archive_entry_size(ae));
assertA(8 == archive_read_data(a, filedata, 10));
assert(0 == memcmp(filedata, "12345678", 8));
+ /*
+ * Read the second file back.
+ */
+ if (!damaged) {
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+ assertEqualInt(1, archive_entry_mtime(ae));
+ /* Not the same as above: cpio doesn't store hi-res times. */
+ assert(0 == archive_entry_mtime_nsec(ae));
+ assert(0 == archive_entry_atime(ae));
+ assert(0 == archive_entry_ctime(ae));
+ assertEqualString("file2", archive_entry_pathname(ae));
+ assert((S_IFREG | 0755) == archive_entry_mode(ae));
+ assertEqualInt(4, archive_entry_size(ae));
+ assertEqualIntA(a, 4, archive_read_data(a, filedata, 10));
+ assert(0 == memcmp(filedata, "1234", 4));
+ }
+
+ /*
+ * Read the dir entry back.
+ */
+ assertEqualIntA(a,
+ damaged ? ARCHIVE_WARN : ARCHIVE_OK,
+ archive_read_next_header(a, &ae));
+ assertEqualInt(11, archive_entry_mtime(ae));
+ assert(0 == archive_entry_mtime_nsec(ae));
+ assert(0 == archive_entry_atime(ae));
+ assert(0 == archive_entry_ctime(ae));
+ assertEqualString("dir", archive_entry_pathname(ae));
+ assertEqualInt((S_IFDIR | 0755), archive_entry_mode(ae));
+ assertEqualInt(0, archive_entry_size(ae));
+ assertEqualIntA(a, 0, archive_read_data(a, filedata, 10));
+
/* Verify the end of the archive. */
- assert(1 == archive_read_next_header(a, &ae));
+ assertEqualIntA(a, 1, archive_read_next_header(a, &ae));
assert(0 == archive_read_close(a));
#if ARCHIVE_API_VERSION > 1
assert(0 == archive_read_finish(a));
diff --git a/archivers/libarchive/files/libarchive/test/test_write_format_cpio_newc.c b/archivers/libarchive/files/libarchive/test/test_write_format_cpio_newc.c
new file mode 100644
index 00000000000..733e4ab26cd
--- /dev/null
+++ b/archivers/libarchive/files/libarchive/test/test_write_format_cpio_newc.c
@@ -0,0 +1,172 @@
+/*-
+ * Copyright (c) 2003-2007 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"
+__FBSDID("$FreeBSD$");
+
+
+static int
+is_hex(const char *p, size_t l)
+{
+ while (l > 0) {
+ if (*p >= 0 && *p <= '9') {
+ /* Ascii digit */
+ } else if (*p >= 'a' && *p <= 'f') {
+ /* lowercase letter a-f */
+ } else {
+ /* Not hex. */
+ return (0);
+ }
+ --l;
+ ++p;
+ }
+ return (1);
+}
+
+/*
+ * Detailed verification that cpio 'newc' archives are written with
+ * the correct format.
+ */
+DEFINE_TEST(test_write_format_cpio_newc)
+{
+ struct archive *a;
+ struct archive_entry *entry;
+ char *buff, *e;
+ size_t buffsize = 100000;
+ size_t used;
+
+ buff = malloc(buffsize);
+
+ /* Create a new archive in memory. */
+ assert((a = archive_write_new()) != NULL);
+ assertEqualIntA(a, 0, archive_write_set_format_cpio_newc(a));
+ assertEqualIntA(a, 0, archive_write_set_compression_none(a));
+ assertEqualIntA(a, 0, archive_write_open_memory(a, buff, buffsize, &used));
+
+ /*
+ * Add various files to it.
+ * TODO: Extend this to cover more filetypes.
+ */
+ assert((entry = archive_entry_new()) != NULL);
+ archive_entry_set_mtime(entry, 1, 10);
+ archive_entry_set_pathname(entry, "file");
+ archive_entry_set_mode(entry, S_IFREG | 0664);
+ archive_entry_set_size(entry, 10);
+ archive_entry_set_uid(entry, 80);
+ archive_entry_set_gid(entry, 90);
+ archive_entry_set_dev(entry, 12);
+ archive_entry_set_ino(entry, 89);
+ archive_entry_set_nlink(entry, 1);
+ assertEqualIntA(a, 0, archive_write_header(a, entry));
+ archive_entry_free(entry);
+ assertEqualIntA(a, 10, archive_write_data(a, "1234567890", 10));
+
+ assert((entry = archive_entry_new()) != NULL);
+ archive_entry_set_mtime(entry, 2, 20);
+ archive_entry_set_pathname(entry, "dir");
+ archive_entry_set_mode(entry, S_IFDIR | 0775);
+ archive_entry_set_size(entry, 10);
+ archive_entry_set_nlink(entry, 2);
+ assertEqualIntA(a, 0, archive_write_header(a, entry));
+ archive_entry_free(entry);
+ assertEqualIntA(a, 0, archive_write_data(a, "1234567890", 10));
+
+#if ARCHIVE_API_VERSION > 1
+ assert(0 == archive_write_finish(a));
+#else
+ archive_write_finish(a);
+#endif
+
+ /*
+ * Verify the archive format.
+ */
+ e = buff;
+
+ /* First entry is "file" */
+ assert(is_hex(e, 110)); /* Entire header is hex digits. */
+ assertEqualMem(e + 0, "070701", 6); /* Magic */
+ assertEqualMem(e + 6, "00000059", 8); /* ino */
+ assertEqualMem(e + 14, "000081b4", 8); /* Mode */
+ assertEqualMem(e + 22, "00000050", 8); /* uid */
+ assertEqualMem(e + 30, "0000005a", 8); /* gid */
+ assertEqualMem(e + 38, "00000001", 8); /* nlink */
+ assertEqualMem(e + 46, "00000001", 8); /* mtime */
+ assertEqualMem(e + 54, "0000000a", 8); /* File size */
+ assertEqualMem(e + 62, "00000000", 8); /* devmajor */
+ assertEqualMem(e + 70, "0000000c", 8); /* devminor */
+ assertEqualMem(e + 78, "00000000", 8); /* rdevmajor */
+ assertEqualMem(e + 86, "00000000", 8); /* rdevminor */
+ assertEqualMem(e + 94, "00000005", 8); /* Name size */
+ assertEqualMem(e + 102, "00000000", 8); /* CRC */
+ assertEqualMem(e + 110, "file\0\0", 6); /* Name contents */
+ assertEqualMem(e + 116, "1234567890", 10); /* File body */
+ assertEqualMem(e + 126, "\0\0", 2); /* Pad to multiple of 4 */
+ e += 128;
+
+ /* Second entry is "dir" */
+ assert(is_hex(e, 110));
+ assertEqualMem(e + 0, "070701", 6); /* Magic */
+ assertEqualMem(e + 6, "00000000", 8); /* ino */
+ assertEqualMem(e + 14, "000041fd", 8); /* Mode */
+ assertEqualMem(e + 22, "00000000", 8); /* uid */
+ assertEqualMem(e + 30, "00000000", 8); /* gid */
+ assertEqualMem(e + 38, "00000002", 8); /* nlink */
+ assertEqualMem(e + 46, "00000002", 8); /* mtime */
+ assertEqualMem(e + 54, "00000000", 8); /* File size */
+ assertEqualMem(e + 62, "00000000", 8); /* devmajor */
+ assertEqualMem(e + 70, "00000000", 8); /* devminor */
+ assertEqualMem(e + 78, "00000000", 8); /* rdevmajor */
+ assertEqualMem(e + 86, "00000000", 8); /* rdevminor */
+ assertEqualMem(e + 94, "00000004", 8); /* Name size */
+ assertEqualMem(e + 102, "00000000", 8); /* CRC */
+ assertEqualMem(e + 110, "dir\0", 4); /* name */
+ assertEqualMem(e + 114, "\0\0", 2); /* Pad to multiple of 4 */
+ e += 116;
+
+ /* TODO: Verify other types of entries. */
+
+ /* Last entry is end-of-archive marker. */
+ assert(is_hex(e, 76));
+ assertEqualMem(e + 0, "070701", 6); /* Magic */
+ assertEqualMem(e + 6, "00000000", 8); /* ino */
+ assertEqualMem(e + 14, "00000000", 8); /* Mode */
+ assertEqualMem(e + 22, "00000000", 8); /* uid */
+ assertEqualMem(e + 30, "00000000", 8); /* gid */
+ assertEqualMem(e + 38, "00000001", 8); /* nlink */
+ assertEqualMem(e + 46, "00000000", 8); /* mtime */
+ assertEqualMem(e + 54, "00000000", 8); /* File size */
+ assertEqualMem(e + 62, "00000000", 8); /* devmajor */
+ assertEqualMem(e + 70, "00000000", 8); /* devminor */
+ assertEqualMem(e + 78, "00000000", 8); /* rdevmajor */
+ assertEqualMem(e + 86, "00000000", 8); /* rdevminor */
+ assertEqualMem(e + 94, "0000000b", 8); /* Name size */
+ assertEqualMem(e + 102, "00000000", 8); /* CRC */
+ assertEqualMem(e + 110, "TRAILER!!!\0", 11); /* Name */
+ assertEqualMem(e + 121, "\0\0\0", 3); /* Pad to multiple of 4 bytes */
+ e += 124;
+
+ assertEqualInt(used, e - buff);
+
+ free(buff);
+}
diff --git a/archivers/libarchive/files/libarchive/test/test_write_format_cpio_odc.c b/archivers/libarchive/files/libarchive/test/test_write_format_cpio_odc.c
new file mode 100644
index 00000000000..796dd7eace9
--- /dev/null
+++ b/archivers/libarchive/files/libarchive/test/test_write_format_cpio_odc.c
@@ -0,0 +1,224 @@
+/*-
+ * Copyright (c) 2003-2007 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"
+__FBSDID("$FreeBSD$");
+
+
+static int
+is_octal(const char *p, size_t l)
+{
+ while (l > 0) {
+ if (*p < '0' || *p > '7')
+ return (0);
+ --l;
+ ++p;
+ }
+ return (1);
+}
+
+/*
+ * Detailed verification that cpio 'odc' archives are written with
+ * the correct format.
+ */
+DEFINE_TEST(test_write_format_cpio_odc)
+{
+ struct archive *a;
+ struct archive_entry *entry;
+ char *buff, *e;
+ size_t buffsize = 100000;
+ size_t used;
+
+ buff = malloc(buffsize);
+
+ /* Create a new archive in memory. */
+ assert((a = archive_write_new()) != NULL);
+ assertEqualIntA(a, 0, archive_write_set_format_cpio(a));
+ assertEqualIntA(a, 0, archive_write_set_compression_none(a));
+ assertEqualIntA(a, 0, archive_write_open_memory(a, buff, buffsize, &used));
+
+ /*
+ * Add various files to it.
+ * TODO: Extend this to cover more filetypes.
+ */
+
+ /* "file" with 10 bytes of content */
+ assert((entry = archive_entry_new()) != NULL);
+ archive_entry_set_mtime(entry, 1, 10);
+ archive_entry_set_pathname(entry, "file");
+ archive_entry_set_mode(entry, S_IFREG | 0664);
+ archive_entry_set_size(entry, 10);
+ archive_entry_set_uid(entry, 80);
+ archive_entry_set_gid(entry, 90);
+ archive_entry_set_dev(entry, 12);
+ archive_entry_set_ino(entry, 89);
+ archive_entry_set_nlink(entry, 2);
+ assertEqualIntA(a, 0, archive_write_header(a, entry));
+ archive_entry_free(entry);
+ assertEqualIntA(a, 10, archive_write_data(a, "1234567890", 10));
+
+ /* Hardlink to "file" with 10 bytes of content */
+ assert((entry = archive_entry_new()) != NULL);
+ archive_entry_set_mtime(entry, 1, 10);
+ archive_entry_set_pathname(entry, "linkfile");
+ archive_entry_set_mode(entry, S_IFREG | 0664);
+ archive_entry_set_size(entry, 10);
+ archive_entry_set_uid(entry, 80);
+ archive_entry_set_gid(entry, 90);
+ archive_entry_set_dev(entry, 12);
+ archive_entry_set_ino(entry, 89);
+ archive_entry_set_nlink(entry, 2);
+ assertEqualIntA(a, 0, archive_write_header(a, entry));
+ archive_entry_free(entry);
+ assertEqualIntA(a, 10, archive_write_data(a, "1234567890", 10));
+
+ /* "dir" */
+ assert((entry = archive_entry_new()) != NULL);
+ archive_entry_set_mtime(entry, 2, 20);
+ archive_entry_set_pathname(entry, "dir");
+ archive_entry_set_mode(entry, S_IFDIR | 0775);
+ archive_entry_set_size(entry, 10);
+ archive_entry_set_nlink(entry, 2);
+ assertEqualIntA(a, 0, archive_write_header(a, entry));
+ archive_entry_free(entry);
+ /* Write of data to dir should fail == zero bytes get written. */
+ assertEqualIntA(a, 0, archive_write_data(a, "1234567890", 10));
+
+ /* "symlink" pointing to "file" */
+ assert((entry = archive_entry_new()) != NULL);
+ archive_entry_set_mtime(entry, 3, 30);
+ archive_entry_set_pathname(entry, "symlink");
+ archive_entry_set_mode(entry, S_IFLNK | 0664);
+ archive_entry_set_symlink(entry,"file");
+ archive_entry_set_size(entry, 0);
+ archive_entry_set_uid(entry, 88);
+ archive_entry_set_gid(entry, 98);
+ archive_entry_set_dev(entry, 12);
+ archive_entry_set_ino(entry, 90);
+ archive_entry_set_nlink(entry, 1);
+ assertEqualIntA(a, 0, archive_write_header(a, entry));
+ archive_entry_free(entry);
+ /* Write of data to symlink should fail == zero bytes get written. */
+ assertEqualIntA(a, 0, archive_write_data(a, "1234567890", 10));
+
+#if ARCHIVE_API_VERSION > 1
+ assert(0 == archive_write_finish(a));
+#else
+ archive_write_finish(a);
+#endif
+
+ /*
+ * Verify the archive format.
+ */
+ e = buff;
+
+ /* "file" */
+ assert(is_octal(e, 76)); /* Entire header is octal digits. */
+ assertEqualMem(e + 0, "070707", 6); /* Magic */
+ assertEqualMem(e + 6, "000014", 6); /* dev */
+ assertEqualMem(e + 12, "000131", 6); /* ino */
+ assertEqualMem(e + 18, "100664", 6); /* Mode */
+ assertEqualMem(e + 24, "000120", 6); /* uid */
+ assertEqualMem(e + 30, "000132", 6); /* gid */
+ assertEqualMem(e + 36, "000002", 6); /* nlink */
+ assertEqualMem(e + 42, "000000", 6); /* rdev */
+ assertEqualMem(e + 48, "00000000001", 11); /* mtime */
+ assertEqualMem(e + 59, "000005", 6); /* Name size */
+ assertEqualMem(e + 65, "00000000012", 11); /* File size */
+ assertEqualMem(e + 76, "file\0", 5); /* Name contents */
+ assertEqualMem(e + 81, "1234567890", 10); /* File contents */
+ e += 91;
+
+ /* hardlink to "file" */
+ assert(is_octal(e, 76)); /* Entire header is octal digits. */
+ assertEqualMem(e + 0, "070707", 6); /* Magic */
+ assertEqualMem(e + 6, "000014", 6); /* dev */
+ assertEqualMem(e + 12, "000131", 6); /* ino */
+ assertEqualMem(e + 18, "100664", 6); /* Mode */
+ assertEqualMem(e + 24, "000120", 6); /* uid */
+ assertEqualMem(e + 30, "000132", 6); /* gid */
+ assertEqualMem(e + 36, "000002", 6); /* nlink */
+ assertEqualMem(e + 42, "000000", 6); /* rdev */
+ assertEqualMem(e + 48, "00000000001", 11); /* mtime */
+ assertEqualMem(e + 59, "000011", 6); /* Name size */
+ assertEqualMem(e + 65, "00000000012", 11); /* File size */
+ assertEqualMem(e + 76, "linkfile\0", 9); /* Name contents */
+ assertEqualMem(e + 85, "1234567890", 10); /* File contents */
+ e += 95;
+
+ /* "dir" */
+ assert(is_octal(e, 76));
+ assertEqualMem(e + 0, "070707", 6); /* Magic */
+ assertEqualMem(e + 6, "000000", 6); /* dev */
+ assertEqualMem(e + 12, "000000", 6); /* ino */
+ assertEqualMem(e + 18, "040775", 6); /* Mode */
+ assertEqualMem(e + 24, "000000", 6); /* uid */
+ assertEqualMem(e + 30, "000000", 6); /* gid */
+ assertEqualMem(e + 36, "000002", 6); /* Nlink */
+ assertEqualMem(e + 42, "000000", 6); /* rdev */
+ assertEqualMem(e + 48, "00000000002", 11); /* mtime */
+ assertEqualMem(e + 59, "000004", 6); /* Name size */
+ assertEqualMem(e + 65, "00000000000", 11); /* File size */
+ assertEqualMem(e + 76, "dir\0", 4); /* name */
+ e += 80;
+
+ /* "symlink" pointing to "file" */
+ assert(is_octal(e, 76)); /* Entire header is octal digits. */
+ assertEqualMem(e + 0, "070707", 6); /* Magic */
+ assertEqualMem(e + 6, "000014", 6); /* dev */
+ assertEqualMem(e + 12, "000132", 6); /* ino */
+ assertEqualMem(e + 18, "120664", 6); /* Mode */
+ assertEqualMem(e + 24, "000130", 6); /* uid */
+ assertEqualMem(e + 30, "000142", 6); /* gid */
+ assertEqualMem(e + 36, "000001", 6); /* nlink */
+ assertEqualMem(e + 42, "000000", 6); /* rdev */
+ assertEqualMem(e + 48, "00000000003", 11); /* mtime */
+ assertEqualMem(e + 59, "000010", 6); /* Name size */
+ assertEqualMem(e + 65, "00000000004", 11); /* File size */
+ assertEqualMem(e + 76, "symlink\0", 8); /* Name contents */
+ assertEqualMem(e + 84, "file", 4); /* File contents == link target */
+ e += 88;
+
+ /* TODO: Verify other types of entries. */
+
+ /* Last entry is end-of-archive marker. */
+ assert(is_octal(e, 76));
+ assertEqualMem(e + 0, "070707", 6); /* Magic */
+ assertEqualMem(e + 6, "000000", 6); /* dev */
+ assertEqualMem(e + 12, "000000", 6); /* ino */
+ assertEqualMem(e + 18, "000000", 6); /* Mode */
+ assertEqualMem(e + 24, "000000", 6); /* uid */
+ assertEqualMem(e + 30, "000000", 6); /* gid */
+ assertEqualMem(e + 36, "000001", 6); /* Nlink */
+ assertEqualMem(e + 42, "000000", 6); /* rdev */
+ assertEqualMem(e + 48, "00000000000", 11); /* mtime */
+ assertEqualMem(e + 59, "000013", 6); /* Name size */
+ assertEqualMem(e + 65, "00000000000", 11); /* File size */
+ assertEqualMem(e + 76, "TRAILER!!!\0", 11); /* Name */
+ e += 87;
+
+ assertEqualInt(used, e - buff);
+
+ free(buff);
+}