1 /* Temporary directories and temporary files with automatic cleanup.
2 Copyright (C) 2001, 2003, 2006 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2006.
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software Foundation,
17 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
23 #include "clean-temp.h"
33 #include "fatal-signal.h"
39 #include "gl_linkedhash_list.h"
42 #define _(str) gettext (str)
45 /* The use of 'volatile' in the types below (and ISO C 99 section 5.1.2.3.(5))
46 ensure that while constructing or modifying the data structures, the field
47 values are written to memory in the order of the C statements. So the
48 signal handler can rely on these field values to be up to date. */
51 /* Registry for a single temporary directory.
52 'struct temp_dir' from the public header file overlaps with this. */
55 /* The absolute pathname of the directory. */
56 char * volatile dirname;
57 /* Whether errors during explicit cleanup are reported to standard error. */
59 /* Absolute pathnames of subdirectories. */
60 gl_list_t /* <char *> */ volatile subdirs;
61 /* Absolute pathnames of files. */
62 gl_list_t /* <char *> */ volatile files;
65 /* List of all temporary directories. */
68 struct tempdir * volatile * volatile tempdir_list;
69 size_t volatile tempdir_count;
70 size_t tempdir_allocated;
71 } cleanup_list /* = { NULL, 0, 0 } */;
74 /* For the subdirs and for the files, we use a gl_list_t of type LINKEDHASH.
75 Why? We need a data structure that
77 1) Can contain an arbitrary number of 'char *' values. The strings
78 are compared via strcmp, not pointer comparison.
79 2) Has insertion and deletion operations that are fast: ideally O(1),
80 or possibly O(log n). This is important for GNU sort, which may
81 create a large number of temporary files.
82 3) Allows iteration through all elements from within a signal handler.
83 4) May or may not allow duplicates. It doesn't matter here, since
84 any file or subdir can only be removed once.
86 Criterion 1) would allow any gl_list_t or gl_oset_t implementation.
88 Criterion 2) leaves only GL_LINKEDHASH_LIST, GL_TREEHASH_LIST, or
91 Criterion 3) puts at disadvantage GL_TREEHASH_LIST and GL_TREE_OSET.
92 Namely, iteration through the elements of a binary tree requires access
93 to many ->left, ->right, ->parent pointers. However, the rebalancing
94 code for insertion and deletion in an AVL or red-black tree is so
95 complicated that we cannot assume that >left, ->right, ->parent pointers
96 are in a consistent state throughout these operations. Therefore, to
97 avoid a crash in the signal handler, all destructive operations to the
98 lists would have to be protected by a
99 block_fatal_signals ();
101 unblock_fatal_signals ();
102 pair. Which causes extra system calls.
104 Criterion 3) would also discourage GL_ARRAY_LIST and GL_CARRAY_LIST,
105 if they were not already excluded. Namely, these implementations use
106 xrealloc(), leaving a time window in which in the list->elements pointer
107 points to already deallocated memory. To avoid a crash in the signal
108 handler at such a moment, all destructive operations would have to
109 protected by block/unblock_fatal_signals (), in this case too.
111 A list of type GL_LINKEDHASH_LIST without duplicates fulfills all
113 2) Insertion and deletion are O(1) on average.
114 3) The gl_list_iterator, gl_list_iterator_next implementations do
115 not trigger memory allocations, nor other system calls, and are
116 therefore safe to be called from a signal handler.
117 Furthermore, since SIGNAL_SAFE_LIST is defined, the implementation
118 of the destructive functions ensures that the list structure is
119 safe to be traversed at any moment, even when interrupted by an
123 /* String equality and hash code functions used by the lists. */
126 string_equals (const void *x1, const void *x2)
130 return strcmp (s1, s2) == 0;
133 #define SIZE_BITS (sizeof (size_t) * CHAR_BIT)
135 /* A hash function for NUL-terminated char* strings using
136 the method described by Bruno Haible.
137 See http://www.haible.de/bruno/hashfunc.html. */
139 string_hash (const void *x)
145 h = *s + ((h << 9) | (h >> (SIZE_BITS - 9)));
151 /* The signal handler. It gets called asynchronously. */
157 for (i = 0; i < cleanup_list.tempdir_count; i++)
159 struct tempdir *dir = cleanup_list.tempdir_list[i];
163 gl_list_iterator_t iter;
166 /* First cleanup the files in the subdirectories. */
167 iter = gl_list_iterator (dir->files);
168 while (gl_list_iterator_next (&iter, &element, NULL))
170 const char *file = (const char *) element;
173 gl_list_iterator_free (&iter);
175 /* Then cleanup the subdirectories. */
176 iter = gl_list_iterator (dir->subdirs);
177 while (gl_list_iterator_next (&iter, &element, NULL))
179 const char *subdir = (const char *) element;
182 gl_list_iterator_free (&iter);
184 /* Then cleanup the temporary directory itself. */
185 rmdir (dir->dirname);
190 /* Create a temporary directory.
191 PREFIX is used as a prefix for the name of the temporary directory. It
192 should be short and still give an indication about the program.
193 PARENTDIR can be used to specify the parent directory; if NULL, a default
194 parent directory is used (either $TMPDIR or /tmp or similar).
195 CLEANUP_VERBOSE determines whether errors during explicit cleanup are
196 reported to standard error.
197 Return a fresh 'struct temp_dir' on success. Upon error, an error message
198 is shown and NULL is returned. */
200 create_temp_dir (const char *prefix, const char *parentdir,
201 bool cleanup_verbose)
203 struct tempdir * volatile *tmpdirp = NULL;
204 struct tempdir *tmpdir;
209 /* See whether it can take the slot of an earlier temporary directory
210 already cleaned up. */
211 for (i = 0; i < cleanup_list.tempdir_count; i++)
212 if (cleanup_list.tempdir_list[i] == NULL)
214 tmpdirp = &cleanup_list.tempdir_list[i];
219 /* See whether the array needs to be extended. */
220 if (cleanup_list.tempdir_count == cleanup_list.tempdir_allocated)
222 /* Note that we cannot use xrealloc(), because then the cleanup()
223 function could access an already deallocated array. */
224 struct tempdir * volatile *old_array = cleanup_list.tempdir_list;
225 size_t old_allocated = cleanup_list.tempdir_allocated;
226 size_t new_allocated = 2 * cleanup_list.tempdir_allocated + 1;
227 struct tempdir * volatile *new_array =
228 (struct tempdir * volatile *)
229 xmalloc (new_allocated * sizeof (struct tempdir * volatile));
231 if (old_allocated == 0)
232 /* First use of this facility. Register the cleanup handler. */
233 at_fatal_signal (&cleanup);
236 /* Don't use memcpy() here, because memcpy takes non-volatile
237 arguments and is therefore not guaranteed to complete all
238 memory stores before the next statement. */
241 for (k = 0; k < old_allocated; k++)
242 new_array[k] = old_array[k];
245 cleanup_list.tempdir_list = new_array;
246 cleanup_list.tempdir_allocated = new_allocated;
248 /* Now we can free the old array. */
249 if (old_array != NULL)
250 free ((struct tempdir **) old_array);
253 tmpdirp = &cleanup_list.tempdir_list[cleanup_list.tempdir_count];
254 /* Initialize *tmpdirp before incrementing tempdir_count, so that
255 cleanup() will skip this entry before it is fully initialized. */
257 cleanup_list.tempdir_count++;
260 /* Initialize a 'struct tempdir'. */
261 tmpdir = (struct tempdir *) xmalloc (sizeof (struct tempdir));
262 tmpdir->dirname = NULL;
263 tmpdir->cleanup_verbose = cleanup_verbose;
264 tmpdir->subdirs = gl_list_create_empty (GL_LINKEDHASH_LIST,
265 string_equals, string_hash, false);
266 tmpdir->files = gl_list_create_empty (GL_LINKEDHASH_LIST,
267 string_equals, string_hash, false);
269 /* Create the temporary directory. */
270 template = (char *) xallocsa (PATH_MAX);
271 if (path_search (template, PATH_MAX, parentdir, prefix, parentdir == NULL))
274 _("cannot find a temporary directory, try setting $TMPDIR"));
277 block_fatal_signals ();
278 tmpdirname = mkdtemp (template);
279 if (tmpdirname != NULL)
281 tmpdir->dirname = tmpdirname;
284 unblock_fatal_signals ();
285 if (tmpdirname == NULL)
288 _("cannot create a temporary directory using template \"%s\""),
292 /* Replace tmpdir->dirname with a copy that has indefinite extent.
293 We cannot do this inside the block_fatal_signals/unblock_fatal_signals
294 block because then the cleanup handler would not remove the directory
296 tmpdir->dirname = xstrdup (tmpdirname);
298 return (struct temp_dir *) tmpdir;
305 /* Register the given ABSOLUTE_FILE_NAME as being a file inside DIR, that
306 needs to be removed before DIR can be removed.
307 Should be called before the file ABSOLUTE_FILE_NAME is created. */
309 register_temp_file (struct temp_dir *dir,
310 const char *absolute_file_name)
312 struct tempdir *tmpdir = (struct tempdir *)dir;
314 /* Add absolute_file_name to tmpdir->files, without duplicates. */
315 if (gl_list_search (tmpdir->files, absolute_file_name) == NULL)
316 gl_list_add_first (tmpdir->files, xstrdup (absolute_file_name));
319 /* Unregister the given ABSOLUTE_FILE_NAME as being a file inside DIR, that
320 needs to be removed before DIR can be removed.
321 Should be called when the file ABSOLUTE_FILE_NAME could not be created. */
323 unregister_temp_file (struct temp_dir *dir,
324 const char *absolute_file_name)
326 struct tempdir *tmpdir = (struct tempdir *)dir;
327 gl_list_t list = tmpdir->files;
330 node = gl_list_search (list, absolute_file_name);
333 char *old_string = (char *) gl_list_node_value (list, node);
335 gl_list_remove_node (list, node);
340 /* Register the given ABSOLUTE_DIR_NAME as being a subdirectory inside DIR,
341 that needs to be removed before DIR can be removed.
342 Should be called before the subdirectory ABSOLUTE_DIR_NAME is created. */
344 register_temp_subdir (struct temp_dir *dir,
345 const char *absolute_dir_name)
347 struct tempdir *tmpdir = (struct tempdir *)dir;
349 /* Add absolute_dir_name to tmpdir->subdirs, without duplicates. */
350 if (gl_list_search (tmpdir->subdirs, absolute_dir_name) == NULL)
351 gl_list_add_first (tmpdir->subdirs, xstrdup (absolute_dir_name));
354 /* Unregister the given ABSOLUTE_DIR_NAME as being a subdirectory inside DIR,
355 that needs to be removed before DIR can be removed.
356 Should be called when the subdirectory ABSOLUTE_DIR_NAME could not be
359 unregister_temp_subdir (struct temp_dir *dir,
360 const char *absolute_dir_name)
362 struct tempdir *tmpdir = (struct tempdir *)dir;
363 gl_list_t list = tmpdir->subdirs;
366 node = gl_list_search (list, absolute_dir_name);
369 char *old_string = (char *) gl_list_node_value (list, node);
371 gl_list_remove_node (list, node);
376 /* Remove a file, with optional error message. */
378 do_unlink (struct temp_dir *dir, const char *absolute_file_name)
380 if (unlink (absolute_file_name) < 0 && dir->cleanup_verbose
382 error (0, errno, _("cannot remove temporary file %s"), absolute_file_name);
385 /* Remove a directory, with optional error message. */
387 do_rmdir (struct temp_dir *dir, const char *absolute_dir_name)
389 if (rmdir (absolute_dir_name) < 0 && dir->cleanup_verbose
392 _("cannot remove temporary directory %s"), absolute_dir_name);
395 /* Remove the given ABSOLUTE_FILE_NAME and unregister it. */
397 cleanup_temp_file (struct temp_dir *dir,
398 const char *absolute_file_name)
400 do_unlink (dir, absolute_file_name);
401 unregister_temp_file (dir, absolute_file_name);
404 /* Remove the given ABSOLUTE_DIR_NAME and unregister it. */
406 cleanup_temp_subdir (struct temp_dir *dir,
407 const char *absolute_dir_name)
409 do_rmdir (dir, absolute_dir_name);
410 unregister_temp_subdir (dir, absolute_dir_name);
413 /* Remove all registered files and subdirectories inside DIR. */
415 cleanup_temp_dir_contents (struct temp_dir *dir)
417 struct tempdir *tmpdir = (struct tempdir *)dir;
419 gl_list_iterator_t iter;
423 /* First cleanup the files in the subdirectories. */
424 list = tmpdir->files;
425 iter = gl_list_iterator (list);
426 while (gl_list_iterator_next (&iter, &element, &node))
428 char *file = (char *) element;
430 do_unlink (dir, file);
431 gl_list_remove_node (list, node);
432 /* Now only we can free file. */
435 gl_list_iterator_free (&iter);
437 /* Then cleanup the subdirectories. */
438 list = tmpdir->subdirs;
439 iter = gl_list_iterator (list);
440 while (gl_list_iterator_next (&iter, &element, &node))
442 char *subdir = (char *) element;
444 do_rmdir (dir, subdir);
445 gl_list_remove_node (list, node);
446 /* Now only we can free subdir. */
449 gl_list_iterator_free (&iter);
452 /* Remove all registered files and subdirectories inside DIR and DIR itself.
453 DIR cannot be used any more after this call. */
455 cleanup_temp_dir (struct temp_dir *dir)
457 struct tempdir *tmpdir = (struct tempdir *)dir;
460 cleanup_temp_dir_contents (dir);
461 do_rmdir (dir, tmpdir->dirname);
463 for (i = 0; i < cleanup_list.tempdir_count; i++)
464 if (cleanup_list.tempdir_list[i] == tmpdir)
466 /* Remove cleanup_list.tempdir_list[i]. */
467 if (i + 1 == cleanup_list.tempdir_count)
469 while (i > 0 && cleanup_list.tempdir_list[i - 1] == NULL)
471 cleanup_list.tempdir_count = i;
474 cleanup_list.tempdir_list[i] = NULL;
475 /* Now only we can free the tmpdir->dirname and tmpdir itself. */
476 free (tmpdir->dirname);
481 /* The user passed an invalid DIR argument. */