Add basic suuport for extended attributes.
[tar.git] / src / unlink.c
blob522ae118ca3cb2adb5ca0be9413157a7e4dcd25e
1 /* This file is part of GNU tar.
2 Copyright (C) 2009 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify it
5 under the terms of the GNU General Public License as published by the
6 Free Software Foundation; either version 3, or (at your option) any later
7 version.
9 This program is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
12 Public License for more details.
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
18 #include <system.h>
19 #include "common.h"
20 #include <quotearg.h>
22 struct deferred_unlink
24 struct deferred_unlink *next; /* Next unlink in the queue */
25 char *file_name; /* Absolute name of the file to unlink */
26 bool is_dir; /* True if file_name is a directory */
27 off_t records_written; /* Number of records written when this
28 entry got added to the queue */
31 /* The unlink queue */
32 static struct deferred_unlink *dunlink_head, *dunlink_tail;
34 /* Number of entries in the queue */
35 static size_t dunlink_count;
37 /* List of entries available for allocation */
38 static struct deferred_unlink *dunlink_avail;
40 /* Delay (number of records written) between adding entry to the
41 list and its actual removal. */
42 size_t deferred_unlink_delay = 0;
44 static struct deferred_unlink *
45 dunlink_alloc (void)
47 struct deferred_unlink *p;
48 if (dunlink_avail)
50 p = dunlink_avail;
51 dunlink_avail = p->next;
52 p->next = NULL;
54 else
55 p = xmalloc (sizeof (*p));
56 return p;
59 static void
60 dunlink_reclaim (struct deferred_unlink *p)
62 free (p->file_name);
63 p->next = dunlink_avail;
64 dunlink_avail = p;
67 static void
68 flush_deferred_unlinks (bool force)
70 struct deferred_unlink *p, *prev = NULL;
72 for (p = dunlink_head; p; )
74 struct deferred_unlink *next = p->next;
75 if (force
76 || records_written > p->records_written + deferred_unlink_delay)
78 if (p->is_dir)
80 if (unlinkat (chdir_fd, p->file_name, AT_REMOVEDIR) != 0)
82 switch (errno)
84 case ENOENT:
85 /* nothing to worry about */
86 break;
87 case ENOTEMPTY:
88 if (!force)
90 /* Keep the record in list, in the hope we'll
91 be able to remove it later */
92 prev = p;
93 p = next;
94 continue;
96 /* fall through */
97 default:
98 rmdir_error (p->file_name);
102 else
104 if (unlinkat (chdir_fd, p->file_name, 0) != 0 && errno != ENOENT)
105 unlink_error (p->file_name);
107 dunlink_reclaim (p);
108 dunlink_count--;
109 p = next;
110 if (prev)
111 prev->next = p;
112 else
113 dunlink_head = p;
115 else
117 prev = p;
118 p = next;
121 if (!dunlink_head)
122 dunlink_tail = NULL;
125 void
126 finish_deferred_unlinks (void)
128 flush_deferred_unlinks (true);
129 while (dunlink_avail)
131 struct deferred_unlink *next = dunlink_avail->next;
132 free (dunlink_avail);
133 dunlink_avail = next;
137 void
138 queue_deferred_unlink (const char *name, bool is_dir)
140 struct deferred_unlink *p;
142 if (dunlink_head
143 && records_written > dunlink_head->records_written + deferred_unlink_delay)
144 flush_deferred_unlinks (false);
146 p = dunlink_alloc ();
147 p->next = NULL;
148 p->file_name = normalize_filename (name);
149 p->is_dir = is_dir;
150 p->records_written = records_written;
152 if (dunlink_tail)
153 dunlink_tail->next = p;
154 else
155 dunlink_head = p;
156 dunlink_tail = p;
157 dunlink_count++;