From: Michihiro NAKAJIMA Date: Sun, 3 Aug 2014 05:51:15 +0000 (+0900) Subject: Fix issue336:7zip can not be read when opened with archive_read_open_fd. X-Git-Tag: v3.1.900a~254 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c0dd6ae5c5369384c14fcc1486886d8463c98909;p=thirdparty%2Flibarchive.git Fix issue336:7zip can not be read when opened with archive_read_open_fd. Implenent a seek callback in archive_read_open_fd by bringin the code from archive_open_filename. --- diff --git a/libarchive/archive_read_open_fd.c b/libarchive/archive_read_open_fd.c index e0f95bf41..f59cd07fe 100644 --- a/libarchive/archive_read_open_fd.c +++ b/libarchive/archive_read_open_fd.c @@ -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) { diff --git a/libarchive/test/test_read_format_7zip.c b/libarchive/test/test_read_format_7zip.c index 6081d2bf1..ea9035aa7 100644 --- a/libarchive/test/test_read_format_7zip.c +++ b/libarchive/test/test_read_format_7zip.c @@ -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");