]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Fix issue336:7zip can not be read when opened with archive_read_open_fd.
authorMichihiro NAKAJIMA <ggcueroad@gmail.com>
Sun, 3 Aug 2014 05:51:15 +0000 (14:51 +0900)
committerMichihiro NAKAJIMA <ggcueroad@gmail.com>
Sun, 3 Aug 2014 05:56:40 +0000 (14:56 +0900)
Implenent a seek callback in archive_read_open_fd by bringin the code
from archive_open_filename.

libarchive/archive_read_open_fd.c
libarchive/test/test_read_format_7zip.c

index e0f95bf41b65e8d28c0db7bc3396bf83698d54be..f59cd07fe6c0aaa8c350db7011d8b60d7abae358 100644 (file)
@@ -59,6 +59,7 @@ struct read_fd_data {
 
 static int     file_close(struct archive *, void *);
 static ssize_t file_read(struct archive *, void *, const void **buff);
+static int64_t file_seek(struct archive *, void *, int64_t request, int);
 static int64_t file_skip(struct archive *, void *, int64_t request);
 
 int
@@ -102,6 +103,7 @@ archive_read_open_fd(struct archive *a, int fd, size_t block_size)
 
        archive_read_set_read_callback(a, file_read);
        archive_read_set_skip_callback(a, file_skip);
+       archive_read_set_seek_callback(a, file_seek);
        archive_read_set_close_callback(a, file_close);
        archive_read_set_callback_data(a, mine);
        return (archive_read_open1(a));
@@ -170,6 +172,33 @@ file_skip(struct archive *a, void *client_data, int64_t request)
        return (-1);
 }
 
+/*
+ * TODO: Store the offset and use it in the read callback.
+ */
+static int64_t
+file_seek(struct archive *a, void *client_data, int64_t request, int whence)
+{
+       struct read_fd_data *mine = (struct read_fd_data *)client_data;
+       int64_t r;
+
+       /* We use off_t here because lseek() is declared that way. */
+       /* See above for notes about when off_t is less than 64 bits. */
+       r = lseek(mine->fd, request, whence);
+       if (r >= 0)
+               return r;
+
+       if (errno == ESPIPE) {
+               archive_set_error(a, errno,
+                   "A file descriptor(%d) is not seekable(PIPE)", mine->fd);
+               return (ARCHIVE_FAILED);
+       } else {
+               /* If the input is corrupted or truncated, fail. */
+               archive_set_error(a, errno,
+                   "Error seeking in a file descriptor(%d)", mine->fd);
+               return (ARCHIVE_FATAL);
+       }
+}
+
 static int
 file_close(struct archive *a, void *client_data)
 {
index 6081d2bf1b95ba0a21bd2f8d4ea4c5033f4d4d38..ea9035aa79e83ff729a6c4d6416ff5f0222065ee 100644 (file)
@@ -30,19 +30,26 @@ __FBSDID("$FreeBSD");
  * The header of the 7z archive files is not encoded.
  */
 static void
-test_copy()
+test_copy(int use_open_fd)
 {
        const char *refname = "test_read_format_7zip_copy.7z";
        struct archive_entry *ae;
        struct archive *a;
        char buff[128];
+       int fd = -1;
 
        extract_reference_file(refname);
        assert((a = archive_read_new()) != NULL);
        assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
        assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
-       assertEqualIntA(a, ARCHIVE_OK,
-           archive_read_open_filename(a, refname, 10240));
+       if (use_open_fd) {
+               fd = open(refname, O_RDONLY | O_BINARY); 
+               assertEqualIntA(a, ARCHIVE_OK,
+                   archive_read_open_fd(a, fd, 10240));
+       } else {
+               assertEqualIntA(a, ARCHIVE_OK,
+                   archive_read_open_filename(a, refname, 10240));
+       }
 
        /* Verify regular file1. */
        assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
@@ -67,6 +74,8 @@ test_copy()
        /* Close the archive. */
        assertEqualInt(ARCHIVE_OK, archive_read_close(a));
        assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+       if (fd != -1)
+               close(fd);
 }
 
 /*
@@ -735,9 +744,14 @@ DEFINE_TEST(test_read_format_7zip_bzip2)
        assertEqualInt(ARCHIVE_OK, archive_read_free(a));
 }
 
+DEFINE_TEST(test_read_format_7zip_from_fd)
+{
+       test_copy(1);/* read a 7zip file from a file descriptor. */
+}
+
 DEFINE_TEST(test_read_format_7zip_copy)
 {
-       test_copy();
+       test_copy(0);
        test_bcj("test_read_format_7zip_bcj_copy.7z");
        test_bcj("test_read_format_7zip_bcj2_copy_1.7z");
        test_bcj("test_read_format_7zip_bcj2_copy_2.7z");