* clean-temp: add support for temporary files anywhere
@ 2020-07-04 13:30 Bruno Haible
2020-07-04 16:08 ` Bruno Haible
0 siblings, 1 reply; 2+ messages in thread
From: Bruno Haible @ 2020-07-04 13:30 UTC (permalink / raw)
To: bug-gnulib
[-- Attachment #1: Type: text/plain, Size: 1695 bytes --]
Sometimes, temporary files are better placed in temporary subdirectories,
so that you have full control over the file names and access permissions.
But sometimes, temporary files are better placed in a given directory,
so that you can be sure that a 'rename' to another name in the same
directory will succeed.
These two patches add support for creating temporary files at a given
place, with automatic cleanup.
And some documentation improvement.
2020-07-04 Bruno Haible <bruno@clisp.org>
clean-temp: Document limitations.
* lib/clean-temp.h: Document limitations.
2020-07-04 Bruno Haible <bruno@clisp.org>
clean-temp: Add support for temporary files with unpredictable names.
* lib/clean-temp.h (gen_register_open_temp): New declaration.
* lib/clean-temp.c: Include tempname.h.
(gen_register_open_temp): New function.
* modules/tempname (configure.ac): Define a module indicator.
2020-07-04 Bruno Haible <bruno@clisp.org>
clean-temp: Add support for temporary files anywhere in the file system.
* lib/clean-temp.h (register_temporary_file, unregister_temporary_file,
cleanup_temporary_file): New declarations.
* lib/clean-temp.c (file_cleanup_list_lock, file_cleanup_list): New
variables.
(dir_cleanup_list_lock): Renamed from cleanup_list_lock.
(dir_cleanup_list): Renamed from cleanup_list.
(cleanup_action): Process the file_cleanup_list as well.
(do_init_clean_temp): New function.
(clean_temp_once): New variable.
(init_clean_temp): New function.
(create_temp_dir): Invoke it.
(register_temporary_file, unregister_temporary_file,
cleanup_temporary_file): New functions.
(do_unlink, do_rmdir): Remove 'dir' argument. Add 'cleanup_verbose'
argument.
[-- Attachment #2: 0001-clean-temp-Add-support-for-temporary-files-anywhere-.patch --]
[-- Type: text/x-patch, Size: 22245 bytes --]
From 629e348003127a1d780fc2edf4f5d38f42e09fb9 Mon Sep 17 00:00:00 2001
From: Bruno Haible <bruno@clisp.org>
Date: Sat, 4 Jul 2020 15:17:32 +0200
Subject: [PATCH 1/3] clean-temp: Add support for temporary files anywhere in
the file system.
* lib/clean-temp.h (register_temporary_file, unregister_temporary_file,
cleanup_temporary_file): New declarations.
* lib/clean-temp.c (file_cleanup_list_lock, file_cleanup_list): New
variables.
(dir_cleanup_list_lock): Renamed from cleanup_list_lock.
(dir_cleanup_list): Renamed from cleanup_list.
(cleanup_action): Process the file_cleanup_list as well.
(do_init_clean_temp): New function.
(clean_temp_once): New variable.
(init_clean_temp): New function.
(create_temp_dir): Invoke it.
(register_temporary_file, unregister_temporary_file,
cleanup_temporary_file): New functions.
(do_unlink, do_rmdir): Remove 'dir' argument. Add 'cleanup_verbose'
argument.
---
ChangeLog | 19 +++++
lib/clean-temp.c | 244 +++++++++++++++++++++++++++++++++++++++++--------------
lib/clean-temp.h | 42 ++++++++--
3 files changed, 233 insertions(+), 72 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index aa31cfa..4c6319f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,24 @@
2020-07-04 Bruno Haible <bruno@clisp.org>
+ clean-temp: Add support for temporary files anywhere in the file system.
+ * lib/clean-temp.h (register_temporary_file, unregister_temporary_file,
+ cleanup_temporary_file): New declarations.
+ * lib/clean-temp.c (file_cleanup_list_lock, file_cleanup_list): New
+ variables.
+ (dir_cleanup_list_lock): Renamed from cleanup_list_lock.
+ (dir_cleanup_list): Renamed from cleanup_list.
+ (cleanup_action): Process the file_cleanup_list as well.
+ (do_init_clean_temp): New function.
+ (clean_temp_once): New variable.
+ (init_clean_temp): New function.
+ (create_temp_dir): Invoke it.
+ (register_temporary_file, unregister_temporary_file,
+ cleanup_temporary_file): New functions.
+ (do_unlink, do_rmdir): Remove 'dir' argument. Add 'cleanup_verbose'
+ argument.
+
+2020-07-04 Bruno Haible <bruno@clisp.org>
+
clean-temp: Improve comments.
* lib/clean-temp.h (open_temp, fopen_temp, close_temp, fclose_temp,
fwriteerror_temp, close_stream_temp): Clarify intended use.
diff --git a/lib/clean-temp.c b/lib/clean-temp.c
index 75bd1ee..275dc78 100644
--- a/lib/clean-temp.c
+++ b/lib/clean-temp.c
@@ -84,6 +84,14 @@
signal handler can rely on these field values to be up to date. */
+/* Lock that protects the file_cleanup_list from concurrent modification in
+ different threads. */
+gl_lock_define_initialized (static, file_cleanup_list_lock)
+
+/* List of all temporary files without temporary directories. */
+static gl_list_t /* <char *> */ volatile file_cleanup_list;
+
+
/* Registry for a single temporary directory.
'struct temp_dir' from the public header file overlaps with this. */
struct tempdir
@@ -98,9 +106,9 @@ struct tempdir
gl_list_t /* <char *> */ volatile files;
};
-/* Lock that protects the cleanup_list from concurrent modification in
+/* Lock that protects the dir_cleanup_list from concurrent modification in
different threads. */
-gl_lock_define_initialized (static, cleanup_list_lock)
+gl_lock_define_initialized (static, dir_cleanup_list_lock)
/* List of all temporary directories. */
static struct
@@ -108,7 +116,8 @@ static struct
struct tempdir * volatile * volatile tempdir_list;
size_t volatile tempdir_count;
size_t tempdir_allocated;
-} cleanup_list /* = { NULL, 0, 0 } */;
+} dir_cleanup_list /* = { NULL, 0, 0 } */;
+
/* A file descriptor to be closed.
In multithreaded programs, it is forbidden to close the same fd twice,
@@ -313,9 +322,27 @@ cleanup_action (int sig _GL_UNUSED)
}
}
- for (i = 0; i < cleanup_list.tempdir_count; i++)
+ {
+ gl_list_t files = file_cleanup_list;
+
+ if (files != NULL)
+ {
+ gl_list_iterator_t iter;
+ const void *element;
+
+ iter = gl_list_iterator (files);
+ while (gl_list_iterator_next (&iter, &element, NULL))
+ {
+ const char *file = (const char *) element;
+ unlink (file);
+ }
+ gl_list_iterator_free (&iter);
+ }
+ }
+
+ for (i = 0; i < dir_cleanup_list.tempdir_count; i++)
{
- struct tempdir *dir = cleanup_list.tempdir_list[i];
+ struct tempdir *dir = dir_cleanup_list.tempdir_list[i];
if (dir != NULL)
{
@@ -346,6 +373,110 @@ cleanup_action (int sig _GL_UNUSED)
}
}
+
+/* Initializes this facility. */
+static void
+do_init_clean_temp (void)
+{
+ /* Initialize the data used by the cleanup handler. */
+ init_fatal_signal_set ();
+ /* Register the cleanup handler. */
+ at_fatal_signal (&cleanup_action);
+}
+
+/* Ensure that do_init_clean_temp is called once only. */
+gl_once_define(static, clean_temp_once)
+
+/* Initializes this facility upon first use. */
+static void
+init_clean_temp (void)
+{
+ gl_once (clean_temp_once, do_init_clean_temp);
+}
+
+
+/* ============= Temporary files without temporary directories ============= */
+
+/* Register the given ABSOLUTE_FILE_NAME as being a file that needs to be
+ removed.
+ Should be called before the file ABSOLUTE_FILE_NAME is created. */
+void
+register_temporary_file (const char *absolute_file_name)
+{
+ gl_lock_lock (file_cleanup_list_lock);
+
+ /* Make sure that this facility and the file_cleanup_list are initialized. */
+ if (file_cleanup_list == NULL)
+ {
+ init_clean_temp ();
+ file_cleanup_list =
+ gl_list_create_empty (GL_LINKEDHASH_LIST,
+ string_equals, string_hash, NULL, false);
+ }
+
+ /* Add absolute_file_name to file_cleanup_list, without duplicates. */
+ if (gl_list_search (file_cleanup_list, absolute_file_name) == NULL)
+ gl_list_add_first (file_cleanup_list, xstrdup (absolute_file_name));
+
+ gl_lock_unlock (file_cleanup_list_lock);
+}
+
+/* Unregister the given ABSOLUTE_FILE_NAME as being a file that needs to be
+ removed.
+ Should be called when the file ABSOLUTE_FILE_NAME could not be created. */
+void
+unregister_temporary_file (const char *absolute_file_name)
+{
+ gl_lock_lock (file_cleanup_list_lock);
+
+ gl_list_t list = file_cleanup_list;
+ if (list != NULL)
+ {
+ gl_list_node_t node = gl_list_search (list, absolute_file_name);
+ if (node != NULL)
+ {
+ char *old_string = (char *) gl_list_node_value (list, node);
+
+ gl_list_remove_node (list, node);
+ free (old_string);
+ }
+ }
+
+ gl_lock_unlock (file_cleanup_list_lock);
+}
+
+/* Remove a file, with optional error message.
+ Return 0 upon success, or -1 if there was some problem. */
+static int
+do_unlink (const char *absolute_file_name, bool cleanup_verbose)
+{
+ if (unlink (absolute_file_name) < 0 && cleanup_verbose
+ && errno != ENOENT)
+ {
+ error (0, errno,
+ _("cannot remove temporary file %s"), absolute_file_name);
+ return -1;
+ }
+ return 0;
+}
+
+/* Remove the given ABSOLUTE_FILE_NAME and unregister it.
+ CLEANUP_VERBOSE determines whether errors are reported to standard error.
+ Return 0 upon success, or -1 if there was some problem. */
+int
+cleanup_temporary_file (const char *absolute_file_name, bool cleanup_verbose)
+{
+ int err;
+
+ err = do_unlink (absolute_file_name, cleanup_verbose);
+ unregister_temporary_file (absolute_file_name);
+
+ return err;
+}
+
+
+/* ========= Temporary directories and temporary files inside them ========= */
+
/* Create a temporary directory.
PREFIX is used as a prefix for the name of the temporary directory. It
should be short and still give an indication about the program.
@@ -359,7 +490,7 @@ struct temp_dir *
create_temp_dir (const char *prefix, const char *parentdir,
bool cleanup_verbose)
{
- gl_lock_lock (cleanup_list_lock);
+ gl_lock_lock (dir_cleanup_list_lock);
struct tempdir * volatile *tmpdirp = NULL;
struct tempdir *tmpdir;
@@ -369,30 +500,29 @@ create_temp_dir (const char *prefix, const char *parentdir,
/* See whether it can take the slot of an earlier temporary directory
already cleaned up. */
- for (i = 0; i < cleanup_list.tempdir_count; i++)
- if (cleanup_list.tempdir_list[i] == NULL)
+ for (i = 0; i < dir_cleanup_list.tempdir_count; i++)
+ if (dir_cleanup_list.tempdir_list[i] == NULL)
{
- tmpdirp = &cleanup_list.tempdir_list[i];
+ tmpdirp = &dir_cleanup_list.tempdir_list[i];
break;
}
if (tmpdirp == NULL)
{
/* See whether the array needs to be extended. */
- if (cleanup_list.tempdir_count == cleanup_list.tempdir_allocated)
+ if (dir_cleanup_list.tempdir_count == dir_cleanup_list.tempdir_allocated)
{
/* Note that we cannot use xrealloc(), because then the cleanup()
function could access an already deallocated array. */
- struct tempdir * volatile *old_array = cleanup_list.tempdir_list;
- size_t old_allocated = cleanup_list.tempdir_allocated;
- size_t new_allocated = 2 * cleanup_list.tempdir_allocated + 1;
+ struct tempdir * volatile *old_array = dir_cleanup_list.tempdir_list;
+ size_t old_allocated = dir_cleanup_list.tempdir_allocated;
+ size_t new_allocated = 2 * dir_cleanup_list.tempdir_allocated + 1;
struct tempdir * volatile *new_array =
XNMALLOC (new_allocated, struct tempdir * volatile);
if (old_allocated == 0)
{
- /* First use of this facility. Register the cleanup handler. */
- init_fatal_signal_set ();
- at_fatal_signal (&cleanup_action);
+ /* First use of this facility. */
+ init_clean_temp ();
}
else
{
@@ -405,8 +535,8 @@ create_temp_dir (const char *prefix, const char *parentdir,
new_array[k] = old_array[k];
}
- cleanup_list.tempdir_list = new_array;
- cleanup_list.tempdir_allocated = new_allocated;
+ dir_cleanup_list.tempdir_list = new_array;
+ dir_cleanup_list.tempdir_allocated = new_allocated;
/* Now we can free the old array. */
/* No, we can't do that. If cleanup_action is running in a different
@@ -420,11 +550,11 @@ create_temp_dir (const char *prefix, const char *parentdir,
#endif
}
- tmpdirp = &cleanup_list.tempdir_list[cleanup_list.tempdir_count];
+ tmpdirp = &dir_cleanup_list.tempdir_list[dir_cleanup_list.tempdir_count];
/* Initialize *tmpdirp before incrementing tempdir_count, so that
cleanup() will skip this entry before it is fully initialized. */
*tmpdirp = NULL;
- cleanup_list.tempdir_count++;
+ dir_cleanup_list.tempdir_count++;
}
/* Initialize a 'struct tempdir'. */
@@ -467,12 +597,12 @@ create_temp_dir (const char *prefix, const char *parentdir,
block because then the cleanup handler would not remove the directory
if xstrdup fails. */
tmpdir->dirname = xstrdup (tmpdirname);
- gl_lock_unlock (cleanup_list_lock);
+ gl_lock_unlock (dir_cleanup_list_lock);
freea (xtemplate);
return (struct temp_dir *) tmpdir;
quit:
- gl_lock_unlock (cleanup_list_lock);
+ gl_lock_unlock (dir_cleanup_list_lock);
freea (xtemplate);
return NULL;
}
@@ -486,13 +616,13 @@ register_temp_file (struct temp_dir *dir,
{
struct tempdir *tmpdir = (struct tempdir *)dir;
- gl_lock_lock (cleanup_list_lock);
+ gl_lock_lock (dir_cleanup_list_lock);
/* Add absolute_file_name to tmpdir->files, without duplicates. */
if (gl_list_search (tmpdir->files, absolute_file_name) == NULL)
gl_list_add_first (tmpdir->files, xstrdup (absolute_file_name));
- gl_lock_unlock (cleanup_list_lock);
+ gl_lock_unlock (dir_cleanup_list_lock);
}
/* Unregister the given ABSOLUTE_FILE_NAME as being a file inside DIR, that
@@ -504,7 +634,7 @@ unregister_temp_file (struct temp_dir *dir,
{
struct tempdir *tmpdir = (struct tempdir *)dir;
- gl_lock_lock (cleanup_list_lock);
+ gl_lock_lock (dir_cleanup_list_lock);
gl_list_t list = tmpdir->files;
gl_list_node_t node;
@@ -518,7 +648,7 @@ unregister_temp_file (struct temp_dir *dir,
free (old_string);
}
- gl_lock_unlock (cleanup_list_lock);
+ gl_lock_unlock (dir_cleanup_list_lock);
}
/* Register the given ABSOLUTE_DIR_NAME as being a subdirectory inside DIR,
@@ -530,13 +660,13 @@ register_temp_subdir (struct temp_dir *dir,
{
struct tempdir *tmpdir = (struct tempdir *)dir;
- gl_lock_lock (cleanup_list_lock);
+ gl_lock_lock (dir_cleanup_list_lock);
/* Add absolute_dir_name to tmpdir->subdirs, without duplicates. */
if (gl_list_search (tmpdir->subdirs, absolute_dir_name) == NULL)
gl_list_add_first (tmpdir->subdirs, xstrdup (absolute_dir_name));
- gl_lock_unlock (cleanup_list_lock);
+ gl_lock_unlock (dir_cleanup_list_lock);
}
/* Unregister the given ABSOLUTE_DIR_NAME as being a subdirectory inside DIR,
@@ -549,7 +679,7 @@ unregister_temp_subdir (struct temp_dir *dir,
{
struct tempdir *tmpdir = (struct tempdir *)dir;
- gl_lock_lock (cleanup_list_lock);
+ gl_lock_lock (dir_cleanup_list_lock);
gl_list_t list = tmpdir->subdirs;
gl_list_node_t node;
@@ -563,29 +693,15 @@ unregister_temp_subdir (struct temp_dir *dir,
free (old_string);
}
- gl_lock_unlock (cleanup_list_lock);
-}
-
-/* Remove a file, with optional error message.
- Return 0 upon success, or -1 if there was some problem. */
-static int
-do_unlink (struct temp_dir *dir, const char *absolute_file_name)
-{
- if (unlink (absolute_file_name) < 0 && dir->cleanup_verbose
- && errno != ENOENT)
- {
- error (0, errno, _("cannot remove temporary file %s"), absolute_file_name);
- return -1;
- }
- return 0;
+ gl_lock_unlock (dir_cleanup_list_lock);
}
/* Remove a directory, with optional error message.
Return 0 upon success, or -1 if there was some problem. */
static int
-do_rmdir (struct temp_dir *dir, const char *absolute_dir_name)
+do_rmdir (const char *absolute_dir_name, bool cleanup_verbose)
{
- if (rmdir (absolute_dir_name) < 0 && dir->cleanup_verbose
+ if (rmdir (absolute_dir_name) < 0 && cleanup_verbose
&& errno != ENOENT)
{
error (0, errno,
@@ -603,7 +719,7 @@ cleanup_temp_file (struct temp_dir *dir,
{
int err;
- err = do_unlink (dir, absolute_file_name);
+ err = do_unlink (absolute_file_name, dir->cleanup_verbose);
unregister_temp_file (dir, absolute_file_name);
return err;
@@ -617,14 +733,14 @@ cleanup_temp_subdir (struct temp_dir *dir,
{
int err;
- err = do_rmdir (dir, absolute_dir_name);
+ err = do_rmdir (absolute_dir_name, dir->cleanup_verbose);
unregister_temp_subdir (dir, absolute_dir_name);
return err;
}
/* Remove all registered files and subdirectories inside DIR.
- Only to be called with cleanup_list_lock locked.
+ Only to be called with dir_cleanup_list_lock locked.
Return 0 upon success, or -1 if there was some problem. */
int
cleanup_temp_dir_contents (struct temp_dir *dir)
@@ -643,7 +759,7 @@ cleanup_temp_dir_contents (struct temp_dir *dir)
{
char *file = (char *) element;
- err |= do_unlink (dir, file);
+ err |= do_unlink (file, dir->cleanup_verbose);
gl_list_remove_node (list, node);
/* Now only we can free file. */
free (file);
@@ -657,7 +773,7 @@ cleanup_temp_dir_contents (struct temp_dir *dir)
{
char *subdir = (char *) element;
- err |= do_rmdir (dir, subdir);
+ err |= do_rmdir (subdir, dir->cleanup_verbose);
gl_list_remove_node (list, node);
/* Now only we can free subdir. */
free (subdir);
@@ -673,34 +789,34 @@ cleanup_temp_dir_contents (struct temp_dir *dir)
int
cleanup_temp_dir (struct temp_dir *dir)
{
- gl_lock_lock (cleanup_list_lock);
+ gl_lock_lock (dir_cleanup_list_lock);
struct tempdir *tmpdir = (struct tempdir *)dir;
int err = 0;
size_t i;
err |= cleanup_temp_dir_contents (dir);
- err |= do_rmdir (dir, tmpdir->dirname);
+ err |= do_rmdir (tmpdir->dirname, dir->cleanup_verbose);
- for (i = 0; i < cleanup_list.tempdir_count; i++)
- if (cleanup_list.tempdir_list[i] == tmpdir)
+ for (i = 0; i < dir_cleanup_list.tempdir_count; i++)
+ if (dir_cleanup_list.tempdir_list[i] == tmpdir)
{
- /* Remove cleanup_list.tempdir_list[i]. */
- if (i + 1 == cleanup_list.tempdir_count)
+ /* Remove dir_cleanup_list.tempdir_list[i]. */
+ if (i + 1 == dir_cleanup_list.tempdir_count)
{
- while (i > 0 && cleanup_list.tempdir_list[i - 1] == NULL)
+ while (i > 0 && dir_cleanup_list.tempdir_list[i - 1] == NULL)
i--;
- cleanup_list.tempdir_count = i;
+ dir_cleanup_list.tempdir_count = i;
}
else
- cleanup_list.tempdir_list[i] = NULL;
+ dir_cleanup_list.tempdir_list[i] = NULL;
/* Now only we can free the tmpdir->dirname, tmpdir->subdirs,
tmpdir->files, and tmpdir itself. */
gl_list_free (tmpdir->files);
gl_list_free (tmpdir->subdirs);
free (tmpdir->dirname);
free (tmpdir);
- gl_lock_unlock (cleanup_list_lock);
+ gl_lock_unlock (dir_cleanup_list_lock);
return err;
}
@@ -709,6 +825,8 @@ cleanup_temp_dir (struct temp_dir *dir)
}
+/* ================== Opening and closing temporary files ================== */
+
#if defined _WIN32 && ! defined __CYGWIN__
/* On Windows, opening a file with _O_TEMPORARY has the effect of passing
@@ -840,7 +958,7 @@ fopen_temp (const char *file_name, const char *mode, bool delete_on_close)
return fp;
}
-/* Close a temporary file in a temporary directory.
+/* Close a temporary file.
FD must have been returned by open_temp.
Unregisters the previously registered file descriptor. */
int
@@ -968,7 +1086,7 @@ fclose_variant_temp (FILE *fp, int (*fclose_variant) (FILE *))
return result;
}
-/* Close a temporary file in a temporary directory.
+/* Close a temporary file.
FP must have been returned by fopen_temp, or by fdopen on a file descriptor
returned by open_temp.
Unregisters the previously registered file descriptor. */
diff --git a/lib/clean-temp.h b/lib/clean-temp.h
index 7848a15..c828d72 100644
--- a/lib/clean-temp.h
+++ b/lib/clean-temp.h
@@ -37,19 +37,41 @@ extern "C" {
and the temporary directories can be removed, because only on Unix
(excluding Cygwin) can one remove directories containing open files.
- This module provides support for temporary directories and temporary files
- inside these temporary directories. Temporary files without temporary
- directories are not supported here. The temporary directories and files
- are automatically cleaned up (at the latest) when the program exits or
- dies from a fatal signal such as SIGINT, SIGTERM, SIGHUP, but not if it
- dies from a fatal signal such as SIGQUIT, SIGKILL, or SIGABRT, SIGSEGV,
- SIGBUS, SIGILL, SIGFPE.
+ This module provides support for
+ - temporary directories and temporary files inside these temporary
+ directories,
+ - temporary files without temporary directories.
+ The temporary directories and files are automatically cleaned up (at the
+ latest) when the program exits or dies from a fatal signal such as SIGINT,
+ SIGTERM, SIGHUP, but not if it dies from a fatal signal such as SIGQUIT,
+ SIGKILL, or SIGABRT, SIGSEGV, SIGBUS, SIGILL, SIGFPE.
For the cleanup in the normal case, programs that use this module need to
call 'cleanup_temp_dir' for each successful return of 'create_temp_dir'.
The cleanup in the case of a fatal signal such as SIGINT, SIGTERM, SIGHUP,
is done entirely automatically by the functions of this module. */
+
+/* ============= Temporary files without temporary directories ============= */
+
+/* Register the given ABSOLUTE_FILE_NAME as being a file that needs to be
+ removed.
+ Should be called before the file ABSOLUTE_FILE_NAME is created. */
+extern void register_temporary_file (const char *absolute_file_name);
+
+/* Unregister the given ABSOLUTE_FILE_NAME as being a file that needs to be
+ removed.
+ Should be called when the file ABSOLUTE_FILE_NAME could not be created. */
+extern void unregister_temporary_file (const char *absolute_file_name);
+
+/* Remove the given ABSOLUTE_FILE_NAME and unregister it.
+ CLEANUP_VERBOSE determines whether errors are reported to standard error.
+ Return 0 upon success, or -1 if there was some problem. */
+extern int cleanup_temporary_file (const char *absolute_file_name,
+ bool cleanup_verbose);
+
+/* ========= Temporary directories and temporary files inside them ========= */
+
struct temp_dir
{
/* The absolute pathname of the directory. */
@@ -116,6 +138,8 @@ extern int cleanup_temp_dir_contents (struct temp_dir *dir);
Return 0 upon success, or -1 if there was some problem. */
extern int cleanup_temp_dir (struct temp_dir *dir);
+/* ================== Opening and closing temporary files ================== */
+
/* Open a temporary file in a temporary directory.
FILE_NAME must already have been passed to register_temp_file.
Registers the resulting file descriptor to be closed.
@@ -126,12 +150,12 @@ extern int open_temp (const char *file_name, int flags, mode_t mode,
extern FILE * fopen_temp (const char *file_name, const char *mode,
bool delete_on_close);
-/* Close a temporary file in a temporary directory.
+/* Close a temporary file.
FD must have been returned by open_temp.
Unregisters the previously registered file descriptor. */
extern int close_temp (int fd);
-/* Close a temporary file in a temporary directory.
+/* Close a temporary file.
FP must have been returned by fopen_temp, or by fdopen on a file descriptor
returned by open_temp.
Unregisters the previously registered file descriptor. */
--
2.7.4
[-- Attachment #3: 0002-clean-temp-Add-support-for-temporary-files-with-unpr.patch --]
[-- Type: text/x-patch, Size: 6245 bytes --]
From 7ee75d845dbbd2791c99668fef18438652113a00 Mon Sep 17 00:00:00 2001
From: Bruno Haible <bruno@clisp.org>
Date: Sat, 4 Jul 2020 15:18:20 +0200
Subject: [PATCH 2/3] clean-temp: Add support for temporary files with
unpredictable names.
* lib/clean-temp.h (gen_register_open_temp): New declaration.
* lib/clean-temp.c: Include tempname.h.
(gen_register_open_temp): New function.
* modules/tempname (configure.ac): Define a module indicator.
---
ChangeLog | 8 ++++++++
lib/clean-temp.c | 37 +++++++++++++++++++++++++++++++++----
lib/clean-temp.h | 17 +++++++++++++----
modules/tempname | 1 +
4 files changed, 55 insertions(+), 8 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 4c6319f..0b48871 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,13 @@
2020-07-04 Bruno Haible <bruno@clisp.org>
+ clean-temp: Add support for temporary files with unpredictable names.
+ * lib/clean-temp.h (gen_register_open_temp): New declaration.
+ * lib/clean-temp.c: Include tempname.h.
+ (gen_register_open_temp): New function.
+ * modules/tempname (configure.ac): Define a module indicator.
+
+2020-07-04 Bruno Haible <bruno@clisp.org>
+
clean-temp: Add support for temporary files anywhere in the file system.
* lib/clean-temp.h (register_temporary_file, unregister_temporary_file,
cleanup_temporary_file): New declarations.
diff --git a/lib/clean-temp.c b/lib/clean-temp.c
index 275dc78..948a7ed 100644
--- a/lib/clean-temp.c
+++ b/lib/clean-temp.c
@@ -48,6 +48,9 @@
#include "gl_linkedhash_list.h"
#include "gl_linked_list.h"
#include "gettext.h"
+#if GNULIB_TEMPNAME
+# include "tempname.h"
+#endif
#if GNULIB_FWRITEERROR
# include "fwriteerror.h"
#endif
@@ -958,8 +961,34 @@ fopen_temp (const char *file_name, const char *mode, bool delete_on_close)
return fp;
}
+#if GNULIB_TEMPNAME
+/* Open a temporary file, generating its name based on FILE_NAME_TMPL.
+ FILE_NAME_TMPL must match the rules for mk[s]temp (i.e. end in "XXXXXX",
+ possibly with a suffix). The name constructed does not exist at the time
+ of the call. FILE_NAME_TMPL is overwritten with the result.
+ Registers the file for deletion.
+ Opens the file, with the given FLAGS and mode 0600.
+ Registers the resulting file descriptor to be closed. */
+int
+gen_register_open_temp (char *file_name_tmpl, int suffixlen, int flags)
+{
+ block_fatal_signals ();
+ int fd = gen_tempname (file_name_tmpl, suffixlen, flags, GT_FILE);
+ int saved_errno = errno;
+ if (fd >= 0)
+ {
+ init_clean_temp ();
+ register_fd (fd);
+ register_temporary_file (file_name_tmpl);
+ }
+ unblock_fatal_signals ();
+ errno = saved_errno;
+ return fd;
+}
+#endif
+
/* Close a temporary file.
- FD must have been returned by open_temp.
+ FD must have been returned by open_temp or gen_register_open_temp.
Unregisters the previously registered file descriptor. */
int
close_temp (int fd)
@@ -1088,7 +1117,7 @@ fclose_variant_temp (FILE *fp, int (*fclose_variant) (FILE *))
/* Close a temporary file.
FP must have been returned by fopen_temp, or by fdopen on a file descriptor
- returned by open_temp.
+ returned by open_temp or gen_register_open_temp.
Unregisters the previously registered file descriptor. */
int
fclose_temp (FILE *fp)
@@ -1099,7 +1128,7 @@ fclose_temp (FILE *fp)
#if GNULIB_FWRITEERROR
/* Like fwriteerror.
FP must have been returned by fopen_temp, or by fdopen on a file descriptor
- returned by open_temp.
+ returned by open_temp or gen_register_open_temp.
Unregisters the previously registered file descriptor. */
int
fwriteerror_temp (FILE *fp)
@@ -1111,7 +1140,7 @@ fwriteerror_temp (FILE *fp)
#if GNULIB_CLOSE_STREAM
/* Like close_stream.
FP must have been returned by fopen_temp, or by fdopen on a file descriptor
- returned by open_temp.
+ returned by open_temp or gen_register_open_temp.
Unregisters the previously registered file descriptor. */
int
close_stream_temp (FILE *fp)
diff --git a/lib/clean-temp.h b/lib/clean-temp.h
index c828d72..087db45 100644
--- a/lib/clean-temp.h
+++ b/lib/clean-temp.h
@@ -150,26 +150,35 @@ extern int open_temp (const char *file_name, int flags, mode_t mode,
extern FILE * fopen_temp (const char *file_name, const char *mode,
bool delete_on_close);
+/* Open a temporary file, generating its name based on FILE_NAME_TMPL.
+ FILE_NAME_TMPL must match the rules for mk[s]temp (i.e. end in "XXXXXX",
+ possibly with a suffix). The name constructed does not exist at the time
+ of the call. FILE_NAME_TMPL is overwritten with the result.
+ Registers the file for deletion.
+ Opens the file, with the given FLAGS and mode 0600.
+ Registers the resulting file descriptor to be closed. */
+extern int gen_register_open_temp (char *file_name_tmpl, int suffixlen, int flags);
+
/* Close a temporary file.
- FD must have been returned by open_temp.
+ FD must have been returned by open_temp or gen_register_open_temp.
Unregisters the previously registered file descriptor. */
extern int close_temp (int fd);
/* Close a temporary file.
FP must have been returned by fopen_temp, or by fdopen on a file descriptor
- returned by open_temp.
+ returned by open_temp or gen_register_open_temp.
Unregisters the previously registered file descriptor. */
extern int fclose_temp (FILE *fp);
/* Like fwriteerror.
FP must have been returned by fopen_temp, or by fdopen on a file descriptor
- returned by open_temp.
+ returned by open_temp or gen_register_open_temp.
Unregisters the previously registered file descriptor. */
extern int fwriteerror_temp (FILE *fp);
/* Like close_stream.
FP must have been returned by fopen_temp, or by fdopen on a file descriptor
- returned by open_temp.
+ returned by open_temp or gen_register_open_temp.
Unregisters the previously registered file descriptor. */
extern int close_stream_temp (FILE *fp);
diff --git a/modules/tempname b/modules/tempname
index ca88522..794a763 100644
--- a/modules/tempname
+++ b/modules/tempname
@@ -19,6 +19,7 @@ sys_stat
configure.ac:
gl_FUNC_GEN_TEMPNAME
+gl_MODULE_INDICATOR([tempname])
Makefile.am:
lib_SOURCES += tempname.c
--
2.7.4
[-- Attachment #4: 0003-clean-temp-Document-limitations.patch --]
[-- Type: text/x-patch, Size: 1975 bytes --]
From 564370e171d3e503d10463288bee2ff5273b2a33 Mon Sep 17 00:00:00 2001
From: Bruno Haible <bruno@clisp.org>
Date: Sat, 4 Jul 2020 15:22:33 +0200
Subject: [PATCH 3/3] clean-temp: Document limitations.
* lib/clean-temp.h: Document limitations.
---
ChangeLog | 5 +++++
lib/clean-temp.h | 12 +++++++++++-
2 files changed, 16 insertions(+), 1 deletion(-)
diff --git a/ChangeLog b/ChangeLog
index 0b48871..8e0408c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
2020-07-04 Bruno Haible <bruno@clisp.org>
+ clean-temp: Document limitations.
+ * lib/clean-temp.h: Document limitations.
+
+2020-07-04 Bruno Haible <bruno@clisp.org>
+
clean-temp: Add support for temporary files with unpredictable names.
* lib/clean-temp.h (gen_register_open_temp): New declaration.
* lib/clean-temp.c: Include tempname.h.
diff --git a/lib/clean-temp.h b/lib/clean-temp.h
index 087db45..df7e744 100644
--- a/lib/clean-temp.h
+++ b/lib/clean-temp.h
@@ -49,7 +49,17 @@ extern "C" {
For the cleanup in the normal case, programs that use this module need to
call 'cleanup_temp_dir' for each successful return of 'create_temp_dir'.
The cleanup in the case of a fatal signal such as SIGINT, SIGTERM, SIGHUP,
- is done entirely automatically by the functions of this module. */
+ is done entirely automatically by the functions of this module.
+
+ Limitations: Files or directories can still be left over if
+ - the program is dies from a fatal signal such as SIGQUIT, SIGKILL, or
+ SIGABRT, SIGSEGV, SIGBUS, SIGILL, SIGFPE, or
+ - in a multithreaded program, the fatal signal handler is already running
+ while another thread of the program creates a new temporary directory
+ or temporary file, or
+ - on native Windows, some temporary files are used by a subprocess while
+ the fatal signal interrupts the program.
+ */
/* ============= Temporary files without temporary directories ============= */
--
2.7.4
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: clean-temp: add support for temporary files anywhere
2020-07-04 13:30 clean-temp: add support for temporary files anywhere Bruno Haible
@ 2020-07-04 16:08 ` Bruno Haible
0 siblings, 0 replies; 2+ messages in thread
From: Bruno Haible @ 2020-07-04 16:08 UTC (permalink / raw)
To: bug-gnulib
> 2020-07-04 Bruno Haible <bruno@clisp.org>
>
> clean-temp: Add support for temporary files with unpredictable names.
> * lib/clean-temp.h (gen_register_open_temp): New declaration.
This can be made a bit more powerful, by adding a 'mode' argument.
2020-07-04 Bruno Haible <bruno@clisp.org>
clean-temp: Add support for temporary files with given mode.
* lib/clean-temp.h (gen_register_open_temp): Add mode argument.
* lib/clean-temp.c (struct try_create_file_params): New type.
(try_create_file): New function.
(gen_register_open_temp): Add mode argument. Use try_tempname instead of
gen_tempname.
diff --git a/lib/clean-temp.c b/lib/clean-temp.c
index 948a7ed..34ebb9b 100644
--- a/lib/clean-temp.c
+++ b/lib/clean-temp.c
@@ -962,18 +962,42 @@ fopen_temp (const char *file_name, const char *mode, bool delete_on_close)
}
#if GNULIB_TEMPNAME
+
+struct try_create_file_params
+{
+ int flags;
+ mode_t mode;
+};
+
+static int
+try_create_file (char *file_name_tmpl, void *params_)
+{
+ struct try_create_file_params *params = params_;
+ return open (file_name_tmpl,
+ (params->flags & ~O_ACCMODE) | O_RDWR | O_CREAT | O_EXCL,
+ params->mode);
+}
+
/* Open a temporary file, generating its name based on FILE_NAME_TMPL.
FILE_NAME_TMPL must match the rules for mk[s]temp (i.e. end in "XXXXXX",
possibly with a suffix). The name constructed does not exist at the time
of the call. FILE_NAME_TMPL is overwritten with the result.
+ A safe choice for MODE is S_IRUSR | S_IWUSR, a.k.a. 0600.
Registers the file for deletion.
- Opens the file, with the given FLAGS and mode 0600.
+ Opens the file, with the given FLAGS and mode MODE.
Registers the resulting file descriptor to be closed. */
int
-gen_register_open_temp (char *file_name_tmpl, int suffixlen, int flags)
+gen_register_open_temp (char *file_name_tmpl, int suffixlen,
+ int flags, mode_t mode)
{
block_fatal_signals ();
- int fd = gen_tempname (file_name_tmpl, suffixlen, flags, GT_FILE);
+
+ struct try_create_file_params params;
+ params.flags = flags;
+ params.mode = mode;
+
+ int fd = try_tempname (file_name_tmpl, suffixlen, ¶ms, try_create_file);
+
int saved_errno = errno;
if (fd >= 0)
{
@@ -985,6 +1009,7 @@ gen_register_open_temp (char *file_name_tmpl, int suffixlen, int flags)
errno = saved_errno;
return fd;
}
+
#endif
/* Close a temporary file.
diff --git a/lib/clean-temp.h b/lib/clean-temp.h
index df7e744..d660b18 100644
--- a/lib/clean-temp.h
+++ b/lib/clean-temp.h
@@ -164,10 +164,12 @@ extern FILE * fopen_temp (const char *file_name, const char *mode,
FILE_NAME_TMPL must match the rules for mk[s]temp (i.e. end in "XXXXXX",
possibly with a suffix). The name constructed does not exist at the time
of the call. FILE_NAME_TMPL is overwritten with the result.
+ A safe choice for MODE is S_IRUSR | S_IWUSR, a.k.a. 0600.
Registers the file for deletion.
- Opens the file, with the given FLAGS and mode 0600.
+ Opens the file, with the given FLAGS and mode MODE.
Registers the resulting file descriptor to be closed. */
-extern int gen_register_open_temp (char *file_name_tmpl, int suffixlen, int flags);
+extern int gen_register_open_temp (char *file_name_tmpl, int suffixlen,
+ int flags, mode_t mode);
/* Close a temporary file.
FD must have been returned by open_temp or gen_register_open_temp.
^ permalink raw reply related [flat|nested] 2+ messages in thread
end of thread, other threads:[~2020-07-04 16:09 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-07-04 13:30 clean-temp: add support for temporary files anywhere Bruno Haible
2020-07-04 16:08 ` Bruno Haible
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).