X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Ftar;a=blobdiff_plain;f=src%2Funlink.c;h=225d49b1bf2654ae8b08e769e41cc85d9ee09256;hp=2af6f9957b2887eea74b9fe0b394207d60937e32;hb=45ccda119355a1087450039a250359c1d0de0d08;hpb=4dfcd6c054a5e9e1a371c822a3be90564dd9b690 diff --git a/src/unlink.c b/src/unlink.c index 2af6f99..225d49b 100644 --- a/src/unlink.c +++ b/src/unlink.c @@ -1,19 +1,21 @@ -/* This file is part of GNU tar. - Copyright (C) 2009 Free Software Foundation, Inc. +/* Unlink files. - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 3, or (at your option) any later - version. + Copyright 2009, 2013-2014 Free Software Foundation, Inc. - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General - Public License for more details. + This file is part of GNU tar. - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + 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 . */ #include #include "common.h" @@ -22,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 */ @@ -39,10 +43,10 @@ static struct deferred_unlink *dunlink_avail; /* Delay (number of records written) between adding entry to the list and its actual removal. */ -size_t deferred_unlink_delay = 0; +static size_t deferred_unlink_delay = 0; static struct deferred_unlink * -dunlink_alloc () +dunlink_alloc (void) { struct deferred_unlink *p; if (dunlink_avail) @@ -68,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 (rmdir (p->file_name) != 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,13 +113,13 @@ flush_deferred_unlinks (bool force) } /* fall through */ default: - rmdir_error (p->file_name); + rmdir_error (fname); } } } else { - if (unlink (p->file_name) != 0 && errno != ENOENT) + if (unlinkat (chdir_fd, p->file_name, 0) != 0 && errno != ENOENT) unlink_error (p->file_name); } dunlink_reclaim (p); @@ -116,14 +134,15 @@ flush_deferred_unlinks (bool force) { prev = p; p = next; - } + } } if (!dunlink_head) dunlink_tail = NULL; + chdir_do (saved_chdir); } void -finish_deferred_unlinks () +finish_deferred_unlinks (void) { flush_deferred_unlinks (true); while (dunlink_avail) @@ -142,13 +161,15 @@ queue_deferred_unlink (const char *name, bool is_dir) if (dunlink_head && records_written > dunlink_head->records_written + deferred_unlink_delay) flush_deferred_unlinks (false); - + 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; - + if (dunlink_tail) dunlink_tail->next = p; else