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