PLplot: plstdio.c Source File

PLplot 5.10.0

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

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