1 /* Temporary directories and temporary files with automatic cleanup.
2 Copyright (C) 2001, 2003, 2006-2007, 2009-2024 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"
32 #if defined _WIN32 && ! defined __CYGWIN__
33 # define WIN32_LEAN_AND_MEAN /* avoid including junk */
37 #include "clean-temp-simple.h"
38 #include "clean-temp-private.h"
40 #include "fatal-signal.h"
41 #include "asyncsafe-spin.h"
46 #include "glthread/lock.h"
47 #include "thread-optim.h"
49 #include "gl_linkedhash_list.h"
50 #include "gl_linked_list.h"
53 # include "tempname.h"
55 #if GNULIB_FWRITEERROR
56 # include "fwriteerror.h"
58 #if GNULIB_CLOSE_STREAM
59 # include "close-stream.h"
61 #if GNULIB_FCNTL_SAFER
64 #if GNULIB_FOPEN_SAFER
68 #define _(str) gettext (str)
70 /* GNU Hurd doesn't have PATH_MAX. Use a fallback.
71 Temporary directory names are usually not that long. */
73 # define PATH_MAX 1024
76 #if defined _WIN32 && ! defined __CYGWIN__
77 /* Don't assume that UNICODE is not defined. */
79 # define OSVERSIONINFO OSVERSIONINFOA
81 # define GetVersionEx GetVersionExA
85 /* Lock that protects the dir_cleanup_list from concurrent modification in
87 gl_lock_define_initialized (static, dir_cleanup_list_lock
)
89 /* Lock that protects the descriptors list from concurrent modification in
91 gl_lock_define_initialized (static, descriptors_lock
)
94 /* Close a file descriptor and the stream that contains it.
95 Avoids race conditions with signal-handler code that might want to close the
96 same file descriptor. */
98 asyncsafe_fclose_variant (struct closeable_fd
*element
, FILE *fp
,
99 int (*fclose_variant
) (FILE *))
101 if (fileno (fp
) != element
->fd
)
104 /* Flush buffered data first, to minimize the duration of the spin lock. */
111 asyncsafe_spin_lock (&element
->lock
, get_fatal_signal_set (), &saved_mask
);
112 if (!element
->closed
)
114 ret
= fclose_variant (fp
); /* invokes close (element->fd) */
116 element
->closed
= true;
123 asyncsafe_spin_unlock (&element
->lock
, &saved_mask
);
124 element
->done
= true;
131 /* ========= Temporary directories and temporary files inside them ========= */
133 /* Create a temporary directory.
134 PREFIX is used as a prefix for the name of the temporary directory. It
135 should be short and still give an indication about the program.
136 PARENTDIR can be used to specify the parent directory; if NULL, a default
137 parent directory is used (either $TMPDIR or /tmp or similar).
138 CLEANUP_VERBOSE determines whether errors during explicit cleanup are
139 reported to standard error.
140 Return a fresh 'struct temp_dir' on success. Upon error, an error message
141 is shown and NULL is returned. */
143 create_temp_dir (const char *prefix
, const char *parentdir
,
144 bool cleanup_verbose
)
146 bool mt
= gl_multithreaded ();
148 if (mt
) gl_lock_lock (dir_cleanup_list_lock
);
150 struct tempdir
* volatile *tmpdirp
= NULL
;
151 struct tempdir
*tmpdir
;
156 /* See whether it can take the slot of an earlier temporary directory
157 already cleaned up. */
158 for (i
= 0; i
< dir_cleanup_list
.tempdir_count
; i
++)
159 if (dir_cleanup_list
.tempdir_list
[i
] == NULL
)
161 tmpdirp
= &dir_cleanup_list
.tempdir_list
[i
];
166 /* See whether the array needs to be extended. */
167 if (dir_cleanup_list
.tempdir_count
== dir_cleanup_list
.tempdir_allocated
)
169 /* Note that we cannot use xrealloc(), because then the cleanup()
170 function could access an already deallocated array. */
171 struct tempdir
* volatile *old_array
= dir_cleanup_list
.tempdir_list
;
172 size_t old_allocated
= dir_cleanup_list
.tempdir_allocated
;
173 size_t new_allocated
= 2 * dir_cleanup_list
.tempdir_allocated
+ 1;
174 struct tempdir
* volatile *new_array
=
175 XNMALLOC (new_allocated
, struct tempdir
* volatile);
177 if (old_allocated
== 0)
179 /* First use of this facility. */
180 if (clean_temp_init () < 0)
185 /* Don't use memcpy() here, because memcpy takes non-volatile
186 arguments and is therefore not guaranteed to complete all
187 memory stores before the next statement. */
190 for (k
= 0; k
< old_allocated
; k
++)
191 new_array
[k
] = old_array
[k
];
194 dir_cleanup_list
.tempdir_list
= new_array
;
195 dir_cleanup_list
.tempdir_allocated
= new_allocated
;
197 /* Now we can free the old array. */
198 /* No, we can't do that. If cleanup_action is running in a different
199 thread and has already fetched the tempdir_list pointer (getting
200 old_array) but not yet accessed its i-th element, that thread may
201 crash when accessing an element of the already freed old_array
204 if (old_array
!= NULL
)
205 free ((struct tempdir
**) old_array
);
209 tmpdirp
= &dir_cleanup_list
.tempdir_list
[dir_cleanup_list
.tempdir_count
];
210 /* Initialize *tmpdirp before incrementing tempdir_count, so that
211 cleanup() will skip this entry before it is fully initialized. */
213 dir_cleanup_list
.tempdir_count
++;
216 /* Initialize a 'struct tempdir'. */
217 tmpdir
= XMALLOC (struct tempdir
);
218 tmpdir
->dirname
= NULL
;
219 tmpdir
->cleanup_verbose
= cleanup_verbose
;
221 gl_list_create_empty (GL_LINKEDHASH_LIST
,
222 clean_temp_string_equals
, clean_temp_string_hash
,
225 gl_list_create_empty (GL_LINKEDHASH_LIST
,
226 clean_temp_string_equals
, clean_temp_string_hash
,
229 /* Create the temporary directory. */
230 xtemplate
= (char *) xmalloca (PATH_MAX
);
231 if (path_search (xtemplate
, PATH_MAX
, parentdir
, prefix
, parentdir
== NULL
))
234 _("cannot find a temporary directory, try setting $TMPDIR"));
237 block_fatal_signals ();
238 tmpdirname
= mkdtemp (xtemplate
);
239 int saved_errno
= errno
;
240 if (tmpdirname
!= NULL
)
242 tmpdir
->dirname
= tmpdirname
;
245 unblock_fatal_signals ();
246 if (tmpdirname
== NULL
)
248 error (0, saved_errno
,
249 _("cannot create a temporary directory using template \"%s\""),
253 /* Replace tmpdir->dirname with a copy that has indefinite extent.
254 We cannot do this inside the block_fatal_signals/unblock_fatal_signals
255 block because then the cleanup handler would not remove the directory
257 tmpdir
->dirname
= xstrdup (tmpdirname
);
258 if (mt
) gl_lock_unlock (dir_cleanup_list_lock
);
260 return (struct temp_dir
*) tmpdir
;
263 if (mt
) gl_lock_unlock (dir_cleanup_list_lock
);
268 /* Register the given ABSOLUTE_FILE_NAME as being a file inside DIR, that
269 needs to be removed before DIR can be removed.
270 Should be called before the file ABSOLUTE_FILE_NAME is created. */
272 register_temp_file (struct temp_dir
*dir
,
273 const char *absolute_file_name
)
275 struct tempdir
*tmpdir
= (struct tempdir
*)dir
;
276 bool mt
= gl_multithreaded ();
278 if (mt
) gl_lock_lock (dir_cleanup_list_lock
);
280 /* Add absolute_file_name to tmpdir->files, without duplicates. */
281 if (gl_list_search (tmpdir
->files
, absolute_file_name
) == NULL
)
282 gl_list_add_first (tmpdir
->files
, xstrdup (absolute_file_name
));
284 if (mt
) gl_lock_unlock (dir_cleanup_list_lock
);
287 /* Unregister the given ABSOLUTE_FILE_NAME as being a file inside DIR, that
288 needs to be removed before DIR can be removed.
289 Should be called when the file ABSOLUTE_FILE_NAME could not be created. */
291 unregister_temp_file (struct temp_dir
*dir
,
292 const char *absolute_file_name
)
294 struct tempdir
*tmpdir
= (struct tempdir
*)dir
;
295 bool mt
= gl_multithreaded ();
297 if (mt
) gl_lock_lock (dir_cleanup_list_lock
);
299 gl_list_t list
= tmpdir
->files
;
302 node
= gl_list_search (list
, absolute_file_name
);
305 char *old_string
= (char *) gl_list_node_value (list
, node
);
307 gl_list_remove_node (list
, node
);
311 if (mt
) gl_lock_unlock (dir_cleanup_list_lock
);
314 /* Register the given ABSOLUTE_DIR_NAME as being a subdirectory inside DIR,
315 that needs to be removed before DIR can be removed.
316 Should be called before the subdirectory ABSOLUTE_DIR_NAME is created. */
318 register_temp_subdir (struct temp_dir
*dir
,
319 const char *absolute_dir_name
)
321 struct tempdir
*tmpdir
= (struct tempdir
*)dir
;
322 bool mt
= gl_multithreaded ();
324 if (mt
) gl_lock_lock (dir_cleanup_list_lock
);
326 /* Add absolute_dir_name to tmpdir->subdirs, without duplicates. */
327 if (gl_list_search (tmpdir
->subdirs
, absolute_dir_name
) == NULL
)
328 gl_list_add_first (tmpdir
->subdirs
, xstrdup (absolute_dir_name
));
330 if (mt
) gl_lock_unlock (dir_cleanup_list_lock
);
333 /* Unregister the given ABSOLUTE_DIR_NAME as being a subdirectory inside DIR,
334 that needs to be removed before DIR can be removed.
335 Should be called when the subdirectory ABSOLUTE_DIR_NAME could not be
338 unregister_temp_subdir (struct temp_dir
*dir
,
339 const char *absolute_dir_name
)
341 struct tempdir
*tmpdir
= (struct tempdir
*)dir
;
342 bool mt
= gl_multithreaded ();
344 if (mt
) gl_lock_lock (dir_cleanup_list_lock
);
346 gl_list_t list
= tmpdir
->subdirs
;
349 node
= gl_list_search (list
, absolute_dir_name
);
352 char *old_string
= (char *) gl_list_node_value (list
, node
);
354 gl_list_remove_node (list
, node
);
358 if (mt
) gl_lock_unlock (dir_cleanup_list_lock
);
361 /* Remove a directory, with optional error message.
362 Return 0 upon success, or -1 if there was some problem. */
364 do_rmdir (const char *absolute_dir_name
, bool cleanup_verbose
)
366 if (rmdir (absolute_dir_name
) < 0 && cleanup_verbose
370 _("cannot remove temporary directory %s"), absolute_dir_name
);
376 /* Remove the given ABSOLUTE_FILE_NAME and unregister it.
377 Return 0 upon success, or -1 if there was some problem. */
379 cleanup_temp_file (struct temp_dir
*dir
,
380 const char *absolute_file_name
)
384 err
= clean_temp_unlink (absolute_file_name
, dir
->cleanup_verbose
);
385 unregister_temp_file (dir
, absolute_file_name
);
390 /* Remove the given ABSOLUTE_DIR_NAME and unregister it.
391 Return 0 upon success, or -1 if there was some problem. */
393 cleanup_temp_subdir (struct temp_dir
*dir
,
394 const char *absolute_dir_name
)
398 err
= do_rmdir (absolute_dir_name
, dir
->cleanup_verbose
);
399 unregister_temp_subdir (dir
, absolute_dir_name
);
404 /* Remove all registered files and subdirectories inside DIR.
405 Only to be called with dir_cleanup_list_lock locked.
406 Return 0 upon success, or -1 if there was some problem. */
408 cleanup_temp_dir_contents (struct temp_dir
*dir
)
410 struct tempdir
*tmpdir
= (struct tempdir
*)dir
;
413 gl_list_iterator_t iter
;
417 /* First cleanup the files in the subdirectories. */
418 list
= tmpdir
->files
;
419 iter
= gl_list_iterator (list
);
420 while (gl_list_iterator_next (&iter
, &element
, &node
))
422 char *file
= (char *) element
;
424 err
|= clean_temp_unlink (file
, dir
->cleanup_verbose
);
425 gl_list_remove_node (list
, node
);
426 /* Now only we can free file. */
429 gl_list_iterator_free (&iter
);
431 /* Then cleanup the subdirectories. */
432 list
= tmpdir
->subdirs
;
433 iter
= gl_list_iterator (list
);
434 while (gl_list_iterator_next (&iter
, &element
, &node
))
436 char *subdir
= (char *) element
;
438 err
|= do_rmdir (subdir
, dir
->cleanup_verbose
);
439 gl_list_remove_node (list
, node
);
440 /* Now only we can free subdir. */
443 gl_list_iterator_free (&iter
);
448 /* Remove all registered files and subdirectories inside DIR and DIR itself.
449 DIR cannot be used any more after this call.
450 Return 0 upon success, or -1 if there was some problem. */
452 cleanup_temp_dir (struct temp_dir
*dir
)
454 bool mt
= gl_multithreaded ();
456 if (mt
) gl_lock_lock (dir_cleanup_list_lock
);
458 struct tempdir
*tmpdir
= (struct tempdir
*)dir
;
462 err
|= cleanup_temp_dir_contents (dir
);
463 err
|= do_rmdir (tmpdir
->dirname
, dir
->cleanup_verbose
);
465 for (i
= 0; i
< dir_cleanup_list
.tempdir_count
; i
++)
466 if (dir_cleanup_list
.tempdir_list
[i
] == tmpdir
)
468 /* Remove dir_cleanup_list.tempdir_list[i]. */
469 if (i
+ 1 == dir_cleanup_list
.tempdir_count
)
471 while (i
> 0 && dir_cleanup_list
.tempdir_list
[i
- 1] == NULL
)
473 dir_cleanup_list
.tempdir_count
= i
;
476 dir_cleanup_list
.tempdir_list
[i
] = NULL
;
477 /* Now only we can free the tmpdir->dirname, tmpdir->subdirs,
478 tmpdir->files, and tmpdir itself. */
479 gl_list_free (tmpdir
->files
);
480 gl_list_free (tmpdir
->subdirs
);
481 free (tmpdir
->dirname
);
483 if (mt
) gl_lock_unlock (dir_cleanup_list_lock
);
487 /* The user passed an invalid DIR argument. */
492 /* ================== Opening and closing temporary files ================== */
494 #if defined _WIN32 && ! defined __CYGWIN__
496 /* On Windows, opening a file with _O_TEMPORARY has the effect of passing
497 the FILE_FLAG_DELETE_ON_CLOSE flag to CreateFile(), which has the effect
498 of deleting the file when it is closed - even when the program crashes.
499 But (according to the Cygwin sources) it works only on Windows NT or newer.
500 So we cache the info whether we are running on Windows NT or newer. */
503 supports_delete_on_close ()
505 static int known
; /* 1 = yes, -1 = no, 0 = unknown */
511 <https://docs.microsoft.com/en-us/windows/desktop/api/sysinfoapi/nf-sysinfoapi-getversionexa>
512 this structure must be initialized as follows: */
513 v
.dwOSVersionInfoSize
= sizeof (OSVERSIONINFO
);
515 if (GetVersionEx (&v
))
516 known
= (v
.dwPlatformId
== VER_PLATFORM_WIN32_NT
? 1 : -1);
526 /* Register a file descriptor to be closed. */
530 bool mt
= gl_multithreaded ();
532 if (mt
) gl_lock_lock (descriptors_lock
);
534 if (descriptors
== NULL
)
535 descriptors
= gl_list_create_empty (GL_LINKED_LIST
, NULL
, NULL
, NULL
,
538 struct closeable_fd
*element
= XMALLOC (struct closeable_fd
);
540 element
->closed
= false;
541 asyncsafe_spin_init (&element
->lock
);
542 element
->done
= false;
544 gl_list_add_first (descriptors
, element
);
546 if (mt
) gl_lock_unlock (descriptors_lock
);
549 /* Open a temporary file in a temporary directory.
550 FILE_NAME must already have been passed to register_temp_file.
551 Registers the resulting file descriptor to be closed.
552 DELETE_ON_CLOSE indicates whether the file can be deleted when the resulting
553 file descriptor or stream is closed. */
555 open_temp (const char *file_name
, int flags
, mode_t mode
, bool delete_on_close
)
560 block_fatal_signals ();
561 /* Note: 'open' here is actually open() or open_safer(). */
562 #if defined _WIN32 && ! defined __CYGWIN__
563 /* Use _O_TEMPORARY when possible, to increase the chances that the
564 temporary file is removed when the process crashes. */
565 if (delete_on_close
&& supports_delete_on_close ())
566 fd
= open (file_name
, flags
| _O_TEMPORARY
, mode
);
569 fd
= open (file_name
, flags
, mode
);
573 unblock_fatal_signals ();
578 /* Open a temporary file in a temporary directory.
579 FILE_NAME must already have been passed to register_temp_file.
580 Registers the resulting file descriptor to be closed.
581 DELETE_ON_CLOSE indicates whether the file can be deleted when the resulting
582 file descriptor or stream is closed. */
584 fopen_temp (const char *file_name
, const char *mode
, bool delete_on_close
)
589 block_fatal_signals ();
590 /* Note: 'fopen' here is actually fopen() or fopen_safer(). */
591 #if defined _WIN32 && ! defined __CYGWIN__
592 /* Use _O_TEMPORARY when possible, to increase the chances that the
593 temporary file is removed when the process crashes. */
594 if (delete_on_close
&& supports_delete_on_close ())
596 size_t mode_len
= strlen (mode
);
597 char *augmented_mode
= (char *) xmalloca (mode_len
+ 2);
598 memcpy (augmented_mode
, mode
, mode_len
);
599 memcpy (augmented_mode
+ mode_len
, "D", 2);
601 fp
= fopen (file_name
, augmented_mode
);
604 freea (augmented_mode
);
609 fp
= fopen (file_name
, mode
);
614 /* It is sufficient to register fileno (fp) instead of the entire fp,
615 because at cleanup time there is no need to do an fflush (fp); a
616 close (fileno (fp)) will be enough. */
617 int fd
= fileno (fp
);
622 unblock_fatal_signals ();
629 struct try_create_file_params
636 try_create_file (char *file_name_tmpl
, void *params_
)
638 struct try_create_file_params
*params
= params_
;
639 return open (file_name_tmpl
,
640 (params
->flags
& ~O_ACCMODE
) | O_RDWR
| O_CREAT
| O_EXCL
,
644 /* Open a temporary file, generating its name based on FILE_NAME_TMPL.
645 FILE_NAME_TMPL must match the rules for mk[s]temp (i.e. end in "XXXXXX",
646 possibly with a suffix). The name constructed does not exist at the time
647 of the call. FILE_NAME_TMPL is overwritten with the result.
648 A safe choice for MODE is S_IRUSR | S_IWUSR, a.k.a. 0600.
649 Registers the file for deletion.
650 Opens the file, with the given FLAGS and mode MODE.
651 Registers the resulting file descriptor to be closed. */
653 gen_register_open_temp (char *file_name_tmpl
, int suffixlen
,
654 int flags
, mode_t mode
)
656 block_fatal_signals ();
658 struct try_create_file_params params
;
659 params
.flags
= flags
;
662 int fd
= try_tempname (file_name_tmpl
, suffixlen
, ¶ms
, try_create_file
);
664 int saved_errno
= errno
;
667 if (clean_temp_init () < 0)
670 if (register_temporary_file (file_name_tmpl
) < 0)
673 unblock_fatal_signals ();
680 /* Close a temporary file.
681 FD must have been returned by open_temp or gen_register_open_temp.
682 Unregisters the previously registered file descriptor. */
689 clean_temp_init_asyncsafe_close ();
694 bool mt
= gl_multithreaded ();
696 if (mt
) gl_lock_lock (descriptors_lock
);
698 gl_list_t list
= descriptors
;
700 /* descriptors should already contain fd. */
703 /* Search through the list, and clean it up on the fly. */
705 gl_list_iterator_t iter
= gl_list_iterator (list
);
708 if (gl_list_iterator_next (&iter
, &elt
, &node
))
711 struct closeable_fd
*element
= (struct closeable_fd
*) elt
;
713 /* Close the file descriptor, avoiding races with the signal
715 if (element
->fd
== fd
)
718 result
= clean_temp_asyncsafe_close (element
);
722 bool free_this_node
= element
->done
;
723 struct closeable_fd
*element_to_free
= element
;
724 gl_list_node_t node_to_free
= node
;
726 bool have_next
= gl_list_iterator_next (&iter
, &elt
, &node
);
730 free (element_to_free
);
731 gl_list_remove_node (list
, node_to_free
);
737 gl_list_iterator_free (&iter
);
739 /* descriptors should already contain fd. */
742 if (mt
) gl_lock_unlock (descriptors_lock
);
749 fclose_variant_temp (FILE *fp
, int (*fclose_variant
) (FILE *))
751 int fd
= fileno (fp
);
756 bool mt
= gl_multithreaded ();
758 if (mt
) gl_lock_lock (descriptors_lock
);
760 gl_list_t list
= descriptors
;
762 /* descriptors should already contain fd. */
765 /* Search through the list, and clean it up on the fly. */
767 gl_list_iterator_t iter
= gl_list_iterator (list
);
770 if (gl_list_iterator_next (&iter
, &elt
, &node
))
773 struct closeable_fd
*element
= (struct closeable_fd
*) elt
;
775 /* Close the file descriptor and the stream, avoiding races with the
777 if (element
->fd
== fd
)
780 result
= asyncsafe_fclose_variant (element
, fp
, fclose_variant
);
784 bool free_this_node
= element
->done
;
785 struct closeable_fd
*element_to_free
= element
;
786 gl_list_node_t node_to_free
= node
;
788 bool have_next
= gl_list_iterator_next (&iter
, &elt
, &node
);
792 free (element_to_free
);
793 gl_list_remove_node (list
, node_to_free
);
799 gl_list_iterator_free (&iter
);
801 /* descriptors should have contained fd. */
804 if (mt
) gl_lock_unlock (descriptors_lock
);
810 /* Close a temporary file.
811 FP must have been returned by fopen_temp, or by fdopen on a file descriptor
812 returned by open_temp or gen_register_open_temp.
813 Unregisters the previously registered file descriptor. */
815 fclose_temp (FILE *fp
)
817 return fclose_variant_temp (fp
, fclose
);
820 #if GNULIB_FWRITEERROR
822 FP must have been returned by fopen_temp, or by fdopen on a file descriptor
823 returned by open_temp or gen_register_open_temp.
824 Unregisters the previously registered file descriptor. */
826 fwriteerror_temp (FILE *fp
)
828 return fclose_variant_temp (fp
, fwriteerror
);
832 #if GNULIB_CLOSE_STREAM
833 /* Like close_stream.
834 FP must have been returned by fopen_temp, or by fdopen on a file descriptor
835 returned by open_temp or gen_register_open_temp.
836 Unregisters the previously registered file descriptor. */
838 close_stream_temp (FILE *fp
)
840 return fclose_variant_temp (fp
, close_stream
);