X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Flibpspp%2Ftemp-file.c;h=cc90a37559b2cb532e8cc60f5589da531b8bd211;hb=3c7e6939901e8c2f24eb4975e6feb68e74678f92;hp=554a6d7d5f74276774057905fe2e71ef318df919;hpb=70514b3f2f32d57e58b04c01c83bc5f372559824;p=pspp diff --git a/src/libpspp/temp-file.c b/src/libpspp/temp-file.c index 554a6d7d5f..cc90a37559 100644 --- a/src/libpspp/temp-file.c +++ b/src/libpspp/temp-file.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2007, 2009, 2010 Free Software Foundation, Inc. + Copyright (C) 2010, 2011 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 @@ -14,154 +14,119 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/* A interface to allow a temporary file to be treated as an - array of data. */ +/* Functions for temporary files that honor $TMPDIR. */ #include -#include +#include "libpspp/temp-file.h" +#include "libpspp/hmapx.h" +#include "libpspp/hash-functions.h" -#include -#include #include -#include -#include +#include "gl/clean-temp.h" +#include "gl/xvasprintf.h" -#include "error.h" -#include "xalloc.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. -#include "gettext.h" -#define _(msgid) gettext (msgid) + Returns NULL if creating the temporary file fails. -struct temp_file - { - FILE *file; /* Underlying file. */ + This is similar to tmpfile(), except: - /* Current byte offset in file. We track this manually, - instead of using ftello, because in glibc ftello flushes - the stream buffer, making the common case of sequential - access to cases unreasonably slow. */ - off_t position; - }; + - It honors the $TMPDIR environment variable. -/* Creates and returns a new temporary file. The temporary file - will be automatically deleted when the process exits. */ -struct temp_file * -temp_file_create (void) +*/ + +static void cleanup (void); + +static struct temp_dir *temp_dir; +static struct hmapx map; + +static void +setup (void) { - struct temp_file *tf = xmalloc (sizeof *tf); - tf->file = tmpfile (); - if (tf->file == NULL) - error (0, errno, _("failed to create temporary file")); - tf->position = 0; - return tf; + hmapx_init (&map); + temp_dir = create_temp_dir ("pspp", NULL, true); } -/* Closes and destroys temporary file TF. Returns true if I/O on - TF always succeeded, false if an I/O error occurred at some - point. */ -bool -temp_file_destroy (struct temp_file *tf) +static void +initialise (void) { - bool ok = true; - if (tf != NULL) + if (temp_dir == NULL) { - ok = !temp_file_error (tf); - if (tf->file != NULL) - fclose (tf->file); - free (tf); + setup (); + if (temp_dir == NULL) + return ; + atexit (cleanup); } - return ok; } -/* Seeks TF's underlying file to the start of `union value' - VALUE_IDX within case CASE_IDX. - Returns true if the seek is successful and TF is not - otherwise tainted, false otherwise. */ -static bool -do_seek (const struct temp_file *tf_, off_t offset) + +const char * +temp_dir_name (void) { - struct temp_file *tf = CONST_CAST (struct temp_file *, tf_); + initialise (); - if (!temp_file_error (tf)) - { - if (tf->position == offset) - return true; - else if (fseeko (tf->file, offset, SEEK_SET) == 0) - { - tf->position = offset; - return true; - } - else - error (0, errno, _("seeking in temporary file")); - } + if (temp_dir) + return temp_dir->dir_name; - return false; + return NULL; } -/* Reads BYTES bytes from TF's underlying file into BUFFER. - TF must not be tainted upon entry into this function. - Returns true if successful, false upon an I/O error (in which - case TF is marked tainted). */ -static bool -do_read (const struct temp_file *tf_, void *buffer, size_t bytes) +static void +cleanup (void) { - struct temp_file *tf = CONST_CAST (struct temp_file *, tf_); + struct hmapx_node *node; + char *fn; - assert (!temp_file_error (tf)); - if (bytes > 0 && fread (buffer, bytes, 1, tf->file) != 1) - { - if (ferror (tf->file)) - error (0, errno, _("reading temporary file")); - else if (feof (tf->file)) - error (0, 0, _("unexpected end of file reading temporary file")); - else - NOT_REACHED (); - return false; - } - tf->position += bytes; - return true; -} + cleanup_temp_dir (temp_dir); -/* Writes BYTES bytes from BUFFER into TF's underlying file. - TF must not be tainted upon entry into this function. - Returns true if successful, false upon an I/O error (in which - case TF is marked tainted). */ -static bool -do_write (struct temp_file *tf, const void *buffer, size_t bytes) -{ - assert (!temp_file_error (tf)); - if (bytes > 0 && fwrite (buffer, bytes, 1, tf->file) != 1) + HMAPX_FOR_EACH (fn, node, &map) { - error (0, errno, _("writing to temporary file")); - return false; + free (fn); } - tf->position += bytes; - return true; -} -/* Reads N bytes from TF at byte offset OFFSET into DATA. - Returns true if successful, false on failure. */ -bool -temp_file_read (const struct temp_file *tf, off_t offset, size_t n, void *data) -{ - return do_seek (tf, offset) && do_read (tf, data, n); + hmapx_destroy (&map); } -/* Writes the N bytes in DATA to TF at byte offset OFFSET. - Returns true if successful, false on failure. */ -bool -temp_file_write (struct temp_file *tf, off_t offset, size_t n, - const void *data) +FILE * +create_temp_file (void) { - return do_seek (tf, offset) && do_write (tf, data, n); + static int idx = 0; + char *file_name; + FILE *stream; + + initialise (); + if (temp_dir == NULL) + return NULL; + + file_name = xasprintf ("%s/%d", temp_dir->dir_name, idx++); + register_temp_file (temp_dir, file_name); + stream = fopen_temp (file_name, "wb+", true); + if (stream == NULL) + unregister_temp_file (temp_dir, file_name); + else + setvbuf (stream, NULL, _IOFBF, 65536); + + hmapx_insert (&map, file_name, hash_pointer (stream, 0)); + + return stream; } -/* Returns true if an error has occurred in I/O on TF, - false if no error has been detected. */ -bool -temp_file_error (const struct temp_file *tf) +/* Closes and removes a temporary file created by create_temp_file(). */ +void +close_temp_file (FILE *file) { - return tf->file == NULL || ferror (tf->file) || feof (tf->file); + if (file != NULL) + { + struct hmapx_node *node = hmapx_first_with_hash (&map, hash_pointer (file, 0)); + char *fn = node->data; + fclose_temp (file); + cleanup_temp_file (temp_dir, fn); + hmapx_delete (&map, node); + free (fn); + } }