temp-file: New functions for creating temporary files honoring $TMPDIR.
authorBen Pfaff <blp@cs.stanford.edu>
Fri, 30 Jul 2010 05:08:33 +0000 (22:08 -0700)
committerBen Pfaff <blp@cs.stanford.edu>
Fri, 30 Jul 2010 05:08:33 +0000 (22:08 -0700)
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
src/language/stats/flip.c
src/libpspp/automake.mk
src/libpspp/ext-array.c
src/libpspp/pool.c
src/libpspp/pool.h
src/libpspp/temp-file.c [new file with mode: 0644]
src/libpspp/temp-file.h [new file with mode: 0644]
src/output/odt.c
tests/automake.mk

diff --git a/Smake b/Smake
index d6ebd795bf78db820bd6ceffe2e5d2516ef95979..b90bdbe829d252f9474b4771876d58caf4751515 100644 (file)
--- 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 \
index 8f73c1debabfc0b1898f1429f6c344b345f378b5..de7f52c043bcb4d85fa263d3fc91debd8e916488 100644 (file)
@@ -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);
 
index 5cf669553b1144e3ffc775d57f6639a7d6509bb7..de7912bb08cd81f7f9bbb8bda8dc8819c72eba9f 100644 (file)
@@ -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 \
index df3b589fe0c893dad1828c52e86b2542ce78f5b4..b1eded3a3f4d41e658dd2c5aad57d4991e251bc7 100644 (file)
 
 #include <config.h>
 
-#include <libpspp/ext-array.h>
+#include "libpspp/ext-array.h"
 
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
 
-#include <libpspp/assertion.h>
-#include <libpspp/cast.h>
+#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;
index dbdd71b6cbbf250fbb91248e6c8cc820da13e4f0..7a8a591da58a7e84ebaf6952f784cec17f7571d0 100644 (file)
@@ -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
    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 
 #include <config.h>
-#include "pool.h"
+
+#include "libpspp/pool.h"
+
 #include <stdint.h>
 #include <stdlib.h>
-#include <libpspp/assertion.h>
-#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);
index fc24b2f9e6ff0ae38221a2ac7f9d3bba60aa8fbf..da95f4ec7ca243066987820128123a082020cfb3 100644 (file)
@@ -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 (file)
index 0000000..c1ffbea
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>. */
+
+/* Functions for temporary files that honor $TMPDIR. */
+
+#include <config.h>
+
+#include "libpspp/temp-file.h"
+
+#include <stdlib.h>
+
+#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 (file)
index 0000000..499c1e3
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>. */
+
+/* Functions for temporary files that honor $TMPDIR. */
+
+#ifndef LIBPSPP_TEMP_FILE_H
+#define LIBPSPP_TEMP_FILE_H 1
+
+#include <stdio.h>
+
+FILE *create_temp_file (void);
+void close_temp_file (FILE *);
+
+#endif /* libpspp/ext-array.h */
index 49a55b4ccef3cbf9d3827607f673397d2f3cb670..906323964cb85ca13eddec3d4b8078a194946b9a 100644 (file)
@@ -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);
     }
index 46524f9aa233a762ff53d70fa80d4f3725cde78e..d4db92246598cf25c36c4e6b34b7883537d795a5 100644 (file)
@@ -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