From: Sergey Poznyakoff Date: Thu, 26 Sep 2013 12:41:47 +0000 (+0300) Subject: Use relative addressing in deferred unlinks. X-Git-Url: https://git.brokenzipper.com/gitweb?a=commitdiff_plain;h=f7077dd38b018f19d3a5c7df6accc6b07b8a2356;p=chaz%2Ftar 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. --- diff --git a/src/common.h b/src/common.h index 2a6d7d4..c2cad54 100644 --- a/src/common.h +++ b/src/common.h @@ -597,6 +597,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); @@ -609,6 +610,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); /* Represent N using a signed integer I such that (uintmax_t) I == N. With a good optimizing compiler, this is equivalent to (intmax_t) i diff --git a/src/misc.c b/src/misc.c index bd396a3..343d5f9 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) @@ -978,6 +980,12 @@ chdir_do (int i) } } +const char * +tar_dirname (void) +{ + return wd[chdir_current].name; +} + const char * tar_getcwd (void) { @@ -993,8 +1001,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 8c58b8d..6677148 100644 --- a/src/unlink.c +++ b/src/unlink.c @@ -24,7 +24,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 */ @@ -70,16 +72,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) { @@ -97,7 +113,7 @@ flush_deferred_unlinks (bool force) } /* fall through */ default: - rmdir_error (p->file_name); + rmdir_error (fname); } } } @@ -122,6 +138,7 @@ flush_deferred_unlinks (bool force) } if (!dunlink_head) dunlink_tail = NULL; + chdir_do (saved_chdir); } void @@ -147,7 +164,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 4823b60..f40c664 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -166,6 +166,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 0fa8c15..3c3dbf4 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 0192ac4..e28513e 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -382,6 +382,7 @@ m4_include([remfiles04.at]) m4_include([remfiles05.at]) m4_include([remfiles06.at]) m4_include([remfiles07.at]) +m4_include([remfiles08.at]) AT_BANNER([Extended attributes]) m4_include([xattr01.at])