PLplot
5.15.0
Toggle main menu visibility
Loading...
Searching...
No Matches
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
// Copyright (C) 2016 Alan W. Irwin
6
//
7
// This file is part of PLplot.
8
//
9
// PLplot is free software; you can redistribute it and/or modify
10
// it under the terms of the GNU Library General Public License as published
11
// by the Free Software Foundation; either version 2 of the License, or
12
// (at your option) any later version.
13
//
14
// PLplot is distributed in the hope that it will be useful,
15
// but WITHOUT ANY WARRANTY; without even the implied warranty of
16
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
// GNU Library General Public License for more details.
18
//
19
// You should have received a copy of the GNU Library General Public License
20
// along with PLplot; if not, write to the Free Software
21
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22
//
23
//
24
25
#define DEBUG
26
#define NEED_PLDEBUG
27
#include "
plplotP.h
"
28
29
// These three are needed for open.
30
#include <sys/types.h>
31
#include <sys/stat.h>
32
#include <fcntl.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
// AM: getcwd has a somewhat strange status on Windows, its proper
48
// name is _getcwd, this is a problem in the case of DLLs, like with
49
// the Java bindings. The function _getcwd() is
50
// declared in direct.h for Visual C++.
51
#if defined ( _MSC_VER )
52
# include <direct.h>
53
# define getcwd _getcwd
54
#endif
55
56
// Static function declaration
57
static
PLINT
58
get_tmpdir_list
(
PLINT
max_ntmpdir_list,
char
** tmpdir_list,
PLINT
maxcurrdir,
char
* currdir );
59
60
//
61
// plio_write()
62
//
63
// Writes the contents of buf to stream. Handles any I/O error conditions
64
// so that the caller can "fire and forget."
65
//
66
67
void
68
plio_fwrite
(
void
*
buf
,
size_t
size,
size_t
nmemb, FILE *stream )
69
{
70
dbug_enter
(
"plio_fwrite"
);
71
72
// Exit if there is nothing to write
73
if
( size == 0 || nmemb == 0 )
74
return
;
75
76
// Clear the error flag for this steam
77
clearerr( stream );
78
79
fwrite(
buf
, size, nmemb, stream );
80
81
if
( ferror( stream ) )
82
{
83
// Perhaps we can add a flag (global or per output stream)
84
// in order to decide if we should abort or warn. I think
85
// I/O errors should generate an abort
86
plabort
(
"Error writing to file"
);
87
}
88
}
89
90
//
91
// plio_fread()
92
//
93
// Read from stream into buf. Like plio_write(), this function will
94
// handle any I/O error conditions.
95
//
96
97
void
98
plio_fread
(
void
*
buf
,
size_t
size,
size_t
nmemb, FILE *stream )
99
{
100
size_t
bytes;
101
102
dbug_enter
(
"plio_fread"
);
103
104
// If the buffer has a size of zero, we should complain
105
if
( size == 0 || nmemb == 0 )
106
{
107
plwarn
(
"Zero length buffer size in plio_fread, returning"
);
108
return
;
109
}
110
111
// Clear the error flag for this steam
112
clearerr( stream );
113
114
bytes = fread(
buf
, size, nmemb, stream );
115
116
if
( ( bytes < nmemb ) && ferror( stream ) )
117
{
118
// The read resulted in an error
119
plabort
(
"Error reading from file"
);
120
}
121
}
122
123
//
124
// plio_fgets()
125
//
126
// Read from stream into buf. This version of fgets is designed for the occasions
127
// where the caller wants to ignore the return value.
128
//
129
// NOTE: If one is reading from a file until an EOF condition, fgets() is better suited
130
// than this function, i.e.
131
//
132
// while(fgets(buf, size, fp) != NULL) { ... do some stuff ... }
133
//
134
// rather than
135
//
136
// while(!feof(fp)) { plio_fgets(buf, size, fp); ... do some stuff ... }
137
//
138
// which would require checking for an empty buffer.
139
//
140
141
void
142
plio_fgets
(
char
*
buf
,
int
size, FILE *stream )
143
{
144
char
*s;
145
146
dbug_enter
(
"plio_fgets"
);
147
148
// If the buffer has a size of zero, we should complain
149
if
( size == 0 )
150
{
151
plwarn
(
"Zero length buffer size in plio_fgets, returning"
);
152
return
;
153
}
154
155
// Clear the error flag for this steam
156
clearerr( stream );
157
158
s = fgets(
buf
, size, stream );
159
160
if
( s == NULL && ferror( stream ) )
161
{
162
// The read resulted in an error
163
plabort
(
"Error reading from file"
);
164
}
165
}
166
167
// Get list of possible directories for creating temporary files.
168
// This list of directories is as follows:
169
// The directory names in the environment variables:
170
// "TMP" [Windows only]
171
// "TEMP" [Windows only]
172
// "TMPDIR" [Unix only]
173
// The value of the P_tmpdir macro as defined in <stdio.h> [Unix only]
174
// The current working directory
175
// Some specific hard-coded locations that are guessed for the
176
// Unix and Windows cases.
177
178
static
PLINT
179
get_tmpdir_list
(
PLINT
max_ntmpdir_list,
char
** tmpdir_list,
PLINT
maxcurrdir,
char
* currdir )
180
{
181
PLINT
ntmpdir_list = 0;
182
#if defined ( MSDOS ) || defined ( _WIN32 )
183
tmpdir_list[ntmpdir_list] = getenv(
"TMP"
);
184
if
( tmpdir_list[ntmpdir_list] != NULL && ntmpdir_list < max_ntmpdir_list )
185
ntmpdir_list++;
186
187
tmpdir_list[ntmpdir_list] = getenv(
"TEMP"
);
188
if
( tmpdir_list[ntmpdir_list] != NULL && ntmpdir_list < max_ntmpdir_list )
189
ntmpdir_list++;
190
#else
191
tmpdir_list[ntmpdir_list] = getenv(
"TMPDIR"
);
192
if
( tmpdir_list[ntmpdir_list] != NULL && ntmpdir_list < max_ntmpdir_list )
193
ntmpdir_list++;
194
195
// The P_tmpdir macro is defined in stdio.h on many UNIX systems - try that
196
#ifdef P_tmpdir
197
tmpdir_list[ntmpdir_list] = P_tmpdir;
198
if
( tmpdir_list[ntmpdir_list] != NULL && ntmpdir_list < max_ntmpdir_list )
199
ntmpdir_list++;
200
#endif
201
#endif
//#if defined ( MSDOS ) || defined ( _WIN32 )
202
203
// Add current working directory to list where the currdir char array
204
// space should be provided by the calling routine with size of maxcurrdir.
205
if
( getcwd( currdir, maxcurrdir ) == NULL )
206
plexit
(
"get_tmpdir_list: getcwd error"
);
207
tmpdir_list[ntmpdir_list] = currdir;
208
if
( ntmpdir_list < max_ntmpdir_list )
209
ntmpdir_list++;
210
211
#if defined ( MSDOS ) || defined ( _WIN32 )
212
tmpdir_list[ntmpdir_list] =
"c:\\windows\\Temp"
;
213
#else
214
tmpdir_list[ntmpdir_list] =
"/tmp"
;
215
#endif
216
if
( ntmpdir_list < max_ntmpdir_list )
217
ntmpdir_list++;
218
return
ntmpdir_list;
219
}
220
221
//
222
// pl_create_tempfile()
223
//
224
// Securely create a temporary file and return a file handle to it.
225
// This provides cross-platform compatibility and also adds some
226
// additional functionality over mkstemp in that it uses the
227
// potential temporary directory locations specified in the
228
// get_tmpdir_list function.
229
//
230
// The function returns the file handle.
231
//
232
// If the fname variable is not NULL, then on return it will contain
233
// a pointer to the full temporary file name. This will be allocated
234
// with malloc. It is the caller's responsibility to ensure this
235
// memory is free'd and to ensure the file is deleted after use.
236
// If fname is NULL then the file will be automatically deleted
237
// when it is closed.
238
//
239
FILE *
240
pl_create_tempfile
(
char
**fname )
241
{
242
FILE *fd;
243
char
*tmpdir;
244
char
*
template
= NULL;
245
PLCHAR_VECTOR
tmpname =
"plplot_XXXXXX"
;
246
#ifndef PL_HAVE_MKSTEMP
247
int
flags;
248
#endif
249
PLINT
ntmpdir_list;
250
#define PL_MAXNTMPDIR_LIST 5
251
char
* tmpdir_list[
PL_MAXNTMPDIR_LIST
];
252
char
currdir[
PLPLOT_MAX_PATH
];
253
int
itmpdir;
254
255
ntmpdir_list =
get_tmpdir_list
(
PL_MAXNTMPDIR_LIST
, tmpdir_list,
PLPLOT_MAX_PATH
, currdir );
256
for
( itmpdir = 0; itmpdir < ntmpdir_list; itmpdir++ )
257
{
258
// Only guarantee is that tmpdir is not NULL and points to a NULL-terminated string.
259
tmpdir = tmpdir_list[itmpdir];
260
pldebug(
"pl_create_tempfile"
,
"Attempting to create temporary file in %s directory\n"
, tmpdir );
261
262
// N.B. realloc ensures template is long enough so strcpy and strcat
263
// are safe here.
264
template
= (
char
*) realloc(
template
,
sizeof
(
char
) * ( strlen( tmpdir ) + strlen( tmpname ) + 2 ) );
265
strcpy(
template
, tmpdir );
266
#if defined ( MSDOS ) || defined ( _WIN32 )
267
strcat(
template
,
"\\"
);
268
#else
269
strcat(
template
,
"/"
);
270
#endif
271
strcat(
template
, tmpname );
272
273
#ifdef PL_HAVE_MKSTEMP
274
fd = fdopen( mkstemp(
template
),
"wb+"
);
275
#else
//#ifdef PL_HAVE_MKSTEMP
276
// This conditionally compiled code branch is only an insecure last resort
277
// if mkstemp is not available.
278
#if !defined ( _S_IREAD )
279
#define _S_IREAD 256
280
#endif
281
#if !defined ( _S_IWRITE )
282
#define _S_IWRITE 128
283
#endif
284
fd = NULL;
285
flags = O_RDWR | O_CREAT | O_EXCL;
286
#if defined ( MSDOS ) || defined ( _WIN32 )
287
// These are flags that are only relevant to Windows open.
288
flags = flags | O_BINARY | _O_SHORT_LIVED;
289
// If we are not returning the file name then add (Windows) flag to automatically
290
// delete file once all file handles are closed.
291
if
( fname == NULL )
292
flags = flags | _O_TEMPORARY;
293
#endif
294
mktemp(
template
);
295
fd = fdopen( open(
template
, flags,
_S_IREAD
|
_S_IWRITE
),
"wb+"
);
296
#endif
// #ifdef PL_HAVE_MKSTEMP
297
if
( fd == NULL )
298
continue
;
299
else
300
break
;
301
}
302
if
( fd == NULL )
303
{
304
plwarn
(
"pl_create_tempfile: Unable to open temporary file - returning"
);
305
if
( fname != NULL )
306
*fname = NULL;
307
free(
template
);
308
return
NULL;
309
}
310
#if defined ( PL_HAVE_MKSTEMP ) && defined ( PL_HAVE_UNLINK )
311
// If we are not returning the file name then unlink the file so it is
312
// automatically deleted.
313
if
( fname == NULL )
314
unlink(
template
);
315
#endif
316
if
( fname != NULL )
317
{
318
*fname =
template
;
319
}
320
else
321
{
322
free(
template
);
323
}
324
325
return
fd;
326
}
327
328
//
329
// pl_create_tempfifo()
330
//
331
// Securely create a temporary fifo and return the file name.
332
// This only works on POSIX compliant platforms at the moment.
333
// It creates a secure directory first using mkdtemp, then
334
// creates the named fifo in this directory. The combination of
335
// a private directory and mkfifo failing if the file name already exists
336
// makes this secure against race conditions / DoS attacks. This function
337
// includes additional functionality over mkdtemp in that it uses the
338
// potential temporary directory locations specified in the
339
// get_tmpdir_list function.
340
//
341
// The function returns the file name of the fifo.
342
//
343
char
*
344
pl_create_tempfifo
(
const
char
**p_fifoname,
const
char
**p_dirname )
345
{
346
#if !defined PL_HAVE_MKDTEMP || !defined PL_HAVE_MKFIFO
347
plwarn
(
"Creating fifos not supported on this platform"
);
348
return
NULL;
349
#else
350
char
*tmpdir;
351
char
*
template
= NULL;
352
char
*dirname = NULL;
353
PLCHAR_VECTOR
tmpname =
"plplot_dir_XXXXXX"
;
354
PLCHAR_VECTOR
fifoname =
"plplot_fifo"
;
355
356
PLINT
ntmpdir_list;
357
#define PL_MAXNTMPDIR_LIST 5
358
char
* tmpdir_list[
PL_MAXNTMPDIR_LIST
];
359
char
currdir[
PLPLOT_MAX_PATH
];
360
int
itmpdir;
361
int
mkfifo_rc;
362
363
ntmpdir_list =
get_tmpdir_list
(
PL_MAXNTMPDIR_LIST
, tmpdir_list,
PLPLOT_MAX_PATH
, currdir );
364
for
( itmpdir = 0; itmpdir < ntmpdir_list; itmpdir++ )
365
{
366
// Only guarantee is that tmpdir is not NULL and points to a NULL-terminated string.
367
tmpdir = tmpdir_list[itmpdir];
368
pldebug(
"pl_create_tempfifo"
,
"Attempting to create temporary fifo in %s directory\n"
, tmpdir );
369
370
// N.B. realloc ensures template is long enough so strcpy and strcat
371
// are safe here.
372
dirname = (
char
*) realloc( dirname,
sizeof
(
char
) * ( strlen( tmpdir ) + strlen( tmpname ) + 2 ) );
373
strcpy( dirname, tmpdir );
374
#if defined ( MSDOS ) || defined ( _WIN32 )
375
strcat( dirname,
"\\"
);
376
#else
377
strcat( dirname,
"/"
);
378
#endif
379
strcat( dirname, tmpname );
380
// Create the temporary directory
381
dirname = mkdtemp( dirname );
382
if
( dirname == NULL )
383
{
384
// Mark this attempt as a failure.
385
mkfifo_rc = -1;
386
// This is a failed attempt so try other possibilities.
387
continue
;
388
}
389
*p_dirname = dirname;
390
391
// Now create the fifo in the directory
392
template
= (
char
*) realloc(
template
,
sizeof
(
char
) * ( strlen( tmpdir ) + strlen( tmpname ) + strlen( fifoname ) + 4 ) );
393
strcpy(
template
, dirname );
394
#if defined ( MSDOS ) || defined ( _WIN32 )
395
strcat(
template
,
"\\"
);
396
#else
397
strcat(
template
,
"/"
);
398
#endif
399
strcat(
template
, fifoname );
400
*p_fifoname =
template
;
401
402
// Check that mkfifo succeeds safely
403
mkfifo_rc = mkfifo(
template
, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH );
404
if
( mkfifo_rc < 0 )
405
// This is a failed attempt so try other possibilities.
406
continue
;
407
else
408
break
;
409
}
410
// Check for failure of all attempts in above loop.
411
if
( mkfifo_rc < 0 )
412
{
413
plwarn
(
"mkfifo error"
);
414
free(
template
);
415
*p_fifoname = NULL;
416
free( dirname );
417
*p_dirname = NULL;
418
return
NULL;
419
}
420
421
return
template
;
422
#endif
423
}
plwarn
void plwarn(PLCHAR_VECTOR errormsg)
Definition
plctrl.c:1863
plexit
void plexit(PLCHAR_VECTOR errormsg)
Definition
plctrl.c:1958
plabort
void plabort(PLCHAR_VECTOR errormsg)
Definition
plctrl.c:1894
plplotP.h
PLPLOT_MAX_PATH
#define PLPLOT_MAX_PATH
Definition
plplotP.h:446
PLCHAR_VECTOR
const char * PLCHAR_VECTOR
Definition
plplot.h:243
PLINT
int PLINT
Definition
plplot.h:181
PL_MAXNTMPDIR_LIST
#define PL_MAXNTMPDIR_LIST
plio_fwrite
void plio_fwrite(void *buf, size_t size, size_t nmemb, FILE *stream)
Definition
plstdio.c:68
plio_fgets
void plio_fgets(char *buf, int size, FILE *stream)
Definition
plstdio.c:142
get_tmpdir_list
static PLINT get_tmpdir_list(PLINT max_ntmpdir_list, char **tmpdir_list, PLINT maxcurrdir, char *currdir)
Definition
plstdio.c:179
plio_fread
void plio_fread(void *buf, size_t size, size_t nmemb, FILE *stream)
Definition
plstdio.c:98
pl_create_tempfile
FILE * pl_create_tempfile(char **fname)
Definition
plstdio.c:240
_S_IWRITE
#define _S_IWRITE
_S_IREAD
#define _S_IREAD
pl_create_tempfifo
char * pl_create_tempfifo(const char **p_fifoname, const char **p_dirname)
Definition
plstdio.c:344
buf
static char buf[200]
Definition
tclAPI.c:873
dbug_enter
#define dbug_enter(a)
Definition
tclMatrix.c:59
src
plstdio.c
Generated on
for PLplot by
1.17.0