diff --git a/tar-1.15.1-lseek.patch b/tar-1.15.1-lseek.patch new file mode 100644 index 0000000..1fedbe4 --- /dev/null +++ b/tar-1.15.1-lseek.patch @@ -0,0 +1,162 @@ +--- tar-1.15.1/src/sparse.c.lseek 2004-09-06 13:30:57.000000000 +0200 ++++ tar-1.15.1/src/sparse.c 2005-04-15 10:33:17.990735744 +0200 +@@ -46,6 +46,9 @@ + struct tar_sparse_file + { + int fd; /* File descriptor */ ++ bool seekable; /* Is fd seekable? */ ++ size_t offset; /* Current offset in fd if seekable==false. ++ Otherwise unused */ + size_t dumped_size; /* Number of bytes actually written + to the archive */ + struct tar_stat_info *stat_info; /* Information about the file */ +@@ -54,6 +57,39 @@ + reqiure */ + }; + ++/* Dump zeros to file->fd until offset is reached. It is used instead of ++ lseek if the output file is not seekable */ ++static long ++dump_zeros (struct tar_sparse_file *file, off_t offset) ++{ ++ char buf[BLOCKSIZE]; ++ ++ if (offset - file->offset < 0) ++ { ++ errno = EINVAL; ++ return -1; ++ } ++ ++ memset (buf, 0, sizeof buf); ++ while (file->offset < offset) ++ { ++ size_t size = offset - file->offset; ++ size_t wrbytes; ++ ++ if (size > sizeof buf) ++ size = sizeof buf; ++ wrbytes = write (file->fd, buf, size); ++ if (wrbytes <= 0) ++ { ++ if (wrbytes == 0) ++ errno = EINVAL; ++ return -1; ++ } ++ file->offset += wrbytes; ++ } ++ return file->offset; ++} ++ + static bool + tar_sparse_member_p (struct tar_sparse_file *file) + { +@@ -130,9 +166,16 @@ + + + static bool +-lseek_or_error (struct tar_sparse_file *file, off_t offset, int whence) ++lseek_or_error (struct tar_sparse_file *file, off_t offset) + { +- if (lseek (file->fd, offset, whence) < 0) ++ off_t off; ++ ++ if (file->seekable) ++ off = lseek (file->fd, offset, SEEK_SET); ++ else ++ off = dump_zeros (file, offset); ++ ++ if (off < 0) + { + seek_diag_details (file->stat_info->orig_file_name, offset); + return false; +@@ -182,10 +225,10 @@ + { + static char buffer[BLOCKSIZE]; + size_t count; +- size_t offset = 0; ++ off_t offset = 0; + struct sp_array sp = {0, 0}; + +- if (!lseek_or_error (file, 0, SEEK_SET)) ++ if (!lseek_or_error (file, 0)) + return false; + clear_block (buffer); + +@@ -269,8 +312,7 @@ + union block *blk; + off_t bytes_left = file->stat_info->sparse_map[i].numbytes; + +- if (!lseek_or_error (file, file->stat_info->sparse_map[i].offset, +- SEEK_SET)) ++ if (!lseek_or_error (file, file->stat_info->sparse_map[i].offset)) + return false; + + while (bytes_left > 0) +@@ -304,8 +346,7 @@ + { + size_t write_size; + +- if (!lseek_or_error (file, file->stat_info->sparse_map[i].offset, +- SEEK_SET)) ++ if (!lseek_or_error (file, file->stat_info->sparse_map[i].offset)) + return false; + + write_size = file->stat_info->sparse_map[i].numbytes; +@@ -313,7 +354,7 @@ + if (write_size == 0) + { + /* Last block of the file is a hole */ +- if (sys_truncate (file->fd)) ++ if (file->seekable && sys_truncate (file->fd)) + truncate_warn (file->stat_info->orig_file_name); + } + else while (write_size > 0) +@@ -330,6 +371,7 @@ + count = full_write (file->fd, blk->buffer, wrbytes); + write_size -= count; + file->dumped_size += count; ++ file->offset += count; + if (count != wrbytes) + { + write_error_details (file->stat_info->orig_file_name, +@@ -351,7 +393,9 @@ + + file.stat_info = st; + file.fd = fd; +- ++ file.seekable = true; /* File *must* be seekable for dump to work */ ++ file.offset = 0; ++ + if (!sparse_select_optab (&file) + || !tar_sparse_init (&file)) + return dump_status_not_implemented; +@@ -414,7 +458,9 @@ + + file.stat_info = st; + file.fd = fd; +- ++ file.seekable = lseek (fd, 0, SEEK_SET) == 0; ++ file.offset = 0; ++ + if (!sparse_select_optab (&file) + || !tar_sparse_init (&file)) + return dump_status_not_implemented; +@@ -450,7 +496,7 @@ + static bool + check_sparse_region (struct tar_sparse_file *file, off_t beg, off_t end) + { +- if (!lseek_or_error (file, beg, SEEK_SET)) ++ if (!lseek_or_error (file, beg)) + return false; + + while (beg < end) +@@ -486,8 +532,7 @@ + { + size_t size_left; + +- if (!lseek_or_error (file, file->stat_info->sparse_map[i].offset, +- SEEK_SET)) ++ if (!lseek_or_error (file, file->stat_info->sparse_map[i].offset)) + return false; + size_left = file->stat_info->sparse_map[i].numbytes; + while (size_left > 0) diff --git a/tar.spec b/tar.spec index 53cc1f1..e5efa6f 100644 --- a/tar.spec +++ b/tar.spec @@ -1,7 +1,7 @@ Summary: A GNU file archiving program. Name: tar Version: 1.15.1 -Release: 4 +Release: 5 License: GPL Group: Applications/Archiving URL: http://www.gnu.org/software/tar/ @@ -13,6 +13,7 @@ Patch7: tar-1.14-err.patch Patch8: tar-1.14-loneZeroWarning.patch Patch9: tar-1.15.1-makeCheck.patch Patch10: tar-1.15.1-gcc4.patch +Patch11: tar-1.15.1-lseek.patch Prereq: info BuildRequires: autoconf automake gzip Buildroot: %{_tmppath}/%{name}-%{version}-root @@ -37,6 +38,7 @@ the rmt package. %patch8 -p1 -b .loneZeroWarning %patch9 -p1 -b .makeCheck %patch10 -p1 -b .gcc4 +%patch11 -p1 -b .lseek %build @@ -107,6 +109,10 @@ fi %{_infodir}/tar.info* %changelog +* Fri Apr 15 2005 Peter Vrabec 1.15.1-5 +- extract sparse files even if the output fd is not seekable.(#154882) +- (sparse_scan_file): Bugfix. offset had incorrect type. + * Mon Mar 14 2005 Peter Vrabec - gcc4 fix (#150993) 1.15.1-4