PLplot  5.10.0
plstdio.c
Go to the documentation of this file.
00001 // Standardized I/O handler for PLplot.
00002 //
00003 // Copyright (C) 2006  Jim Dishaw
00004 // Copyright (C) 2006  Hazen Babcock
00005 //
00006 // This file is part of PLplot.
00007 //
00008 // PLplot is free software; you can redistribute it and/or modify
00009 // it under the terms of the GNU Library General Public License as published
00010 // by the Free Software Foundation; either version 2 of the License, or
00011 // (at your option) any later version.
00012 //
00013 // PLplot is distributed in the hope that it will be useful,
00014 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016 // GNU Library General Public License for more details.
00017 //
00018 // You should have received a copy of the GNU Library General Public License
00019 // along with PLplot; if not, write to the Free Software
00020 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00021 //
00022 //
00023 
00024 #include "plplotP.h"
00025 
00026 #if defined ( MSDOS ) || defined ( WIN32 )
00027 #include <sys/types.h>
00028 #include <fcntl.h>
00029 #endif
00030 
00031 // This is needed for mode flags for mkfifo as well sa for MSDOS / WIN32
00032 #include <sys/stat.h>
00033 
00034 // For Visual C++ 2005 and later mktemp() and open() are deprecated (see
00035 // http://msdn.microsoft.com/en-us/library/ms235413.aspx and
00036 // http://msdn.microsoft.com/en-us/library/ms235491.aspx). mktemp()
00037 // is redefined to _mktemp() as well as open() to _open(). In addition
00038 // we need to include io.h.
00039 //
00040 #if defined ( _MSC_VER ) && _MSC_VER >= 1400
00041 #include <io.h>
00042 #define mktemp    _mktemp
00043 #define open      _open
00044 #define fdopen    _fdopen
00045 #endif
00046 //
00047 // plio_write()
00048 //
00049 // Writes the contents of buf to stream.  Handles any I/O error conditions
00050 // so that the caller can "fire and forget."
00051 //
00052 
00053 void
00054 plio_fwrite( void *buf, size_t size, size_t nmemb, FILE *stream )
00055 {
00056     dbug_enter( "plio_fwrite" );
00057 
00058     // Exit if there is nothing to write
00059     if ( size == 0 || nmemb == 0 )
00060         return;
00061 
00062     // Clear the error flag for this steam
00063     clearerr( stream );
00064 
00065     fwrite( buf, size, nmemb, stream );
00066 
00067     if ( ferror( stream ) )
00068     {
00069         // Perhaps we can add a flag (global or per output stream)
00070         // in order to decide if we should abort or warn.  I think
00071         // I/O errors should generate an abort
00072         plabort( "Error writing to file" );
00073     }
00074 }
00075 
00076 //
00077 // plio_fread()
00078 //
00079 // Read from stream into buf.  Like plio_write(), this function will
00080 // handle any I/O error conditions.
00081 //
00082 
00083 void
00084 plio_fread( void *buf, size_t size, size_t nmemb, FILE *stream )
00085 {
00086     size_t bytes;
00087 
00088     dbug_enter( "plio_fread" );
00089 
00090     // If the buffer has a size of zero, we should complain
00091     if ( size == 0 || nmemb == 0 )
00092     {
00093         plwarn( "Zero length buffer size in plio_fread, returning" );
00094         return;
00095     }
00096 
00097     // Clear the error flag for this steam
00098     clearerr( stream );
00099 
00100     bytes = fread( buf, size, nmemb, stream );
00101 
00102     if ( ( bytes < nmemb ) && ferror( stream ) )
00103     {
00104         // The read resulted in an error
00105         plabort( "Error reading from file" );
00106     }
00107 }
00108 
00109 //
00110 // plio_fgets()
00111 //
00112 // Read from stream into buf.  This version of fgets is designed for the occasions
00113 // where the caller wants to ignore the return value.
00114 //
00115 // NOTE: If one is reading from a file until an EOF condition, fgets() is better suited
00116 // than this function, i.e.
00117 //
00118 //     while(fgets(buf, size, fp) != NULL) { ... do some stuff ... }
00119 //
00120 // rather than
00121 //
00122 //     while(!feof(fp)) { plio_fgets(buf, size, fp);  ... do some stuff ... }
00123 //
00124 // which would require checking for an empty buffer.
00125 //
00126 
00127 void
00128 plio_fgets( char *buf, int size, FILE *stream )
00129 {
00130     char *s;
00131 
00132     dbug_enter( "plio_fgets" );
00133 
00134     // If the buffer has a size of zero, we should complain
00135     if ( size == 0 )
00136     {
00137         plwarn( "Zero length buffer size in plio_fgets, returning" );
00138         return;
00139     }
00140 
00141     // Clear the error flag for this steam
00142     clearerr( stream );
00143 
00144     s = fgets( buf, size, stream );
00145 
00146     if ( s == NULL && ferror( stream ) )
00147     {
00148         // The read resulted in an error
00149         plabort( "Error reading from file" );
00150     }
00151 }
00152 
00153 //
00154 // pl_create_tempfile()
00155 //
00156 // Securely create a temporary file and return a file handle to it.
00157 // This provides cross-platform compatibility and also adds some
00158 // additional functionality over mkstemp in that it honours the TMP /
00159 // TMPDIR / TEMP environment variables.
00160 //
00161 // The function returns the file handle.
00162 //
00163 // If the fname variable is not NULL, then on return it will contain
00164 // a pointer to the full temporary file name. This will be allocated
00165 // with malloc. It is the caller's responsibility to ensure this
00166 // memory is free'd and to ensure the file is deleted after use.
00167 // If fname is NULL then the file will be automatically deleted
00168 // when it is closed.
00169 //
00170 FILE *
00171 pl_create_tempfile( char **fname )
00172 {
00173     FILE       *fd;
00174     const char *tmpdir;
00175     char       *template;
00176     const char *tmpname = "plplot_XXXXXX";
00177 #if !defined PL_HAVE_MKSTEMP
00178     int        flags;
00179 #endif
00180 
00181 #if defined ( MSDOS ) || defined ( WIN32 )
00182     tmpdir = getenv( "TEMP" );
00183 #else
00184     tmpdir = getenv( "TMPDIR" );
00185 #endif
00186 
00187 // The P_TMPDIR macro is defined in stdio.h on many UNIX systems - try that
00188 #ifdef P_TMPDIR
00189     if ( tmpdir == NULL )
00190         tmpdir = P_TMPDIR;
00191 #endif
00192 
00193     if ( tmpdir == NULL )
00194     {
00195 #if defined ( MSDOS ) || defined ( WIN32 )
00196         tmpdir = "c:\\windows\\Temp";
00197 #else
00198         tmpdir = "/tmp";
00199 #endif
00200     }
00201 
00202     // N.B. Malloc ensures template is long enough so strcpy and strcat are safe here
00203     template = (char *) malloc( sizeof ( char ) * ( strlen( tmpdir ) + strlen( tmpname ) + 2 ) );
00204     strcpy( template, tmpdir );
00205 #if defined ( MSDOS ) || defined ( WIN32 )
00206     strcat( template, "\\" );
00207 #else
00208     strcat( template, "/" );
00209 #endif
00210     strcat( template, tmpname );
00211 
00212 #ifdef PL_HAVE_MKSTEMP
00213     fd = fdopen( mkstemp( template ), "wb+" );
00214     if ( fd == NULL )
00215     {
00216         plwarn( "pl_create_tempfile: Unable to open temporary file - returning" );
00217         if ( fname != NULL )
00218             *fname = NULL;
00219         free( template );
00220         return NULL;
00221     }
00222     // If we are not returning the file name then unlink the file so it is
00223     // automatically deleted.
00224 #ifdef PL_HAVE_UNLINK
00225     if ( fname == NULL )
00226         unlink( template );
00227 #endif
00228 #else
00229 #if !defined ( _S_IREAD )
00230 #define _S_IREAD     256
00231 #endif
00232 #if !defined ( _S_IWRITE )
00233 #define _S_IWRITE    128
00234 #endif
00235     fd    = NULL;
00236     flags = O_RDWR | O_BINARY | O_CREAT | O_EXCL | _O_SHORT_LIVED;
00237     // If we are not returning the file name then add flag to automatically
00238     // delete file once all file handles are closed.
00239     if ( fname == NULL )
00240         flags = flags | _O_TEMPORARY;
00241     mktemp( template );
00242     fd = fdopen( open( template, flags, _S_IREAD | _S_IWRITE ), "wb+" );
00243 #endif
00244 
00245     if ( fname != NULL )
00246     {
00247         *fname = template;
00248     }
00249     else
00250     {
00251         free( template );
00252     }
00253 
00254     return fd;
00255 }
00256 
00257 //
00258 // pl_create_tempfifo()
00259 //
00260 // Securely create a temporary fifo and return the file name.
00261 // This only works on POSIX compliant platforms at the moment.
00262 // It creates a secure directory first using mkdtemp, then
00263 // creates the named fifo in this directory. The combination of
00264 // a private directory and mkfifo failing if the file name already exists
00265 // makes this secure against race conditions / DoS attacks. This function
00266 // includes additional functionality over mkdtemp in that it honours the
00267 // TMP / TMPDIR / TEMP environment variables.
00268 //
00269 // The function returns the file name of the fifo.
00270 //
00271 char *
00272 pl_create_tempfifo( const char **p_fifoname, const char **p_dirname )
00273 {
00274 #if !defined PL_HAVE_MKDTEMP || !defined PL_HAVE_MKFIFO
00275     plwarn( "Creating fifos not supported on this platform" );
00276     return NULL;
00277 #else
00278     const char *tmpdir;
00279     char       *template;
00280     char       *dirname;
00281     const char *tmpname  = "plplot_dir_XXXXXX";
00282     const char *fifoname = "plplot_fifo";
00283 
00284 #if defined ( MSDOS ) || defined ( WIN32 )
00285     tmpdir = getenv( "TEMP" );
00286 #else
00287     tmpdir = getenv( "TMPDIR" );
00288 #endif
00289 
00290 // The P_TMPDIR macro is defined in stdio.h on many UNIX systems - try that
00291 #ifdef P_TMPDIR
00292     if ( tmpdir == NULL )
00293         tmpdir = P_TMPDIR;
00294 #endif
00295 
00296     if ( tmpdir == NULL )
00297     {
00298 #if defined ( MSDOS ) || defined ( WIN32 )
00299         tmpdir = "c:\\windows\\Temp";
00300 #else
00301         tmpdir = "/tmp";
00302 #endif
00303     }
00304 
00305     // N.B. Malloc ensures template is long enough so strcpy and strcat are safe here
00306     dirname = (char *) malloc( sizeof ( char ) * ( strlen( tmpdir ) + strlen( tmpname ) + 2 ) );
00307     strcpy( dirname, tmpdir );
00308 #if defined ( MSDOS ) || defined ( WIN32 )
00309     strcat( dirname, "\\" );
00310 #else
00311     strcat( dirname, "/" );
00312 #endif
00313     strcat( dirname, tmpname );
00314     // Create the temporary directory
00315     dirname    = mkdtemp( dirname );
00316     *p_dirname = dirname;
00317 
00318     // Now create the fifo in the directory
00319     template = (char *) malloc( sizeof ( char ) * ( strlen( tmpdir ) + strlen( tmpname ) + strlen( fifoname ) + 4 ) );
00320     strcpy( template, dirname );
00321 #if defined ( MSDOS ) || defined ( WIN32 )
00322     strcat( template, "\\" );
00323 #else
00324     strcat( template, "/" );
00325 #endif
00326     strcat( template, fifoname );
00327     *p_fifoname = template;
00328 
00329     // Check that mkfifo succeeds safely
00330     if ( mkfifo( template, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ) < 0 )
00331     {
00332         plwarn( "mkfifo error" );
00333         free( template );
00334         *p_fifoname = NULL;
00335         free( dirname );
00336         *p_dirname = NULL;
00337         return NULL;
00338     }
00339 
00340     return template;
00341 #endif
00342 }
00343 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines