Mercurial > hg > octave-lyh > gnulib-hg
changeset 7411:67235cf9199a
Have clean-temp register file open descriptors to temporary files.
author | Bruno Haible <bruno@clisp.org> |
---|---|
date | Fri, 06 Oct 2006 12:17:22 +0000 |
parents | 9704ff2cbdfe |
children | 066c3e27ecd1 |
files | ChangeLog lib/ChangeLog lib/clean-temp.c lib/clean-temp.h modules/fwriteerror |
diffstat | 5 files changed, 199 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2006-10-05 Bruno Haible <bruno@clisp.org> + + * modules/fwriteerror (configure.ac): Define GNULIB_FWRITEERROR. + 2006-10-02 Eric Blake <ebb9@byu.net> * modules/strnlen (Depends-on): Add extensions.
--- a/lib/ChangeLog +++ b/lib/ChangeLog @@ -1,3 +1,13 @@ +2006-10-05 Bruno Haible <bruno@clisp.org> + + * clean-temp.h (open_temp, fopen_temp, close_temp, fclose_temp, + fwriteerror_temp): New declarations. + * clean-temp.c (uintptr_t): Provide fallback definition. + (descriptors): New variable. + (cleanup): First, close the descriptors. + (register_fd, unregister_fd, open_temp, fopen_temp, close_temp, + fclose_temp, fwriteerror_temp): New functions. + 2006-10-03 Bruno Haible * gl_list.h (gl_sortedlist_search_from_to,
--- a/lib/clean-temp.c +++ b/lib/clean-temp.c @@ -41,6 +41,10 @@ #define _(str) gettext (str) +#ifndef uintptr_t +# define uintptr_t unsigned long +#endif + /* The use of 'volatile' in the types below (and ISO C 99 section 5.1.2.3.(5)) ensure that while constructing or modifying the data structures, the field @@ -70,6 +74,9 @@ size_t tempdir_allocated; } cleanup_list /* = { NULL, 0, 0 } */; +/* List of all open file descriptors to temporary files. */ +static gl_list_t /* <int> */ volatile descriptors; + /* For the subdirs and for the files, we use a gl_list_t of type LINKEDHASH. Why? We need a data structure that @@ -154,6 +161,25 @@ { size_t i; + /* First close all file descriptors to temporary files. */ + { + gl_list_t fds = descriptors; + + if (fds != NULL) + { + gl_list_iterator_t iter; + const void *element; + + iter = gl_list_iterator (fds); + while (gl_list_iterator_next (&iter, &element, NULL)) + { + int fd = (int) (uintptr_t) element; + close (fd); + } + gl_list_iterator_free (&iter); + } + } + for (i = 0; i < cleanup_list.tempdir_count; i++) { struct tempdir *dir = cleanup_list.tempdir_list[i]; @@ -481,3 +507,140 @@ /* The user passed an invalid DIR argument. */ abort (); } + + +/* Register a file descriptor to be closed. */ +static void +register_fd (int fd) +{ + if (descriptors == NULL) + descriptors = gl_list_create_empty (GL_LINKEDHASH_LIST, NULL, NULL, false); + gl_list_add_first (descriptors, (void *) (uintptr_t) fd); +} + +/* Unregister a file descriptor to be closed. */ +static void +unregister_fd (int fd) +{ + gl_list_t fds = descriptors; + gl_list_node_t node; + + if (fds == NULL) + /* descriptors should already contain fd. */ + abort (); + node = gl_list_search (fds, (void *) (uintptr_t) fd); + if (node == NULL) + /* descriptors should already contain fd. */ + abort (); + gl_list_remove_node (fds, node); +} + +/* Open a temporary file in a temporary directory. + Registers the resulting file descriptor to be closed. */ +int +open_temp (const char *file_name, int flags, mode_t mode) +{ + int fd; + int saved_errno; + + block_fatal_signals (); + fd = open (file_name, flags, mode); + saved_errno = errno; + if (fd >= 0) + register_fd (fd); + unblock_fatal_signals (); + errno = saved_errno; + return fd; +} + +/* Open a temporary file in a temporary directory. + Registers the resulting file descriptor to be closed. */ +FILE * +fopen_temp (const char *file_name, const char *mode) +{ + FILE *fp; + int saved_errno; + + block_fatal_signals (); + fp = fopen (file_name, mode); + saved_errno = errno; + if (fp != NULL) + { + /* It is sufficient to register fileno (fp) instead of the entire fp, + because at cleanup time there is no need to do an fflush (fp); a + close (fileno (fp)) will be enough. */ + int fd = fileno (fp); + if (!(fd >= 0)) + abort (); + register_fd (fd); + } + unblock_fatal_signals (); + errno = saved_errno; + return fp; +} + +/* Close a temporary file in a temporary directory. + Unregisters the previously registered file descriptor. */ +int +close_temp (int fd) +{ + if (fd >= 0) + { + /* No blocking of signals is needed here, since a double close of a + file descriptor is harmless. */ + int result = close (fd); + int saved_errno = errno; + + /* No race condition here: we assume a single-threaded program, hence + fd cannot be re-opened here. */ + + unregister_fd (fd); + + errno = saved_errno; + return result; + } + else + return close (fd); +} + +/* Close a temporary file in a temporary directory. + Unregisters the previously registered file descriptor. */ +int +fclose_temp (FILE *fp) +{ + int fd = fileno (fp); + /* No blocking of signals is needed here, since a double close of a + file descriptor is harmless. */ + int result = fclose (fp); + int saved_errno = errno; + + /* No race condition here: we assume a single-threaded program, hence + fd cannot be re-opened here. */ + + unregister_fd (fd); + + errno = saved_errno; + return result; +} + +#if GNULIB_FWRITEERROR +/* Like fwriteerror. + Unregisters the previously registered file descriptor. */ +int +fwriteerror_temp (FILE *fp) +{ + int fd = fileno (fp); + /* No blocking of signals is needed here, since a double close of a + file descriptor is harmless. */ + int result = fwriteerror (fp); + int saved_errno = errno; + + /* No race condition here: we assume a single-threaded program, hence + fd cannot be re-opened here. */ + + unregister_fd (fd); + + errno = saved_errno; + return result; +} +#endif
--- a/lib/clean-temp.h +++ b/lib/clean-temp.h @@ -20,6 +20,8 @@ #define _CLEAN_TEMP_H #include <stdbool.h> +#include <stdio.h> +#include <sys/types.h> #ifdef __cplusplus extern "C" { @@ -32,6 +34,10 @@ also - if no signal blocking is used - leaves a time window where a fatal signal would not clean up the temporary file. + Also, open file descriptors need to be closed before the temporary files + and the temporary directories can be removed, because only on Unix + (excluding Cygwin) one can 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. */ @@ -98,6 +104,20 @@ DIR cannot be used any more after this call. */ extern void cleanup_temp_dir (struct temp_dir *dir); +/* Open a temporary file in a temporary directory. + Registers the resulting file descriptor to be closed. */ +extern int open_temp (const char *file_name, int flags, mode_t mode); +extern FILE * fopen_temp (const char *file_name, const char *mode); + +/* Close a temporary file in a temporary directory. + Unregisters the previously registered file descriptor. */ +extern int close_temp (int fd); +extern int fclose_temp (FILE *fp); + +/* Like fwriteerror. + Unregisters the previously registered file descriptor. */ +extern int fwriteerror_temp (FILE *fp); + #ifdef __cplusplus }