PLplot
5.10.0
|
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