From a5faebae4a45342f035681844764b46bc962865c Mon Sep 17 00:00:00 2001 From: kientzle Date: Mon, 18 Jun 2007 00:36:54 +0000 Subject: Track whether the current read stream supports seek(). For now, we assume yes unless seek has previously failed, but I fear I'll have to avoid seeks under other circumstances. (For instance, tape drives on FreeBSD seem to return garbage from lseek().) Also, optimize away zero-byte skips. --- lib/libarchive/archive_read_open_fd.c | 11 +++++++++++ lib/libarchive/archive_read_open_filename.c | 11 +++++++++++ 2 files changed, 22 insertions(+) (limited to 'lib') diff --git a/lib/libarchive/archive_read_open_fd.c b/lib/libarchive/archive_read_open_fd.c index 490b00b..0608fd6 100644 --- a/lib/libarchive/archive_read_open_fd.c +++ b/lib/libarchive/archive_read_open_fd.c @@ -47,6 +47,7 @@ __FBSDID("$FreeBSD$"); struct read_fd_data { int fd; size_t block_size; + char can_skip; void *buffer; }; @@ -77,6 +78,7 @@ archive_read_open_fd(struct archive *a, int fd, size_t block_size) return (ARCHIVE_FATAL); } mine->fd = fd; + mine->can_skip = 1; return (archive_read_open2(a, mine, file_open, file_read, file_skip, file_close)); } @@ -121,8 +123,14 @@ file_skip(struct archive *a, void *client_data, off_t request) struct read_fd_data *mine = (struct read_fd_data *)client_data; off_t old_offset, new_offset; + if (!mine->can_skip) + return (0); + /* Reduce request to the next smallest multiple of block_size */ request = (request / mine->block_size) * mine->block_size; + if (request == 0) + return (0); + /* * Hurray for lazy evaluation: if the first lseek fails, the second * one will not be executed. @@ -130,6 +138,9 @@ file_skip(struct archive *a, void *client_data, off_t request) if (((old_offset = lseek(mine->fd, 0, SEEK_CUR)) < 0) || ((new_offset = lseek(mine->fd, request, SEEK_CUR)) < 0)) { + /* If seek failed once, it will probably fail again. */ + mine->can_skip = 0; + if (errno == ESPIPE) { /* diff --git a/lib/libarchive/archive_read_open_filename.c b/lib/libarchive/archive_read_open_filename.c index b4dd2e2..c95e787 100644 --- a/lib/libarchive/archive_read_open_filename.c +++ b/lib/libarchive/archive_read_open_filename.c @@ -52,6 +52,7 @@ struct read_file_data { size_t block_size; void *buffer; mode_t st_mode; /* Mode bits for opened file. */ + char can_skip; /* This file supports skipping. */ char filename[1]; /* Must be last! */ }; @@ -95,6 +96,7 @@ archive_read_open_filename(struct archive *a, const char *filename, mine->block_size = block_size; mine->buffer = NULL; mine->fd = -1; + mine->can_skip = 1; return (archive_read_open2(a, mine, file_open, file_read, file_skip, file_close)); } @@ -165,8 +167,14 @@ file_skip(struct archive *a, void *client_data, off_t request) struct read_file_data *mine = (struct read_file_data *)client_data; off_t old_offset, new_offset; + if (!mine->can_skip) /* We can't skip, so ... */ + return (0); /* ... skip zero bytes. */ + /* Reduce request to the next smallest multiple of block_size */ request = (request / mine->block_size) * mine->block_size; + if (request == 0) + return (0); + /* * Hurray for lazy evaluation: if the first lseek fails, the second * one will not be executed. @@ -174,6 +182,9 @@ file_skip(struct archive *a, void *client_data, off_t request) if (((old_offset = lseek(mine->fd, 0, SEEK_CUR)) < 0) || ((new_offset = lseek(mine->fd, request, SEEK_CUR)) < 0)) { + /* If skip failed once, it will probably fail again. */ + mine->can_skip = 0; + if (errno == ESPIPE) { /* -- cgit v1.1