From 4bf4efe97d25784eb5e56c8ee337af3c7866ec34 Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Tue, 24 Sep 2013 14:01:13 +0300 Subject: [PATCH 01/11] Fix normalize_filename. The function did not take into account eventual -C options, which in particular led to various problems when using -C and --remove-files together. * src/common.h (namebuf_add_dir,namebuf_finish) (tar_getcwd): New prototypes. * src/misc.c (namebuf_add_dir,namebuf_finish) (tar_getcwd): New functions. (normalize_filename): Use tar_getcwd. --- src/common.h | 4 ++++ src/misc.c | 41 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/src/common.h b/src/common.h index 16ba401..85a6977 100644 --- a/src/common.h +++ b/src/common.h @@ -603,6 +603,10 @@ typedef struct namebuf *namebuf_t; namebuf_t namebuf_create (const char *dir); void namebuf_free (namebuf_t buf); char *namebuf_name (namebuf_t buf, const char *name); +void namebuf_add_dir (namebuf_t buf, const char *name); +char *namebuf_finish (namebuf_t buf); + +char *tar_getcwd (void); void code_ns_fraction (int ns, char *p); char const *code_timespec (struct timespec ts, char *sbuf); diff --git a/src/misc.c b/src/misc.c index b75f2ab..f45f79a 100644 --- a/src/misc.c +++ b/src/misc.c @@ -283,7 +283,7 @@ normalize_filename (const char *name) getcwd is slow, it might fail, and it does not necessarily return a canonical name even when it succeeds. Perhaps we can use dev+ino pairs instead of names? */ - copy = xgetcwd (); + copy = tar_getcwd (); if (copy) { size_t copylen = strlen (copy); @@ -777,6 +777,21 @@ chdir_do (int i) } } +char * +tar_getcwd (void) +{ + static char *cwd; + namebuf_t nbuf; + int i; + + if (!cwd) + cwd = xgetcwd (); + nbuf = namebuf_create (cwd); + for (i = 1; i <= chdir_current; i++) + namebuf_add_dir (nbuf, wd[i].name); + return namebuf_finish (nbuf); +} + void close_diag (char const *name) { @@ -945,3 +960,27 @@ namebuf_name (namebuf_t buf, const char *name) return ret; } + +void +namebuf_add_dir (namebuf_t buf, const char *name) +{ + static char dirsep[] = { DIRECTORY_SEPARATOR, 0 }; + if (!ISSLASH (buf->buffer[buf->dir_length - 1])) + { + namebuf_name (buf, dirsep); + buf->dir_length++; + } + namebuf_name (buf, name); + buf->dir_length += strlen (name); +} + +char * +namebuf_finish (namebuf_t buf) +{ + char *res = buf->buffer; + + if (ISSLASH (buf->buffer[buf->dir_length - 1])) + buf->buffer[buf->dir_length] = 0; + free (buf); + return res; +} -- 2.9.3 From 272e1c879644b3684031acd62c9adb0adc5133b5 Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Wed, 25 Sep 2013 15:58:43 +0300 Subject: [PATCH 02/11] Improve tar_getcwd * src/common.h (tar_getcwd): Return pointer is const. * src/misc.c (wd) : New member. (chdir_arg): Initialize cwd. (tar_getcwd): Use cwd member to cache the result. Take into account absolute pathnames, (normalize_filename): Don't free the value returned from tar_getcwd. * src/names.c (name_next_elt): Remove leftover call chdir(). * tests/Makefile.am: Add new tests. * tests/testsuite.at: Likewise. * tests/incr08.at: New testcase. * tests/remfiles04.at: New testcase. * tests/remfiles05.at: New testcase. * tests/remfiles06.at: New testcase. * tests/remfiles07.at: New testcase. --- src/common.h | 2 +- src/misc.c | 57 +++++++++++++++++++++++------------ src/names.c | 3 +- tests/Makefile.am | 5 ++++ tests/incr08.at | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++++ tests/remfiles04.at | 53 +++++++++++++++++++++++++++++++++ tests/remfiles05.at | 60 +++++++++++++++++++++++++++++++++++++ tests/remfiles06.at | 66 ++++++++++++++++++++++++++++++++++++++++ tests/remfiles07.at | 63 +++++++++++++++++++++++++++++++++++++++ tests/testsuite.at | 5 ++++ 10 files changed, 378 insertions(+), 22 deletions(-) create mode 100644 tests/incr08.at create mode 100644 tests/remfiles04.at create mode 100644 tests/remfiles05.at create mode 100644 tests/remfiles06.at create mode 100644 tests/remfiles07.at diff --git a/src/common.h b/src/common.h index 85a6977..99f8552 100644 --- a/src/common.h +++ b/src/common.h @@ -606,7 +606,7 @@ char *namebuf_name (namebuf_t buf, const char *name); void namebuf_add_dir (namebuf_t buf, const char *name); char *namebuf_finish (namebuf_t buf); -char *tar_getcwd (void); +const char *tar_getcwd (void); void code_ns_fraction (int ns, char *p); char const *code_timespec (struct timespec ts, char *sbuf); diff --git a/src/misc.c b/src/misc.c index f45f79a..2fd5280 100644 --- a/src/misc.c +++ b/src/misc.c @@ -283,21 +283,20 @@ normalize_filename (const char *name) getcwd is slow, it might fail, and it does not necessarily return a canonical name even when it succeeds. Perhaps we can use dev+ino pairs instead of names? */ - copy = tar_getcwd (); - if (copy) - { - size_t copylen = strlen (copy); - bool need_separator = ! (DOUBLE_SLASH_IS_DISTINCT_ROOT - && copylen == 2 && ISSLASH (copy[1])); - copy = xrealloc (copy, copylen + need_separator + strlen (name) + 1); - copy[copylen] = DIRECTORY_SEPARATOR; - strcpy (copy + copylen + need_separator, name); - } - else - WARN ((0, errno, _("Cannot get working directory"))); + const char *cwd = tar_getcwd (); + size_t copylen; + bool need_separator; + + copylen = strlen (cwd); + need_separator = ! (DOUBLE_SLASH_IS_DISTINCT_ROOT + && copylen == 2 && ISSLASH (cwd[1])); + copy = xmalloc (copylen + need_separator + strlen (name) + 1); + strcpy (copy, cwd); + copy[copylen] = DIRECTORY_SEPARATOR; + strcpy (copy + copylen + need_separator, name); } - if (! copy) + if (!copy) copy = xstrdup (name); normalize_filename_x (copy); return copy; @@ -632,7 +631,8 @@ struct wd { /* The directory's name. */ char const *name; - + /* Current working directory; initialized by tar_getcwd */ + char *cwd; /* If nonzero, the file descriptor of the directory, or AT_FDCWD if the working directory. If zero, the directory needs to be opened to be used. */ @@ -687,6 +687,7 @@ chdir_arg (char const *dir) if (! wd_count) { wd[wd_count].name = "."; + wd[wd_count].cwd = NULL; wd[wd_count].fd = AT_FDCWD; wd_count++; } @@ -704,6 +705,7 @@ chdir_arg (char const *dir) } wd[wd_count].name = dir; + wd[wd_count].cwd = NULL; wd[wd_count].fd = 0; return wd_count++; } @@ -777,7 +779,7 @@ chdir_do (int i) } } -char * +const char * tar_getcwd (void) { static char *cwd; @@ -786,10 +788,27 @@ tar_getcwd (void) if (!cwd) cwd = xgetcwd (); - nbuf = namebuf_create (cwd); - for (i = 1; i <= chdir_current; i++) - namebuf_add_dir (nbuf, wd[i].name); - return namebuf_finish (nbuf); + if (!wd) + return cwd; + + if (0 == chdir_current || !wd[chdir_current].cwd) + { + if (IS_ABSOLUTE_FILE_NAME (wd[chdir_current].name)) + return wd[chdir_current].name; + + if (!wd[0].cwd) + wd[0].cwd = cwd; + + for (i = chdir_current - 1; i > 0; i--) + if (wd[i].cwd) + break; + + nbuf = namebuf_create (wd[i].cwd); + for (i++; i <= chdir_current; i++) + namebuf_add_dir (nbuf, wd[i].name); + wd[chdir_current].cwd = namebuf_finish (nbuf); + } + return wd[chdir_current].cwd; } void diff --git a/src/names.c b/src/names.c index 3911f8c..8c3052f 100644 --- a/src/names.c +++ b/src/names.c @@ -351,8 +351,7 @@ name_next_elt (int change_dirs) if (change_dirs && ep->type == NELT_CHDIR) { - if (chdir (name_buffer) < 0) - chdir_fatal (name_buffer); + chdir_do (chdir_arg (xstrdup (ep->v.name))); } else { diff --git a/tests/Makefile.am b/tests/Makefile.am index 228e936..1d10360 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -99,6 +99,7 @@ TESTSUITE_AT = \ incr05.at\ incr06.at\ incr07.at\ + incr08.at\ indexfile.at\ ignfail.at\ label01.at\ @@ -139,6 +140,10 @@ TESTSUITE_AT = \ remfiles01.at\ remfiles02.at\ remfiles03.at\ + remfiles04.at\ + remfiles05.at\ + remfiles06.at\ + remfiles07.at\ same-order01.at\ same-order02.at\ shortfile.at\ diff --git a/tests/incr08.at b/tests/incr08.at new file mode 100644 index 0000000..5210d28 --- /dev/null +++ b/tests/incr08.at @@ -0,0 +1,86 @@ +# Process this file with autom4te to create testsuite. -*- Autotest -*- +# Test suite for GNU tar. +# Copyright 2013 Free Software Foundation, Inc. +# +# GNU tar 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 of the License, or +# (at your option) any later version. +# +# GNU tar 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 . + +# Description: In tar 1.26 listed-incremental with -C and absolute path +# would malfunction under certain conditions due to buggy filename +# normalization. +# +# The value returned by normalize_filename() is used to populate the "caname" +# field in both the "directory" structure in incremen.c and the "name" +# structure in names.c, and in both cases that field is then used in the +# "hash" and "compare" functions for the related hash tables. Thus, the +# fact that the returned value doesn't reflect the operation of previous +# "-C" options means that it's possible for two different directories to +# be given the same "caname" value in the hashed structure and thus end up +# being confused with each other. +# +# The bug is triggered when dumping both relative paths after -C and +# absolute paths that match the process' current working directory. +# +# Reported by: Nathan Stratton Treadway +# References: <20130922192135.GJ32256@shire.ontko.com>, +# http://lists.gnu.org/archive/html/bug-tar/2013-09/msg00034.html + +AT_SETUP([filename normalization]) +AT_KEYWORDS([incremental create incr08]) + +AT_TAR_CHECK([ +AT_SORT_PREREQ +mkdir tartest +cd tartest +mkdir foo +mkdir foo/subdir +mkdir foo/subdir/dir1 +mkdir subdir +mkdir subdir/dir2 +decho A +find|sort + +decho B +DIR=`pwd` +tar -cvf ../foo.tar --listed-incremental=../foo.snar -C foo . $DIR 2>../err |\ + sed "s|$DIR|ABSPATH|" +sed "s|$DIR|ABSPATH|" ../err >&2 +], +[0], +[A +. +./foo +./foo/subdir +./foo/subdir/dir1 +./subdir +./subdir/dir2 +B +./ +./subdir/ +./subdir/dir1/ +ABSPATH/ +ABSPATH/subdir/ +ABSPATH/subdir/dir2/ +], +[A +B +tar: .: Directory is new +tar: ./subdir: Directory is new +tar: ./subdir/dir1: Directory is new +tar: ABSPATH: Directory is new +tar: ABSPATH/subdir: Directory is new +tar: ABSPATH/subdir/dir2: Directory is new +tar: Removing leading `/' from member names +],[],[],[gnu]) + +AT_CLEANUP diff --git a/tests/remfiles04.at b/tests/remfiles04.at new file mode 100644 index 0000000..04df45b --- /dev/null +++ b/tests/remfiles04.at @@ -0,0 +1,53 @@ +# Process this file with autom4te to create testsuite. -*- Autotest -*- +# Test suite for GNU tar. +# Copyright 2013 Free Software Foundation, Inc. +# +# GNU tar 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 of the License, or +# (at your option) any later version. +# +# GNU tar 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 . + +# Description: Tar 1.26 would remove wrong files when called with +# --remove-files and -C +# Reported by: Jörgen Strand +# References: <9FC79E5CB90CEC47B9647DCAB7BD327A01AD83B452EE@seldmbx02.corpusers.net> +# http://lists.gnu.org/archive/html/bug-tar/2013-09/msg00024.html + +AT_SETUP([remove-files with -C]) +AT_KEYWORDS([create remove-files remfiles04]) + +AT_TAR_CHECK([ +AT_SORT_PREREQ +mkdir foo +echo bar > bar +echo foobar > foo/bar +tar -cf foo.tar --remove-files -C foo bar +echo A +find . | sort +echo foobar > foo/bar +tar -rf foo.tar --remove-files -C foo bar +echo B +find . | sort +], +[0], +[A +. +./bar +./foo +./foo.tar +B +. +./bar +./foo +./foo.tar +],[],[],[],[gnu]) + +AT_CLEANUP diff --git a/tests/remfiles05.at b/tests/remfiles05.at new file mode 100644 index 0000000..04425a7 --- /dev/null +++ b/tests/remfiles05.at @@ -0,0 +1,60 @@ +# Process this file with autom4te to create testsuite. -*- Autotest -*- +# Test suite for GNU tar. +# Copyright 2013 Free Software Foundation, Inc. +# +# GNU tar 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 of the License, or +# (at your option) any later version. +# +# GNU tar 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 . + +# Description: Tar 1.26 would remove wrong files when invoked with +# --listed-incremental and -C +# Reported by: Nathan Stratton Treadway +# References: <20130921171234.GG32256@shire.ontko.com>, +# http://lists.gnu.org/archive/html/bug-tar/2013-09/msg00028.html + +AT_SETUP([incremental and -C]) +AT_KEYWORDS([incremental create remove-files remfiles05]) + +AT_TAR_CHECK([ +AT_SORT_PREREQ +mkdir foo +echo bar > bar +echo foo/bar > foo/bar +decho A +find . | sort + +decho B +tar -cvf foo.tar --listed-incremental=foo.snar --remove-files -C foo bar +decho C +find . | sort +], +[0], +[A +. +./bar +./foo +./foo/bar +B +bar +C +. +./bar +./foo +./foo.snar +./foo.tar +], +[A +B +C +],[],[],[gnu]) + +AT_CLEANUP diff --git a/tests/remfiles06.at b/tests/remfiles06.at new file mode 100644 index 0000000..75ddcfa --- /dev/null +++ b/tests/remfiles06.at @@ -0,0 +1,66 @@ +# Process this file with autom4te to create testsuite. -*- Autotest -*- +# Test suite for GNU tar. +# Copyright 2013 Free Software Foundation, Inc. +# +# GNU tar 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 of the License, or +# (at your option) any later version. +# +# GNU tar 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 . + +# Description: There was a leftover call to chdir in name_next_elt() in +# tar 1.26. After commit e3d28d84 this call would confuse the tar_getcwd +# function. +# Reported by: Nathan Stratton Treadway +# References: <20130924145657.GM32256@shire.ontko.com>, +# http://lists.gnu.org/archive/html/bug-tar/2013-09/msg00045.html + +AT_SETUP([incremental with two -C]) +AT_KEYWORDS([incremental create remove-files remfiles06]) + +AT_TAR_CHECK([ +AT_SORT_PREREQ +mkdir tartest +cd tartest +mkdir foo +echo foo/file > foo/file +mkdir bar +echo bar/file > bar/file +decho A +find|sort + +decho B +tar -cvf ../foo.tar --remove-files -C foo file -C ../bar file + +decho C +find|sort +], +[0], +[A +. +./bar +./bar/file +./foo +./foo/file +B +file +file +C +. +./bar +./foo +], +[A +B +C +],[],[],[gnu]) + +AT_CLEANUP + diff --git a/tests/remfiles07.at b/tests/remfiles07.at new file mode 100644 index 0000000..84ab625 --- /dev/null +++ b/tests/remfiles07.at @@ -0,0 +1,63 @@ +# Process this file with autom4te to create testsuite. -*- Autotest -*- +# Test suite for GNU tar. +# Copyright 2013 Free Software Foundation, Inc. +# +# GNU tar 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 of the License, or +# (at your option) any later version. +# +# GNU tar 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 . + +# Description: See remfiles06.at +# Reported by: Nathan Stratton Treadway +# References: <20130924185129.GO32256@shire.ontko.com> + +AT_SETUP([incremental with -C to absolute path]) +AT_KEYWORDS([incremental create remove-files remfiles07]) + +AT_TAR_CHECK([ +AT_SORT_PREREQ +mkdir tartest +cd tartest +mkdir foo +echo foo/file > foo/file +mkdir bar +echo bar/file > bar/file +decho A +find|sort + +DIR=`pwd` +decho B +tar -cvf ../foo.tar --remove-files -C foo file -C $DIR/bar file + +decho C +find|sort +], +[0], +[A +. +./bar +./bar/file +./foo +./foo/file +B +file +file +C +. +./bar +./foo +], +[A +B +C +],[],[],[gnu]) + +AT_CLEANUP diff --git a/tests/testsuite.at b/tests/testsuite.at index 10cf26a..5c805e7 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -260,6 +260,7 @@ m4_include([incr03.at]) m4_include([incr05.at]) m4_include([incr06.at]) m4_include([incr07.at]) +m4_include([incr08.at]) m4_include([filerem01.at]) m4_include([filerem02.at]) @@ -330,6 +331,10 @@ m4_include([grow.at]) m4_include([remfiles01.at]) m4_include([remfiles02.at]) m4_include([remfiles03.at]) +m4_include([remfiles04.at]) +m4_include([remfiles05.at]) +m4_include([remfiles06.at]) +m4_include([remfiles07.at]) m4_include([sigpipe.at]) -- 2.9.3 From 0c5f95ca80d507a00825c8e3fd05ed5ad993ce17 Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Thu, 26 Sep 2013 15:41:47 +0300 Subject: [PATCH 03/11] Use relative addressing in deferred unlinks. * src/common.h (tar_dirname): New function. * src/misc.c (normalize_filename_x): Make extern. (tar_dirname): New function. (tar_getcwd): Take into account absoulte pathnames. * src/unlink.c (deferred_unlink) : New member; keeps the value of chdir_current at the moment of structure allocation. (flush_deferred_unlinks): Use chdir_do and relative addressing. (queue_deferred_unlink): Initialize dir_idx. * tests/Makefile.am: Add new tests. * tests/testsuite.at: Add new tests. * tests/remfiles06.at: Fix description. * tests/remfiles07.at: Fix description. * tests/remfiles08.at: New test case. --- src/common.h | 2 ++ src/misc.c | 28 +++++++++++++++++++--------- src/unlink.c | 27 +++++++++++++++++++++++---- tests/Makefile.am | 1 + tests/remfiles06.at | 4 ++-- tests/remfiles07.at | 4 ++-- tests/remfiles08.at | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ tests/testsuite.at | 1 + 8 files changed, 98 insertions(+), 17 deletions(-) create mode 100644 tests/remfiles08.at diff --git a/src/common.h b/src/common.h index 99f8552..7d64227 100644 --- a/src/common.h +++ b/src/common.h @@ -596,6 +596,7 @@ void assign_string (char **dest, const char *src); int unquote_string (char *str); char *zap_slashes (char *name); char *normalize_filename (const char *name); +void normalize_filename_x (char *name); void replace_prefix (char **pname, const char *samp, size_t slen, const char *repl, size_t rlen); char *tar_savedir (const char *name, int must_exist); @@ -607,6 +608,7 @@ void namebuf_add_dir (namebuf_t buf, const char *name); char *namebuf_finish (namebuf_t buf); const char *tar_getcwd (void); +const char *tar_dirname (void); void code_ns_fraction (int ns, char *p); char const *code_timespec (struct timespec ts, char *sbuf); diff --git a/src/misc.c b/src/misc.c index 2fd5280..c7d51b2 100644 --- a/src/misc.c +++ b/src/misc.c @@ -229,11 +229,12 @@ zap_slashes (char *name) } /* Normalize FILE_NAME by removing redundant slashes and "." - components, including redundant trailing slashes. Leave ".." - alone, as it may be significant in the presence of symlinks and on - platforms where "/.." != "/". Destructive version: modifies its - argument. */ -static void + components, including redundant trailing slashes. + Leave ".." alone, as it may be significant in the presence + of symlinks and on platforms where "/.." != "/". + + Destructive version: modifies its argument. */ +void normalize_filename_x (char *file_name) { char *name = file_name + FILE_SYSTEM_PREFIX_LEN (file_name); @@ -267,8 +268,9 @@ normalize_filename_x (char *file_name) } /* Normalize NAME by removing redundant slashes and "." components, - including redundant trailing slashes. Return a normalized - newly-allocated copy. */ + including redundant trailing slashes. + + Return a normalized newly-allocated copy. */ char * normalize_filename (const char *name) @@ -780,6 +782,12 @@ chdir_do (int i) } const char * +tar_dirname (void) +{ + return wd[chdir_current].name; +} + +const char * tar_getcwd (void) { static char *cwd; @@ -794,8 +802,10 @@ tar_getcwd (void) if (0 == chdir_current || !wd[chdir_current].cwd) { if (IS_ABSOLUTE_FILE_NAME (wd[chdir_current].name)) - return wd[chdir_current].name; - + { + wd[chdir_current].cwd = xstrdup (wd[chdir_current].name); + return wd[chdir_current].cwd; + } if (!wd[0].cwd) wd[0].cwd = cwd; diff --git a/src/unlink.c b/src/unlink.c index b281636..10e0b41 100644 --- a/src/unlink.c +++ b/src/unlink.c @@ -22,7 +22,9 @@ struct deferred_unlink { struct deferred_unlink *next; /* Next unlink in the queue */ - char *file_name; /* Absolute name of the file to unlink */ + int dir_idx; /* Directory index in wd */ + char *file_name; /* Name of the file to unlink, relative + to dir_idx */ bool is_dir; /* True if file_name is a directory */ off_t records_written; /* Number of records written when this entry got added to the queue */ @@ -68,16 +70,30 @@ static void flush_deferred_unlinks (bool force) { struct deferred_unlink *p, *prev = NULL; + int saved_chdir = chdir_current; for (p = dunlink_head; p; ) { struct deferred_unlink *next = p->next; + if (force || records_written > p->records_written + deferred_unlink_delay) { + chdir_do (p->dir_idx); if (p->is_dir) { - if (unlinkat (chdir_fd, p->file_name, AT_REMOVEDIR) != 0) + const char *fname; + + if (p->file_name[0] == 0 || + strcmp (p->file_name, ".") == 0) + { + fname = tar_dirname (); + chdir_do (p->dir_idx - 1); + } + else + fname = p->file_name; + + if (unlinkat (chdir_fd, fname, AT_REMOVEDIR) != 0) { switch (errno) { @@ -95,7 +111,7 @@ flush_deferred_unlinks (bool force) } /* fall through */ default: - rmdir_error (p->file_name); + rmdir_error (fname); } } } @@ -120,6 +136,7 @@ flush_deferred_unlinks (bool force) } if (!dunlink_head) dunlink_tail = NULL; + chdir_do (saved_chdir); } void @@ -145,7 +162,9 @@ queue_deferred_unlink (const char *name, bool is_dir) p = dunlink_alloc (); p->next = NULL; - p->file_name = normalize_filename (name); + p->dir_idx = chdir_current; + p->file_name = xstrdup (name); + normalize_filename_x (p->file_name); p->is_dir = is_dir; p->records_written = records_written; diff --git a/tests/Makefile.am b/tests/Makefile.am index 1d10360..29ebab1 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -144,6 +144,7 @@ TESTSUITE_AT = \ remfiles05.at\ remfiles06.at\ remfiles07.at\ + remfiles08.at\ same-order01.at\ same-order02.at\ shortfile.at\ diff --git a/tests/remfiles06.at b/tests/remfiles06.at index 75ddcfa..c2d9876 100644 --- a/tests/remfiles06.at +++ b/tests/remfiles06.at @@ -22,8 +22,8 @@ # References: <20130924145657.GM32256@shire.ontko.com>, # http://lists.gnu.org/archive/html/bug-tar/2013-09/msg00045.html -AT_SETUP([incremental with two -C]) -AT_KEYWORDS([incremental create remove-files remfiles06]) +AT_SETUP([remove with two -C]) +AT_KEYWORDS([remove-files remfiles06]) AT_TAR_CHECK([ AT_SORT_PREREQ diff --git a/tests/remfiles07.at b/tests/remfiles07.at index 84ab625..742e0a1 100644 --- a/tests/remfiles07.at +++ b/tests/remfiles07.at @@ -19,8 +19,8 @@ # Reported by: Nathan Stratton Treadway # References: <20130924185129.GO32256@shire.ontko.com> -AT_SETUP([incremental with -C to absolute path]) -AT_KEYWORDS([incremental create remove-files remfiles07]) +AT_SETUP([remove with -C to absolute path]) +AT_KEYWORDS([create remove-files remfiles07]) AT_TAR_CHECK([ AT_SORT_PREREQ diff --git a/tests/remfiles08.at b/tests/remfiles08.at new file mode 100644 index 0000000..54f5de1 --- /dev/null +++ b/tests/remfiles08.at @@ -0,0 +1,48 @@ +# Process this file with autom4te to create testsuite. -*- Autotest -*- +# Test suite for GNU tar. +# Copyright 2013 Free Software Foundation, Inc. +# +# GNU tar 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 of the License, or +# (at your option) any later version. +# +# GNU tar 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 . + +# Description: See remfiles06.at +# Reported by: Nathan Stratton Treadway +# References: <20130926050634.GW32256@shire.ontko.com> + +AT_SETUP([remove with -C to absolute and relative paths]) +AT_KEYWORDS([incremental create remove-files remfiles08]) + +AT_TAR_CHECK([ +mkdir foo +mkdir bar +echo foo/foo_file > foo/foo_file +echo bar/bar_file > bar/bar_file +decho A +tar -cvf foo.tar --remove-files -C `pwd`/foo . -C ../bar . +decho B +], +[0], +[A +./ +./foo_file +./ +./bar_file +B +. +./foo.tar +], +[A +B +],[],[],[gnu]) + +AT_CLEANUP diff --git a/tests/testsuite.at b/tests/testsuite.at index 5c805e7..d468dcf 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -335,6 +335,7 @@ m4_include([remfiles04.at]) m4_include([remfiles05.at]) m4_include([remfiles06.at]) m4_include([remfiles07.at]) +m4_include([remfiles08.at]) m4_include([sigpipe.at]) -- 2.9.3 From 195c6f2b71f49ecc374ae01e20d7287f24501178 Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Fri, 27 Sep 2013 00:59:18 +0300 Subject: [PATCH 04/11] Bugfix * tests/remfiles08.at: Restore missing find --- tests/remfiles08.at | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/remfiles08.at b/tests/remfiles08.at index 54f5de1..0649e85 100644 --- a/tests/remfiles08.at +++ b/tests/remfiles08.at @@ -30,6 +30,7 @@ echo bar/bar_file > bar/bar_file decho A tar -cvf foo.tar --remove-files -C `pwd`/foo . -C ../bar . decho B +find ], [0], [A -- 2.9.3 From 2cce74ec554ec7fca4c3b1d2963beb6a729881fe Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Tue, 1 Oct 2013 21:48:30 +0300 Subject: [PATCH 05/11] Revamp tar_getcwd/normalize_filename stuff. The changes are based on the discussion with Nathan. * src/common.h (normalize_filename): Take two arguments. All callers updated. (tar_getcwd): Replaced with .. (tar_getcdpath): New proto. * src/misc.c (normalize_filename): Take two arguments. (chdir_arg): Populate cwd along with creating the structure. (tar_getcwd): Removed. (tar_getcdpath): New function. * tests/incr09.at: New test case. * tests/Makefile.am: Add new tests. * tests/testsuite.at: Likewise. --- src/common.h | 4 ++-- src/incremen.c | 4 ++-- src/misc.c | 48 ++++++++++++++++---------------------------- src/names.c | 6 ++---- tests/Makefile.am | 1 + tests/incr09.at | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ tests/testsuite.at | 1 + 7 files changed, 84 insertions(+), 39 deletions(-) create mode 100644 tests/incr09.at diff --git a/src/common.h b/src/common.h index 7d64227..16b501b 100644 --- a/src/common.h +++ b/src/common.h @@ -595,7 +595,7 @@ void skip_member (void); void assign_string (char **dest, const char *src); int unquote_string (char *str); char *zap_slashes (char *name); -char *normalize_filename (const char *name); +char *normalize_filename (int cdidx, const char *name); void normalize_filename_x (char *name); void replace_prefix (char **pname, const char *samp, size_t slen, const char *repl, size_t rlen); @@ -607,7 +607,7 @@ char *namebuf_name (namebuf_t buf, const char *name); void namebuf_add_dir (namebuf_t buf, const char *name); char *namebuf_finish (namebuf_t buf); -const char *tar_getcwd (void); +const char *tar_getcdpath (int); const char *tar_dirname (void); void code_ns_fraction (int ns, char *p); diff --git a/src/incremen.c b/src/incremen.c index b2ab5bf..cb12bbc 100644 --- a/src/incremen.c +++ b/src/incremen.c @@ -279,7 +279,7 @@ free_directory (struct directory *dir) static struct directory * attach_directory (const char *name) { - char *cname = normalize_filename (name); + char *cname = normalize_filename (chdir_current, name); struct directory *dir = make_directory (name, cname); if (dirtail) dirtail->next = dir; @@ -350,7 +350,7 @@ find_directory (const char *name) return 0; else { - char *caname = normalize_filename (name); + char *caname = normalize_filename (chdir_current, name); struct directory *dir = make_directory (name, caname); struct directory *ret = hash_lookup (directory_table, dir); free_directory (dir); diff --git a/src/misc.c b/src/misc.c index c7d51b2..280f85c 100644 --- a/src/misc.c +++ b/src/misc.c @@ -273,7 +273,7 @@ normalize_filename_x (char *file_name) Return a normalized newly-allocated copy. */ char * -normalize_filename (const char *name) +normalize_filename (int cdidx, const char *name) { char *copy = NULL; @@ -285,7 +285,7 @@ normalize_filename (const char *name) getcwd is slow, it might fail, and it does not necessarily return a canonical name even when it succeeds. Perhaps we can use dev+ino pairs instead of names? */ - const char *cwd = tar_getcwd (); + const char *cwd = tar_getcdpath (cdidx); size_t copylen; bool need_separator; @@ -689,7 +689,7 @@ chdir_arg (char const *dir) if (! wd_count) { wd[wd_count].name = "."; - wd[wd_count].cwd = NULL; + wd[wd_count].cwd = xgetcwd (); wd[wd_count].fd = AT_FDCWD; wd_count++; } @@ -707,7 +707,14 @@ chdir_arg (char const *dir) } wd[wd_count].name = dir; - wd[wd_count].cwd = NULL; + if (IS_ABSOLUTE_FILE_NAME (wd[wd_count].name)) + wd[wd_count].cwd = xstrdup (wd[wd_count].name); + else + { + namebuf_t nbuf = namebuf_create (wd[wd_count - 1].cwd); + namebuf_add_dir (nbuf, wd[wd_count].name); + wd[wd_count].cwd = namebuf_finish (nbuf); + } wd[wd_count].fd = 0; return wd_count++; } @@ -788,37 +795,16 @@ tar_dirname (void) } const char * -tar_getcwd (void) +tar_getcdpath (int idx) { - static char *cwd; - namebuf_t nbuf; - int i; - - if (!cwd) - cwd = xgetcwd (); if (!wd) - return cwd; - - if (0 == chdir_current || !wd[chdir_current].cwd) { - if (IS_ABSOLUTE_FILE_NAME (wd[chdir_current].name)) - { - wd[chdir_current].cwd = xstrdup (wd[chdir_current].name); - return wd[chdir_current].cwd; - } - if (!wd[0].cwd) - wd[0].cwd = cwd; - - for (i = chdir_current - 1; i > 0; i--) - if (wd[i].cwd) - break; - - nbuf = namebuf_create (wd[i].cwd); - for (i++; i <= chdir_current; i++) - namebuf_add_dir (nbuf, wd[i].name); - wd[chdir_current].cwd = namebuf_finish (nbuf); + static char *cwd; + if (!cwd) + cwd = xgetcwd (); + return cwd; } - return wd[chdir_current].cwd; + return wd[idx].cwd; } void diff --git a/src/names.c b/src/names.c index 8c3052f..125f0b5 100644 --- a/src/names.c +++ b/src/names.c @@ -1004,13 +1004,11 @@ collect_and_sort_names (void) namelist = merge_sort (namelist, num_names, compare_names); num_names = 0; - nametab = hash_initialize (0, 0, - name_hash, - name_compare, NULL); + nametab = hash_initialize (0, 0, name_hash, name_compare, NULL); for (name = namelist; name; name = next_name) { next_name = name->next; - name->caname = normalize_filename (name->name); + name->caname = normalize_filename (name->change_dir, name->name); if (prev_name) { struct name *p = hash_lookup (nametab, name); diff --git a/tests/Makefile.am b/tests/Makefile.am index 29ebab1..b05a151 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -99,6 +99,7 @@ TESTSUITE_AT = \ incr06.at\ incr07.at\ incr08.at\ + incr09.at\ indexfile.at\ ignfail.at\ label01.at\ diff --git a/tests/incr09.at b/tests/incr09.at new file mode 100644 index 0000000..b6130a6 --- /dev/null +++ b/tests/incr09.at @@ -0,0 +1,59 @@ +# Process this file with autom4te to create testsuite. -*- Autotest -*- +# Test suite for GNU tar. +# Copyright 2013 Free Software Foundation, Inc. +# +# GNU tar 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 of the License, or +# (at your option) any later version. +# +# GNU tar 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 . + +AT_SETUP([incremental with alternating -C]) +AT_KEYWORDS([incremental create incr09]) + +AT_TAR_CHECK([ +AT_SORT_PREREQ +mkdir foo bar middle +echo foo/foo_file > foo/foo_file +echo bar/bar_file > bar/bar_file +echo middle/file > middle/middle_file +decho A +tar -cvf foo.tar --incremental -C foo . -C `pwd` middle -C bar . + +rm foo.tar +>toplevel_file +decho B +tar -cvf foo.tar --incremental -C foo . -C `pwd` toplevel_file -C bar . +], +[0], +[A +./ +./ +middle/ +./bar_file +./foo_file +middle/middle_file +B +./ +./ +toplevel_file +./bar_file +./foo_file +], +[A +tar: .: Directory is new +tar: middle: Directory is new +tar: .: Directory is new +B +tar: .: Directory is new +tar: .: Directory is new +],[],[],[gnu]) + +AT_CLEANUP diff --git a/tests/testsuite.at b/tests/testsuite.at index d468dcf..a9f2ab6 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -260,6 +260,7 @@ m4_include([incr04.at]) m4_include([incr06.at]) m4_include([incr07.at]) m4_include([incr08.at]) +m4_include([incr09.at]) m4_include([filerem01.at]) m4_include([filerem02.at]) -- 2.9.3 From 779b02280a9561029d0e459275af3b3a59e521c3 Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Thu, 3 Oct 2013 22:41:04 +0300 Subject: [PATCH 06/11] Tiny changes. * src/misc.c: Fix comments, rename wd.cwd to wd.abspath (Nathan Stratton Treadway); * src/tar.c (options): Reword description of the --starting-file and --preserve-order options. (decode_options): Both --starting-file and --preserve-order have meaning only when used together with an archive reading command. (Pavel Raiskup). --- src/misc.c | 44 +++++++++++++++++++++++++++++--------------- src/tar.c | 5 +++-- 2 files changed, 32 insertions(+), 17 deletions(-) diff --git a/src/misc.c b/src/misc.c index 280f85c..201ed16 100644 --- a/src/misc.c +++ b/src/misc.c @@ -279,21 +279,23 @@ normalize_filename (int cdidx, const char *name) if (IS_RELATIVE_FILE_NAME (name)) { - /* Set COPY to the absolute file name if possible. + /* Set COPY to the absolute path for this name. FIXME: There should be no need to get the absolute file name. - getcwd is slow, it might fail, and it does not necessarily - return a canonical name even when it succeeds. Perhaps we - can use dev+ino pairs instead of names? */ - const char *cwd = tar_getcdpath (cdidx); + tar_getcdpath does not return a true "canonical" path, so + this following approach may lead to situations where the same + file or directory is processed twice under different absolute + paths without that duplication being detected. Perhaps we + should use dev+ino pairs instead of names? */ + const char *cdpath = tar_getcdpath (cdidx); size_t copylen; bool need_separator; - copylen = strlen (cwd); + copylen = strlen (cdpath); need_separator = ! (DOUBLE_SLASH_IS_DISTINCT_ROOT - && copylen == 2 && ISSLASH (cwd[1])); + && copylen == 2 && ISSLASH (cdpath[1])); copy = xmalloc (copylen + need_separator + strlen (name) + 1); - strcpy (copy, cwd); + strcpy (copy, cdpath); copy[copylen] = DIRECTORY_SEPARATOR; strcpy (copy + copylen + need_separator, name); } @@ -633,8 +635,10 @@ struct wd { /* The directory's name. */ char const *name; - /* Current working directory; initialized by tar_getcwd */ - char *cwd; + /* "absolute" path representing this directory; in the contrast to + the real absolute pathname, it can contain /../ components (see + normalize_filename_x for the reason of it). */ + char *abspath; /* If nonzero, the file descriptor of the directory, or AT_FDCWD if the working directory. If zero, the directory needs to be opened to be used. */ @@ -689,7 +693,7 @@ chdir_arg (char const *dir) if (! wd_count) { wd[wd_count].name = "."; - wd[wd_count].cwd = xgetcwd (); + wd[wd_count].abspath = xgetcwd (); wd[wd_count].fd = AT_FDCWD; wd_count++; } @@ -707,13 +711,16 @@ chdir_arg (char const *dir) } wd[wd_count].name = dir; + /* if the given name is an absolute path, then use that path + to represent this working directory; otherwise, construct + a path based on the previous -C option's absolute path */ if (IS_ABSOLUTE_FILE_NAME (wd[wd_count].name)) - wd[wd_count].cwd = xstrdup (wd[wd_count].name); + wd[wd_count].abspath = xstrdup (wd[wd_count].name); else { - namebuf_t nbuf = namebuf_create (wd[wd_count - 1].cwd); + namebuf_t nbuf = namebuf_create (wd[wd_count - 1].abspath); namebuf_add_dir (nbuf, wd[wd_count].name); - wd[wd_count].cwd = namebuf_finish (nbuf); + wd[wd_count].abspath = namebuf_finish (nbuf); } wd[wd_count].fd = 0; return wd_count++; @@ -794,6 +801,13 @@ tar_dirname (void) return wd[chdir_current].name; } +/* Return the absolute path that represents the working + directory referenced by IDX. + + If wd is empty, then there were no -C options given, and + chdir_args() has never been called, so we simply return the + process's actual cwd. (Note that in this case IDX is ignored, + since it should always be 0.) */ const char * tar_getcdpath (int idx) { @@ -804,7 +818,7 @@ tar_getcdpath (int idx) cwd = xgetcwd (); return cwd; } - return wd[idx].cwd; + return wd[idx].abspath; } void diff --git a/src/tar.c b/src/tar.c index 18277e4..d11daa1 100644 --- a/src/tar.c +++ b/src/tar.c @@ -536,7 +536,8 @@ static struct argp_option options[] = { {"no-same-permissions", NO_SAME_PERMISSIONS_OPTION, 0, 0, N_("apply the user's umask when extracting permissions from the archive (default for ordinary users)"), GRID+1 }, {"preserve-order", 's', 0, 0, - N_("sort names to extract to match archive"), GRID+1 }, + N_("member arguments are listed in the same order as the " + "files in the archive"), GRID+1 }, {"same-order", 0, 0, OPTION_ALIAS, NULL, GRID+1 }, {"preserve", PRESERVE_OPTION, 0, 0, N_("same as both -p and -s"), GRID+1 }, @@ -730,7 +731,7 @@ static struct argp_option options[] = { {"hard-dereference", HARD_DEREFERENCE_OPTION, 0, 0, N_("follow hard links; archive and dump the files they refer to"), GRID+1 }, {"starting-file", 'K', N_("MEMBER-NAME"), 0, - N_("begin at member MEMBER-NAME in the archive"), GRID+1 }, + N_("begin at member MEMBER-NAME when reading the archive"), GRID+1 }, {"newer", 'N', N_("DATE-OR-FILE"), 0, N_("only store files newer than DATE-OR-FILE"), GRID+1 }, {"after-date", 0, 0, OPTION_ALIAS, NULL, GRID+1 }, -- 2.9.3 From 79f04038e17dec01031113f4ba68f291f22012c3 Mon Sep 17 00:00:00 2001 From: Nathan Stratton Treadway Date: Sat, 5 Oct 2013 08:53:08 +0300 Subject: [PATCH 07/11] Provide comprehensive testcases for various file removal modes. * tests/Makefile.am: Add new testcases. * tests/testsuite.at: Likewise. * tests/incr09.at: Add description. * tests/remfiles04a.at: New file. * tests/remfiles05.at: Rename to ... * tests/remfiles04b.at: ... this. * tests/remfiles04.at: Rename to ... * tests/remfiles04c.at: ... this. * tests/remfiles05a.at: New file. * tests/remfiles05b.at: New file. * tests/remfiles06.at: Rename to ... * tests/remfiles05c.at: ... this. * tests/remfiles06a.at: New file. * tests/remfiles06b.at: New file. * tests/remfiles06c.at: New file. * tests/remfiles07a.at: New file. * tests/remfiles07b.at: New file. * tests/remfiles07c.at: New file. * tests/remfiles08a.at: New file. * tests/remfiles08b.at: New file. * tests/remfiles08c.at: New file. * tests/remfiles08.at: Rename to ... * tests/remfiles09a.at: ... this. * tests/remfiles09b.at: New file. * tests/remfiles07.at: Rename to ... * tests/remfiles09c.at: ... this. --- tests/Makefile.am | 23 ++++++++--- tests/incr09.at | 8 ++++ tests/remfiles04a.at | 45 ++++++++++++++++++++++ tests/remfiles04b.at | 53 +++++++++++++++++++++++++ tests/{remfiles04.at => remfiles04c.at} | 21 +++++++--- tests/remfiles05a.at | 64 +++++++++++++++++++++++++++++++ tests/remfiles05b.at | 55 ++++++++++++++++++++++++++ tests/{remfiles05.at => remfiles05c.at} | 35 ++++++++++------- tests/remfiles06.at | 65 ------------------------------- tests/remfiles06a.at | 56 +++++++++++++++++++++++++++ tests/remfiles06b.at | 56 +++++++++++++++++++++++++++ tests/remfiles06c.at | 68 +++++++++++++++++++++++++++++++++ tests/remfiles07a.at | 56 +++++++++++++++++++++++++++ tests/remfiles07b.at | 56 +++++++++++++++++++++++++++ tests/remfiles07c.at | 68 +++++++++++++++++++++++++++++++++ tests/remfiles08a.at | 56 +++++++++++++++++++++++++++ tests/remfiles08b.at | 56 +++++++++++++++++++++++++++ tests/remfiles08c.at | 68 +++++++++++++++++++++++++++++++++ tests/{remfiles08.at => remfiles09a.at} | 27 +++++++------ tests/remfiles09b.at | 57 +++++++++++++++++++++++++++ tests/{remfiles07.at => remfiles09c.at} | 37 ++++++++---------- tests/testsuite.at | 23 ++++++++--- 22 files changed, 923 insertions(+), 130 deletions(-) create mode 100644 tests/remfiles04a.at create mode 100644 tests/remfiles04b.at rename tests/{remfiles04.at => remfiles04c.at} (69%) create mode 100644 tests/remfiles05a.at create mode 100644 tests/remfiles05b.at rename tests/{remfiles05.at => remfiles05c.at} (63%) create mode 100644 tests/remfiles06a.at create mode 100644 tests/remfiles06b.at create mode 100644 tests/remfiles06c.at create mode 100644 tests/remfiles07a.at create mode 100644 tests/remfiles07b.at create mode 100644 tests/remfiles07c.at create mode 100644 tests/remfiles08a.at create mode 100644 tests/remfiles08b.at create mode 100644 tests/remfiles08c.at rename tests/{remfiles08.at => remfiles09a.at} (66%) create mode 100644 tests/remfiles09b.at rename tests/{remfiles07.at => remfiles09c.at} (68%) diff --git a/tests/Makefile.am b/tests/Makefile.am index b05a151..cf6f576 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -141,11 +141,24 @@ TESTSUITE_AT = \ remfiles01.at\ remfiles02.at\ remfiles03.at\ - remfiles04.at\ - remfiles05.at\ - remfiles06.at\ - remfiles07.at\ - remfiles08.at\ + remfiles04a.at\ + remfiles04b.at\ + remfiles04c.at\ + remfiles05a.at\ + remfiles05b.at\ + remfiles05c.at\ + remfiles06a.at\ + remfiles06b.at\ + remfiles06c.at\ + remfiles07a.at\ + remfiles07b.at\ + remfiles07c.at\ + remfiles08a.at\ + remfiles08b.at\ + remfiles08c.at\ + remfiles09a.at\ + remfiles09b.at\ + remfiles09c.at\ same-order01.at\ same-order02.at\ shortfile.at\ diff --git a/tests/incr09.at b/tests/incr09.at index b6130a6..e91fb5a 100644 --- a/tests/incr09.at +++ b/tests/incr09.at @@ -15,6 +15,14 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +# Description: For some intermediate versions of tar 1.26.90, +# tar would fail to correctly cannonicalize archive member names +# in incremental mode if there was a -C options with an absolute path +# on the command line without any archive members specified within that +# directory. (In that case, the canonical name generated for +# members specified after later -C options wouldn't correctly reflect the +# previous absolute path.) + AT_SETUP([incremental with alternating -C]) AT_KEYWORDS([incremental create incr09]) diff --git a/tests/remfiles04a.at b/tests/remfiles04a.at new file mode 100644 index 0000000..d1e4614 --- /dev/null +++ b/tests/remfiles04a.at @@ -0,0 +1,45 @@ +# Process this file with autom4te to create testsuite. -*- Autotest -*- +# Test suite for GNU tar. +# Copyright 2013 Free Software Foundation, Inc. +# +# GNU tar 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 of the License, or +# (at your option) any later version. +# +# GNU tar 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 . + +# Description: ensure tar correctly respects -C option when deleting +# files due to the --remove-files option. +# +# This case checks the use of a single relative-path -C option, +# in --create/non-incremental mode. +# + +AT_SETUP([remove-files with -C:rel in -c/non-incr. mode]) +AT_KEYWORDS([create remove-files remfiles04 remfiles04a]) + +AT_TAR_CHECK([ +AT_SORT_PREREQ +mkdir foo +echo bar > bar +echo foobar > foo/bar +tar -cf foo.tar --remove-files -C foo bar +echo A +find . | sort +], +[0], +[A +. +./bar +./foo +./foo.tar +],[],[],[],[gnu]) + +AT_CLEANUP diff --git a/tests/remfiles04b.at b/tests/remfiles04b.at new file mode 100644 index 0000000..3208557 --- /dev/null +++ b/tests/remfiles04b.at @@ -0,0 +1,53 @@ +# Process this file with autom4te to create testsuite. -*- Autotest -*- +# Test suite for GNU tar. +# Copyright 2013 Free Software Foundation, Inc. +# +# GNU tar 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 of the License, or +# (at your option) any later version. +# +# GNU tar 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 . + +# Description: ensure tar correctly respects -C option when deleting +# files due to the --remove-files option. +# +# This case checks the use of a single relative-path -C option, +# in --create/incremental mode. +# +# (Tar 1.26 would remove files in original working directory when called in +# this manner. [It would follow the -C for archiving the files, but ignore it +# for removing them afterwards.] +# +# Reported by: Nathan Stratton Treadway +# References: <20130921171234.GG32256@shire.ontko.com>, +# http://lists.gnu.org/archive/html/bug-tar/2013-09/msg00028.html +# ) + +AT_SETUP([remove-files with -C:rel in -c/incr. mode]) +AT_KEYWORDS([create incremental remove-files remfiles04 remfiles04b]) + +AT_TAR_CHECK([ +AT_SORT_PREREQ +mkdir foo +echo bar > bar +echo foobar > foo/bar +tar -cf foo.tar --incremental --remove-files -C foo bar +echo A +find . | sort +], +[0], +[A +. +./bar +./foo +./foo.tar +],[],[],[],[gnu]) + +AT_CLEANUP diff --git a/tests/remfiles04.at b/tests/remfiles04c.at similarity index 69% rename from tests/remfiles04.at rename to tests/remfiles04c.at index 04df45b..a1b6d56 100644 --- a/tests/remfiles04.at +++ b/tests/remfiles04c.at @@ -15,24 +15,32 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -# Description: Tar 1.26 would remove wrong files when called with -# --remove-files and -C +# Description: ensure tar correctly respects -C option when deleting +# files due to the --remove-files option. +# +# This case checks the use of a single relative-path -C option, +# in --append mode. +# +# (Tar 1.26 would remove files in original working directory when called in +# this manner. [It would follow the -C for archiving the files, but ignore it +# for removing them afterwards.] +# # Reported by: Jörgen Strand # References: <9FC79E5CB90CEC47B9647DCAB7BD327A01AD83B452EE@seldmbx02.corpusers.net> # http://lists.gnu.org/archive/html/bug-tar/2013-09/msg00024.html +# ) -AT_SETUP([remove-files with -C]) -AT_KEYWORDS([create remove-files remfiles04]) +AT_SETUP([remove-files with -C:rel in -r mode]) +AT_KEYWORDS([create append remove-files remfiles04 remfiles04c]) AT_TAR_CHECK([ AT_SORT_PREREQ mkdir foo echo bar > bar echo foobar > foo/bar -tar -cf foo.tar --remove-files -C foo bar +tar -cf foo.tar -C foo bar echo A find . | sort -echo foobar > foo/bar tar -rf foo.tar --remove-files -C foo bar echo B find . | sort @@ -43,6 +51,7 @@ find . | sort ./bar ./foo ./foo.tar +./foo/bar B . ./bar diff --git a/tests/remfiles05a.at b/tests/remfiles05a.at new file mode 100644 index 0000000..4ceec37 --- /dev/null +++ b/tests/remfiles05a.at @@ -0,0 +1,64 @@ +# Process this file with autom4te to create testsuite. -*- Autotest -*- +# Test suite for GNU tar. +# Copyright 2013 Free Software Foundation, Inc. +# +# GNU tar 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 of the License, or +# (at your option) any later version. +# +# GNU tar 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 . + +# Description: ensure tar correctly respects -C option when deleting +# files due to the --remove-files option. +# +# This case checks the use of two relative-path -C options, +# in --create/non-incremental mode. +# +# (This specific case failed during development of tar 1.26.90: +# There was a leftover call to chdir in name_next_elt() in +# tar 1.26. After commit e3d28d84 this call would confuse the +# tar_getcwd function. +# +# Reported by: Nathan Stratton Treadway +# References: <20130924145657.GM32256@shire.ontko.com>, +# http://lists.gnu.org/archive/html/bug-tar/2013-09/msg00045.html +# ) + +AT_SETUP([remove-files with -C:rel,rel in -c/non-incr. mode]) +AT_KEYWORDS([create remove-files remfiles05 remfiles05a]) + +AT_TAR_CHECK([ +AT_SORT_PREREQ +mkdir foo +mkdir bar +echo file > file +echo foo/file > foo/file +echo bar/file > bar/file +decho A +tar -cvf foo.tar --remove-files -C foo file -C ../bar file +decho B +find . | sort +], +[0], +[A +file +file +B +. +./bar +./file +./foo +./foo.tar +], +[A +B +],[],[],[gnu]) + +AT_CLEANUP diff --git a/tests/remfiles05b.at b/tests/remfiles05b.at new file mode 100644 index 0000000..d120efd --- /dev/null +++ b/tests/remfiles05b.at @@ -0,0 +1,55 @@ +# Process this file with autom4te to create testsuite. -*- Autotest -*- +# Test suite for GNU tar. +# Copyright 2013 Free Software Foundation, Inc. +# +# GNU tar 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 of the License, or +# (at your option) any later version. +# +# GNU tar 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 . + +# Description: ensure tar correctly respects -C option when deleting +# files due to the --remove-files option. +# +# This case checks the use of two relative-path -C options, +# in --create/incremental mode. +# + +AT_SETUP([remove-files with -C:rel,rel in -c/incr. mode]) +AT_KEYWORDS([create incremental remove-files remfiles05 remfiles05b]) + +AT_TAR_CHECK([ +AT_SORT_PREREQ +mkdir foo +mkdir bar +echo file > file +echo foo/file > foo/file +echo bar/file > bar/file +decho A +tar -cvf foo.tar --incremental --remove-files -C foo file -C ../bar file +decho B +find . | sort +], +[0], +[A +file +file +B +. +./bar +./file +./foo +./foo.tar +], +[A +B +],[],[],[gnu]) + +AT_CLEANUP diff --git a/tests/remfiles05.at b/tests/remfiles05c.at similarity index 63% rename from tests/remfiles05.at rename to tests/remfiles05c.at index 04425a7..a01b092 100644 --- a/tests/remfiles05.at +++ b/tests/remfiles05c.at @@ -15,25 +15,28 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -# Description: Tar 1.26 would remove wrong files when invoked with -# --listed-incremental and -C -# Reported by: Nathan Stratton Treadway -# References: <20130921171234.GG32256@shire.ontko.com>, -# http://lists.gnu.org/archive/html/bug-tar/2013-09/msg00028.html +# Description: ensure tar correctly respects -C option when deleting +# files due to the --remove-files option. +# +# This case checks the use of two relative-path -C options, +# in --append mode. +# -AT_SETUP([incremental and -C]) -AT_KEYWORDS([incremental create remove-files remfiles05]) +AT_SETUP([remove-files with -C:rel,rel in -r mode]) +AT_KEYWORDS([create append remove-files remfiles05 remfiles05c]) AT_TAR_CHECK([ AT_SORT_PREREQ mkdir foo -echo bar > bar -echo foo/bar > foo/bar +mkdir bar +echo file > file +echo foo/file > foo/file +echo bar/file > bar/file +tar -cf foo.tar -C foo file -C ../bar file decho A find . | sort - decho B -tar -cvf foo.tar --listed-incremental=foo.snar --remove-files -C foo bar +tar -rvf foo.tar --remove-files -C foo file -C ../bar file decho C find . | sort ], @@ -41,15 +44,19 @@ find . | sort [A . ./bar +./bar/file +./file ./foo -./foo/bar +./foo.tar +./foo/file B -bar +file +file C . ./bar +./file ./foo -./foo.snar ./foo.tar ], [A diff --git a/tests/remfiles06.at b/tests/remfiles06.at deleted file mode 100644 index c2d9876..8b13789 --- a/tests/remfiles06.at +++ /dev/null @@ -1,66 +0,0 @@ -# Process this file with autom4te to create testsuite. -*- Autotest -*- -# Test suite for GNU tar. -# Copyright 2013 Free Software Foundation, Inc. -# -# GNU tar 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 of the License, or -# (at your option) any later version. -# -# GNU tar 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 . - -# Description: There was a leftover call to chdir in name_next_elt() in -# tar 1.26. After commit e3d28d84 this call would confuse the tar_getcwd -# function. -# Reported by: Nathan Stratton Treadway -# References: <20130924145657.GM32256@shire.ontko.com>, -# http://lists.gnu.org/archive/html/bug-tar/2013-09/msg00045.html - -AT_SETUP([remove with two -C]) -AT_KEYWORDS([remove-files remfiles06]) - -AT_TAR_CHECK([ -AT_SORT_PREREQ -mkdir tartest -cd tartest -mkdir foo -echo foo/file > foo/file -mkdir bar -echo bar/file > bar/file -decho A -find|sort - -decho B -tar -cvf ../foo.tar --remove-files -C foo file -C ../bar file - -decho C -find|sort -], -[0], -[A -. -./bar -./bar/file -./foo -./foo/file -B -file -file -C -. -./bar -./foo -], -[A -B -C -],[],[],[gnu]) - -AT_CLEANUP - diff --git a/tests/remfiles06a.at b/tests/remfiles06a.at new file mode 100644 index 0000000..fe762c1 --- /dev/null +++ b/tests/remfiles06a.at @@ -0,0 +1,56 @@ +# Process this file with autom4te to create testsuite. -*- Autotest -*- +# Test suite for GNU tar. +# Copyright 2013 Free Software Foundation, Inc. +# +# GNU tar 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 of the License, or +# (at your option) any later version. +# +# GNU tar 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 . + +# Description: ensure tar correctly respects -C option when deleting +# files due to the --remove-files option. +# +# This case checks the use of a relative -C option followed by an absolute -C, +# in --create/non-incremental mode. +# + +AT_SETUP([remove-files with -C:rel,abs in -c/non-incr. mode]) +AT_KEYWORDS([create remove-files remfiles06 remfiles06a]) + +AT_TAR_CHECK([ +AT_SORT_PREREQ +mkdir foo +mkdir bar +echo file > file +echo foo/file > foo/file +echo bar/file > bar/file +DIR=`pwd` +decho A +tar -cvf foo.tar --remove-files -C foo file -C $DIR/bar file +decho B +find . | sort +], +[0], +[A +file +file +B +. +./bar +./file +./foo +./foo.tar +], +[A +B +],[],[],[gnu]) + +AT_CLEANUP diff --git a/tests/remfiles06b.at b/tests/remfiles06b.at new file mode 100644 index 0000000..3b867fb --- /dev/null +++ b/tests/remfiles06b.at @@ -0,0 +1,56 @@ +# Process this file with autom4te to create testsuite. -*- Autotest -*- +# Test suite for GNU tar. +# Copyright 2013 Free Software Foundation, Inc. +# +# GNU tar 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 of the License, or +# (at your option) any later version. +# +# GNU tar 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 . + +# Description: ensure tar correctly respects -C option when deleting +# files due to the --remove-files option. +# +# This case checks the use of a relative -C option followed by an absolute -C, +# in --create/incremental mode. +# + +AT_SETUP([remove-files with -C:rel,abs in -c/incr. mode]) +AT_KEYWORDS([create incremental remove-files remfiles06 remfiles06b]) + +AT_TAR_CHECK([ +AT_SORT_PREREQ +mkdir foo +mkdir bar +echo file > file +echo foo/file > foo/file +echo bar/file > bar/file +DIR=`pwd` +decho A +tar -cvf foo.tar --incremental --remove-files -C foo file -C $DIR/bar file +decho B +find . | sort +], +[0], +[A +file +file +B +. +./bar +./file +./foo +./foo.tar +], +[A +B +],[],[],[gnu]) + +AT_CLEANUP diff --git a/tests/remfiles06c.at b/tests/remfiles06c.at new file mode 100644 index 0000000..ad9164d --- /dev/null +++ b/tests/remfiles06c.at @@ -0,0 +1,68 @@ +# Process this file with autom4te to create testsuite. -*- Autotest -*- +# Test suite for GNU tar. +# Copyright 2013 Free Software Foundation, Inc. +# +# GNU tar 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 of the License, or +# (at your option) any later version. +# +# GNU tar 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 . + +# Description: ensure tar correctly respects -C option when deleting +# files due to the --remove-files option. +# +# This case checks the use of a relative -C option followed by an absolute -C, +# in --append mode. +# + +AT_SETUP([remove-files with -C:rel,abs in -r mode]) +AT_KEYWORDS([create append remove-files remfiles06 remfiles06c]) + +AT_TAR_CHECK([ +AT_SORT_PREREQ +mkdir foo +mkdir bar +echo file > file +echo foo/file > foo/file +echo bar/file > bar/file +DIR=`pwd` +tar -cf foo.tar -C foo file -C $DIR/bar file +decho A +find . | sort +decho B +tar -rvf foo.tar --remove-files -C foo file -C ../bar file +decho C +find . | sort +], +[0], +[A +. +./bar +./bar/file +./file +./foo +./foo.tar +./foo/file +B +file +file +C +. +./bar +./file +./foo +./foo.tar +], +[A +B +C +],[],[],[gnu]) + +AT_CLEANUP diff --git a/tests/remfiles07a.at b/tests/remfiles07a.at new file mode 100644 index 0000000..95f645c --- /dev/null +++ b/tests/remfiles07a.at @@ -0,0 +1,56 @@ +# Process this file with autom4te to create testsuite. -*- Autotest -*- +# Test suite for GNU tar. +# Copyright 2013 Free Software Foundation, Inc. +# +# GNU tar 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 of the License, or +# (at your option) any later version. +# +# GNU tar 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 . + +# Description: ensure tar correctly respects -C option when deleting +# files due to the --remove-files option. +# +# This case checks the use of a relative -C option followed by an absolute -C, +# in --create/non-incremental mode. +# + +AT_SETUP([remove-files with -C:rel,abs in -c/non-incr. mode]) +AT_KEYWORDS([create remove-files remfiles07 remfiles07a]) + +AT_TAR_CHECK([ +AT_SORT_PREREQ +mkdir foo +mkdir bar +echo file > file +echo foo/file > foo/file +echo bar/file > bar/file +DIR=`pwd` +decho A +tar -cvf foo.tar --remove-files -C foo file -C $DIR/bar file +decho B +find . | sort +], +[0], +[A +file +file +B +. +./bar +./file +./foo +./foo.tar +], +[A +B +],[],[],[gnu]) + +AT_CLEANUP diff --git a/tests/remfiles07b.at b/tests/remfiles07b.at new file mode 100644 index 0000000..ca67e5d --- /dev/null +++ b/tests/remfiles07b.at @@ -0,0 +1,56 @@ +# Process this file with autom4te to create testsuite. -*- Autotest -*- +# Test suite for GNU tar. +# Copyright 2013 Free Software Foundation, Inc. +# +# GNU tar 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 of the License, or +# (at your option) any later version. +# +# GNU tar 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 . + +# Description: ensure tar correctly respects -C option when deleting +# files due to the --remove-files option. +# +# This case checks the use of a relative -C option followed by an absolute -C, +# in --create/incremental mode. +# + +AT_SETUP([remove-files with -C:rel,abs in -c/incr. mode]) +AT_KEYWORDS([create incremental remove-files remfiles07 remfiles07b]) + +AT_TAR_CHECK([ +AT_SORT_PREREQ +mkdir foo +mkdir bar +echo file > file +echo foo/file > foo/file +echo bar/file > bar/file +DIR=`pwd` +decho A +tar -cvf foo.tar --incremental --remove-files -C foo file -C $DIR/bar file +decho B +find . | sort +], +[0], +[A +file +file +B +. +./bar +./file +./foo +./foo.tar +], +[A +B +],[],[],[gnu]) + +AT_CLEANUP diff --git a/tests/remfiles07c.at b/tests/remfiles07c.at new file mode 100644 index 0000000..6a5c870 --- /dev/null +++ b/tests/remfiles07c.at @@ -0,0 +1,68 @@ +# Process this file with autom4te to create testsuite. -*- Autotest -*- +# Test suite for GNU tar. +# Copyright 2013 Free Software Foundation, Inc. +# +# GNU tar 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 of the License, or +# (at your option) any later version. +# +# GNU tar 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 . + +# Description: ensure tar correctly respects -C option when deleting +# files due to the --remove-files option. +# +# This case checks the use of a relative -C option followed by an absolute -C, +# in --append mode. +# + +AT_SETUP([remove-files with -C:rel,abs in -r mode]) +AT_KEYWORDS([create append remove-files remfiles07 remfiles07c]) + +AT_TAR_CHECK([ +AT_SORT_PREREQ +mkdir foo +mkdir bar +echo file > file +echo foo/file > foo/file +echo bar/file > bar/file +DIR=`pwd` +tar -cf foo.tar -C foo file -C $DIR/bar file +decho A +find . | sort +decho B +tar -rvf foo.tar --remove-files -C foo file -C $DIR/bar file +decho C +find . | sort +], +[0], +[A +. +./bar +./bar/file +./file +./foo +./foo.tar +./foo/file +B +file +file +C +. +./bar +./file +./foo +./foo.tar +], +[A +B +C +],[],[],[gnu]) + +AT_CLEANUP diff --git a/tests/remfiles08a.at b/tests/remfiles08a.at new file mode 100644 index 0000000..eadf149 --- /dev/null +++ b/tests/remfiles08a.at @@ -0,0 +1,56 @@ +# Process this file with autom4te to create testsuite. -*- Autotest -*- +# Test suite for GNU tar. +# Copyright 2013 Free Software Foundation, Inc. +# +# GNU tar 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 of the License, or +# (at your option) any later version. +# +# GNU tar 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 . + +# Description: ensure tar correctly respects -C option when deleting +# files due to the --remove-files option. +# +# This case checks the use of an absolute -C option followed by a relative -C, +# in --create/non-incremental mode. +# + +AT_SETUP([remove-files with -C:abs,rel in -c/non-incr. mode]) +AT_KEYWORDS([create remove-files remfiles08 remfiles08a]) + +AT_TAR_CHECK([ +AT_SORT_PREREQ +mkdir foo +mkdir bar +echo file > file +echo foo/file > foo/file +echo bar/file > bar/file +DIR=`pwd` +decho A +tar -cvf foo.tar --remove-files -C $DIR/foo file -C ../bar file +decho B +find . | sort +], +[0], +[A +file +file +B +. +./bar +./file +./foo +./foo.tar +], +[A +B +],[],[],[gnu]) + +AT_CLEANUP diff --git a/tests/remfiles08b.at b/tests/remfiles08b.at new file mode 100644 index 0000000..9faf2bb --- /dev/null +++ b/tests/remfiles08b.at @@ -0,0 +1,56 @@ +# Process this file with autom4te to create testsuite. -*- Autotest -*- +# Test suite for GNU tar. +# Copyright 2013 Free Software Foundation, Inc. +# +# GNU tar 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 of the License, or +# (at your option) any later version. +# +# GNU tar 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 . + +# Description: ensure tar correctly respects -C option when deleting +# files due to the --remove-files option. +# +# This case checks the use of an absolute -C option followed by a relative -C, +# in --create/incremental mode. +# + +AT_SETUP([remove-files with -C:abs,rel in -c/incr. mode]) +AT_KEYWORDS([create incremental remove-files remfiles08 remfiles08b]) + +AT_TAR_CHECK([ +AT_SORT_PREREQ +mkdir foo +mkdir bar +echo file > file +echo foo/file > foo/file +echo bar/file > bar/file +DIR=`pwd` +decho A +tar -cvf foo.tar --incremental --remove-files -C $DIR/foo file -C ../bar file +decho B +find . | sort +], +[0], +[A +file +file +B +. +./bar +./file +./foo +./foo.tar +], +[A +B +],[],[],[gnu]) + +AT_CLEANUP diff --git a/tests/remfiles08c.at b/tests/remfiles08c.at new file mode 100644 index 0000000..a220f4c --- /dev/null +++ b/tests/remfiles08c.at @@ -0,0 +1,68 @@ +# Process this file with autom4te to create testsuite. -*- Autotest -*- +# Test suite for GNU tar. +# Copyright 2013 Free Software Foundation, Inc. +# +# GNU tar 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 of the License, or +# (at your option) any later version. +# +# GNU tar 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 . + +# Description: ensure tar correctly respects -C option when deleting +# files due to the --remove-files option. +# +# This case checks the use of an absolute -C option followed by a relative -C, +# in --append mode. +# + +AT_SETUP([remove-files with -C:abs,rel in -r mode]) +AT_KEYWORDS([create append remove-files remfiles08 remfiles08c]) + +AT_TAR_CHECK([ +AT_SORT_PREREQ +mkdir foo +mkdir bar +echo file > file +echo foo/file > foo/file +echo bar/file > bar/file +DIR=`pwd` +tar -cf foo.tar -C $DIR/foo file -C ../bar file +decho A +find . | sort +decho B +tar -rvf foo.tar --remove-files -C $DIR/foo file -C ../bar file +decho C +find . | sort +], +[0], +[A +. +./bar +./bar/file +./file +./foo +./foo.tar +./foo/file +B +file +file +C +. +./bar +./file +./foo +./foo.tar +], +[A +B +C +],[],[],[gnu]) + +AT_CLEANUP diff --git a/tests/remfiles08.at b/tests/remfiles09a.at similarity index 66% rename from tests/remfiles08.at rename to tests/remfiles09a.at index 0649e85..fd28b4f 100644 --- a/tests/remfiles08.at +++ b/tests/remfiles09a.at @@ -15,29 +15,28 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -# Description: See remfiles06.at -# Reported by: Nathan Stratton Treadway -# References: <20130926050634.GW32256@shire.ontko.com> +# Description: check --remove-files operation when archiving/deleting +# directory trees. +# +# This case checks the operation +# in --create/non-incremental mode. +# -AT_SETUP([remove with -C to absolute and relative paths]) -AT_KEYWORDS([incremental create remove-files remfiles08]) +AT_SETUP([remove-files on full directory in -c/non-incr. mode]) +AT_KEYWORDS([create remove-files remfiles09 remfiles09a]) AT_TAR_CHECK([ mkdir foo -mkdir bar -echo foo/foo_file > foo/foo_file -echo bar/bar_file > bar/bar_file +echo foo/file > foo/file decho A -tar -cvf foo.tar --remove-files -C `pwd`/foo . -C ../bar . +tar -cvf foo.tar --remove-files foo decho B -find +find . ], [0], [A -./ -./foo_file -./ -./bar_file +foo/ +foo/file B . ./foo.tar diff --git a/tests/remfiles09b.at b/tests/remfiles09b.at new file mode 100644 index 0000000..30cc3ee --- /dev/null +++ b/tests/remfiles09b.at @@ -0,0 +1,57 @@ +# Process this file with autom4te to create testsuite. -*- Autotest -*- +# Test suite for GNU tar. +# Copyright 2013 Free Software Foundation, Inc. +# +# GNU tar 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 of the License, or +# (at your option) any later version. +# +# GNU tar 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 . + +# Description: check --remove-files operation when archiving/deleting +# directory trees. +# +# This case checks the operation +# in --create/incremental mode. +# +# Note: in tar 1.27, when run in incremental mode tar will attempt to remove +# the directory before removing the files within that directory, and thus +# the --remove-files operation will cause tar to abort with an error status. +# This issue will be fixed in a later version of tar. + +AT_SETUP([remove-files on full directory in -c/incr. mode]) +AT_KEYWORDS([create incremental remove-files remfiles09 remfiles09b]) + +AT_TAR_CHECK([ +AT_SORT_PREREQ +mkdir foo +echo foo/file > foo/file +decho A +tar -cvf foo.tar --incremental --remove-files foo +TARSTAT=$? +decho B +find . +test $TARSTAT -ne 0 && AT_SKIP_TEST # we expect to fail in tar 1.27 +], +[0], +[A +foo/ +foo/file +B +. +./foo +./foo.tar +], +[A +tar: foo: Directory is new +B +],[],[],[gnu]) + +AT_CLEANUP diff --git a/tests/remfiles07.at b/tests/remfiles09c.at similarity index 68% rename from tests/remfiles07.at rename to tests/remfiles09c.at index 742e0a1..7241608 100644 --- a/tests/remfiles07.at +++ b/tests/remfiles09c.at @@ -15,45 +15,40 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -# Description: See remfiles06.at -# Reported by: Nathan Stratton Treadway -# References: <20130924185129.GO32256@shire.ontko.com> +# Description: check --remove-files operation when archiving/deleting +# directory trees. +# +# This case checks the operation +# in --append mode. +# -AT_SETUP([remove with -C to absolute path]) -AT_KEYWORDS([create remove-files remfiles07]) +AT_SETUP([remove-files on full directory in -r mode]) +AT_KEYWORDS([create append remove-files remfiles09 remfiles09c]) AT_TAR_CHECK([ AT_SORT_PREREQ -mkdir tartest -cd tartest mkdir foo echo foo/file > foo/file -mkdir bar -echo bar/file > bar/file +tar -cf foo.tar foo decho A -find|sort - -DIR=`pwd` +find . | sort decho B -tar -cvf ../foo.tar --remove-files -C foo file -C $DIR/bar file - +tar -rvf foo.tar --remove-files foo decho C -find|sort +find . | sort ], [0], [A . -./bar -./bar/file ./foo +./foo.tar ./foo/file B -file -file +foo/ +foo/file C . -./bar -./foo +./foo.tar ], [A B diff --git a/tests/testsuite.at b/tests/testsuite.at index a9f2ab6..1cc425f 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -332,11 +332,24 @@ m4_include([grow.at]) m4_include([remfiles01.at]) m4_include([remfiles02.at]) m4_include([remfiles03.at]) -m4_include([remfiles04.at]) -m4_include([remfiles05.at]) -m4_include([remfiles06.at]) -m4_include([remfiles07.at]) -m4_include([remfiles08.at]) +m4_include([remfiles04a.at]) +m4_include([remfiles04b.at]) +m4_include([remfiles04c.at]) +m4_include([remfiles05a.at]) +m4_include([remfiles05b.at]) +m4_include([remfiles05c.at]) +m4_include([remfiles06a.at]) +m4_include([remfiles06b.at]) +m4_include([remfiles06c.at]) +m4_include([remfiles07a.at]) +m4_include([remfiles07b.at]) +m4_include([remfiles07c.at]) +m4_include([remfiles08a.at]) +m4_include([remfiles08b.at]) +m4_include([remfiles08c.at]) +m4_include([remfiles09a.at]) +m4_include([remfiles09b.at]) +m4_include([remfiles09c.at]) m4_include([sigpipe.at]) -- 2.9.3 From c3d32c9c848f1f305cd9aefd9f485cdfbcee51b2 Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Sat, 5 Oct 2013 09:29:55 +0300 Subject: [PATCH 08/11] Xfail the remfiles09b test. * tests/remfiles09b.at: Turn into expected failure. --- tests/remfiles09b.at | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/remfiles09b.at b/tests/remfiles09b.at index 30cc3ee..de9b172 100644 --- a/tests/remfiles09b.at +++ b/tests/remfiles09b.at @@ -29,6 +29,8 @@ AT_SETUP([remove-files on full directory in -c/incr. mode]) AT_KEYWORDS([create incremental remove-files remfiles09 remfiles09b]) +AT_XFAIL_IF(true) # we expect to fail in tar 1.27 + AT_TAR_CHECK([ AT_SORT_PREREQ mkdir foo @@ -38,7 +40,6 @@ tar -cvf foo.tar --incremental --remove-files foo TARSTAT=$? decho B find . -test $TARSTAT -ne 0 && AT_SKIP_TEST # we expect to fail in tar 1.27 ], [0], [A -- 2.9.3 From 2c5449cc473b0a9affed02feaf3ad42e5e89bfb5 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Tue, 29 Apr 2014 14:22:07 -0700 Subject: [PATCH 09/11] tar: do not dereference NULL pointer with '--remove-files .' Problem reported by Thorsten Hirsch in: http://lists.gnu.org/archive/html/bug-tar/2014-04/msg00011.html * src/unlink.c (flush_deferred_unlinks): Do not attempt to find the parent of "." when "." is at the top level. * tests/remfiles10.at: New file. * tests/Makefile.am (TESTSUITE_AT): * tests/testsuite.at: Add it. --- src/unlink.c | 5 +++-- tests/Makefile.am | 1 + tests/remfiles10.at | 46 ++++++++++++++++++++++++++++++++++++++++++++++ tests/testsuite.at | 1 + 4 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 tests/remfiles10.at diff --git a/src/unlink.c b/src/unlink.c index 10e0b41..6e41acc 100644 --- a/src/unlink.c +++ b/src/unlink.c @@ -84,8 +84,9 @@ flush_deferred_unlinks (bool force) { const char *fname; - if (p->file_name[0] == 0 || - strcmp (p->file_name, ".") == 0) + if (p->dir_idx + && (p->file_name[0] == 0 + || strcmp (p->file_name, ".") == 0)) { fname = tar_dirname (); chdir_do (p->dir_idx - 1); diff --git a/tests/Makefile.am b/tests/Makefile.am index cf6f576..792c83c 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -159,6 +159,7 @@ TESTSUITE_AT = \ remfiles09a.at\ remfiles09b.at\ remfiles09c.at\ + remfiles10.at\ same-order01.at\ same-order02.at\ shortfile.at\ diff --git a/tests/remfiles10.at b/tests/remfiles10.at new file mode 100644 index 0000000..b4fe139 --- /dev/null +++ b/tests/remfiles10.at @@ -0,0 +1,46 @@ +# Process this file with autom4te to create testsuite. -*- Autotest -*- +# Test suite for GNU tar. +# Copyright 2014 Free Software Foundation, Inc. +# +# GNU tar 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 of the License, or +# (at your option) any later version. +# +# GNU tar 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 . + +# Check --remove-files with . + +AT_SETUP([remove-files]) +AT_KEYWORDS([create remove-files remfiles10]) + +AT_TAR_CHECK([ +mkdir foo +echo foo/file > foo/file +decho A +(cd foo && tar -cvf ../foo.tar --remove-files .) +tar_status=$? +decho B +find foo +exit $tar_status +], +[2], +[A +./ +./file +B +foo +], +[A +tar: .: Cannot rmdir: Invalid argument +tar: Exiting with failure status due to previous errors +B +],[],[],[gnu]) + +AT_CLEANUP diff --git a/tests/testsuite.at b/tests/testsuite.at index 1cc425f..1078724 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -350,6 +350,7 @@ m4_include([remfiles08c.at]) m4_include([remfiles09a.at]) m4_include([remfiles09b.at]) m4_include([remfiles09c.at]) +m4_include([remfiles10.at]) m4_include([sigpipe.at]) -- 2.9.3 From 612e134f4905f479b78b6d7faf9798494697a742 Mon Sep 17 00:00:00 2001 From: Nathan Stratton Treadway Date: Sun, 27 Jul 2014 23:27:28 +0300 Subject: [PATCH 10/11] Restructure the remfiles testsuite. --- tests/remfiles06c.at | 2 +- tests/remfiles07a.at | 6 +++--- tests/remfiles07b.at | 6 +++--- tests/remfiles07c.at | 8 ++++---- tests/remfiles08a.at | 31 +++++++++++++++---------------- tests/remfiles08b.at | 38 ++++++++++++++++++++++---------------- tests/remfiles08c.at | 37 ++++++++++++++++++------------------- tests/remfiles09a.at | 2 +- tests/remfiles09b.at | 3 --- 9 files changed, 67 insertions(+), 66 deletions(-) diff --git a/tests/remfiles06c.at b/tests/remfiles06c.at index ad9164d..abb8e68 100644 --- a/tests/remfiles06c.at +++ b/tests/remfiles06c.at @@ -37,7 +37,7 @@ tar -cf foo.tar -C foo file -C $DIR/bar file decho A find . | sort decho B -tar -rvf foo.tar --remove-files -C foo file -C ../bar file +tar -rvf foo.tar --remove-files -C foo file -C $DIR/bar file decho C find . | sort ], diff --git a/tests/remfiles07a.at b/tests/remfiles07a.at index 95f645c..5b7df3e 100644 --- a/tests/remfiles07a.at +++ b/tests/remfiles07a.at @@ -18,11 +18,11 @@ # Description: ensure tar correctly respects -C option when deleting # files due to the --remove-files option. # -# This case checks the use of a relative -C option followed by an absolute -C, +# This case checks the use of an absolute -C option followed by a relative -C, # in --create/non-incremental mode. # -AT_SETUP([remove-files with -C:rel,abs in -c/non-incr. mode]) +AT_SETUP([remove-files with -C:abs,rel in -c/non-incr. mode]) AT_KEYWORDS([create remove-files remfiles07 remfiles07a]) AT_TAR_CHECK([ @@ -34,7 +34,7 @@ echo foo/file > foo/file echo bar/file > bar/file DIR=`pwd` decho A -tar -cvf foo.tar --remove-files -C foo file -C $DIR/bar file +tar -cvf foo.tar --remove-files -C $DIR/foo file -C ../bar file decho B find . | sort ], diff --git a/tests/remfiles07b.at b/tests/remfiles07b.at index ca67e5d..0147c5d 100644 --- a/tests/remfiles07b.at +++ b/tests/remfiles07b.at @@ -18,11 +18,11 @@ # Description: ensure tar correctly respects -C option when deleting # files due to the --remove-files option. # -# This case checks the use of a relative -C option followed by an absolute -C, +# This case checks the use of an absolute -C option followed by a relative -C, # in --create/incremental mode. # -AT_SETUP([remove-files with -C:rel,abs in -c/incr. mode]) +AT_SETUP([remove-files with -C:abs,rel in -c/incr. mode]) AT_KEYWORDS([create incremental remove-files remfiles07 remfiles07b]) AT_TAR_CHECK([ @@ -34,7 +34,7 @@ echo foo/file > foo/file echo bar/file > bar/file DIR=`pwd` decho A -tar -cvf foo.tar --incremental --remove-files -C foo file -C $DIR/bar file +tar -cvf foo.tar --incremental --remove-files -C $DIR/foo file -C ../bar file decho B find . | sort ], diff --git a/tests/remfiles07c.at b/tests/remfiles07c.at index 6a5c870..f190539 100644 --- a/tests/remfiles07c.at +++ b/tests/remfiles07c.at @@ -18,11 +18,11 @@ # Description: ensure tar correctly respects -C option when deleting # files due to the --remove-files option. # -# This case checks the use of a relative -C option followed by an absolute -C, +# This case checks the use of an absolute -C option followed by a relative -C, # in --append mode. # -AT_SETUP([remove-files with -C:rel,abs in -r mode]) +AT_SETUP([remove-files with -C:abs,rel in -r mode]) AT_KEYWORDS([create append remove-files remfiles07 remfiles07c]) AT_TAR_CHECK([ @@ -33,11 +33,11 @@ echo file > file echo foo/file > foo/file echo bar/file > bar/file DIR=`pwd` -tar -cf foo.tar -C foo file -C $DIR/bar file +tar -cf foo.tar -C $DIR/foo file -C ../bar file decho A find . | sort decho B -tar -rvf foo.tar --remove-files -C foo file -C $DIR/bar file +tar -rvf foo.tar --remove-files -C $DIR/foo file -C ../bar file decho C find . | sort ], diff --git a/tests/remfiles08a.at b/tests/remfiles08a.at index eadf149..1ffffb2 100644 --- a/tests/remfiles08a.at +++ b/tests/remfiles08a.at @@ -15,38 +15,37 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -# Description: ensure tar correctly respects -C option when deleting -# files due to the --remove-files option. +# Description: If tar 1.26 was called with the --remove-files option and told +# to archive (and thus delete) two subdirectories where the second was +# specified relative to the first, it would be unable to delete the +# second directory (and its contents), since the relative path would no +# longer be valid once the first directory was deleted. # -# This case checks the use of an absolute -C option followed by a relative -C, +# This case checks for successful deletion of all archived items # in --create/non-incremental mode. # -AT_SETUP([remove-files with -C:abs,rel in -c/non-incr. mode]) +AT_SETUP([remove-files deleting two subdirs in -c/non-incr. mode]) AT_KEYWORDS([create remove-files remfiles08 remfiles08a]) AT_TAR_CHECK([ -AT_SORT_PREREQ mkdir foo mkdir bar -echo file > file -echo foo/file > foo/file -echo bar/file > bar/file -DIR=`pwd` +echo foo/foo_file > foo/foo_file +echo bar/bar_file > bar/bar_file decho A -tar -cvf foo.tar --remove-files -C $DIR/foo file -C ../bar file +tar -cvf foo.tar --remove-files -C foo . -C ../bar . decho B -find . | sort +find . ], [0], [A -file -file +./ +./foo_file +./ +./bar_file B . -./bar -./file -./foo ./foo.tar ], [A diff --git a/tests/remfiles08b.at b/tests/remfiles08b.at index 9faf2bb..d61c9ab 100644 --- a/tests/remfiles08b.at +++ b/tests/remfiles08b.at @@ -15,41 +15,47 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -# Description: ensure tar correctly respects -C option when deleting -# files due to the --remove-files option. +# Description: If tar 1.26 was called with the --remove-files option and told +# to archive (and thus delete) two subdirectories where the second was +# specified relative to the first, it would be unable to delete the +# second directory (and its contents), since the relative path would no +# longer be valid once the first directory was deleted. # -# This case checks the use of an absolute -C option followed by a relative -C, +# This case checks for successful deletion of all archived items # in --create/incremental mode. # +# Note: tar 1.27 fails this test case due to a more general issue +# archving-and-removing a full directory tree when run in incremental +# mode; see remfiles09b.at for that specific test case. -AT_SETUP([remove-files with -C:abs,rel in -c/incr. mode]) +AT_SETUP([remove-files deleting two subdirs in -c/incr. mode]) AT_KEYWORDS([create incremental remove-files remfiles08 remfiles08b]) +AT_XFAIL_IF(true) # we expect to fail in tar 1.27 + AT_TAR_CHECK([ -AT_SORT_PREREQ mkdir foo mkdir bar -echo file > file -echo foo/file > foo/file -echo bar/file > bar/file -DIR=`pwd` +echo foo/foo_file > foo/foo_file +echo bar/bar_file > bar/bar_file decho A -tar -cvf foo.tar --incremental --remove-files -C $DIR/foo file -C ../bar file +tar -cvf foo.tar --incremental --remove-files -C foo . -C ../bar . decho B -find . | sort +find . ], [0], [A -file -file +./ +./ +./foo_file +./bar_file B . -./bar -./file -./foo ./foo.tar ], [A +tar: .: Directory is new +tar: .: Directory is new B ],[],[],[gnu]) diff --git a/tests/remfiles08c.at b/tests/remfiles08c.at index a220f4c..19b18e2 100644 --- a/tests/remfiles08c.at +++ b/tests/remfiles08c.at @@ -15,49 +15,48 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -# Description: ensure tar correctly respects -C option when deleting -# files due to the --remove-files option. +# Description: If tar 1.26 was called with the --remove-files option and told +# to archive (and thus delete) two subdirectories where the second was +# specified relative to the first, it would be unable to delete the +# second directory (and its contents), since the relative path would no +# longer be valid once the first directory was deleted. # -# This case checks the use of an absolute -C option followed by a relative -C, +# This case checks for successful deletion of all archived items # in --append mode. # -AT_SETUP([remove-files with -C:abs,rel in -r mode]) +AT_SETUP([remove-files deleting two subdirs in -r mode]) AT_KEYWORDS([create append remove-files remfiles08 remfiles08c]) AT_TAR_CHECK([ AT_SORT_PREREQ mkdir foo mkdir bar -echo file > file -echo foo/file > foo/file -echo bar/file > bar/file -DIR=`pwd` -tar -cf foo.tar -C $DIR/foo file -C ../bar file +echo foo/foo_file > foo/foo_file +echo bar/bar_file > bar/bar_file +tar -cf foo.tar -C foo . -C ../bar . decho A find . | sort decho B -tar -rvf foo.tar --remove-files -C $DIR/foo file -C ../bar file +tar -rvf foo.tar --remove-files -C foo . -C ../bar . decho C -find . | sort +find . ], [0], [A . ./bar -./bar/file -./file +./bar/bar_file ./foo ./foo.tar -./foo/file +./foo/foo_file B -file -file +./ +./foo_file +./ +./bar_file C . -./bar -./file -./foo ./foo.tar ], [A diff --git a/tests/remfiles09a.at b/tests/remfiles09a.at index fd28b4f..f4a3bf5 100644 --- a/tests/remfiles09a.at +++ b/tests/remfiles09a.at @@ -31,7 +31,7 @@ echo foo/file > foo/file decho A tar -cvf foo.tar --remove-files foo decho B -find . +find . ], [0], [A diff --git a/tests/remfiles09b.at b/tests/remfiles09b.at index de9b172..e12fe32 100644 --- a/tests/remfiles09b.at +++ b/tests/remfiles09b.at @@ -32,12 +32,10 @@ AT_KEYWORDS([create incremental remove-files remfiles09 remfiles09b]) AT_XFAIL_IF(true) # we expect to fail in tar 1.27 AT_TAR_CHECK([ -AT_SORT_PREREQ mkdir foo echo foo/file > foo/file decho A tar -cvf foo.tar --incremental --remove-files foo -TARSTAT=$? decho B find . ], @@ -47,7 +45,6 @@ foo/ foo/file B . -./foo ./foo.tar ], [A -- 2.9.3 From 6030b8a2589ff69d9200578e0aecc1f10aedb073 Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Wed, 11 Nov 2015 13:01:45 +0200 Subject: [PATCH 11/11] Work around unlinkat bug on FreeBSD and GNU/Hurd * src/unlink.c (dunlink_insert): New function. (flush_deferred_unlinks): Skip cwds and nonempty directories at the first pass. If force is requested, run a second pass removing them. (queue_deferred_unlink): Make sure current working directory entries are sorted in descending order by the value of dir_idx. This makes sure they will be removed in right order, which works around unlinkat bug on FreeBSD and GNU/Hurd. * tests/remfiles08b.at: Remove expected failure. * tests/remfiles09b.at: Likewise. --- src/unlink.c | 91 +++++++++++++++++++++++++++++++++++++++++----------- tests/remfiles08b.at | 2 -- tests/remfiles09b.at | 2 -- 3 files changed, 72 insertions(+), 23 deletions(-) diff --git a/src/unlink.c b/src/unlink.c index 6e41acc..f5fb81d 100644 --- a/src/unlink.c +++ b/src/unlink.c @@ -30,6 +30,10 @@ struct deferred_unlink entry got added to the queue */ }; +#define IS_CWD(p) \ + ((p)->is_dir \ + && ((p)->file_name[0] == 0 || strcmp ((p)->file_name, ".") == 0)) + /* The unlink queue */ static struct deferred_unlink *dunlink_head, *dunlink_tail; @@ -59,6 +63,24 @@ dunlink_alloc (void) } static void +dunlink_insert (struct deferred_unlink *anchor, struct deferred_unlink *p) +{ + if (anchor) + { + p->next = anchor->next; + anchor->next = p; + } + else + { + p->next = dunlink_head; + dunlink_head = p; + } + if (!p->next) + dunlink_tail = p; + dunlink_count++; +} + +static void dunlink_reclaim (struct deferred_unlink *p) { free (p->file_name); @@ -84,12 +106,11 @@ flush_deferred_unlinks (bool force) { const char *fname; - if (p->dir_idx - && (p->file_name[0] == 0 - || strcmp (p->file_name, ".") == 0)) + if (p->dir_idx && IS_CWD (p)) { - fname = tar_dirname (); - chdir_do (p->dir_idx - 1); + prev = p; + p = next; + continue; } else fname = p->file_name; @@ -102,15 +123,12 @@ flush_deferred_unlinks (bool force) /* nothing to worry about */ break; case ENOTEMPTY: - if (!force) - { - /* Keep the record in list, in the hope we'll - be able to remove it later */ - prev = p; - p = next; - continue; - } - /* fall through */ + /* Keep the record in list, in the hope we'll + be able to remove it later */ + prev = p; + p = next; + continue; + default: rmdir_error (fname); } @@ -137,6 +155,34 @@ flush_deferred_unlinks (bool force) } if (!dunlink_head) dunlink_tail = NULL; + else if (force) + { + for (p = dunlink_head; p; ) + { + struct deferred_unlink *next = p->next; + const char *fname; + + chdir_do (p->dir_idx); + if (p->dir_idx && IS_CWD (p)) + { + fname = tar_dirname (); + chdir_do (p->dir_idx - 1); + } + else + fname = p->file_name; + + if (unlinkat (chdir_fd, fname, AT_REMOVEDIR) != 0) + { + if (errno != ENOENT) + rmdir_error (fname); + } + dunlink_reclaim (p); + dunlink_count--; + p = next; + } + dunlink_head = dunlink_tail = NULL; + } + chdir_do (saved_chdir); } @@ -169,10 +215,17 @@ queue_deferred_unlink (const char *name, bool is_dir) p->is_dir = is_dir; p->records_written = records_written; - if (dunlink_tail) - dunlink_tail->next = p; + if (IS_CWD (p)) + { + struct deferred_unlink *q, *prev; + for (q = dunlink_head, prev = NULL; q; prev = q, q = q->next) + if (IS_CWD (q) && q->dir_idx < p->dir_idx) + break; + if (q) + dunlink_insert (prev, p); + else + dunlink_insert (dunlink_tail, p); + } else - dunlink_head = p; - dunlink_tail = p; - dunlink_count++; + dunlink_insert (dunlink_tail, p); } diff --git a/tests/remfiles08b.at b/tests/remfiles08b.at index d61c9ab..4487f83 100644 --- a/tests/remfiles08b.at +++ b/tests/remfiles08b.at @@ -31,8 +31,6 @@ AT_SETUP([remove-files deleting two subdirs in -c/incr. mode]) AT_KEYWORDS([create incremental remove-files remfiles08 remfiles08b]) -AT_XFAIL_IF(true) # we expect to fail in tar 1.27 - AT_TAR_CHECK([ mkdir foo mkdir bar diff --git a/tests/remfiles09b.at b/tests/remfiles09b.at index e12fe32..4d05aa5 100644 --- a/tests/remfiles09b.at +++ b/tests/remfiles09b.at @@ -29,8 +29,6 @@ AT_SETUP([remove-files on full directory in -c/incr. mode]) AT_KEYWORDS([create incremental remove-files remfiles09 remfiles09b]) -AT_XFAIL_IF(true) # we expect to fail in tar 1.27 - AT_TAR_CHECK([ mkdir foo echo foo/file > foo/file -- 2.9.3