]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Improve test coverage:
authorTim Kientzle <kientzle@gmail.com>
Sun, 29 Mar 2009 04:31:57 +0000 (00:31 -0400)
committerTim Kientzle <kientzle@gmail.com>
Sun, 29 Mar 2009 04:31:57 +0000 (00:31 -0400)
* 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

Makefile.am
libarchive/archive_read_open_fd.c
libarchive/archive_read_open_file.c
libarchive/archive_read_open_filename.c
libarchive/archive_write_open_filename.c
libarchive/test/CMakeLists.txt
libarchive/test/test_open_fd.c [new file with mode: 0644]
libarchive/test/test_open_file.c [new file with mode: 0644]
libarchive/test/test_open_filename.c [new file with mode: 0644]

index 9967f3ae025cf696269576bc4588ce351fd20a6b..78030509b5d8d3d4a6be13b3d926ed3190387f01 100644 (file)
@@ -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                  \
index 2ebd46d6cdf8b8fa48d881bec4040b5383ebcb60..d44d4ad94346f81a9804c8140a6682e22ca93819 100644 (file)
@@ -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);
 }
index 55c431c7da6e6a43e67e6500a773414daa6ff68e..904e84490c65592423c985f672e20111a918559e 100644 (file)
@@ -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
index f8a0fa4cfad98b269cbb05758421e5e4182ad622..18ae079ece7a1cdddb4af926feae0689b677c4db 100644 (file)
@@ -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);
index 72eeb54053debb52c25a8b1749337e10fac316b3..b9ae1747bf7d3490f5eedcbaa46819aa412e0a3f 100644 (file)
@@ -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);
 }
index 19032c6c298599fde3c98c934e90889155ac7eb4..4e765ecf0ed89735aa587653ba564bf2da317e8b 100644 (file)
@@ -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 (file)
index 0000000..0aec1d5
--- /dev/null
@@ -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 (file)
index 0000000..7539914
--- /dev/null
@@ -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 (file)
index 0000000..b096afc
--- /dev/null
@@ -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));
+
+}