From e99991940478d76062c4ab8e44a5747354e33259 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Thu, 29 Jul 2010 22:08:33 -0700 Subject: [PATCH] temp-file: New functions for creating temporary files honoring $TMPDIR. The tmpfile() function is useful, but it doesn't necessarily honor the $TMPDIR environment variable. Some of our users find that a problem, so this commit replaces tmpfile() usage by a new pair of functions create_temp_file() and close_temp_file() that do honor $TMPDIR. Bug #30530. --- Smake | 2 +- src/language/stats/flip.c | 10 ++--- src/libpspp/automake.mk | 2 + src/libpspp/ext-array.c | 13 +++--- src/libpspp/pool.c | 85 ++++++++++++++++++++++++++++++--------- src/libpspp/pool.h | 9 ++++- src/libpspp/temp-file.c | 70 ++++++++++++++++++++++++++++++++ src/libpspp/temp-file.h | 27 +++++++++++++ src/output/odt.c | 15 +++---- tests/automake.mk | 9 ++++- 10 files changed, 198 insertions(+), 44 deletions(-) create mode 100644 src/libpspp/temp-file.c create mode 100644 src/libpspp/temp-file.h diff --git a/Smake b/Smake index d6ebd795bf..b90bdbe829 100644 --- a/Smake +++ b/Smake @@ -9,6 +9,7 @@ GNULIB_MODULES = \ byteswap \ c-ctype \ c-strtod \ + clean-temp \ close \ configmake \ count-one-bits \ @@ -71,7 +72,6 @@ GNULIB_MODULES = \ strtoul \ sys_stat \ tempname \ - tmpfile \ trunc \ unilbrk/ulc-width-linebreaks \ unistd \ diff --git a/src/language/stats/flip.c b/src/language/stats/flip.c index 8f73c1deba..de7f52c043 100644 --- a/src/language/stats/flip.c +++ b/src/language/stats/flip.c @@ -144,7 +144,7 @@ cmd_flip (struct lexer *lexer, struct dataset *ds) } } - flip->file = pool_tmpfile (flip->pool); + flip->file = pool_create_temp_file (flip->pool); if (flip->file == NULL) { msg (SE, _("Could not create temporary file for FLIP.")); @@ -328,7 +328,7 @@ flip_file (struct flip_pgm *flip) return false; } - output_file = pool_tmpfile (flip->pool); + output_file = pool_create_temp_file (flip->pool); if (output_file == NULL) { msg (SE, _("Error creating FLIP source file.")); @@ -379,11 +379,7 @@ flip_file (struct flip_pgm *flip) case_idx += read_cases; } - if (pool_fclose (flip->pool, input_file) == EOF) - { - msg (SE, _("Error closing FLIP source file: %s."), strerror (errno)); - return false; - } + pool_fclose_temp_file (flip->pool, input_file); pool_unregister (flip->pool, input_buf); free (input_buf); diff --git a/src/libpspp/automake.mk b/src/libpspp/automake.mk index 5cf669553b..de7912bb08 100644 --- a/src/libpspp/automake.mk +++ b/src/libpspp/automake.mk @@ -84,6 +84,8 @@ src_libpspp_libpspp_la_SOURCES = \ src/libpspp/str.h \ src/libpspp/taint.c \ src/libpspp/taint.h \ + src/libpspp/temp-file.c \ + src/libpspp/temp-file.h \ src/libpspp/tower.c \ src/libpspp/tower.h \ src/libpspp/version.h \ diff --git a/src/libpspp/ext-array.c b/src/libpspp/ext-array.c index df3b589fe0..b1eded3a3f 100644 --- a/src/libpspp/ext-array.c +++ b/src/libpspp/ext-array.c @@ -19,17 +19,18 @@ #include -#include +#include "libpspp/ext-array.h" #include #include #include -#include -#include +#include "libpspp/assertion.h" +#include "libpspp/cast.h" +#include "libpspp/temp-file.h" -#include "error.h" -#include "xalloc.h" +#include "gl/error.h" +#include "gl/xalloc.h" #include "gettext.h" #define _(msgid) gettext (msgid) @@ -50,7 +51,7 @@ struct ext_array * ext_array_create (void) { struct ext_array *ea = xmalloc (sizeof *ea); - ea->file = tmpfile (); + ea->file = create_temp_file (); if (ea->file == NULL) error (0, errno, _("failed to create temporary file")); ea->position = 0; diff --git a/src/libpspp/pool.c b/src/libpspp/pool.c index dbdd71b6cb..7a8a591da5 100644 --- a/src/libpspp/pool.c +++ b/src/libpspp/pool.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2000 Free Software Foundation, Inc. + Copyright (C) 2000, 2010 Free Software Foundation, Inc. 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 @@ -15,14 +15,18 @@ along with this program. If not, see . */ #include -#include "pool.h" + +#include "libpspp/pool.h" + #include #include -#include -#include "message.h" -#include "str.h" -#include "xalloc.h" +#include "libpspp/assertion.h" +#include "libpspp/message.h" +#include "libpspp/temp-file.h" +#include "libpspp/str.h" + +#include "gl/xalloc.h" /* Fast, low-overhead memory block suballocator. */ struct pool @@ -45,6 +49,7 @@ enum { POOL_GIZMO_MALLOC, POOL_GIZMO_FILE, + POOL_GIZMO_TEMP_FILE, POOL_GIZMO_SUBPOOL, POOL_GIZMO_REGISTERED, }; @@ -64,7 +69,7 @@ struct pool_gizmo /* Type-dependent info. */ union { - FILE *file; /* POOL_GIZMO_FILE. */ + FILE *file; /* POOL_GIZMO_FILE, POOL_GIZMO_TEMP_FILE. */ struct pool *subpool; /* POOL_GIZMO_SUBPOOL. */ /* POOL_GIZMO_REGISTERED. */ @@ -755,41 +760,78 @@ pool_fclose (struct pool *pool, FILE *file) return fclose (file); } -/* Creates a temporary file with tmpfile() and returns a handle to it - if successful or a null pointer if not. +/* Attaches FILE to POOL. The file will be closed automatically when POOL is destroyed, or it may be closed explicitly in advance using pool_fclose(), or detached from the pool with pool_detach_file(). */ +void +pool_attach_file (struct pool *pool, FILE *file) +{ + struct pool_gizmo *g = pool_alloc (pool, sizeof *g); + g->type = POOL_GIZMO_FILE; + g->p.file = file; + add_gizmo (pool, g); +} + +/* Detaches FILE from POOL. */ +void +pool_detach_file (struct pool *pool, FILE *file) +{ + struct pool_gizmo *g; + + for (g = pool->gizmos; g; g = g->next) + if (g->type == POOL_GIZMO_FILE && g->p.file == file) + { + delete_gizmo (pool, g); + return; + } +} + +/* Creates a temporary file with create_temp_file() and returns a handle to it + if successful or a null pointer if not. + The file will be closed automatically when POOL is destroyed, or it + may be closed explicitly in advance using pool_fclose_temp_file(), or + detached from the pool with pool_detach_temp_file(). */ FILE * -pool_tmpfile (struct pool *pool) +pool_create_temp_file (struct pool *pool) { - FILE *file = tmpfile (); + FILE *file = create_temp_file (); if (file != NULL) - pool_attach_file (pool, file); + pool_attach_temp_file (pool, file); return file; } -/* Attaches FILE to POOL. +/* Closes file FILE managed by POOL. + FILE must have been opened with create_temp_file(). */ +void +pool_fclose_temp_file (struct pool *pool, FILE *file) +{ + assert (pool && file); + pool_detach_temp_file (pool, file); + close_temp_file (file); +} + +/* Attaches FILE, which must have been opened with create_temp_file(), to POOL. The file will be closed automatically when POOL is destroyed, or it - may be closed explicitly in advance using pool_fclose(), or - detached from the pool with pool_detach_file(). */ + may be closed explicitly in advance using pool_fclose_temp_file(), or + detached from the pool with pool_detach_temp_file(). */ void -pool_attach_file (struct pool *pool, FILE *file) +pool_attach_temp_file (struct pool *pool, FILE *file) { struct pool_gizmo *g = pool_alloc (pool, sizeof *g); - g->type = POOL_GIZMO_FILE; + g->type = POOL_GIZMO_TEMP_FILE; g->p.file = file; add_gizmo (pool, g); } -/* Detaches FILE from POOL. */ +/* Detaches FILE that was opened with create_temp_file() from POOL. */ void -pool_detach_file (struct pool *pool, FILE *file) +pool_detach_temp_file (struct pool *pool, FILE *file) { struct pool_gizmo *g; for (g = pool->gizmos; g; g = g->next) - if (g->type == POOL_GIZMO_FILE && g->p.file == file) + if (g->type == POOL_GIZMO_TEMP_FILE && g->p.file == file) { delete_gizmo (pool, g); return; @@ -947,6 +989,9 @@ free_gizmo (struct pool_gizmo *gizmo) case POOL_GIZMO_FILE: fclose (gizmo->p.file); /* Ignore errors. */ break; + case POOL_GIZMO_TEMP_FILE: + close_temp_file (gizmo->p.file); /* Ignore errors. */ + break; case POOL_GIZMO_SUBPOOL: gizmo->p.subpool->parent = NULL; pool_destroy (gizmo->p.subpool); diff --git a/src/libpspp/pool.h b/src/libpspp/pool.h index fc24b2f9e6..da95f4ec7c 100644 --- a/src/libpspp/pool.h +++ b/src/libpspp/pool.h @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2000, 2006 Free Software Foundation, Inc. + Copyright (C) 2000, 2006, 2010 Free Software Foundation, Inc. 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 @@ -85,10 +85,15 @@ void pool_add_subpool (struct pool *, struct pool *subpool); /* Files. */ FILE *pool_fopen (struct pool *, const char *, const char *); int pool_fclose (struct pool *, FILE *) WARN_UNUSED_RESULT; -FILE *pool_tmpfile (struct pool *); void pool_attach_file (struct pool *, FILE *); void pool_detach_file (struct pool *, FILE *); +/* Temporary files. */ +FILE *pool_create_temp_file (struct pool *); +void pool_fclose_temp_file (struct pool *, FILE *); +void pool_attach_temp_file (struct pool *, FILE *); +void pool_detach_temp_file (struct pool *, FILE *); + /* Custom allocations. */ void pool_register (struct pool *, void (*free) (void *), void *p); bool pool_unregister (struct pool *, void *); diff --git a/src/libpspp/temp-file.c b/src/libpspp/temp-file.c new file mode 100644 index 0000000000..c1ffbea664 --- /dev/null +++ b/src/libpspp/temp-file.c @@ -0,0 +1,70 @@ +/* PSPP - a program for statistical analysis. + Copyright (C) 2010 Free Software Foundation, Inc. + + 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 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 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, see . */ + +/* Functions for temporary files that honor $TMPDIR. */ + +#include + +#include "libpspp/temp-file.h" + +#include + +#include "gl/clean-temp.h" +#include "gl/xvasprintf.h" + +/* Creates and returns a new temporary file that will be removed automatically + when the process exits. The file is opened in mode "wb+". To close the + file before the process exits, use close_temp_file() to ensure that it gets + deleted early. + + Returns NULL if creating the temporary file fails. + + This is similar to tmpfile(), except: + + - It honors the $TMPDIR environment variable. + + - The file will not be automatically deleted upon close. You have to call + close_temp_file() if you want it to be deleted before the process exits. +*/ +FILE * +create_temp_file (void) +{ + static int idx = 0; + static struct temp_dir *temp_dir; + char *file_name; + FILE *stream; + + if (temp_dir == NULL) + { + temp_dir = create_temp_dir ("pspp", NULL, true); + if (temp_dir == NULL) + return NULL; + } + + file_name = xasprintf ("%s/%d", temp_dir->dir_name, idx++); + stream = fopen_temp (file_name, "wb+"); + free (file_name); + + return stream; +} + +/* Closes and removes a temporary file created by create_temp_file(). */ +void +close_temp_file (FILE *file) +{ + if (file != NULL) + fclose_temp (file); +} diff --git a/src/libpspp/temp-file.h b/src/libpspp/temp-file.h new file mode 100644 index 0000000000..499c1e3488 --- /dev/null +++ b/src/libpspp/temp-file.h @@ -0,0 +1,27 @@ +/* PSPP - a program for statistical analysis. + Copyright (C) 2010 Free Software Foundation, Inc. + + 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 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 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, see . */ + +/* Functions for temporary files that honor $TMPDIR. */ + +#ifndef LIBPSPP_TEMP_FILE_H +#define LIBPSPP_TEMP_FILE_H 1 + +#include + +FILE *create_temp_file (void); +void close_temp_file (FILE *); + +#endif /* libpspp/ext-array.h */ diff --git a/src/output/odt.c b/src/output/odt.c index 49a55b4cce..906323964c 100644 --- a/src/output/odt.c +++ b/src/output/odt.c @@ -32,6 +32,7 @@ #include "libpspp/assertion.h" #include "libpspp/cast.h" #include "libpspp/str.h" +#include "libpspp/temp-file.h" #include "libpspp/version.h" #include "libpspp/zip-writer.h" #include "output/driver-provider.h" @@ -87,7 +88,7 @@ create_mimetype (struct zip_writer *zip) { FILE *fp; - fp = tmpfile (); + fp = create_temp_file (); if (fp == NULL) { error (0, errno, _("error creating temporary file")); @@ -96,7 +97,7 @@ create_mimetype (struct zip_writer *zip) fprintf (fp, "application/vnd.oasis.opendocument.text"); zip_writer_add (zip, fp, "mimetype"); - fclose (fp); + close_temp_file (fp); return true; } @@ -107,7 +108,7 @@ static void create_writer (FILE **file, xmlTextWriterPtr *w) { /* XXX this can fail */ - *file = tmpfile (); + *file = create_temp_file (); *w = xmlNewTextWriter (xmlOutputBufferCreateFile (*file, NULL)); xmlTextWriterStartDocument (*w, NULL, "UTF-8", NULL); @@ -218,7 +219,7 @@ write_style_data (struct odt_driver *odt) xmlTextWriterEndDocument (w); xmlFreeTextWriter (w); zip_writer_add (odt->zip, file, "styles.xml"); - fclose (file); + close_temp_file (file); } static void @@ -282,7 +283,7 @@ write_meta_data (struct odt_driver *odt) xmlTextWriterEndDocument (w); xmlFreeTextWriter (w); zip_writer_add (odt->zip, file, "meta.xml"); - fclose (file); + close_temp_file (file); } static struct output_driver * @@ -355,7 +356,7 @@ odt_create (const char *file_name, enum settings_output_devices device_type, xmlTextWriterEndDocument (odt->manifest_wtr); xmlFreeTextWriter (odt->manifest_wtr); zip_writer_add (odt->zip, odt->manifest_file, "META-INF/manifest.xml"); - fclose (odt->manifest_file); + close_temp_file (odt->manifest_file); return d; } @@ -374,7 +375,7 @@ odt_destroy (struct output_driver *driver) xmlTextWriterEndDocument (odt->content_wtr); xmlFreeTextWriter (odt->content_wtr); zip_writer_add (odt->zip, odt->content_file, "content.xml"); - fclose (odt->content_file); + close_temp_file (odt->content_file); zip_writer_close (odt->zip); } diff --git a/tests/automake.mk b/tests/automake.mk index 46524f9aa2..d4db922465 100644 --- a/tests/automake.mk +++ b/tests/automake.mk @@ -207,6 +207,7 @@ tests_libpspp_heap_test_SOURCES = \ src/libpspp/heap.h \ src/libpspp/pool.c \ src/libpspp/pool.h \ + src/libpspp/temp-file.c \ tests/libpspp/heap-test.c tests_libpspp_heap_test_LDADD = gl/libgl.la $(LIBINTL) tests_libpspp_heap_test_CPPFLAGS = $(AM_CPPFLAGS) -DASSERT_LEVEL=10 @@ -257,6 +258,7 @@ tests_libpspp_range_set_test_SOURCES = \ src/libpspp/pool.h \ src/libpspp/range-set.c \ src/libpspp/range-set.h \ + src/libpspp/temp-file.c \ tests/libpspp/range-set-test.c tests_libpspp_range_set_test_LDADD = gl/libgl.la $(LIBINTL) tests_libpspp_range_set_test_CPPFLAGS = $(AM_CPPFLAGS) -DASSERT_LEVEL=10 @@ -282,6 +284,7 @@ tests_libpspp_stringi_map_test_SOURCES = \ src/libpspp/stringi-map.c \ src/libpspp/string-set.c \ src/libpspp/stringi-set.c \ + src/libpspp/temp-file.c \ tests/libpspp/stringi-map-test.c tests_libpspp_stringi_map_test_LDADD = gl/libgl.la $(LIBINTL) tests_libpspp_stringi_map_test_CPPFLAGS = $(AM_CPPFLAGS) -DASSERT_LEVEL=10 @@ -300,6 +303,7 @@ tests_libpspp_stringi_set_test_SOURCES = \ src/libpspp/pool.c \ src/libpspp/str.c \ src/libpspp/stringi-set.c \ + src/libpspp/temp-file.c \ tests/libpspp/stringi-set-test.c tests_libpspp_stringi_set_test_LDADD = gl/libgl.la $(LIBINTL) tests_libpspp_stringi_set_test_CPPFLAGS = $(AM_CPPFLAGS) -DASSERT_LEVEL=10 @@ -309,6 +313,7 @@ tests_libpspp_tower_test_SOURCES = \ src/libpspp/abt.h \ src/libpspp/pool.c \ src/libpspp/pool.h \ + src/libpspp/temp-file.c \ src/libpspp/tower.c \ src/libpspp/tower.h \ tests/libpspp/tower-test.c @@ -320,7 +325,8 @@ tests_libpspp_sparse_array_test_SOURCES = \ src/libpspp/sparse-array.h \ src/libpspp/pool.c \ src/libpspp/pool.h \ - tests/libpspp/sparse-array-test.c + tests/libpspp/sparse-array-test.c \ + src/libpspp/temp-file.c tests_libpspp_sparse_array_test_LDADD = gl/libgl.la $(LIBINTL) tests_libpspp_sparse_array_test_CPPFLAGS = $(AM_CPPFLAGS) -DASSERT_LEVEL=10 @@ -335,6 +341,7 @@ tests_libpspp_sparse_xarray_test_SOURCES = \ src/libpspp/sparse-xarray.c \ src/libpspp/str.c \ src/libpspp/pool.c \ + src/libpspp/temp-file.c \ tests/libpspp/sparse-xarray-test.c tests_libpspp_sparse_xarray_test_LDADD = gl/libgl.la $(LIBINTL) tests_libpspp_sparse_xarray_test_CPPFLAGS = $(AM_CPPFLAGS) -DASSERT_LEVEL=10 -- 2.30.2