]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Fix the problem that bsdtar with new directory traversals code fail
authorMichihiro NAKAJIMA <ggcueroad@gmail.com>
Tue, 28 Feb 2012 05:22:15 +0000 (14:22 +0900)
committerMichihiro NAKAJIMA <ggcueroad@gmail.com>
Tue, 28 Feb 2012 05:22:15 +0000 (14:22 +0900)
when creating a newc archive.

Makefile.am
tar/test/CMakeLists.txt
tar/test/test_format_newc.c [new file with mode: 0644]
tar/write.c

index c6b9c9a4848b4ee08ecf790190136529a846f816..2a58bae6c56f387d1930f92513017fc647c9cdc3 100644 (file)
@@ -651,6 +651,7 @@ bsdtar_test_SOURCES=                                                \
        tar/test/test_basic.c                                   \
        tar/test/test_copy.c                                    \
        tar/test/test_empty_mtree.c                             \
+       tar/test/test_format_newc.c                             \
        tar/test/test_help.c                                    \
        tar/test/test_option_C_upper.c                          \
        tar/test/test_option_H_upper.c                          \
index 067e7f6b995ca2da34616f5d615b1d5e478594bb..d776d781783bcc8aaeee99eebcfd4c2334aa8ccd 100644 (file)
@@ -11,6 +11,7 @@ IF(ENABLE_TAR AND ENABLE_TEST)
     test_basic.c
     test_copy.c
     test_empty_mtree.c
+    test_format_newc.c
     test_help.c
     test_option_C_upper.c
     test_option_H_upper.c
diff --git a/tar/test/test_format_newc.c b/tar/test/test_format_newc.c
new file mode 100644 (file)
index 0000000..808fa4b
--- /dev/null
@@ -0,0 +1,64 @@
+/*-
+ * Copyright (c) 2012 Michihiro NAKAJIMA
+ * 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_format_newc)
+{
+
+       assertMakeFile("file1", 0644, "file1");
+       assertMakeFile("file2", 0644, "file2");
+       assertMakeHardlink("file3", "file1");
+
+       /* Test 1: Create an archive file with a newc format. */
+       assertEqualInt(0,
+           systemf("%s -cf test1.cpio --format newc file1 file2 file3",
+           testprog));
+       assertMakeDir("test1", 0755);
+       assertChdir("test1");
+       assertEqualInt(0,
+           systemf("%s -xf ../test1.cpio >test.out 2>test.err", testprog));
+       assertFileContents("file1", 5, "file1");
+       assertFileContents("file2", 5, "file2");
+       assertFileContents("file1", 5, "file3");
+       assertEmptyFile("test.out");
+       assertEmptyFile("test.err");
+       assertChdir("..");
+
+       /* Test 2: Exclude one of hardlinked files. */
+       assertEqualInt(0,
+           systemf("%s -cf test2.cpio --format newc file1 file2",
+           testprog));
+       assertMakeDir("test2", 0755);
+       assertChdir("test2");
+       assertEqualInt(0,
+           systemf("%s -xf ../test2.cpio >test.out 2>test.err", testprog));
+       assertFileContents("file1", 5, "file1");
+       assertFileContents("file2", 5, "file2");
+       assertFileNotExists("file3");
+       assertEmptyFile("test.out");
+       assertEmptyFile("test.err");
+       assertChdir("..");
+}
index 158d25a08faf476b049cf39e4ea20a6e4ee5d985..3fb861277d117bef0a329a3d9816554a4adaf6da 100644 (file)
@@ -394,6 +394,7 @@ write_archive(struct archive *a, struct bsdtar *bsdtar)
 {
        const char *arg;
        struct archive_entry *entry, *sparse_entry;
+       struct archive *disk, *disk_saved;
 
        /* Choose a suitable copy buffer size */
        bsdtar->buff_size = 64 * 1024;
@@ -474,13 +475,63 @@ write_archive(struct archive *a, struct bsdtar *bsdtar)
        }
 
        entry = NULL;
+       disk = NULL;
+       disk_saved = bsdtar->diskreader;
        archive_entry_linkify(bsdtar->resolver, &entry, &sparse_entry);
        while (entry != NULL) {
+               int r;
+               struct archive_entry *entry2;
+
+               /*
+                * This tricky code here is to correctly read the cotents
+                * of the entry because the disk reader bsdtar->diskreader
+                * is pointing at does not have any information about the
+                * entry by this time and using archive_read_data_block()
+                * with the disk reader consequently must fail. And we
+                * have to create a new disk reader object to read the
+                * contents.
+                */
+               if (disk == NULL && (disk = archive_read_disk_new()) == NULL)
+                       lafe_errc(1, 0, "Cannot create read_disk object");
+               else
+                       bsdtar->diskreader = disk;
+
+               /* TODO: Work with -C option as well. */
+               r = archive_read_disk_open(disk,
+                       archive_entry_sourcepath(entry));
+               if (r != ARCHIVE_OK) {
+                       lafe_warnc(archive_errno(disk),
+                           "%s", archive_error_string(disk));
+                       bsdtar->return_value = 1;
+                       archive_entry_free(entry);
+                       continue;
+               }
+
+               /*
+                * Invoke archive_read_next_header2() to work
+                * archive_read_data_block(), which is called via write_file(),
+                * without failure.
+                */
+               entry2 = archive_entry_new();
+               r = archive_read_next_header2(disk, entry2);
+               archive_entry_free(entry2);
+               if (r != ARCHIVE_OK) {
+                       lafe_warnc(archive_errno(disk),
+                           "%s", archive_error_string(disk));
+                       if (r == ARCHIVE_FATAL)
+                               bsdtar->return_value = 1;
+                       archive_entry_free(entry);
+                       continue;
+               }
+
                write_file(bsdtar, a, entry);
                archive_entry_free(entry);
                entry = NULL;
                archive_entry_linkify(bsdtar->resolver, &entry, &sparse_entry);
        }
+       bsdtar->diskreader = disk_saved;
+       if (disk != NULL)
+               archive_read_free(disk);
 
        if (archive_write_close(a)) {
                lafe_warnc(0, "%s", archive_error_string(a));