PLplot  5.10.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
plstdio.c
Go to the documentation of this file.
1 // Standardized I/O handler for PLplot.
2 //
3 // Copyright (C) 2006 Jim Dishaw
4 // Copyright (C) 2006 Hazen Babcock
5 //
6 // This file is part of PLplot.
7 //
8 // PLplot is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU Library General Public License as published
10 // by the Free Software Foundation; either version 2 of the License, or
11 // (at your option) any later version.
12 //
13 // PLplot is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU Library General Public License for more details.
17 //
18 // You should have received a copy of the GNU Library General Public License
19 // along with PLplot; if not, write to the Free Software
20 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 //
22 //
23 
24 #include "plplotP.h"
25 
26 #if defined ( MSDOS ) || defined ( WIN32 )
27 #include <sys/types.h>
28 #include <fcntl.h>
29 #endif
30 
31 // This is needed for mode flags for mkfifo as well sa for MSDOS / WIN32
32 #include <sys/stat.h>
33 
34 // For Visual C++ 2005 and later mktemp() and open() are deprecated (see
35 // http://msdn.microsoft.com/en-us/library/ms235413.aspx and
36 // http://msdn.microsoft.com/en-us/library/ms235491.aspx). mktemp()
37 // is redefined to _mktemp() as well as open() to _open(). In addition
38 // we need to include io.h.
39 //
40 #if defined ( _MSC_VER ) && _MSC_VER >= 1400
41 #include <io.h>
42 #define mktemp _mktemp
43 #define open _open
44 #define fdopen _fdopen
45 #endif
46 //
47 // plio_write()
48 //
49 // Writes the contents of buf to stream. Handles any I/O error conditions
50 // so that the caller can "fire and forget."
51 //
52 
53 void
54 plio_fwrite( void *buf, size_t size, size_t nmemb, FILE *stream )
55 {
56  dbug_enter( "plio_fwrite" );
57 
58  // Exit if there is nothing to write
59  if ( size == 0 || nmemb == 0 )
60  return;
61 
62  // Clear the error flag for this steam
63  clearerr( stream );
64 
65  fwrite( buf, size, nmemb, stream );
66 
67  if ( ferror( stream ) )
68  {
69  // Perhaps we can add a flag (global or per output stream)
70  // in order to decide if we should abort or warn. I think
71  // I/O errors should generate an abort
72  plabort( "Error writing to file" );
73  }
74 }
75 
76 //
77 // plio_fread()
78 //
79 // Read from stream into buf. Like plio_write(), this function will
80 // handle any I/O error conditions.
81 //
82 
83 void
84 plio_fread( void *buf, size_t size, size_t nmemb, FILE *stream )
85 {
86  size_t bytes;
87 
88  dbug_enter( "plio_fread" );
89 
90  // If the buffer has a size of zero, we should complain
91  if ( size == 0 || nmemb == 0 )
92  {
93  plwarn( "Zero length buffer size in plio_fread, returning" );
94  return;
95  }
96 
97  // Clear the error flag for this steam
98  clearerr( stream );
99 
100  bytes = fread( buf, size, nmemb, stream );
101 
102  if ( ( bytes < nmemb ) && ferror( stream ) )
103  {
104  // The read resulted in an error
105  plabort( "Error reading from file" );
106  }
107 }
108 
109 //
110 // plio_fgets()
111 //
112 // Read from stream into buf. This version of fgets is designed for the occasions
113 // where the caller wants to ignore the return value.
114 //
115 // NOTE: If one is reading from a file until an EOF condition, fgets() is better suited
116 // than this function, i.e.
117 //
118 // while(fgets(buf, size, fp) != NULL) { ... do some stuff ... }
119 //
120 // rather than
121 //
122 // while(!feof(fp)) { plio_fgets(buf, size, fp); ... do some stuff ... }
123 //
124 // which would require checking for an empty buffer.
125 //
126 
127 void
128 plio_fgets( char *buf, int size, FILE *stream )
129 {
130  char *s;
131 
132  dbug_enter( "plio_fgets" );
133 
134  // If the buffer has a size of zero, we should complain
135  if ( size == 0 )
136  {
137  plwarn( "Zero length buffer size in plio_fgets, returning" );
138  return;
139  }
140 
141  // Clear the error flag for this steam
142  clearerr( stream );
143 
144  s = fgets( buf, size, stream );
145 
146  if ( s == NULL && ferror( stream ) )
147  {
148  // The read resulted in an error
149  plabort( "Error reading from file" );
150  }
151 }
152 
153 //
154 // pl_create_tempfile()
155 //
156 // Securely create a temporary file and return a file handle to it.
157 // This provides cross-platform compatibility and also adds some
158 // additional functionality over mkstemp in that it honours the TMP /
159 // TMPDIR / TEMP environment variables.
160 //
161 // The function returns the file handle.
162 //
163 // If the fname variable is not NULL, then on return it will contain
164 // a pointer to the full temporary file name. This will be allocated
165 // with malloc. It is the caller's responsibility to ensure this
166 // memory is free'd and to ensure the file is deleted after use.
167 // If fname is NULL then the file will be automatically deleted
168 // when it is closed.
169 //
170 FILE *
171 pl_create_tempfile( char **fname )
172 {
173  FILE *fd;
174  const char *tmpdir;
175  char *template;
176  const char *tmpname = "plplot_XXXXXX";
177 #if !defined PL_HAVE_MKSTEMP
178  int flags;
179 #endif
180 
181 #if defined ( MSDOS ) || defined ( WIN32 )
182  tmpdir = getenv( "TEMP" );
183 #else
184  tmpdir = getenv( "TMPDIR" );
185 #endif
186 
187 // The P_TMPDIR macro is defined in stdio.h on many UNIX systems - try that
188 #ifdef P_TMPDIR
189  if ( tmpdir == NULL )
190  tmpdir = P_TMPDIR;
191 #endif
192 
193  if ( tmpdir == NULL )
194  {
195 #if defined ( MSDOS ) || defined ( WIN32 )
196  tmpdir = "c:\\windows\\Temp";
197 #else
198  tmpdir = "/tmp";
199 #endif
200  }
201 
202  // N.B. Malloc ensures template is long enough so strcpy and strcat are safe here
203  template = (char *) malloc( sizeof ( char ) * ( strlen( tmpdir ) + strlen( tmpname ) + 2 ) );
204  strcpy( template, tmpdir );
205 #if defined ( MSDOS ) || defined ( WIN32 )
206  strcat( template, "\\" );
207 #else
208  strcat( template, "/" );
209 #endif
210  strcat( template, tmpname );
211 
212 #ifdef PL_HAVE_MKSTEMP
213  fd = fdopen( mkstemp( template ), "wb+" );
214  if ( fd == NULL )
215  {
216  plwarn( "pl_create_tempfile: Unable to open temporary file - returning" );
217  if ( fname != NULL )
218  *fname = NULL;
219  free( template );
220  return NULL;
221  }
222  // If we are not returning the file name then unlink the file so it is
223  // automatically deleted.
224 #ifdef PL_HAVE_UNLINK
225  if ( fname == NULL )
226  unlink( template );
227 #endif
228 #else
229 #if !defined ( _S_IREAD )
230 #define _S_IREAD 256
231 #endif
232 #if !defined ( _S_IWRITE )
233 #define _S_IWRITE 128
234 #endif
235  fd = NULL;
236  flags = O_RDWR | O_BINARY | O_CREAT | O_EXCL | _O_SHORT_LIVED;
237  // If we are not returning the file name then add flag to automatically
238  // delete file once all file handles are closed.
239  if ( fname == NULL )
240  flags = flags | _O_TEMPORARY;
241  mktemp( template );
242  fd = fdopen( open( template, flags, _S_IREAD | _S_IWRITE ), "wb+" );
243 #endif
244 
245  if ( fname != NULL )
246  {
247  *fname = template;
248  }
249  else
250  {
251  free( template );
252  }
253 
254  return fd;
255 }
256 
257 //
258 // pl_create_tempfifo()
259 //
260 // Securely create a temporary fifo and return the file name.
261 // This only works on POSIX compliant platforms at the moment.
262 // It creates a secure directory first using mkdtemp, then
263 // creates the named fifo in this directory. The combination of
264 // a private directory and mkfifo failing if the file name already exists
265 // makes this secure against race conditions / DoS attacks. This function
266 // includes additional functionality over mkdtemp in that it honours the
267 // TMP / TMPDIR / TEMP environment variables.
268 //
269 // The function returns the file name of the fifo.
270 //
271 char *
272 pl_create_tempfifo( const char **p_fifoname, const char **p_dirname )
273 {
274 #if !defined PL_HAVE_MKDTEMP || !defined PL_HAVE_MKFIFO
275  plwarn( "Creating fifos not supported on this platform" );
276  return NULL;
277 #else
278  const char *tmpdir;
279  char *template;
280  char *dirname;
281  const char *tmpname = "plplot_dir_XXXXXX";
282  const char *fifoname = "plplot_fifo";
283 
284 #if defined ( MSDOS ) || defined ( WIN32 )
285  tmpdir = getenv( "TEMP" );
286 #else
287  tmpdir = getenv( "TMPDIR" );
288 #endif
289 
290 // The P_TMPDIR macro is defined in stdio.h on many UNIX systems - try that
291 #ifdef P_TMPDIR
292  if ( tmpdir == NULL )
293  tmpdir = P_TMPDIR;
294 #endif
295 
296  if ( tmpdir == NULL )
297  {
298 #if defined ( MSDOS ) || defined ( WIN32 )
299  tmpdir = "c:\\windows\\Temp";
300 #else
301  tmpdir = "/tmp";
302 #endif
303  }
304 
305  // N.B. Malloc ensures template is long enough so strcpy and strcat are safe here
306  dirname = (char *) malloc( sizeof ( char ) * ( strlen( tmpdir ) + strlen( tmpname ) + 2 ) );
307  strcpy( dirname, tmpdir );
308 #if defined ( MSDOS ) || defined ( WIN32 )
309  strcat( dirname, "\\" );
310 #else
311  strcat( dirname, "/" );
312 #endif
313  strcat( dirname, tmpname );
314  // Create the temporary directory
315  dirname = mkdtemp( dirname );
316  *p_dirname = dirname;
317 
318  // Now create the fifo in the directory
319  template = (char *) malloc( sizeof ( char ) * ( strlen( tmpdir ) + strlen( tmpname ) + strlen( fifoname ) + 4 ) );
320  strcpy( template, dirname );
321 #if defined ( MSDOS ) || defined ( WIN32 )
322  strcat( template, "\\" );
323 #else
324  strcat( template, "/" );
325 #endif
326  strcat( template, fifoname );
327  *p_fifoname = template;
328 
329  // Check that mkfifo succeeds safely
330  if ( mkfifo( template, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ) < 0 )
331  {
332  plwarn( "mkfifo error" );
333  free( template );
334  *p_fifoname = NULL;
335  free( dirname );
336  *p_dirname = NULL;
337  return NULL;
338  }
339 
340  return template;
341 #endif
342 }
343