summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Kientzle <kientzle@gmail.com>2009-03-29 00:31:57 -0400
committerTim Kientzle <kientzle@gmail.com>2009-03-29 00:31:57 -0400
commit854445c448659aa7549d616571b4cf9e244da083 (patch)
tree7202e6559bebda30d17bdb8e29e489bebee19d2f
parente79064781dbbc31cbe8596c84675ac77d8c1a9da (diff)
downloadlibarchive-854445c448659aa7549d616571b4cf9e244da083.tar.gz
Improve test coverage:
* Add new tests of archive_{read,write}_open_{fd,FILE,filename} * Refactor the corresponding code to reduce the number of unreachable cases and eliminate a lot of duplicated code. In particular, {read,write}_open_filename now simply invoke {read,write}_open_fd to handle handle the fallback case of reading stdin when called with an empty filename. * Eliminate the unnecessary "open" callbacks; "open" callbacks are never needed (I plan to eliminate them from the API someday). SVN-Revision: 868
-rw-r--r--Makefile.am3
-rw-r--r--libarchive/archive_read_open_fd.c50
-rw-r--r--libarchive/archive_read_open_file.c41
-rw-r--r--libarchive/archive_read_open_filename.c115
-rw-r--r--libarchive/archive_write_open_filename.c47
-rw-r--r--libarchive/test/CMakeLists.txt3
-rw-r--r--libarchive/test/test_open_fd.c117
-rw-r--r--libarchive/test/test_open_file.c105
-rw-r--r--libarchive/test/test_open_filename.c109
9 files changed, 427 insertions, 163 deletions
diff --git a/Makefile.am b/Makefile.am
index 9967f3ae..78030509 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -223,6 +223,9 @@ libarchive_test_SOURCES= \
libarchive/test/test_fuzz.c \
libarchive/test/test_entry_strmode.c \
libarchive/test/test_link_resolver.c \
+ libarchive/test/test_open_fd.c \
+ libarchive/test/test_open_file.c \
+ libarchive/test/test_open_filename.c \
libarchive/test/test_pax_filename_encoding.c \
libarchive/test/test_read_compress_program.c \
libarchive/test/test_read_data_large.c \
diff --git a/libarchive/archive_read_open_fd.c b/libarchive/archive_read_open_fd.c
index 2ebd46d6..d44d4ad9 100644
--- a/libarchive/archive_read_open_fd.c
+++ b/libarchive/archive_read_open_fd.c
@@ -63,50 +63,41 @@ static off_t file_skip(struct archive *, void *, off_t request);
int
archive_read_open_fd(struct archive *a, int fd, size_t block_size)
{
+ struct stat st;
struct read_fd_data *mine;
+ void *b;
mine = (struct read_fd_data *)malloc(sizeof(*mine));
- if (mine == NULL) {
- archive_set_error(a, ENOMEM, "No memory");
- return (ARCHIVE_FATAL);
- }
- mine->block_size = block_size;
- mine->buffer = malloc(mine->block_size);
- if (mine->buffer == NULL) {
+ b = malloc(block_size);
+ if (mine == NULL || b == NULL) {
archive_set_error(a, ENOMEM, "No memory");
free(mine);
+ free(b);
return (ARCHIVE_FATAL);
}
+ mine->block_size = block_size;
+ mine->buffer = b;
mine->fd = fd;
/* lseek() hardly ever works, so disable it by default. See below. */
- mine->can_skip = 0;
- return (archive_read_open2(a, mine, file_open, file_read, file_skip, file_close));
-}
-
-static int
-file_open(struct archive *a, void *client_data)
-{
- struct read_fd_data *mine = (struct read_fd_data *)client_data;
- struct stat st;
-
if (fstat(mine->fd, &st) != 0) {
archive_set_error(a, errno, "Can't stat fd %d", mine->fd);
return (ARCHIVE_FATAL);
}
-
+ /*
+ * Skip support is a performance optimization for anything
+ * that supports lseek(). On FreeBSD, only regular files and
+ * raw disk devices support lseek() and there's no portable
+ * way to determine if a device is a raw disk device, so we
+ * only enable this optimization for regular files.
+ */
if (S_ISREG(st.st_mode)) {
archive_read_extract_set_skip_file(a, st.st_dev, st.st_ino);
- /*
- * Enabling skip here is a performance optimization for
- * anything that supports lseek(). On FreeBSD, only
- * regular files and raw disk devices support lseek() and
- * there's no portable way to determine if a device is
- * a raw disk device, so we only enable this optimization
- * for regular files.
- */
mine->can_skip = 1;
- }
- return (ARCHIVE_OK);
+ } else
+ mine->can_skip = 0;
+
+ return (archive_read_open2(a, mine,
+ NULL, file_read, file_skip, file_close));
}
static ssize_t
@@ -180,8 +171,7 @@ file_close(struct archive *a, void *client_data)
struct read_fd_data *mine = (struct read_fd_data *)client_data;
(void)a; /* UNUSED */
- if (mine->buffer != NULL)
- free(mine->buffer);
+ free(mine->buffer);
free(mine);
return (ARCHIVE_OK);
}
diff --git a/libarchive/archive_read_open_file.c b/libarchive/archive_read_open_file.c
index 55c431c7..904e8449 100644
--- a/libarchive/archive_read_open_file.c
+++ b/libarchive/archive_read_open_file.c
@@ -66,45 +66,36 @@ static off_t file_skip(struct archive *, void *, off_t request);
int
archive_read_open_FILE(struct archive *a, FILE *f)
{
+ struct stat st;
struct read_FILE_data *mine;
+ size_t block_size = 128 * 1024;
+ void *b;
mine = (struct read_FILE_data *)malloc(sizeof(*mine));
- if (mine == NULL) {
- archive_set_error(a, ENOMEM, "No memory");
- return (ARCHIVE_FATAL);
- }
- mine->block_size = 128 * 1024;
- mine->buffer = malloc(mine->block_size);
- if (mine->buffer == NULL) {
+ b = malloc(block_size);
+ if (mine == NULL || b == NULL) {
archive_set_error(a, ENOMEM, "No memory");
free(mine);
+ free(b);
return (ARCHIVE_FATAL);
}
+ mine->block_size = block_size;
+ mine->buffer = b;
mine->f = f;
- /* Suppress skip by default. See below. */
- mine->can_skip = 0;
- return (archive_read_open2(a, mine, file_open, file_read,
- file_skip, file_close));
-}
-
-static int
-file_open(struct archive *a, void *client_data)
-{
- struct read_FILE_data *mine = (struct read_FILE_data *)client_data;
- struct stat st;
-
/*
- * If we can't fstat() the file, it may just be that
- * it's not a file. (FILE * objects can wrap many kinds
- * of I/O streams.)
+ * If we can't fstat() the file, it may just be that it's not
+ * a file. (FILE * objects can wrap many kinds of I/O
+ * streams, some of which don't support fileno()).)
*/
if (fstat(fileno(mine->f), &st) == 0 && S_ISREG(st.st_mode)) {
archive_read_extract_set_skip_file(a, st.st_dev, st.st_ino);
- /* Enable the seek optimization for regular files. */
+ /* Enable the seek optimization only for regular files. */
mine->can_skip = 1;
- }
+ } else
+ mine->can_skip = 0;
- return (ARCHIVE_OK);
+ return (archive_read_open2(a, mine, NULL, file_read,
+ file_skip, file_close));
}
static ssize_t
diff --git a/libarchive/archive_read_open_filename.c b/libarchive/archive_read_open_filename.c
index f8a0fa4c..18ae079e 100644
--- a/libarchive/archive_read_open_filename.c
+++ b/libarchive/archive_read_open_filename.c
@@ -80,78 +80,53 @@ int
archive_read_open_filename(struct archive *a, const char *filename,
size_t block_size)
{
+ struct stat st;
struct read_file_data *mine;
+ void *b;
- if (filename == NULL || filename[0] == '\0') {
- mine = (struct read_file_data *)malloc(sizeof(*mine));
- if (mine == NULL) {
- archive_set_error(a, ENOMEM, "No memory");
- return (ARCHIVE_FATAL);
- }
- mine->filename[0] = '\0';
- } else {
- mine = (struct read_file_data *)malloc(sizeof(*mine) + strlen(filename));
- if (mine == NULL) {
- archive_set_error(a, ENOMEM, "No memory");
- return (ARCHIVE_FATAL);
- }
- strcpy(mine->filename, filename);
- }
- mine->block_size = block_size;
- mine->buffer = NULL;
- mine->fd = -1;
- /* lseek() almost never works; disable it by default. See below. */
- mine->can_skip = 0;
- return (archive_read_open2(a, mine, file_open, file_read, file_skip, file_close));
-}
-
-static int
-file_open(struct archive *a, void *client_data)
-{
- struct read_file_data *mine = (struct read_file_data *)client_data;
- struct stat st;
+ if (filename == NULL || filename[0] == '\0')
+ return (archive_read_open_fd(a, 0, block_size));
- mine->buffer = malloc(mine->block_size);
- if (mine->buffer == NULL) {
+ mine = (struct read_file_data *)malloc(sizeof(*mine) + strlen(filename));
+ b = malloc(block_size);
+ if (mine == NULL || b == NULL) {
archive_set_error(a, ENOMEM, "No memory");
+ free(mine);
+ free(b);
return (ARCHIVE_FATAL);
}
- if (mine->filename[0] != '\0')
- mine->fd = open(mine->filename, O_RDONLY | O_BINARY);
- else
- mine->fd = 0; /* Fake "open" for stdin. */
+ strcpy(mine->filename, filename);
+ mine->block_size = block_size;
+ mine->buffer = b;
+ mine->fd = open(mine->filename, O_RDONLY | O_BINARY);
if (mine->fd < 0) {
archive_set_error(a, errno, "Failed to open '%s'",
mine->filename);
return (ARCHIVE_FATAL);
}
- if (fstat(mine->fd, &st) == 0) {
- /* If we're reading a file from disk, ensure that we don't
- overwrite it with an extracted file. */
- if (S_ISREG(st.st_mode)) {
- archive_read_extract_set_skip_file(a, st.st_dev, st.st_ino);
- /*
- * Enabling skip here is a performance
- * optimization for anything that supports
- * lseek(). On FreeBSD, only regular files
- * and raw disk devices support lseek() and
- * there's no portable way to determine if a
- * device is a raw disk device, so we only
- * enable this optimization for regular files.
- */
- mine->can_skip = 1;
- }
- /* Remember mode so close can decide whether to flush. */
- mine->st_mode = st.st_mode;
- } else {
- if (mine->filename[0] == '\0')
- archive_set_error(a, errno, "Can't stat stdin");
- else
- archive_set_error(a, errno, "Can't stat '%s'",
- mine->filename);
+ if (fstat(mine->fd, &st) != 0) {
+ archive_set_error(a, errno, "Can't stat '%s'",
+ mine->filename);
return (ARCHIVE_FATAL);
}
- return (0);
+ /* Remember mode so close can decide whether to flush. */
+ mine->st_mode = st.st_mode;
+ /* If we're reading a file from disk, ensure that we don't
+ overwrite it with an extracted file. */
+ if (S_ISREG(st.st_mode)) {
+ archive_read_extract_set_skip_file(a, st.st_dev, st.st_ino);
+ /*
+ * Skip is a performance optimization for anything
+ * that supports lseek(). Generally, that only
+ * includes regular files and possibly raw disk
+ * devices, but there's no good portable way to detect
+ * raw disks.
+ */
+ mine->can_skip = 1;
+ } else
+ mine->can_skip = 0;
+ return (archive_read_open2(a, mine,
+ NULL, file_read, file_skip, file_close));
}
static ssize_t
@@ -163,11 +138,8 @@ file_read(struct archive *a, void *client_data, const void **buff)
*buff = mine->buffer;
bytes_read = read(mine->fd, mine->buffer, mine->block_size);
if (bytes_read < 0) {
- if (mine->filename[0] == '\0')
- archive_set_error(a, errno, "Error reading stdin");
- else
- archive_set_error(a, errno, "Error reading '%s'",
- mine->filename);
+ archive_set_error(a, errno, "Error reading '%s'",
+ mine->filename);
}
return (bytes_read);
}
@@ -217,15 +189,8 @@ file_skip(struct archive *a, void *client_data, off_t request)
* likely caused by a programmer error (too large request)
* or a corrupted archive file.
*/
- if (mine->filename[0] == '\0')
- /*
- * Should never get here, since lseek() on stdin ought
- * to return an ESPIPE error.
- */
- archive_set_error(a, errno, "Error seeking in stdin");
- else
- archive_set_error(a, errno, "Error seeking in '%s'",
- mine->filename);
+ archive_set_error(a, errno, "Error seeking in '%s'",
+ mine->filename);
return (-1);
}
return (new_offset - old_offset);
@@ -259,9 +224,7 @@ file_close(struct archive *a, void *client_data)
mine->block_size);
} while (bytesRead > 0);
}
- /* If a named file was opened, then it needs to be closed. */
- if (mine->filename[0] != '\0')
- close(mine->fd);
+ close(mine->fd);
}
free(mine->buffer);
free(mine);
diff --git a/libarchive/archive_write_open_filename.c b/libarchive/archive_write_open_filename.c
index 72eeb540..b9ae1747 100644
--- a/libarchive/archive_write_open_filename.c
+++ b/libarchive/archive_write_open_filename.c
@@ -71,24 +71,18 @@ archive_write_open_filename(struct archive *a, const char *filename)
{
struct write_file_data *mine;
- if (filename == NULL || filename[0] == '\0') {
- mine = (struct write_file_data *)malloc(sizeof(*mine));
- if (mine == NULL) {
- archive_set_error(a, ENOMEM, "No memory");
- return (ARCHIVE_FATAL);
- }
- mine->filename[0] = '\0'; /* Record that we're using stdout. */
- } else {
- mine = (struct write_file_data *)malloc(sizeof(*mine) + strlen(filename));
- if (mine == NULL) {
- archive_set_error(a, ENOMEM, "No memory");
- return (ARCHIVE_FATAL);
- }
- strcpy(mine->filename, filename);
+ if (filename == NULL || filename[0] == '\0')
+ return (archive_write_open_fd(a, 0));
+
+ mine = (struct write_file_data *)malloc(sizeof(*mine) + strlen(filename));
+ if (mine == NULL) {
+ archive_set_error(a, ENOMEM, "No memory");
+ return (ARCHIVE_FATAL);
}
+ strcpy(mine->filename, filename);
mine->fd = -1;
return (archive_write_open(a, mine,
- file_open, file_write, file_close));
+ file_open, file_write, file_close));
}
static int
@@ -104,21 +98,11 @@ file_open(struct archive *a, void *client_data)
/*
* Open the file.
*/
- if (mine->filename[0] != '\0') {
- mine->fd = open(mine->filename, flags, 0666);
- if (mine->fd < 0) {
- archive_set_error(a, errno, "Failed to open '%s'",
- mine->filename);
- return (ARCHIVE_FATAL);
- }
- } else {
- /*
- * NULL filename is stdout.
- */
- mine->fd = 1;
- /* By default, pad archive when writing to stdout. */
- if (archive_write_get_bytes_in_last_block(a) < 0)
- archive_write_set_bytes_in_last_block(a, 0);
+ mine->fd = open(mine->filename, flags, 0666);
+ if (mine->fd < 0) {
+ archive_set_error(a, errno, "Failed to open '%s'",
+ mine->filename);
+ return (ARCHIVE_FATAL);
}
if (fstat(mine->fd, &st) != 0) {
@@ -172,8 +156,7 @@ file_close(struct archive *a, void *client_data)
struct write_file_data *mine = (struct write_file_data *)client_data;
(void)a; /* UNUSED */
- if (mine->filename[0] != '\0')
- close(mine->fd);
+ close(mine->fd);
free(mine);
return (ARCHIVE_OK);
}
diff --git a/libarchive/test/CMakeLists.txt b/libarchive/test/CMakeLists.txt
index 19032c6c..4e765ecf 100644
--- a/libarchive/test/CMakeLists.txt
+++ b/libarchive/test/CMakeLists.txt
@@ -30,6 +30,9 @@ IF(ENABLE_TEST)
test_extattr_freebsd.c
test_fuzz.c
test_link_resolver.c
+ test_open_fd.c
+ test_open_file.c
+ test_open_filename.c
test_pax_filename_encoding.c
test_read_compress_program.c
test_read_data_large.c
diff --git a/libarchive/test/test_open_fd.c b/libarchive/test/test_open_fd.c
new file mode 100644
index 00000000..0aec1d5e
--- /dev/null
+++ b/libarchive/test/test_open_fd.c
@@ -0,0 +1,117 @@
+/*-
+ * 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_open_fd)
+{
+ char buff[64];
+ struct archive_entry *ae;
+ struct archive *a;
+ int fd;
+
+ fd = open("test.tar", O_RDWR | O_CREAT, 0777);
+ assert(fd >= 0);
+ if (fd < 0)
+ return;
+
+ /* Write an archive through this fd. */
+ assert((a = archive_write_new()) != NULL);
+ assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_ustar(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_write_set_compression_none(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_write_open_fd(a, fd));
+
+ /*
+ * Write a file to it.
+ */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_set_mtime(ae, 1, 0);
+ archive_entry_copy_pathname(ae, "file");
+ archive_entry_set_mode(ae, S_IFREG | 0755);
+ archive_entry_set_size(ae, 8);
+ assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
+ archive_entry_free(ae);
+ assertEqualIntA(a, 8, archive_write_data(a, "12345678", 9));
+
+ /*
+ * Write a second file to it.
+ */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_copy_pathname(ae, "file2");
+ archive_entry_set_mode(ae, S_IFREG | 0755);
+ archive_entry_set_size(ae, 819200);
+ assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
+ archive_entry_free(ae);
+
+ /* Close out the archive. */
+ assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
+ assertEqualInt(ARCHIVE_OK, archive_write_finish(a));
+
+ /*
+ * Now, read the data back.
+ */
+ assert(lseek(fd, 0, SEEK_SET) == 0);
+ assert((a = archive_read_new()) != NULL);
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_compression_all(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_open_fd(a, fd, 512));
+
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+ assertEqualInt(1, archive_entry_mtime(ae));
+ assertEqualInt(0, archive_entry_mtime_nsec(ae));
+ assertEqualInt(0, archive_entry_atime(ae));
+ assertEqualInt(0, archive_entry_ctime(ae));
+ assertEqualString("file", archive_entry_pathname(ae));
+ assert((S_IFREG | 0755) == archive_entry_mode(ae));
+ assertEqualInt(8, archive_entry_size(ae));
+ assertEqualIntA(a, 8, archive_read_data(a, buff, 10));
+ assertEqualMem(buff, "12345678", 8);
+
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+ assertEqualString("file2", archive_entry_pathname(ae));
+ assert((S_IFREG | 0755) == archive_entry_mode(ae));
+ assertEqualInt(819200, archive_entry_size(ae));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_data_skip(a));
+
+ /* Verify the end of the archive. */
+ assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
+ assertEqualInt(ARCHIVE_OK, archive_read_finish(a));
+ close(fd);
+
+
+ /*
+ * Verify some of the error handling.
+ */
+ assert((a = archive_read_new()) != NULL);
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_compression_all(a));
+ /* FD 100 shouldn't be open. */
+ assertEqualIntA(a, ARCHIVE_FATAL,
+ archive_read_open_fd(a, 100, 512));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
+ assertEqualInt(ARCHIVE_OK, archive_read_finish(a));
+}
diff --git a/libarchive/test/test_open_file.c b/libarchive/test/test_open_file.c
new file mode 100644
index 00000000..7539914f
--- /dev/null
+++ b/libarchive/test/test_open_file.c
@@ -0,0 +1,105 @@
+/*-
+ * 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_open_file)
+{
+ char buff[64];
+ struct archive_entry *ae;
+ struct archive *a;
+ FILE *f;
+
+ f = fopen("test.tar", "w");
+ assert(f != NULL);
+ if (f == NULL)
+ return;
+
+ /* Write an archive through this FILE *. */
+ assert((a = archive_write_new()) != NULL);
+ assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_ustar(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_write_set_compression_none(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_write_open_FILE(a, f));
+
+ /*
+ * Write a file to it.
+ */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_set_mtime(ae, 1, 0);
+ archive_entry_copy_pathname(ae, "file");
+ archive_entry_set_mode(ae, S_IFREG | 0755);
+ archive_entry_set_size(ae, 8);
+ assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
+ archive_entry_free(ae);
+ assertEqualIntA(a, 8, archive_write_data(a, "12345678", 9));
+
+ /*
+ * Write a second file to it.
+ */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_copy_pathname(ae, "file2");
+ archive_entry_set_mode(ae, S_IFREG | 0755);
+ archive_entry_set_size(ae, 819200);
+ assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
+ archive_entry_free(ae);
+
+ /* Close out the archive. */
+ assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
+ assertEqualInt(ARCHIVE_OK, archive_write_finish(a));
+ fclose(f);
+
+ /*
+ * Now, read the data back.
+ */
+ f = fopen("test.tar", "r");
+ assert((a = archive_read_new()) != NULL);
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_compression_all(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_open_FILE(a, f));
+
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+ assertEqualInt(1, archive_entry_mtime(ae));
+ assertEqualInt(0, archive_entry_mtime_nsec(ae));
+ assertEqualInt(0, archive_entry_atime(ae));
+ assertEqualInt(0, archive_entry_ctime(ae));
+ assertEqualString("file", archive_entry_pathname(ae));
+ assert((S_IFREG | 0755) == archive_entry_mode(ae));
+ assertEqualInt(8, archive_entry_size(ae));
+ assertEqualIntA(a, 8, archive_read_data(a, buff, 10));
+ assertEqualMem(buff, "12345678", 8);
+
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+ assertEqualString("file2", archive_entry_pathname(ae));
+ assert((S_IFREG | 0755) == archive_entry_mode(ae));
+ assertEqualInt(819200, archive_entry_size(ae));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_data_skip(a));
+
+ /* Verify the end of the archive. */
+ assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
+ assertEqualInt(ARCHIVE_OK, archive_read_finish(a));
+
+ fclose(f);
+}
diff --git a/libarchive/test/test_open_filename.c b/libarchive/test/test_open_filename.c
new file mode 100644
index 00000000..b096afcb
--- /dev/null
+++ b/libarchive/test/test_open_filename.c
@@ -0,0 +1,109 @@
+/*-
+ * 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_open_filename)
+{
+ char buff[64];
+ struct archive_entry *ae;
+ struct archive *a;
+
+ /* Write an archive through this FILE *. */
+ assert((a = archive_write_new()) != NULL);
+ assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_ustar(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_write_set_compression_none(a));
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_write_open_filename(a, "test.tar"));
+
+ /*
+ * Write a file to it.
+ */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_set_mtime(ae, 1, 0);
+ archive_entry_copy_pathname(ae, "file");
+ archive_entry_set_mode(ae, S_IFREG | 0755);
+ archive_entry_set_size(ae, 8);
+ assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
+ archive_entry_free(ae);
+ assertEqualIntA(a, 8, archive_write_data(a, "12345678", 9));
+
+ /*
+ * Write a second file to it.
+ */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_copy_pathname(ae, "file2");
+ archive_entry_set_mode(ae, S_IFREG | 0755);
+ archive_entry_set_size(ae, 819200);
+ assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
+ archive_entry_free(ae);
+
+ /* Close out the archive. */
+ assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
+ assertEqualInt(ARCHIVE_OK, archive_write_finish(a));
+
+ /*
+ * Now, read the data back.
+ */
+ assert((a = archive_read_new()) != NULL);
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_compression_all(a));
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_read_open_filename(a, "test.tar", 512));
+
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+ assertEqualInt(1, archive_entry_mtime(ae));
+ assertEqualInt(0, archive_entry_mtime_nsec(ae));
+ assertEqualInt(0, archive_entry_atime(ae));
+ assertEqualInt(0, archive_entry_ctime(ae));
+ assertEqualString("file", archive_entry_pathname(ae));
+ assert((S_IFREG | 0755) == archive_entry_mode(ae));
+ assertEqualInt(8, archive_entry_size(ae));
+ assertEqualIntA(a, 8, archive_read_data(a, buff, 10));
+ assertEqualMem(buff, "12345678", 8);
+
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+ assertEqualString("file2", archive_entry_pathname(ae));
+ assert((S_IFREG | 0755) == archive_entry_mode(ae));
+ assertEqualInt(819200, archive_entry_size(ae));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_data_skip(a));
+
+ /* Verify the end of the archive. */
+ assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
+ assertEqualInt(ARCHIVE_OK, archive_read_finish(a));
+
+ /*
+ * Verify some of the error handling.
+ */
+ assert((a = archive_read_new()) != NULL);
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_compression_all(a));
+ assertEqualIntA(a, ARCHIVE_FATAL,
+ archive_read_open_filename(a, "nonexistent.tar", 512));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
+ assertEqualInt(ARCHIVE_OK, archive_read_finish(a));
+
+}