Fix --keep-old-files option.

The regression was introduced by 8f390db9.  This patch implements additional
option --skip-old-files, which silently skips members which would cause
writing over existing files, and restores --keep-old-files to its traditional
behavior.

* NEWS: Update.
* configure.ac: Update.
* doc/tar.texi: Document the changes.
* src/common.h (SKIP_OLD_FILES): New old_files mode.
* src/extract.c (maybe_recoverable): Restore KEEP_OLD_FILES behavior.
Handle SKIP_OLD_FILES.
* src/tar.c: New option --skip-old-files.
* tests/extrac18.at: New file.
* tests/extrac19.at: New file.
* tests/Makefile.am: Add new test cases.
* tests/testsuite.at: Likewise.
This commit is contained in:
Sergey Poznyakoff
2011-11-26 15:41:43 +02:00
parent 02bf3a96a9
commit 7a5a3708cb
10 changed files with 209 additions and 27 deletions

19
NEWS
View File

@@ -1,8 +1,8 @@
GNU tar NEWS - User visible changes. 2011-08-13
GNU tar NEWS - User visible changes. 2011-11-26
Please send GNU tar bug reports to <bug-tar@gnu.org>
version ?.? - ?, 201?-??-??
version 1.26.90 (Git)
* New features
@@ -13,6 +13,21 @@ NAME:NUM, so that you can specify both symbolic name and numeric ID
for owner and group. In these options, NAME no longer needs to be
present in the current host's user and group databases.
* The --keep-old-files and --skip-old-files options.
This release restores the traditional functionality of the
--keep-old-files. This option causes tar to avoid replacing
existing files while extracting and to treat such files as errors.
Tar will emit a prominent error message upon encountering such files
and will exit with code 2 when finished extracting the archive.
A new option --skip-old-files is introduced, which acts exactly as
--keep-old-files, except that it does not treat existing files as
errors. Instead it just silently skips them. An additional level of
verbosity can be obtained by using the option --warning=existing-file
together with this option.
version 1.26 - Sergey Poznyakoff, 2011-03-12
* Bugfixes

View File

@@ -19,7 +19,7 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.
AC_INIT([GNU tar], [1.26], [bug-tar@gnu.org])
AC_INIT([GNU tar], [1.26.90], [bug-tar@gnu.org])
AC_CONFIG_SRCDIR([src/tar.c])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_HEADERS([config.h])

View File

@@ -1877,6 +1877,7 @@ The other operations of @command{tar} (@option{--list},
@option{--extract}, @option{--compare}, and @option{--update})
will act on the entire contents of the archive.
@anchor{exit status}
@cindex exit status
@cindex return status
Besides successful exits, @GNUTAR{} may fail for
@@ -2808,7 +2809,10 @@ when extracting files from an archive.
@item --keep-old-files
@itemx -k
Do not overwrite existing files when extracting files from an archive.
Do not overwrite existing files when extracting files from an
archive. Return error if such files exist. See also
@ref{--skip-old-files}.
@xref{Keep Old Files}.
@opsummary{label}
@@ -3261,6 +3265,20 @@ the archive creation operations it instructs @command{tar} to list the
member names stored in the archive, as opposed to the actual file
names. @xref{listing member and file names}.
@opsummary{skip-old-files}
@item --skip-old-files
Do not overwrite existing files when extracting files from an
archive. @xref{Keep Old Files}.
This option differs from @option{--keep-old-files} in that it does not
treat such files as an error, instead it just silently avoids
overwriting them.
The @option{--warning=existing-file} option can be used together with
this option to produce warning messages about existing old files
(@pxref{warnings}).
@opsummary{sparse}
@item --sparse
@itemx -S
@@ -4436,11 +4454,11 @@ in the archive; the most recently archived members will be extracted
last. Additionally, an extracted member will @emph{replace} a file of
the same name which existed in the directory already, and @command{tar}
will not prompt you about this@footnote{Unless you give it
@option{--keep-old-files} option, or the disk copy is newer than
the one in the archive and you invoke @command{tar} with
@option{--keep-newer-files} option.}. Thus, only the most recently archived
member will end up being extracted, as it will replace the one
extracted before it, and so on.
@option{--keep-old-files} (or @option{--skip-old-files}) option, or
the disk copy is newer than the one in the archive and you invoke
@command{tar} with @option{--keep-newer-files} option.}. Thus, only
the most recently archived member will end up being extracted, as it
will replace the one extracted before it, and so on.
@cindex extracting @var{n}th copy of the file
@xopindex{occurrence, described}
@@ -5131,10 +5149,25 @@ such a directory, use the @option{--no-overwrite-dir} option.
@cindex Overwriting old files, prevention
@xopindex{keep-old-files, introduced}
To be even more cautious and prevent existing files from being replaced, use
the @option{--keep-old-files} (@option{-k}) option. It causes @command{tar} to refuse
to replace or update a file that already exists, i.e., a file with the
same name as an archive member prevents extraction of that archive
member. Instead, it reports an error.
the @option{--keep-old-files} (@option{-k}) option. It causes
@command{tar} to refuse to replace or update a file that already
exists, i.e., a file with the same name as an archive member prevents
extraction of that archive member. Instead, it reports an error. For
example:
@example
$ @kbd{ls}
blues
$ @kbd{tar -x -k -f archive.tar}
tar: blues: Cannot open: File exists
tar: Exiting with failure status due to previous errors
@end example
@xopindex{skip-old-files, introduced}
If you wish to preserve old files untouched, but don't want
@command{tar} to treat them as errors, use the
@option{--skip-old-files} option. This option causes @command{tar} to
silently skip extracting over existing files.
@xopindex{overwrite, introduced}
To be more aggressive about altering existing files, use the
@@ -5200,16 +5233,24 @@ archive, but remove other files before extracting.
@node Keep Old Files
@unnumberedsubsubsec Keep Old Files
@GNUTAR{} provides two options to control its actions in a situation
when it is about to extract a file which already exists on disk.
@table @option
@opindex keep-old-files
@item --keep-old-files
@itemx -k
Do not replace existing files from archive. The
@option{--keep-old-files} (@option{-k}) option prevents @command{tar}
from replacing existing files with files with the same name from the
archive. The @option{--keep-old-files} option is meaningless with
@option{--list} (@option{-t}). Prevents @command{tar} from replacing
files in the file system during extraction.
Do not replace existing files from archive. When such a file is
encountered, @command{tar} issues an error message. Upon end of
extraction, @command{tar} exits with code 2 (@pxref{exit status}).
@item --skip-old-files
Do not replace existing files from archive, but do not treat that
as error. Such files are silently skipped and do not affect
@command{tar} exit status.
Additional verbosity can be obtained using @option{--warning=existing-file}
together with that option (@pxref{warnings}).
@end table
@node Keep Newer Files
@@ -11937,11 +11978,16 @@ lets the archive overwrite any file in your system that you can write,
the @option{--absolute-names} (@option{-P}) option should be used only
for trusted archives.
Conversely, with the @option{--keep-old-files} (@option{-k}) option,
@command{tar} refuses to replace existing files when extracting; and
with the @option{--no-overwrite-dir} option, @command{tar} refuses to
replace the permissions or ownership of already-existing directories.
These options may help when extracting from untrusted archives.
Conversely, with the @option{--keep-old-files} (@option{-k}) and
@option{--skip-old-files} options, @command{tar} refuses to replace
existing files when extracting. The difference between the two
options is that the former treats existing files as errors whereas the
latter just silently ignores them.
Finally, with the @option{--no-overwrite-dir} option, @command{tar}
refuses to replace the permissions or ownership of already-existing
directories. These options may help when extracting from untrusted
archives.
@node Live untrusted data
@subsection Dealing with Live Untrusted Data

View File

@@ -183,6 +183,7 @@ enum old_files
OVERWRITE_OLD_FILES, /* --overwrite */
UNLINK_FIRST_OLD_FILES, /* --unlink-first */
KEEP_OLD_FILES, /* --keep-old-files */
SKIP_OLD_FILES, /* --skip-old-files */
KEEP_NEWER_FILES /* --keep-newer-files */
};
GLOBAL enum old_files old_files_option;

View File

@@ -642,11 +642,14 @@ maybe_recoverable (char *file_name, bool regular, bool *interdir_made)
switch (old_files_option)
{
case KEEP_OLD_FILES:
case SKIP_OLD_FILES:
WARNOPT (WARN_EXISTING_FILE,
(0, 0, _("%s: skipping existing file"), file_name));
return RECOVER_SKIP;
case KEEP_OLD_FILES:
return RECOVER_NO;
case KEEP_NEWER_FILES:
if (file_newer_p (file_name, stp, &current_stat_info))
break;

View File

@@ -328,6 +328,7 @@ enum
SHOW_DEFAULTS_OPTION,
SHOW_OMITTED_DIRS_OPTION,
SHOW_TRANSFORMED_NAMES_OPTION,
SKIP_OLD_FILES_OPTION,
SPARSE_VERSION_OPTION,
STRIP_COMPONENTS_OPTION,
SUFFIX_OPTION,
@@ -452,7 +453,11 @@ static struct argp_option options[] = {
{"remove-files", REMOVE_FILES_OPTION, 0, 0,
N_("remove files after adding them to the archive"), GRID+1 },
{"keep-old-files", 'k', 0, 0,
N_("don't replace existing files when extracting"), GRID+1 },
N_("don't replace existing files when extracting, "
"treat them as errors"), GRID+1 },
{"skip-old-files", SKIP_OLD_FILES_OPTION, 0, 0,
N_("don't replace existing files when extracting, silently skip over them"),
GRID+1 },
{"keep-newer-files", KEEP_NEWER_FILES_OPTION, 0, 0,
N_("don't replace existing files that are newer than their archive copies"), GRID+1 },
{"overwrite", OVERWRITE_OPTION, 0, 0,
@@ -1544,7 +1549,7 @@ parse_opt (int key, char *arg, struct argp_state *state)
/* Don't replace existing files. */
old_files_option = KEEP_OLD_FILES;
break;
case 'K':
starting_file_option = true;
addname (arg, 0, true, NULL);
@@ -1674,6 +1679,10 @@ parse_opt (int key, char *arg, struct argp_state *state)
sparse_option = true;
break;
case SKIP_OLD_FILES_OPTION:
old_files_option = SKIP_OLD_FILES;
break;
case SPARSE_VERSION_OPTION:
sparse_option = true;
{

View File

@@ -86,6 +86,8 @@ TESTSUITE_AT = \
extrac15.at\
extrac16.at\
extrac17.at\
extrac18.at\
extrac19.at\
filerem01.at\
filerem02.at\
gzip.at\

60
tests/extrac18.at Normal file
View File

@@ -0,0 +1,60 @@
# Process this file with autom4te to create testsuite. -*- Autotest -*-
#
# Test suite for GNU tar.
# Copyright (C) 2011 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, see <http://www.gnu.org/licenses/>.
# Description: Check the functionality of the --keep-old-files option.
# It should report an error and cause tar to exit with status 2.
#
# There was a regression in versions 1.23 to 1.26 inclusive, where
# this option silently skipped such files.
# Reported by: Doug McLaren <dougmc@frenzied.us>,
# Gary Partis <gary@partis.co.uk>,
# Jim Meyering <jim@meyering.net>
#
# References: <20111117045433.GA8245@algol.frenzied.us>,
# <4F3D824717847C4487F77228F83329A3514CBB@server.Partis.local>,
# <87wrar6zzz.fsf@rho.meyering.net>
AT_SETUP([keep-old-files])
AT_KEYWORDS([extract extrac18 old-files keep-old-files])
AT_TAR_CHECK([
mkdir dir
cd dir
echo 'Old file a' > a
echo 'Old file b' > b
tar cf ../archive .
rm b
echo 'File a' > a
tar -x -k -f ../archive
echo status=$?
cat a
],
[0],
[status=2
File a
],
[tar: ./a: Cannot open: File exists
tar: Exiting with failure status due to previous errors
])
AT_CLEANUP

44
tests/extrac19.at Normal file
View File

@@ -0,0 +1,44 @@
# Process this file with autom4te to create testsuite. -*- Autotest -*-
#
# Test suite for GNU tar.
# Copyright (C) 2011 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, see <http://www.gnu.org/licenses/>.
AT_SETUP([skip-old-files])
AT_KEYWORDS([extract extrac19 old-files skip-old-files])
AT_TAR_CHECK([
mkdir dir
cd dir
echo 'Old file a' > a
echo 'Old file b' > b
tar cf ../archive .
rm b
echo 'File a' > a
tar -x --skip-old-files -f ../archive
echo status=$?
cat a
],
[0],
[status=0
File a
])
AT_CLEANUP

View File

@@ -166,6 +166,8 @@ m4_include([extrac14.at])
m4_include([extrac15.at])
m4_include([extrac16.at])
m4_include([extrac17.at])
m4_include([extrac18.at])
m4_include([extrac19.at])
m4_include([label01.at])
m4_include([label02.at])