From 3af9cc0f1550e8c882f1a017727d41b54674c2d5 Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Thu, 24 Jul 2008 18:16:08 +0000 Subject: [PATCH] Fix multivolume archive creation when volume length=record size. * src/tar.c (decode_options): Do not allow volume length less than record size. * src/buffer.c (_gnu_flush_write): Compensate for the effect of eventual flush_archive occurring in the middle of buffer move. Increment records_written only if _flush_write was able to write something. * tests/multiv06.at: New testcase. * tests/Makefile.am, test/testsuite.at: Add tests/multiv06.at --- ChangeLog | 13 +++++++++++ src/buffer.c | 19 +++++++++++++--- src/create.c | 2 +- src/tar.c | 3 +++ tests/Makefile.am | 1 + tests/multiv06.at | 57 ++++++++++++++++++++++++++++++++++++++++++++++ tests/testsuite.at | 1 + 7 files changed, 92 insertions(+), 4 deletions(-) create mode 100644 tests/multiv06.at diff --git a/ChangeLog b/ChangeLog index 6b9676c..b2e9452 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2008-07-24 Sergey Poznyakoff + + * src/tar.c (decode_options): Do not allow volume length less + than record size. + + * src/buffer.c (_gnu_flush_write): Compensate for the effect + of eventual flush_archive occurring in the middle of buffer + move. + Increment records_written only if _flush_write was able to write + something. + * tests/multiv06.at: New testcase. + * tests/Makefile.am, test/testsuite.at: Add tests/multiv06.at + 2008-06-26 Sergey Poznyakoff * configure.ac, NEWS: Version 1.20.90 diff --git a/src/buffer.c b/src/buffer.c index be0b378..e590e12 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -1,7 +1,7 @@ /* Buffer management for tar. Copyright (C) 1988, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001, - 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. + 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. Written by John Gilmore, on 1985-08-25. @@ -1599,13 +1599,15 @@ _gnu_flush_write (size_t buffer_level) char *copy_ptr; size_t copy_size; size_t bufsize; - + tarlong wrt; + status = _flush_write (); if (status != record_size && !multi_volume_option) archive_write_error (status); else { - records_written++; + if (status) + records_written++; bytes_written += status; } @@ -1654,6 +1656,7 @@ _gnu_flush_write (size_t buffer_level) if (real_s_name) add_chunk_header (); + wrt = bytes_written; header = find_next_block (); bufsize = available_space_after (header); while (bufsize < copy_size) @@ -1668,6 +1671,16 @@ _gnu_flush_write (size_t buffer_level) memcpy (header->buffer, copy_ptr, copy_size); memset (header->buffer + copy_size, 0, bufsize - copy_size); set_next_block_after (header + (copy_size - 1) / BLOCKSIZE); + if (multi_volume_option && wrt < bytes_written) + { + /* The value of bytes_written has changed while moving data; + that means that flush_archive was executed at least once in + between, and, as a consequence, copy_size bytes were not written + to disk. We need to update sizeleft variables to compensate for + that. */ + save_sizeleft += copy_size; + multi_volume_sync (); + } find_next_block (); } diff --git a/src/create.c b/src/create.c index 413115c..fc26f1e 100644 --- a/src/create.c +++ b/src/create.c @@ -1041,7 +1041,7 @@ dump_regular_file (int fd, struct tar_stat_info *st) while (size_left > 0) { size_t bufsize, count; - + mv_size_left (size_left); blk = find_next_block (); diff --git a/src/tar.c b/src/tar.c index cc11ba5..4680f46 100644 --- a/src/tar.c +++ b/src/tar.c @@ -2324,6 +2324,9 @@ decode_options (int argc, char **argv) else if (utc_option) verbose_option = 2; + if (tape_length_option && tape_length_option < record_size) + USAGE_ERROR ((0, 0, _("Volume length cannot be less than record size"))); + /* Forbid using -c with no input files whatsoever. Check that `-f -', explicit or implied, is used correctly. */ diff --git a/tests/Makefile.am b/tests/Makefile.am index 729bdd9..263f6ee 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -89,6 +89,7 @@ TESTSUITE_AT = \ multiv03.at\ multiv04.at\ multiv05.at\ + multiv06.at\ old.at\ options.at\ options02.at\ diff --git a/tests/multiv06.at b/tests/multiv06.at new file mode 100644 index 0000000..4df9cd7 --- /dev/null +++ b/tests/multiv06.at @@ -0,0 +1,57 @@ +# Process this file with autom4te to create testsuite. -*- Autotest -*- + +# Test suite for GNU tar. +# Copyright (C) 2008 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +# When volume size equals record size, swapping buffers in +# new_volume triggers a call to flush_archive. The size left variables +# must be corrected after that, which was not done in versions <= 1.20. +# Reported by: Marek Kielar +# References: <1907cbb6.79e32b49.48887f09.fd55@o2.pl> + +AT_SETUP([Multivolumes with L=record_size]) +AT_KEYWORDS([multivolume multiv multiv06]) + +m4_define([echo2],[ +echo $* +echo >&2 $* +]) + +AT_TAR_CHECK([ +exec <&- +echo2("Creating file") +genfile --length 20139 --file file +echo2("Creating archive") +tar -c -M -L10 -b20 -farc.1 -farc.2 -farc.3 file +echo2("Testing archive") +tar -t -M -farc.1 -farc.2 -farc.3], +[0], +[Creating file +Creating archive +Testing archive +file +], +[Creating file +Creating archive +Testing archive +], +[],[], +[gnu, pax]) + +AT_CLEANUP + diff --git a/tests/testsuite.at b/tests/testsuite.at index 5b63354..11f108b 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -155,6 +155,7 @@ m4_include([multiv02.at]) m4_include([multiv03.at]) m4_include([multiv04.at]) m4_include([multiv05.at]) +m4_include([multiv06.at]) m4_include([old.at]) -- 2.45.2