1 /* Temporary directories and temporary files with automatic cleanup.
2 Copyright (C) 2001, 2003, 2006-2007, 2009-2021 Free Software Foundation,
4 Written by Bruno Haible <bruno@clisp.org>, 2006.
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <https://www.gnu.org/licenses/>. */
22 #include "clean-temp.h"
33 #if defined _WIN32 && ! defined __CYGWIN__
34 # define WIN32_LEAN_AND_MEAN /* avoid including junk */
38 #include "clean-temp-simple.h"
39 #include "clean-temp-private.h"
41 #include "fatal-signal.h"
42 #include "asyncsafe-spin.h"
47 #include "glthread/lock.h"
48 #include "thread-optim.h"
50 #include "gl_linkedhash_list.h"
51 #include "gl_linked_list.h"
54 # include "tempname.h"
56 #if GNULIB_FWRITEERROR
57 # include "fwriteerror.h"
59 #if GNULIB_CLOSE_STREAM
60 # include "close-stream.h"
62 #if GNULIB_FCNTL_SAFER
65 #if GNULIB_FOPEN_SAFER
69 #define _(str) gettext (str)
71 /* GNU Hurd doesn't have PATH_MAX. Use a fallback.
72 Temporary directory names are usually not that long. */
74 # define PATH_MAX 1024
77 #if defined _WIN32 && ! defined __CYGWIN__
78 /* Don't assume that UNICODE is not defined. */
80 # define OSVERSIONINFO OSVERSIONINFOA
82 # define GetVersionEx GetVersionExA
86 /* Lock that protects the dir_cleanup_list from concurrent modification in
88 gl_lock_define_initialized (static, dir_cleanup_list_lock)
90 /* Lock that protects the descriptors list from concurrent modification in
92 gl_lock_define_initialized (static, descriptors_lock)
95 /* Close a file descriptor and the stream that contains it.
96 Avoids race conditions with signal-handler code that might want to close the
97 same file descriptor. */
99 asyncsafe_fclose_variant (struct closeable_fd *element, FILE *fp,
100 int (*fclose_variant) (FILE *))
102 if (fileno (fp) != element->fd)
105 /* Flush buffered data first, to minimize the duration of the spin lock. */
112 asyncsafe_spin_lock (&element->lock, get_fatal_signal_set (), &saved_mask);
113 if (!element->closed)
115 ret = fclose_variant (fp); /* invokes close (element->fd) */
117 element->closed = true;
124 asyncsafe_spin_unlock (&element->lock, &saved_mask);
125 element->done = true;
132 /* ========= Temporary directories and temporary files inside them ========= */
134 /* Create a temporary directory.
135 PREFIX is used as a prefix for the name of the temporary directory. It
136 should be short and still give an indication about the program.
137 PARENTDIR can be used to specify the parent directory; if NULL, a default
138 parent directory is used (either $TMPDIR or /tmp or similar).
139 CLEANUP_VERBOSE determines whether errors during explicit cleanup are
140 reported to standard error.
141 Return a fresh 'struct temp_dir' on success. Upon error, an error message
142 is shown and NULL is returned. */
144 create_temp_dir (const char *prefix, const char *parentdir,
145 bool cleanup_verbose)
147 bool mt = gl_multithreaded ();
149 if (mt) gl_lock_lock (dir_cleanup_list_lock);
151 struct tempdir * volatile *tmpdirp = NULL;
152 struct tempdir *tmpdir;
157 /* See whether it can take the slot of an earlier temporary directory
158 already cleaned up. */
159 for (i = 0; i < dir_cleanup_list.tempdir_count; i++)
160 if (dir_cleanup_list.tempdir_list[i] == NULL)
162 tmpdirp = &dir_cleanup_list.tempdir_list[i];
167 /* See whether the array needs to be extended. */
168 if (dir_cleanup_list.tempdir_count == dir_cleanup_list.tempdir_allocated)
170 /* Note that we cannot use xrealloc(), because then the cleanup()
171 function could access an already deallocated array. */
172 struct tempdir * volatile *old_array = dir_cleanup_list.tempdir_list;
173 size_t old_allocated = dir_cleanup_list.tempdir_allocated;
174 size_t new_allocated = 2 * dir_cleanup_list.tempdir_allocated + 1;
175 struct tempdir * volatile *new_array =
176 XNMALLOC (new_allocated, struct tempdir * volatile);
178 if (old_allocated == 0)
180 /* First use of this facility. */
181 if (clean_temp_init () < 0)
186 /* Don't use memcpy() here, because memcpy takes non-volatile
187 arguments and is therefore not guaranteed to complete all
188 memory stores before the next statement. */
191 for (k = 0; k < old_allocated; k++)
192 new_array[k] = old_array[k];
195 dir_cleanup_list.tempdir_list = new_array;
196 dir_cleanup_list.tempdir_allocated = new_allocated;
198 /* Now we can free the old array. */
199 /* No, we can't do that. If cleanup_action is running in a different
200 thread and has already fetched the tempdir_list pointer (getting
201 old_array) but not yet accessed its i-th element, that thread may
202 crash when accessing an element of the already freed old_array
205 if (old_array != NULL)
206 free ((struct tempdir **) old_array);
210 tmpdirp = &dir_cleanup_list.tempdir_list[dir_cleanup_list.tempdir_count];
211 /* Initialize *tmpdirp before incrementing tempdir_count, so that
212 cleanup() will skip this entry before it is fully initialized. */
214 dir_cleanup_list.tempdir_count++;
217 /* Initialize a 'struct tempdir'. */
218 tmpdir = XMALLOC (struct tempdir);
219 tmpdir->dirname = NULL;
220 tmpdir->cleanup_verbose = cleanup_verbose;
222 gl_list_create_empty (GL_LINKEDHASH_LIST,
223 clean_temp_string_equals, clean_temp_string_hash,
226 gl_list_create_empty (GL_LINKEDHASH_LIST,
227 clean_temp_string_equals, clean_temp_string_hash,
230 /* Create the temporary directory. */
231 xtemplate = (char *) xmalloca (PATH_MAX);
232 if (path_search (xtemplate, PATH_MAX, parentdir, prefix, parentdir == NULL))
235 _("cannot find a temporary directory, try setting $TMPDIR"));
238 block_fatal_signals ();
239 tmpdirname = mkdtemp (xtemplate);
240 int saved_errno = errno;
241 if (tmpdirname != NULL)
243 tmpdir->dirname = tmpdirname;
246 unblock_fatal_signals ();
247 if (tmpdirname == NULL)
249 error (0, saved_errno,
250 _("cannot create a temporary directory using template \"%s\""),
254 /* Replace tmpdir->dirname with a copy that has indefinite extent.
255 We cannot do this inside the block_fatal_signals/unblock_fatal_signals
256 block because then the cleanup handler would not remove the directory
258 tmpdir->dirname = xstrdup (tmpdirname);
259 if (mt) gl_lock_unlock (dir_cleanup_list_lock);
261 return (struct temp_dir *) tmpdir;
264 if (mt) gl_lock_unlock (dir_cleanup_list_lock);
269 /* Register the given ABSOLUTE_FILE_NAME as being a file inside DIR, that
270 needs to be removed before DIR can be removed.
271 Should be called before the file ABSOLUTE_FILE_NAME is created. */
273 register_temp_file (struct temp_dir *dir,
274 const char *absolute_file_name)
276 struct tempdir *tmpdir = (struct tempdir *)dir;
277 bool mt = gl_multithreaded ();
279 if (mt) gl_lock_lock (dir_cleanup_list_lock);
281 /* Add absolute_file_name to tmpdir->files, without duplicates. */
282 if (gl_list_search (tmpdir->files, absolute_file_name) == NULL)
283 gl_list_add_first (tmpdir->files, xstrdup (absolute_file_name));
285 if (mt) gl_lock_unlock (dir_cleanup_list_lock);
288 /* Unregister the given ABSOLUTE_FILE_NAME as being a file inside DIR, that
289 needs to be removed before DIR can be removed.
290 Should be called when the file ABSOLUTE_FILE_NAME could not be created. */
292 unregister_temp_file (struct temp_dir *dir,
293 const char *absolute_file_name)
295 struct tempdir *tmpdir = (struct tempdir *)dir;
296 bool mt = gl_multithreaded ();
298 if (mt) gl_lock_lock (dir_cleanup_list_lock);
300 gl_list_t list = tmpdir->files;
303 node = gl_list_search (list, absolute_file_name);
306 char *old_string = (char *) gl_list_node_value (list, node);
308 gl_list_remove_node (list, node);
312 if (mt) gl_lock_unlock (dir_cleanup_list_lock);
315 /* Register the given ABSOLUTE_DIR_NAME as being a subdirectory inside DIR,
316 that needs to be removed before DIR can be removed.
317 Should be called before the subdirectory ABSOLUTE_DIR_NAME is created. */
319 register_temp_subdir (struct temp_dir *dir,
320 const char *absolute_dir_name)
322 struct tempdir *tmpdir = (struct tempdir *)dir;
323 bool mt = gl_multithreaded ();
325 if (mt) gl_lock_lock (dir_cleanup_list_lock);
327 /* Add absolute_dir_name to tmpdir->subdirs, without duplicates. */
328 if (gl_list_search (tmpdir->subdirs, absolute_dir_name) == NULL)
329 gl_list_add_first (tmpdir->subdirs, xstrdup (absolute_dir_name));
331 if (mt) gl_lock_unlock (dir_cleanup_list_lock);
334 /* Unregister the given ABSOLUTE_DIR_NAME as being a subdirectory inside DIR,
335 that needs to be removed before DIR can be removed.
336 Should be called when the subdirectory ABSOLUTE_DIR_NAME could not be
339 unregister_temp_subdir (struct temp_dir *dir,
340 const char *absolute_dir_name)
342 struct tempdir *tmpdir = (struct tempdir *)dir;
343 bool mt = gl_multithreaded ();
345 if (mt) gl_lock_lock (dir_cleanup_list_lock);
347 gl_list_t list = tmpdir->subdirs;
350 node = gl_list_search (list, absolute_dir_name);
353 char *old_string = (char *) gl_list_node_value (list, node);
355 gl_list_remove_node (list, node);
359 if (mt) gl_lock_unlock (dir_cleanup_list_lock);
362 /* Remove a directory, with optional error message.
363 Return 0 upon success, or -1 if there was some problem. */
365 do_rmdir (const char *absolute_dir_name, bool cleanup_verbose)
367 if (rmdir (absolute_dir_name) < 0 && cleanup_verbose
371 _("cannot remove temporary directory %s"), absolute_dir_name);
377 /* Remove the given ABSOLUTE_FILE_NAME and unregister it.
378 Return 0 upon success, or -1 if there was some problem. */
380 cleanup_temp_file (struct temp_dir *dir,
381 const char *absolute_file_name)
385 err = clean_temp_unlink (absolute_file_name, dir->cleanup_verbose);
386 unregister_temp_file (dir, absolute_file_name);
391 /* Remove the given ABSOLUTE_DIR_NAME and unregister it.
392 Return 0 upon success, or -1 if there was some problem. */
394 cleanup_temp_subdir (struct temp_dir *dir,
395 const char *absolute_dir_name)
399 err = do_rmdir (absolute_dir_name, dir->cleanup_verbose);
400 unregister_temp_subdir (dir, absolute_dir_name);
405 /* Remove all registered files and subdirectories inside DIR.
406 Only to be called with dir_cleanup_list_lock locked.
407 Return 0 upon success, or -1 if there was some problem. */
409 cleanup_temp_dir_contents (struct temp_dir *dir)
411 struct tempdir *tmpdir = (struct tempdir *)dir;
414 gl_list_iterator_t iter;
418 /* First cleanup the files in the subdirectories. */
419 list = tmpdir->files;
420 iter = gl_list_iterator (list);
421 while (gl_list_iterator_next (&iter, &element, &node))
423 char *file = (char *) element;
425 err |= clean_temp_unlink (file, dir->cleanup_verbose);
426 gl_list_remove_node (list, node);
427 /* Now only we can free file. */
430 gl_list_iterator_free (&iter);
432 /* Then cleanup the subdirectories. */
433 list = tmpdir->subdirs;
434 iter = gl_list_iterator (list);
435 while (gl_list_iterator_next (&iter, &element, &node))
437 char *subdir = (char *) element;
439 err |= do_rmdir (subdir, dir->cleanup_verbose);
440 gl_list_remove_node (list, node);
441 /* Now only we can free subdir. */
444 gl_list_iterator_free (&iter);
449 /* Remove all registered files and subdirectories inside DIR and DIR itself.
450 DIR cannot be used any more after this call.
451 Return 0 upon success, or -1 if there was some problem. */
453 cleanup_temp_dir (struct temp_dir *dir)
455 bool mt = gl_multithreaded ();
457 if (mt) gl_lock_lock (dir_cleanup_list_lock);
459 struct tempdir *tmpdir = (struct tempdir *)dir;
463 err |= cleanup_temp_dir_contents (dir);
464 err |= do_rmdir (tmpdir->dirname, dir->cleanup_verbose);
466 for (i = 0; i < dir_cleanup_list.tempdir_count; i++)
467 if (dir_cleanup_list.tempdir_list[i] == tmpdir)
469 /* Remove dir_cleanup_list.tempdir_list[i]. */
470 if (i + 1 == dir_cleanup_list.tempdir_count)
472 while (i > 0 && dir_cleanup_list.tempdir_list[i - 1] == NULL)
474 dir_cleanup_list.tempdir_count = i;
477 dir_cleanup_list.tempdir_list[i] = NULL;
478 /* Now only we can free the tmpdir->dirname, tmpdir->subdirs,
479 tmpdir->files, and tmpdir itself. */
480 gl_list_free (tmpdir->files);
481 gl_list_free (tmpdir->subdirs);
482 free (tmpdir->dirname);
484 if (mt) gl_lock_unlock (dir_cleanup_list_lock);
488 /* The user passed an invalid DIR argument. */
493 /* ================== Opening and closing temporary files ================== */
495 #if defined _WIN32 && ! defined __CYGWIN__
497 /* On Windows, opening a file with _O_TEMPORARY has the effect of passing
498 the FILE_FLAG_DELETE_ON_CLOSE flag to CreateFile(), which has the effect
499 of deleting the file when it is closed - even when the program crashes.
500 But (according to the Cygwin sources) it works only on Windows NT or newer.
501 So we cache the info whether we are running on Windows NT or newer. */
504 supports_delete_on_close ()
506 static int known; /* 1 = yes, -1 = no, 0 = unknown */
512 <https://docs.microsoft.com/en-us/windows/desktop/api/sysinfoapi/nf-sysinfoapi-getversionexa>
513 this structure must be initialized as follows: */
514 v.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
516 if (GetVersionEx (&v))
517 known = (v.dwPlatformId == VER_PLATFORM_WIN32_NT ? 1 : -1);
527 /* Register a file descriptor to be closed. */
531 bool mt = gl_multithreaded ();
533 if (mt) gl_lock_lock (descriptors_lock);
535 if (descriptors == NULL)
536 descriptors = gl_list_create_empty (GL_LINKED_LIST, NULL, NULL, NULL,
539 struct closeable_fd *element = XMALLOC (struct closeable_fd);
541 element->closed = false;
542 asyncsafe_spin_init (&element->lock);
543 element->done = false;
545 gl_list_add_first (descriptors, element);
547 if (mt) gl_lock_unlock (descriptors_lock);
550 /* Open a temporary file in a temporary directory.
551 FILE_NAME must already have been passed to register_temp_file.
552 Registers the resulting file descriptor to be closed.
553 DELETE_ON_CLOSE indicates whether the file can be deleted when the resulting
554 file descriptor or stream is closed. */
556 open_temp (const char *file_name, int flags, mode_t mode, bool delete_on_close)
561 block_fatal_signals ();
562 /* Note: 'open' here is actually open() or open_safer(). */
563 #if defined _WIN32 && ! defined __CYGWIN__
564 /* Use _O_TEMPORARY when possible, to increase the chances that the
565 temporary file is removed when the process crashes. */
566 if (delete_on_close && supports_delete_on_close ())
567 fd = open (file_name, flags | _O_TEMPORARY, mode);
570 fd = open (file_name, flags, mode);
574 unblock_fatal_signals ();
579 /* Open a temporary file in a temporary directory.
580 FILE_NAME must already have been passed to register_temp_file.
581 Registers the resulting file descriptor to be closed.
582 DELETE_ON_CLOSE indicates whether the file can be deleted when the resulting
583 file descriptor or stream is closed. */
585 fopen_temp (const char *file_name, const char *mode, bool delete_on_close)
590 block_fatal_signals ();
591 /* Note: 'fopen' here is actually fopen() or fopen_safer(). */
592 #if defined _WIN32 && ! defined __CYGWIN__
593 /* Use _O_TEMPORARY when possible, to increase the chances that the
594 temporary file is removed when the process crashes. */
595 if (delete_on_close && supports_delete_on_close ())
597 size_t mode_len = strlen (mode);
598 char *augmented_mode = (char *) xmalloca (mode_len + 2);
599 memcpy (augmented_mode, mode, mode_len);
600 memcpy (augmented_mode + mode_len, "D", 2);
602 fp = fopen (file_name, augmented_mode);
605 freea (augmented_mode);
610 fp = fopen (file_name, mode);
615 /* It is sufficient to register fileno (fp) instead of the entire fp,
616 because at cleanup time there is no need to do an fflush (fp); a
617 close (fileno (fp)) will be enough. */
618 int fd = fileno (fp);
623 unblock_fatal_signals ();
630 struct try_create_file_params
637 try_create_file (char *file_name_tmpl, void *params_)
639 struct try_create_file_params *params = params_;
640 return open (file_name_tmpl,
641 (params->flags & ~O_ACCMODE) | O_RDWR | O_CREAT | O_EXCL,
645 /* Open a temporary file, generating its name based on FILE_NAME_TMPL.
646 FILE_NAME_TMPL must match the rules for mk[s]temp (i.e. end in "XXXXXX",
647 possibly with a suffix). The name constructed does not exist at the time
648 of the call. FILE_NAME_TMPL is overwritten with the result.
649 A safe choice for MODE is S_IRUSR | S_IWUSR, a.k.a. 0600.
650 Registers the file for deletion.
651 Opens the file, with the given FLAGS and mode MODE.
652 Registers the resulting file descriptor to be closed. */
654 gen_register_open_temp (char *file_name_tmpl, int suffixlen,
655 int flags, mode_t mode)
657 block_fatal_signals ();
659 struct try_create_file_params params;
660 params.flags = flags;
663 int fd = try_tempname (file_name_tmpl, suffixlen, ¶ms, try_create_file);
665 int saved_errno = errno;
668 if (clean_temp_init () < 0)
671 if (register_temporary_file (file_name_tmpl) < 0)
674 unblock_fatal_signals ();
681 /* Close a temporary file.
682 FD must have been returned by open_temp or gen_register_open_temp.
683 Unregisters the previously registered file descriptor. */
690 clean_temp_init_asyncsafe_close ();
695 bool mt = gl_multithreaded ();
697 if (mt) gl_lock_lock (descriptors_lock);
699 gl_list_t list = descriptors;
701 /* descriptors should already contain fd. */
704 /* Search through the list, and clean it up on the fly. */
706 gl_list_iterator_t iter = gl_list_iterator (list);
709 if (gl_list_iterator_next (&iter, &elt, &node))
712 struct closeable_fd *element = (struct closeable_fd *) elt;
714 /* Close the file descriptor, avoiding races with the signal
716 if (element->fd == fd)
719 result = clean_temp_asyncsafe_close (element);
723 bool free_this_node = element->done;
724 struct closeable_fd *element_to_free = element;
725 gl_list_node_t node_to_free = node;
727 bool have_next = gl_list_iterator_next (&iter, &elt, &node);
731 free (element_to_free);
732 gl_list_remove_node (list, node_to_free);
738 gl_list_iterator_free (&iter);
740 /* descriptors should already contain fd. */
743 if (mt) gl_lock_unlock (descriptors_lock);
750 fclose_variant_temp (FILE *fp, int (*fclose_variant) (FILE *))
752 int fd = fileno (fp);
757 bool mt = gl_multithreaded ();
759 if (mt) gl_lock_lock (descriptors_lock);
761 gl_list_t list = descriptors;
763 /* descriptors should already contain fd. */
766 /* Search through the list, and clean it up on the fly. */
768 gl_list_iterator_t iter = gl_list_iterator (list);
771 if (gl_list_iterator_next (&iter, &elt, &node))
774 struct closeable_fd *element = (struct closeable_fd *) elt;
776 /* Close the file descriptor and the stream, avoiding races with the
778 if (element->fd == fd)
781 result = asyncsafe_fclose_variant (element, fp, fclose_variant);
785 bool free_this_node = element->done;
786 struct closeable_fd *element_to_free = element;
787 gl_list_node_t node_to_free = node;
789 bool have_next = gl_list_iterator_next (&iter, &elt, &node);
793 free (element_to_free);
794 gl_list_remove_node (list, node_to_free);
800 gl_list_iterator_free (&iter);
802 /* descriptors should have contained fd. */
805 if (mt) gl_lock_unlock (descriptors_lock);
811 /* Close a temporary file.
812 FP must have been returned by fopen_temp, or by fdopen on a file descriptor
813 returned by open_temp or gen_register_open_temp.
814 Unregisters the previously registered file descriptor. */
816 fclose_temp (FILE *fp)
818 return fclose_variant_temp (fp, fclose);
821 #if GNULIB_FWRITEERROR
823 FP must have been returned by fopen_temp, or by fdopen on a file descriptor
824 returned by open_temp or gen_register_open_temp.
825 Unregisters the previously registered file descriptor. */
827 fwriteerror_temp (FILE *fp)
829 return fclose_variant_temp (fp, fwriteerror);
833 #if GNULIB_CLOSE_STREAM
834 /* Like close_stream.
835 FP must have been returned by fopen_temp, or by fdopen on a file descriptor
836 returned by open_temp or gen_register_open_temp.
837 Unregisters the previously registered file descriptor. */
839 close_stream_temp (FILE *fp)
841 return fclose_variant_temp (fp, close_stream);