| 1 | /* Temporary directories and temporary files with automatic cleanup.
|
|---|
| 2 | Copyright (C) 2001, 2003, 2006 Free Software Foundation, Inc.
|
|---|
| 3 | Written by Bruno Haible <[email protected]>, 2006.
|
|---|
| 4 |
|
|---|
| 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)
|
|---|
| 8 | any later version.
|
|---|
| 9 |
|
|---|
| 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.
|
|---|
| 14 |
|
|---|
| 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. */
|
|---|
| 18 |
|
|---|
| 19 |
|
|---|
| 20 | #include <config.h>
|
|---|
| 21 |
|
|---|
| 22 | /* Specification. */
|
|---|
| 23 | #include "clean-temp.h"
|
|---|
| 24 |
|
|---|
| 25 | #include <errno.h>
|
|---|
| 26 | #include <fcntl.h>
|
|---|
| 27 | #include <limits.h>
|
|---|
| 28 | #include <stdbool.h>
|
|---|
| 29 | #include <stdlib.h>
|
|---|
| 30 | #include <string.h>
|
|---|
| 31 | #include <unistd.h>
|
|---|
| 32 |
|
|---|
| 33 | #include "error.h"
|
|---|
| 34 | #include "fatal-signal.h"
|
|---|
| 35 | #include "pathmax.h"
|
|---|
| 36 | #include "tmpdir.h"
|
|---|
| 37 | #include "mkdtemp.h"
|
|---|
| 38 | #include "xalloc.h"
|
|---|
| 39 | #include "xallocsa.h"
|
|---|
| 40 | #include "gl_linkedhash_list.h"
|
|---|
| 41 | #include "gettext.h"
|
|---|
| 42 | #if GNULIB_FWRITEERROR
|
|---|
| 43 | # include "fwriteerror.h"
|
|---|
| 44 | #endif
|
|---|
| 45 | #if GNULIB_CLOSE_STREAM
|
|---|
| 46 | # include "close-stream.h"
|
|---|
| 47 | #endif
|
|---|
| 48 | #if GNULIB_FCNTL_SAFER
|
|---|
| 49 | # include "fcntl--.h"
|
|---|
| 50 | #endif
|
|---|
| 51 | #if GNULIB_FOPEN_SAFER
|
|---|
| 52 | # include "stdio--.h"
|
|---|
| 53 | #endif
|
|---|
| 54 |
|
|---|
| 55 | #define _(str) gettext (str)
|
|---|
| 56 |
|
|---|
| 57 | /* GNU Hurd doesn't have PATH_MAX. */
|
|---|
| 58 | #ifndef PATH_MAX
|
|---|
| 59 | # ifdef MAXPATHLEN
|
|---|
| 60 | # define PATH_MAX MAXPATHLEN
|
|---|
| 61 | # else
|
|---|
| 62 | # define PATH_MAX 1024
|
|---|
| 63 | # endif
|
|---|
| 64 | #endif
|
|---|
| 65 |
|
|---|
| 66 | #ifndef uintptr_t
|
|---|
| 67 | # define uintptr_t unsigned long
|
|---|
| 68 | #endif
|
|---|
| 69 |
|
|---|
| 70 |
|
|---|
| 71 | /* The use of 'volatile' in the types below (and ISO C 99 section 5.1.2.3.(5))
|
|---|
| 72 | ensure that while constructing or modifying the data structures, the field
|
|---|
| 73 | values are written to memory in the order of the C statements. So the
|
|---|
| 74 | signal handler can rely on these field values to be up to date. */
|
|---|
| 75 |
|
|---|
| 76 |
|
|---|
| 77 | /* Registry for a single temporary directory.
|
|---|
| 78 | 'struct temp_dir' from the public header file overlaps with this. */
|
|---|
| 79 | struct tempdir
|
|---|
| 80 | {
|
|---|
| 81 | /* The absolute pathname of the directory. */
|
|---|
| 82 | char * volatile dirname;
|
|---|
| 83 | /* Whether errors during explicit cleanup are reported to standard error. */
|
|---|
| 84 | bool cleanup_verbose;
|
|---|
| 85 | /* Absolute pathnames of subdirectories. */
|
|---|
| 86 | gl_list_t /* <char *> */ volatile subdirs;
|
|---|
| 87 | /* Absolute pathnames of files. */
|
|---|
| 88 | gl_list_t /* <char *> */ volatile files;
|
|---|
| 89 | };
|
|---|
| 90 |
|
|---|
| 91 | /* List of all temporary directories. */
|
|---|
| 92 | static struct
|
|---|
| 93 | {
|
|---|
| 94 | struct tempdir * volatile * volatile tempdir_list;
|
|---|
| 95 | size_t volatile tempdir_count;
|
|---|
| 96 | size_t tempdir_allocated;
|
|---|
| 97 | } cleanup_list /* = { NULL, 0, 0 } */;
|
|---|
| 98 |
|
|---|
| 99 | /* List of all open file descriptors to temporary files. */
|
|---|
| 100 | static gl_list_t /* <int> */ volatile descriptors;
|
|---|
| 101 |
|
|---|
| 102 |
|
|---|
| 103 | /* For the subdirs and for the files, we use a gl_list_t of type LINKEDHASH.
|
|---|
| 104 | Why? We need a data structure that
|
|---|
| 105 |
|
|---|
| 106 | 1) Can contain an arbitrary number of 'char *' values. The strings
|
|---|
| 107 | are compared via strcmp, not pointer comparison.
|
|---|
| 108 | 2) Has insertion and deletion operations that are fast: ideally O(1),
|
|---|
| 109 | or possibly O(log n). This is important for GNU sort, which may
|
|---|
| 110 | create a large number of temporary files.
|
|---|
| 111 | 3) Allows iteration through all elements from within a signal handler.
|
|---|
| 112 | 4) May or may not allow duplicates. It doesn't matter here, since
|
|---|
| 113 | any file or subdir can only be removed once.
|
|---|
| 114 |
|
|---|
| 115 | Criterion 1) would allow any gl_list_t or gl_oset_t implementation.
|
|---|
| 116 |
|
|---|
| 117 | Criterion 2) leaves only GL_LINKEDHASH_LIST, GL_TREEHASH_LIST, or
|
|---|
| 118 | GL_TREE_OSET.
|
|---|
| 119 |
|
|---|
| 120 | Criterion 3) puts at disadvantage GL_TREEHASH_LIST and GL_TREE_OSET.
|
|---|
| 121 | Namely, iteration through the elements of a binary tree requires access
|
|---|
| 122 | to many ->left, ->right, ->parent pointers. However, the rebalancing
|
|---|
| 123 | code for insertion and deletion in an AVL or red-black tree is so
|
|---|
| 124 | complicated that we cannot assume that >left, ->right, ->parent pointers
|
|---|
| 125 | are in a consistent state throughout these operations. Therefore, to
|
|---|
| 126 | avoid a crash in the signal handler, all destructive operations to the
|
|---|
| 127 | lists would have to be protected by a
|
|---|
| 128 | block_fatal_signals ();
|
|---|
| 129 | ...
|
|---|
| 130 | unblock_fatal_signals ();
|
|---|
| 131 | pair. Which causes extra system calls.
|
|---|
| 132 |
|
|---|
| 133 | Criterion 3) would also discourage GL_ARRAY_LIST and GL_CARRAY_LIST,
|
|---|
| 134 | if they were not already excluded. Namely, these implementations use
|
|---|
| 135 | xrealloc(), leaving a time window in which in the list->elements pointer
|
|---|
| 136 | points to already deallocated memory. To avoid a crash in the signal
|
|---|
| 137 | handler at such a moment, all destructive operations would have to
|
|---|
| 138 | protected by block/unblock_fatal_signals (), in this case too.
|
|---|
| 139 |
|
|---|
| 140 | A list of type GL_LINKEDHASH_LIST without duplicates fulfills all
|
|---|
| 141 | requirements:
|
|---|
| 142 | 2) Insertion and deletion are O(1) on average.
|
|---|
| 143 | 3) The gl_list_iterator, gl_list_iterator_next implementations do
|
|---|
| 144 | not trigger memory allocations, nor other system calls, and are
|
|---|
| 145 | therefore safe to be called from a signal handler.
|
|---|
| 146 | Furthermore, since SIGNAL_SAFE_LIST is defined, the implementation
|
|---|
| 147 | of the destructive functions ensures that the list structure is
|
|---|
| 148 | safe to be traversed at any moment, even when interrupted by an
|
|---|
| 149 | asynchronous signal.
|
|---|
| 150 | */
|
|---|
| 151 |
|
|---|
| 152 | /* String equality and hash code functions used by the lists. */
|
|---|
| 153 |
|
|---|
| 154 | static bool
|
|---|
| 155 | string_equals (const void *x1, const void *x2)
|
|---|
| 156 | {
|
|---|
| 157 | const char *s1 = (const char *) x1;
|
|---|
| 158 | const char *s2 = (const char *) x2;
|
|---|
| 159 | return strcmp (s1, s2) == 0;
|
|---|
| 160 | }
|
|---|
| 161 |
|
|---|
| 162 | #define SIZE_BITS (sizeof (size_t) * CHAR_BIT)
|
|---|
| 163 |
|
|---|
| 164 | /* A hash function for NUL-terminated char* strings using
|
|---|
| 165 | the method described by Bruno Haible.
|
|---|
| 166 | See http://www.haible.de/bruno/hashfunc.html. */
|
|---|
| 167 | static size_t
|
|---|
| 168 | string_hash (const void *x)
|
|---|
| 169 | {
|
|---|
| 170 | const char *s = (const char *) x;
|
|---|
| 171 | size_t h = 0;
|
|---|
| 172 |
|
|---|
| 173 | for (; *s; s++)
|
|---|
| 174 | h = *s + ((h << 9) | (h >> (SIZE_BITS - 9)));
|
|---|
| 175 |
|
|---|
| 176 | return h;
|
|---|
| 177 | }
|
|---|
| 178 |
|
|---|
| 179 |
|
|---|
| 180 | /* The signal handler. It gets called asynchronously. */
|
|---|
| 181 | static void
|
|---|
| 182 | cleanup ()
|
|---|
| 183 | {
|
|---|
| 184 | size_t i;
|
|---|
| 185 |
|
|---|
| 186 | /* First close all file descriptors to temporary files. */
|
|---|
| 187 | {
|
|---|
| 188 | gl_list_t fds = descriptors;
|
|---|
| 189 |
|
|---|
| 190 | if (fds != NULL)
|
|---|
| 191 | {
|
|---|
| 192 | gl_list_iterator_t iter;
|
|---|
| 193 | const void *element;
|
|---|
| 194 |
|
|---|
| 195 | iter = gl_list_iterator (fds);
|
|---|
| 196 | while (gl_list_iterator_next (&iter, &element, NULL))
|
|---|
| 197 | {
|
|---|
| 198 | int fd = (int) (uintptr_t) element;
|
|---|
| 199 | close (fd);
|
|---|
| 200 | }
|
|---|
| 201 | gl_list_iterator_free (&iter);
|
|---|
| 202 | }
|
|---|
| 203 | }
|
|---|
| 204 |
|
|---|
| 205 | for (i = 0; i < cleanup_list.tempdir_count; i++)
|
|---|
| 206 | {
|
|---|
| 207 | struct tempdir *dir = cleanup_list.tempdir_list[i];
|
|---|
| 208 |
|
|---|
| 209 | if (dir != NULL)
|
|---|
| 210 | {
|
|---|
| 211 | gl_list_iterator_t iter;
|
|---|
| 212 | const void *element;
|
|---|
| 213 |
|
|---|
| 214 | /* First cleanup the files in the subdirectories. */
|
|---|
| 215 | iter = gl_list_iterator (dir->files);
|
|---|
| 216 | while (gl_list_iterator_next (&iter, &element, NULL))
|
|---|
| 217 | {
|
|---|
| 218 | const char *file = (const char *) element;
|
|---|
| 219 | unlink (file);
|
|---|
| 220 | }
|
|---|
| 221 | gl_list_iterator_free (&iter);
|
|---|
| 222 |
|
|---|
| 223 | /* Then cleanup the subdirectories. */
|
|---|
| 224 | iter = gl_list_iterator (dir->subdirs);
|
|---|
| 225 | while (gl_list_iterator_next (&iter, &element, NULL))
|
|---|
| 226 | {
|
|---|
| 227 | const char *subdir = (const char *) element;
|
|---|
| 228 | rmdir (subdir);
|
|---|
| 229 | }
|
|---|
| 230 | gl_list_iterator_free (&iter);
|
|---|
| 231 |
|
|---|
| 232 | /* Then cleanup the temporary directory itself. */
|
|---|
| 233 | rmdir (dir->dirname);
|
|---|
| 234 | }
|
|---|
| 235 | }
|
|---|
| 236 | }
|
|---|
| 237 |
|
|---|
| 238 | /* Create a temporary directory.
|
|---|
| 239 | PREFIX is used as a prefix for the name of the temporary directory. It
|
|---|
| 240 | should be short and still give an indication about the program.
|
|---|
| 241 | PARENTDIR can be used to specify the parent directory; if NULL, a default
|
|---|
| 242 | parent directory is used (either $TMPDIR or /tmp or similar).
|
|---|
| 243 | CLEANUP_VERBOSE determines whether errors during explicit cleanup are
|
|---|
|
|---|