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. */
25 #include "clean-temp.h"
35 #include "fatal-signal.h"
41 #include "gl_linkedhash_list.h"
44 #define _(str) gettext (str)
47 /* The use of 'volatile' in the types below (and ISO C 99 section 5.1.2.3.(5))
48 ensure that while constructing or modifying the data structures, the field
49 values are written to memory in the order of the C statements. So the
50 signal handler can rely on these field values to be up to date. */
53 /* Registry for a single temporary directory.
54 'struct temp_dir' from the public header file overlaps with this. */
57 /* The absolute pathname of the directory. */
58 char * volatile dirname;
59 /* Whether errors during explicit cleanup are reported to standard error. */
61 /* Absolute pathnames of subdirectories. */
62 gl_list_t /* <char *> */ volatile subdirs;
63 /* Absolute pathnames of files. */
64 gl_list_t /* <char *> */ volatile files;
67 /* List of all temporary directories. */
70 struct tempdir * volatile * volatile tempdir_list;
71 size_t volatile tempdir_count;
72 size_t tempdir_allocated;
73 } cleanup_list /* = { NULL, 0, 0 } */;
76 /* For the subdirs and for the files, we use a gl_list_t of type LINKEDHASH.
77 Why? We need a data structure that
79 1) Can contain an arbitrary number of 'char *' values. The strings
80 are compared via strcmp, not pointer comparison.
81 2) Has insertion and deletion operations that are fast: ideally O(1),
82 or possibly O(log n). This is important for GNU sort, which may
83 create a large number of temporary files.
84 3) Allows iteration through all elements from within a signal handler.
85 4) May or may not allow duplicates. It doesn't matter here, since
86 any file or subdir can only be removed once.
88 Criterion 1) would allow any gl_list_t or gl_oset_t implementation.
90 Criterion 2) leaves only GL_LINKEDHASH_LIST, GL_TREEHASH_LIST, or
93 Criterion 3) puts at disadvantage GL_TREEHASH_LIST and GL_TREE_OSET.
94 Namely, iteration through the elements of a binary tree requires access
95 to many ->left, ->right, ->parent pointers. However, the rebalancing
96 code for insertion and deletion in an AVL or red-black tree is so
97 complicated that we cannot assume that >left, ->right, ->parent pointers
98 are in a consistent state throughout these operations. Therefore, to
99 avoid a crash in the signal handler, all destructive operations to the
100 lists would have to be protected by a
101 block_fatal_signals ();
103 unblock_fatal_signals ();
104 pair. Which causes extra system calls.
106 Criterion 3) would also discourage GL_ARRAY_LIST and GL_CARRAY_LIST,
107 if they were not already excluded. Namely, these implementations use
108 xrealloc(), leaving a time window in which in the list->elements pointer
109 points to already deallocated memory. To avoid a crash in the signal
110 handler at such a moment, all destructive operations would have to
111 protected by block/unblock_fatal_signals (), in this case too.
113 A list of type GL_LINKEDHASH_LIST without duplicates fulfills all
115 2) Insertion and deletion are O(1) on average.
116 3) The gl_list_iterator, gl_list_iterator_next implementations do
117 not trigger memory allocations, nor other system calls, and are
118 therefore safe to be called from a signal handler.
119 Furthermore, since SIGNAL_SAFE_LIST is defined, the implementation
120 of the destructive functions ensures that the list structure is
121 safe to be traversed at any moment, even when interrupted by an
125 /* String equality and hash code functions used by the lists. */
128 string_equals (const void *x1, const void *x2)
132 return strcmp (s1, s2) == 0;
135 #define SIZE_BITS (sizeof (size_t) * CHAR_BIT)
137 /* A hash function for NUL-terminated char* strings using
138 the method described by Bruno Haible.
139 See http://www.haible.de/bruno/hashfunc.html. */
141 string_hash (const void *x)
147 h = *s + ((h << 9) | (h >> (SIZE_BITS - 9)));
153 /* The signal handler. It gets called asynchronously. */
159 for (i = 0; i < cleanup_list.tempdir_count; i++)
161 struct tempdir *dir = cleanup_list.tempdir_list[i];
165 gl_list_iterator_t iter;
168 /* First cleanup the files in the subdirectories. */
169 iter = gl_list_iterator (dir->files);
170 while (gl_list_iterator_next (&iter, &element, NULL))
172 const char *file = (const char *) element;
175 gl_list_iterator_free (&iter);
177 /* Then cleanup the subdirectories. */
178 iter = gl_list_iterator (dir->subdirs);
179 while (gl_list_iterator_next (&iter, &element, NULL))
181 const char *subdir = (const char *) element;
184 gl_list_iterator_free (&iter);
186 /* Then cleanup the temporary directory itself. */
187 rmdir (dir->dirname);
192 /* Create a temporary directory.
193 PREFIX is used as a prefix for the name of the temporary directory. It
194 should be short and still give an indication about the program.
195 PARENTDIR can be used to specify the parent directory; if NULL, a default
196 parent directory is used (either $TMPDIR or /tmp or similar).
197 CLEANUP_VERBOSE determines whether errors during explicit cleanup are
198 reported to standard error.
199 Return a fresh 'struct temp_dir' on success. Upon error, an error message
200 is shown and NULL is returned. */
202 create_temp_dir (const char *prefix, const char *parentdir,
203 bool cleanup_verbose)
205 struct tempdir * volatile *tmpdirp = NULL;
206 struct tempdir *tmpdir;
211 /* See whether it can take the slot of an earlier temporary directory
212 already cleaned up. */
213 for (i = 0; i < cleanup_list.tempdir_count; i++)
214 if (cleanup_list.tempdir_list[i] == NULL)
216 tmpdirp = &cleanup_list.tempdir_list[i];
221 /* See whether the array needs to be extended. */
222 if (cleanup_list.tempdir_count == cleanup_list.tempdir_allocated)
224 /* Note that we cannot use xrealloc(), because then the cleanup()
225 function could access an already deallocated array. */
226 struct tempdir * volatile *old_array = cleanup_list.tempdir_list;
227 size_t old_allocated = cleanup_list.tempdir_allocated;
228 size_t new_allocated = 2 * cleanup_list.tempdir_allocated + 1;
229 struct tempdir * volatile *new_array =
230 (struct tempdir * volatile *)
231 xmalloc (new_allocated * sizeof (struct tempdir * volatile));
233 if (old_allocated == 0)
234 /* First use of this facility. Register the cleanup handler. */
235 at_fatal_signal (&cleanup);
238 /* Don't use memcpy() here, because memcpy takes non-volatile
239 arguments and is therefore not guaranteed to complete all
240 memory stores before the next statement. */
243 for (k = 0; k < old_allocated; k++)
244 new_array[k] = old_array[k];
247 cleanup_list.tempdir_list = new_array;
248 cleanup_list.tempdir_allocated = new_allocated;
250 /* Now we can free the old array. */
251 if (old_array != NULL)
252 free ((struct tempdir **) old_array);
255 tmpdirp = &cleanup_list.tempdir_list[cleanup_list.tempdir_count];
256 /* Initialize *tmpdirp before incrementing tempdir_count, so that
257 cleanup() will skip this entry before it is fully initialized. */
259 cleanup_list.tempdir_count++;
262 /* Initialize a 'struct tempdir'. */
263 tmpdir = (struct tempdir *) xmalloc (sizeof (struct tempdir));
264 tmpdir->dirname = NULL;
265 tmpdir->cleanup_verbose = cleanup_verbose;
266 tmpdir->subdirs = gl_list_create_empty (GL_LINKEDHASH_LIST,
267 string_equals, string_hash, false);
268 tmpdir->files = gl_list_create_empty (GL_LINKEDHASH_LIST,
269 string_equals, string_hash, false);
271 /* Create the temporary directory. */
272 template = (char *) xallocsa (PATH_MAX);
273 if (path_search (template, PATH_MAX, parentdir, prefix, parentdir == NULL))
276 _("cannot find a temporary directory, try setting $TMPDIR"));
279 block_fatal_signals ();
280 tmpdirname = mkdtemp (template);
281 if (tmpdirname != NULL)
283 tmpdir->dirname = tmpdirname;
286 unblock_fatal_signals ();
287 if (tmpdirname == NULL)
290 _("cannot create a temporary directory using template \"%s\""),
294 /* Replace tmpdir->dirname with a copy that has indefinite extent.
295 We cannot do this inside the block_fatal_signals/unblock_fatal_signals
296 block because then the cleanup handler would not remove the directory
298 tmpdir->dirname = xstrdup (tmpdirname);
300 return (struct temp_dir *) tmpdir;
307 /* Register the given ABSOLUTE_FILE_NAME as being a file inside DIR, that
308 needs to be removed before DIR can be removed.
309 Should be called before the file ABSOLUTE_FILE_NAME is created. */
311 register_temp_file (struct temp_dir *dir,
312 const char *absolute_file_name)
314 struct tempdir *tmpdir = (struct tempdir *)dir;
316 /* Add absolute_file_name to tmpdir->files, without duplicates. */
317 if (gl_list_search (tmpdir->files, absolute_file_name) == NULL)
318 gl_list_add_first (tmpdir->files, xstrdup (absolute_file_name));
321 /* Unregister the given ABSOLUTE_FILE_NAME as being a file inside DIR, that
322 needs to be removed before DIR can be removed.
323 Should be called when the file ABSOLUTE_FILE_NAME could not be created. */
325 unregister_temp_file (struct temp_dir *dir,
326 const char *absolute_file_name)
328 struct tempdir *tmpdir = (struct tempdir *)dir;
329 gl_list_t list = tmpdir->files;
332 node = gl_list_search (list, absolute_file_name);
335 char *old_string = (char *) gl_list_node_value (list, node);
337 gl_list_remove_node (list, node);
342 /* Register the given ABSOLUTE_DIR_NAME as being a subdirectory inside DIR,
343 that needs to be removed before DIR can be removed.
344 Should be called before the subdirectory ABSOLUTE_DIR_NAME is created. */
346 register_temp_subdir (struct temp_dir *dir,
347 const char *absolute_dir_name)
349 struct tempdir *tmpdir = (struct tempdir *)dir;
351 /* Add absolute_dir_name to tmpdir->subdirs, without duplicates. */
352 if (gl_list_search (tmpdir->subdirs, absolute_dir_name) == NULL)
353 gl_list_add_first (tmpdir->subdirs, xstrdup (absolute_dir_name));
356 /* Unregister the given ABSOLUTE_DIR_NAME as being a subdirectory inside DIR,
357 that needs to be removed before DIR can be removed.
358 Should be called when the subdirectory ABSOLUTE_DIR_NAME could not be
361 unregister_temp_subdir (struct temp_dir *dir,
362 const char *absolute_dir_name)
364 struct tempdir *tmpdir = (struct tempdir *)dir;
365 gl_list_t list = tmpdir->subdirs;
368 node = gl_list_search (list, absolute_dir_name);
371 char *old_string = (char *) gl_list_node_value (list, node);
373 gl_list_remove_node (list, node);
378 /* Remove a file, with optional error message. */
380 do_unlink (struct temp_dir *dir, const char *absolute_file_name)
382 if (unlink (absolute_file_name) < 0 && dir->cleanup_verbose
384 error (0, errno, _("cannot remove temporary file %s"), absolute_file_name);
387 /* Remove a directory, with optional error message. */
389 do_rmdir (struct temp_dir *dir, const char *absolute_dir_name)
391 if (rmdir (absolute_dir_name) < 0 && dir->cleanup_verbose
394 _("cannot remove temporary directory %s"), absolute_dir_name);
397 /* Remove the given ABSOLUTE_FILE_NAME and unregister it. */
399 cleanup_temp_file (struct temp_dir *dir,
400 const char *absolute_file_name)
402 do_unlink (dir, absolute_file_name);
403 unregister_temp_file (dir, absolute_file_name);
406 /* Remove the given ABSOLUTE_DIR_NAME and unregister it. */
408 cleanup_temp_subdir (struct temp_dir *dir,
409 const char *absolute_dir_name)
411 do_rmdir (dir, absolute_dir_name);
412 unregister_temp_subdir (dir, absolute_dir_name);
415 /* Remove all registered files and subdirectories inside DIR. */
417 cleanup_temp_dir_contents (struct temp_dir *dir)
419 struct tempdir *tmpdir = (struct tempdir *)dir;
421 gl_list_iterator_t iter;
425 /* First cleanup the files in the subdirectories. */
426 list = tmpdir->files;
427 iter = gl_list_iterator (list);
428 while (gl_list_iterator_next (&iter, &element, &node))
430 char *file = (char *) element;
432 do_unlink (dir, file);
433 gl_list_remove_node (list, node);
434 /* Now only we can free file. */
437 gl_list_iterator_free (&iter);
439 /* Then cleanup the subdirectories. */
440 list = tmpdir->subdirs;
441 iter = gl_list_iterator (list);
442 while (gl_list_iterator_next (&iter, &element, &node))
444 char *subdir = (char *) element;
446 do_rmdir (dir, subdir);
447 gl_list_remove_node (list, node);
448 /* Now only we can free subdir. */
451 gl_list_iterator_free (&iter);
454 /* Remove all registered files and subdirectories inside DIR and DIR itself.
455 DIR cannot be used any more after this call. */
457 cleanup_temp_dir (struct temp_dir *dir)
459 struct tempdir *tmpdir = (struct tempdir *)dir;
462 cleanup_temp_dir_contents (dir);
463 do_rmdir (dir, tmpdir->dirname);
465 for (i = 0; i < cleanup_list.tempdir_count; i++)
466 if (cleanup_list.tempdir_list[i] == tmpdir)
468 /* Remove cleanup_list.tempdir_list[i]. */
469 if (i + 1 == cleanup_list.tempdir_count)
471 while (i > 0 && cleanup_list.tempdir_list[i - 1] == NULL)
473 cleanup_list.tempdir_count = i;
476 cleanup_list.tempdir_list[i] = NULL;
477 /* Now only we can free the tmpdir->dirname and tmpdir itself. */
478 free (tmpdir->dirname);
483 /* The user passed an invalid DIR argument. */