/* Temporary directories and temporary files with automatic cleanup.
- Copyright (C) 2001, 2003, 2006-2007 Free Software Foundation, Inc.
+ Copyright (C) 2001, 2003, 2006-2007, 2009-2010 Free Software Foundation,
+ Inc.
Written by Bruno Haible <bruno@clisp.org>, 2006.
- This program is free software; you can redistribute it and/or modify
+ This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software Foundation,
- Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include <config.h>
#include "fatal-signal.h"
#include "pathmax.h"
#include "tmpdir.h"
-#include "mkdtemp.h"
#include "xalloc.h"
-#include "xallocsa.h"
+#include "xmalloca.h"
+#include "gl_xlist.h"
#include "gl_linkedhash_list.h"
#include "gettext.h"
#if GNULIB_FWRITEERROR
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);
+ 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);
}
}
struct tempdir *dir = cleanup_list.tempdir_list[i];
if (dir != NULL)
- {
- gl_list_iterator_t iter;
- const void *element;
-
- /* First cleanup the files in the subdirectories. */
- iter = gl_list_iterator (dir->files);
- while (gl_list_iterator_next (&iter, &element, NULL))
- {
- const char *file = (const char *) element;
- unlink (file);
- }
- gl_list_iterator_free (&iter);
-
- /* Then cleanup the subdirectories. */
- iter = gl_list_iterator (dir->subdirs);
- while (gl_list_iterator_next (&iter, &element, NULL))
- {
- const char *subdir = (const char *) element;
- rmdir (subdir);
- }
- gl_list_iterator_free (&iter);
-
- /* Then cleanup the temporary directory itself. */
- rmdir (dir->dirname);
- }
+ {
+ gl_list_iterator_t iter;
+ const void *element;
+
+ /* First cleanup the files in the subdirectories. */
+ iter = gl_list_iterator (dir->files);
+ while (gl_list_iterator_next (&iter, &element, NULL))
+ {
+ const char *file = (const char *) element;
+ unlink (file);
+ }
+ gl_list_iterator_free (&iter);
+
+ /* Then cleanup the subdirectories. */
+ iter = gl_list_iterator (dir->subdirs);
+ while (gl_list_iterator_next (&iter, &element, NULL))
+ {
+ const char *subdir = (const char *) element;
+ rmdir (subdir);
+ }
+ gl_list_iterator_free (&iter);
+
+ /* Then cleanup the temporary directory itself. */
+ rmdir (dir->dirname);
+ }
}
}
is shown and NULL is returned. */
struct temp_dir *
create_temp_dir (const char *prefix, const char *parentdir,
- bool cleanup_verbose)
+ bool cleanup_verbose)
{
struct tempdir * volatile *tmpdirp = NULL;
struct tempdir *tmpdir;
for (i = 0; i < cleanup_list.tempdir_count; i++)
if (cleanup_list.tempdir_list[i] == NULL)
{
- tmpdirp = &cleanup_list.tempdir_list[i];
- break;
+ tmpdirp = &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)
- {
- /* 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 *new_array =
- XNMALLOC (new_allocated, struct tempdir * volatile);
-
- if (old_allocated == 0)
- /* First use of this facility. Register the cleanup handler. */
- at_fatal_signal (&cleanup);
- else
- {
- /* Don't use memcpy() here, because memcpy takes non-volatile
- arguments and is therefore not guaranteed to complete all
- memory stores before the next statement. */
- size_t k;
-
- for (k = 0; k < old_allocated; k++)
- new_array[k] = old_array[k];
- }
-
- cleanup_list.tempdir_list = new_array;
- cleanup_list.tempdir_allocated = new_allocated;
-
- /* Now we can free the old array. */
- if (old_array != NULL)
- free ((struct tempdir **) old_array);
- }
+ {
+ /* 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 *new_array =
+ XNMALLOC (new_allocated, struct tempdir * volatile);
+
+ if (old_allocated == 0)
+ /* First use of this facility. Register the cleanup handler. */
+ at_fatal_signal (&cleanup);
+ else
+ {
+ /* Don't use memcpy() here, because memcpy takes non-volatile
+ arguments and is therefore not guaranteed to complete all
+ memory stores before the next statement. */
+ size_t k;
+
+ for (k = 0; k < old_allocated; k++)
+ new_array[k] = old_array[k];
+ }
+
+ cleanup_list.tempdir_list = new_array;
+ cleanup_list.tempdir_allocated = new_allocated;
+
+ /* Now we can free the old array. */
+ if (old_array != NULL)
+ free ((struct tempdir **) old_array);
+ }
tmpdirp = &cleanup_list.tempdir_list[cleanup_list.tempdir_count];
/* Initialize *tmpdirp before incrementing tempdir_count, so that
- cleanup() will skip this entry before it is fully initialized. */
+ cleanup() will skip this entry before it is fully initialized. */
*tmpdirp = NULL;
cleanup_list.tempdir_count++;
}
tmpdir->dirname = NULL;
tmpdir->cleanup_verbose = cleanup_verbose;
tmpdir->subdirs = gl_list_create_empty (GL_LINKEDHASH_LIST,
- string_equals, string_hash, false);
+ string_equals, string_hash, NULL,
+ false);
tmpdir->files = gl_list_create_empty (GL_LINKEDHASH_LIST,
- string_equals, string_hash, false);
+ string_equals, string_hash, NULL,
+ false);
/* Create the temporary directory. */
- xtemplate = (char *) xallocsa (PATH_MAX);
+ xtemplate = (char *) xmalloca (PATH_MAX);
if (path_search (xtemplate, PATH_MAX, parentdir, prefix, parentdir == NULL))
{
error (0, errno,
- _("cannot find a temporary directory, try setting $TMPDIR"));
+ _("cannot find a temporary directory, try setting $TMPDIR"));
goto quit;
}
block_fatal_signals ();
if (tmpdirname == NULL)
{
error (0, errno,
- _("cannot create a temporary directory using template \"%s\""),
- xtemplate);
+ _("cannot create a temporary directory using template \"%s\""),
+ xtemplate);
goto quit;
}
/* Replace tmpdir->dirname with a copy that has indefinite extent.
block because then the cleanup handler would not remove the directory
if xstrdup fails. */
tmpdir->dirname = xstrdup (tmpdirname);
- freesa (xtemplate);
+ freea (xtemplate);
return (struct temp_dir *) tmpdir;
quit:
- freesa (xtemplate);
+ freea (xtemplate);
return NULL;
}
Should be called before the file ABSOLUTE_FILE_NAME is created. */
void
register_temp_file (struct temp_dir *dir,
- const char *absolute_file_name)
+ const char *absolute_file_name)
{
struct tempdir *tmpdir = (struct tempdir *)dir;
Should be called when the file ABSOLUTE_FILE_NAME could not be created. */
void
unregister_temp_file (struct temp_dir *dir,
- const char *absolute_file_name)
+ const char *absolute_file_name)
{
struct tempdir *tmpdir = (struct tempdir *)dir;
gl_list_t list = tmpdir->files;
Should be called before the subdirectory ABSOLUTE_DIR_NAME is created. */
void
register_temp_subdir (struct temp_dir *dir,
- const char *absolute_dir_name)
+ const char *absolute_dir_name)
{
struct tempdir *tmpdir = (struct tempdir *)dir;
created. */
void
unregister_temp_subdir (struct temp_dir *dir,
- const char *absolute_dir_name)
+ const char *absolute_dir_name)
{
struct tempdir *tmpdir = (struct tempdir *)dir;
gl_list_t list = tmpdir->subdirs;
&& errno != ENOENT)
{
error (0, errno,
- _("cannot remove temporary directory %s"), absolute_dir_name);
+ _("cannot remove temporary directory %s"), absolute_dir_name);
return -1;
}
return 0;
Return 0 upon success, or -1 if there was some problem. */
int
cleanup_temp_file (struct temp_dir *dir,
- const char *absolute_file_name)
+ const char *absolute_file_name)
{
int err;
Return 0 upon success, or -1 if there was some problem. */
int
cleanup_temp_subdir (struct temp_dir *dir,
- const char *absolute_dir_name)
+ const char *absolute_dir_name)
{
int err;
for (i = 0; i < cleanup_list.tempdir_count; i++)
if (cleanup_list.tempdir_list[i] == tmpdir)
{
- /* Remove cleanup_list.tempdir_list[i]. */
- if (i + 1 == cleanup_list.tempdir_count)
- {
- while (i > 0 && cleanup_list.tempdir_list[i - 1] == NULL)
- i--;
- cleanup_list.tempdir_count = i;
- }
- else
- cleanup_list.tempdir_list[i] = NULL;
- /* Now only we can free the tmpdir->dirname and tmpdir itself. */
- free (tmpdir->dirname);
- free (tmpdir);
- return err;
+ /* Remove cleanup_list.tempdir_list[i]. */
+ if (i + 1 == cleanup_list.tempdir_count)
+ {
+ while (i > 0 && cleanup_list.tempdir_list[i - 1] == NULL)
+ i--;
+ cleanup_list.tempdir_count = i;
+ }
+ else
+ cleanup_list.tempdir_list[i] = NULL;
+ /* Now only we can free the tmpdir->dirname and tmpdir itself. */
+ free (tmpdir->dirname);
+ free (tmpdir);
+ return err;
}
/* The user passed an invalid DIR argument. */
OSVERSIONINFO v;
if (GetVersionEx (&v))
- known = (v.dwPlatformId == VER_PLATFORM_WIN32_NT ? 1 : -1);
+ known = (v.dwPlatformId == VER_PLATFORM_WIN32_NT ? 1 : -1);
else
- known = -1;
+ known = -1;
}
return (known > 0);
}
register_fd (int fd)
{
if (descriptors == NULL)
- descriptors = gl_list_create_empty (GL_LINKEDHASH_LIST, NULL, NULL, false);
+ descriptors = gl_list_create_empty (GL_LINKEDHASH_LIST, NULL, NULL, NULL,
+ false);
gl_list_add_first (descriptors, (void *) (uintptr_t) fd);
}
if (supports_delete_on_close ())
{
size_t mode_len = strlen (mode);
- char *augmented_mode = (char *) xallocsa (mode_len + 2);
+ char *augmented_mode = (char *) xmalloca (mode_len + 2);
memcpy (augmented_mode, mode, mode_len);
memcpy (augmented_mode + mode_len, "D", 2);
fp = fopen (file_name, augmented_mode);
saved_errno = errno;
- freesa (augmented_mode);
+ freea (augmented_mode);
}
else
#endif
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. */
+ 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 ();
+ abort ();
register_fd (fd);
}
unblock_fatal_signals ();
if (fd >= 0)
{
/* No blocking of signals is needed here, since a double close of a
- file descriptor is harmless. */
+ 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. */
+ fd cannot be re-opened here. */
unregister_fd (fd);