1
1
/* estream.c - Extended Stream I/O Library
2
* Copyright (C) 2004, 2005, 2006, 2007, 2009 g10 Code GmbH
2
* Copyright (C) 2004, 2005, 2006, 2007, 2009, 2010 g10 Code GmbH
4
4
* This file is part of Libestream.
16
16
* You should have received a copy of the GNU General Public License
17
17
* along with Libestream; if not, see <http://www.gnu.org/licenses/>.
19
* ALTERNATIVELY, Libestream may be distributed under the terms of the
20
* following license, in which case the provisions of this license are
21
* required INSTEAD OF the GNU General Public License. If you wish to
22
* allow use of your version of this file only under the terms of the
23
* GNU General Public License, and not to allow others to use your
24
* version of this file under the terms of the following license,
25
* indicate your decision by deleting this paragraph and the license
28
* Redistribution and use in source and binary forms, with or without
29
* modification, are permitted provided that the following conditions
31
* 1. Redistributions of source code must retain the above copyright
32
* notice, and the entire permission notice in its entirety,
33
* including the disclaimer of warranties.
34
* 2. Redistributions in binary form must reproduce the above copyright
35
* notice, this list of conditions and the following disclaimer in the
36
* documentation and/or other materials provided with the distribution.
37
* 3. The name of the author may not be used to endorse or promote
38
* products derived from this software without specific prior
41
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
42
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
43
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
44
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
45
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
46
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
47
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
49
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
50
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
51
* OF THE POSSIBILITY OF SUCH DAMAGE.
20
54
#ifdef USE_ESTREAM_SUPPORT_H
76
116
#define O_BINARY 0
119
#ifdef HAVE_W32CE_SYSTEM
120
# define _set_errno(a) gpg_err_set_errno ((a))
121
/* Setmode is missing in cegcc but available since CE 5.0. */
122
int _setmode (int handle, int mode);
123
# define setmode(a,b) _setmode ((a),(b))
125
# define _set_errno(a) do { errno = (a); } while (0)
128
#ifdef HAVE_W32_SYSTEM
129
# define IS_INVALID_FD(a) ((void*)(a) == (void*)(-1))
131
# define IS_INVALID_FD(a) ((a) == -1)
79
135
/* Generally used types. */
81
137
typedef void *(*func_realloc_t) (void *mem, size_t size);
166
225
unsigned int eof: 1;
168
227
unsigned int deallocate_buffer: 1;
228
unsigned int is_stdstream:1; /* This is a standard stream. */
229
unsigned int stdstream_fd:2; /* 0, 1 or 2 for a standard stream. */
169
230
unsigned int print_err: 1; /* Error in print_fun_writer. */
231
unsigned int printable_fname_inuse: 1; /* es_fname_get has been used. */
170
232
int print_errno; /* Errno from print_fun_writer. */
171
233
size_t print_ntotal; /* Bytes written from in print_fun_writer. */
172
234
FILE *print_fp; /* Stdio stream used by print_fun_writer. */
196
258
#define ESTREAM_LIST_LOCK ESTREAM_MUTEX_LOCK (estream_list_lock)
197
259
#define ESTREAM_LIST_UNLOCK ESTREAM_MUTEX_UNLOCK (estream_list_lock)
261
/* File descriptors registered to be used as the standard file handles. */
262
static int custom_std_fds[3];
263
static unsigned char custom_std_fds_valid[3];
199
266
#ifndef EOPNOTSUPP
200
267
# define EOPNOTSUPP ENOSYS
271
/* Local prototypes. */
272
static void fname_set_internal (estream_t stream, const char *fname, int quote);
208
279
/* Calculate array dimension. */
704
792
estream_cookie_fd_t file_cookie = cookie;
705
793
ssize_t bytes_read;
708
bytes_read = ESTREAM_SYS_READ (file_cookie->fd, buffer, size);
709
while (bytes_read == -1 && errno == EINTR);
795
if (IS_INVALID_FD (file_cookie->fd))
797
ESTREAM_SYS_YIELD ();
803
bytes_read = ESTREAM_SYS_READ (file_cookie->fd, buffer, size);
804
while (bytes_read == -1 && errno == EINTR);
711
807
return bytes_read;
714
810
/* Write function for fd objects. */
716
812
es_func_fd_write (void *cookie, const void *buffer, size_t size)
719
814
estream_cookie_fd_t file_cookie = cookie;
720
815
ssize_t bytes_written;
723
bytes_written = ESTREAM_SYS_WRITE (file_cookie->fd, buffer, size);
724
while (bytes_written == -1 && errno == EINTR);
817
if (IS_INVALID_FD (file_cookie->fd))
819
ESTREAM_SYS_YIELD ();
820
bytes_written = size; /* Yeah: Success writing to the bit bucket. */
825
bytes_written = ESTREAM_SYS_WRITE (file_cookie->fd, buffer, size);
826
while (bytes_written == -1 && errno == EINTR);
726
829
return bytes_written;
836
953
estream_cookie_fp_t file_cookie = cookie;
837
954
size_t bytes_written;
839
bytes_written = fwrite (buffer, 1, size, file_cookie->fp);
958
bytes_written = fwrite (buffer, 1, size, file_cookie->fp);
960
bytes_written = size; /* Successfully written to the bit bucket. */
840
961
if (bytes_written != size)
842
963
return bytes_written;
849
970
estream_cookie_fp_t file_cookie = cookie;
850
971
long int offset_new;
973
if (!file_cookie->fp)
852
979
if ( fseek (file_cookie->fp, (long int)*offset, whence) )
854
fprintf (stderr, "\nfseek failed: errno=%d (%s)\n", errno,strerror (errno));
981
/* fprintf (stderr, "\nfseek failed: errno=%d (%s)\n", */
982
/* errno,strerror (errno)); */
858
986
offset_new = ftell (file_cookie->fp);
859
987
if (offset_new == -1)
861
fprintf (stderr, "\nftell failed: errno=%d (%s)\n", errno,strerror (errno));
989
/* fprintf (stderr, "\nftell failed: errno=%d (%s)\n", */
990
/* errno,strerror (errno)); */
864
993
*offset = offset_new;
868
/* Destroy function for fd objects. */
997
/* Destroy function for FILE* objects. */
870
999
es_func_fp_destroy (void *cookie)
1144
1270
stream->intern->print_fp = NULL;
1145
1271
stream->intern->indicators.err = 0;
1146
1272
stream->intern->indicators.eof = 0;
1273
stream->intern->is_stdstream = 0;
1274
stream->intern->stdstream_fd = 0;
1147
1275
stream->intern->deallocate_buffer = 0;
1276
stream->intern->printable_fname = NULL;
1277
stream->intern->printable_fname_inuse = 0;
1149
1279
stream->data_len = 0;
1150
1280
stream->data_offset = 0;
1152
1282
stream->unread_data_len = 0;
1153
1283
/* Depending on the modeflags we set whether we start in writing or
1154
1284
reading mode. This is required in case we are working on a
1155
wronly stream which is not seeekable (like stdout). Without this
1285
stream which is not seeekable (like stdout). Without this
1156
1286
pre-initialization we would do a seek at the first write call and
1157
1287
as this will fail no utput will be delivered. */
1158
1288
if ((modeflags & O_WRONLY) || (modeflags & O_RDWR) )
1184
1314
if (func_close)
1185
1315
SET_UNLESS_NONZERO (err, tmp_err, (*func_close) (stream->intern->cookie));
1317
mem_free (stream->intern->printable_fname);
1318
stream->intern->printable_fname = NULL;
1319
stream->intern->printable_fname_inuse = 0;
1191
1324
/* Create a new stream object, initialize it. */
1193
1326
es_create (estream_t *stream, void *cookie, int fd,
1194
es_cookie_io_functions_t functions, unsigned int modeflags)
1327
es_cookie_io_functions_t functions, unsigned int modeflags,
1328
int with_locked_list)
1196
1330
estream_internal_t stream_internal_new;
1197
1331
estream_t stream_new;
2055
2191
create_called = 1;
2056
err = es_create (&stream, cookie, fd, estream_functions_file, modeflags);
2192
err = es_create (&stream, cookie, fd, estream_functions_fd, modeflags, 0);
2197
fname_set_internal (stream, path, 1);
2062
2201
if (err && create_called)
2063
(*estream_functions_file.func_close) (cookie);
2202
(*estream_functions_fd.func_close) (cookie);
2194
2334
es_fdopen (int filedes, const char *mode)
2196
return do_fdopen (filedes, mode, 0);
2336
return do_fdopen (filedes, mode, 0, 0);
2199
2339
/* A variant of es_fdopen which does not close FILEDES at the end. */
2201
2341
es_fdopen_nc (int filedes, const char *mode)
2203
return do_fdopen (filedes, mode, 1);
2343
return do_fdopen (filedes, mode, 1, 0);
2208
do_fpopen (FILE *fp, const char *mode, int no_close)
2348
do_fpopen (FILE *fp, const char *mode, int no_close, int with_locked_list)
2210
2350
unsigned int modeflags;
2211
2351
int create_called;
2225
2366
err = es_func_fp_create (&cookie, fp, modeflags, no_close);
2229
2370
create_called = 1;
2230
err = es_create (&stream, cookie, fileno (fp), estream_functions_fp,
2371
err = es_create (&stream, cookie, fp? fileno (fp):-1, estream_functions_fp,
2372
modeflags, with_locked_list);
2259
2400
es_fpopen_nc (FILE *fp, const char *mode)
2261
return do_fpopen (fp, mode, 1);
2402
return do_fpopen (fp, mode, 1, 0);
2406
/* Set custom standard descriptors to be used for stdin, stdout and
2407
stderr. This function needs to be called before any of the
2408
standard streams are accessed. */
2410
_es_set_std_fd (int no, int fd)
2413
if (no >= 0 && no < 3 && !custom_std_fds_valid[no])
2415
custom_std_fds[no] = fd;
2416
custom_std_fds_valid[no] = 1;
2418
ESTREAM_LIST_UNLOCK;
2422
/* Return the stream used for stdin, stdout or stderr. */
2424
_es_get_std_stream (int fd)
2426
estream_list_t list_obj;
2427
estream_t stream = NULL;
2429
fd %= 3; /* We only allow 0, 1 or 2 but we don't want to return an error. */
2431
for (list_obj = estream_list; list_obj; list_obj = list_obj->cdr)
2432
if (list_obj->car->intern->is_stdstream
2433
&& list_obj->car->intern->stdstream_fd == fd)
2435
stream = list_obj->car;
2440
/* Standard stream not yet created. We first try to create them
2441
from registered file descriptors. */
2442
if (!fd && custom_std_fds_valid[0])
2443
stream = do_fdopen (custom_std_fds[0], "r", 1, 1);
2444
else if (fd == 1 && custom_std_fds_valid[1])
2445
stream = do_fdopen (custom_std_fds[1], "a", 1, 1);
2446
else if (custom_std_fds_valid[2])
2447
stream = do_fdopen (custom_std_fds[2], "a", 1, 1);
2451
/* Second try is to use the standard C streams. */
2453
stream = do_fpopen (stdin, "r", 1, 1);
2455
stream = do_fpopen (stdout, "a", 1, 1);
2457
stream = do_fpopen (stderr, "a", 1, 1);
2462
/* Last try: Create a bit bucket. */
2463
stream = do_fpopen (NULL, fd? "a":"r", 0, 1);
2466
fprintf (stderr, "fatal: error creating a dummy estream"
2467
" for %d: %s\n", fd, strerror (errno));
2472
stream->intern->is_stdstream = 1;
2473
stream->intern->stdstream_fd = fd;
2475
es_set_buffering (stream, NULL, _IOLBF, 0);
2476
fname_set_internal (stream,
2477
fd == 0? "[stdin]" :
2478
fd == 1? "[stdout]" : "[stderr]", 0);
2480
ESTREAM_LIST_UNLOCK;
2974
3229
#ifdef HAVE_W32_SYSTEM
2975
3230
int attempts, n;
3231
#ifdef HAVE_W32CE_SYSTEM
3232
wchar_t buffer[MAX_PATH+9+12+1];
3233
# define mystrlen(a) wcslen (a)
2976
3236
char buffer[MAX_PATH+9+12+1];
3237
# define mystrlen(a) strlen (a)
2977
3238
char *name, *p;
2979
3241
int pid = GetCurrentProcessId ();
2980
3242
unsigned int value;
2983
3245
n = GetTempPath (MAX_PATH+1, buffer);
2984
if (!n || n > MAX_PATH || strlen (buffer) > MAX_PATH)
3246
if (!n || n > MAX_PATH || mystrlen (buffer) > MAX_PATH)
3248
_set_errno (ENOENT);
2989
p = buffer + strlen (buffer);
3251
p = buffer + mystrlen (buffer);
3252
#ifdef HAVE_W32CE_SYSTEM
3253
wcscpy (p, L"_estream");
2990
3255
strcpy (p, "_estream");
2992
3258
/* We try to create the directory but don't care about an error as
2993
3259
it may already exist and the CreateFile would throw an error
3425
fname_set_internal (estream_t stream, const char *fname, int quote)
3427
if (stream->intern->printable_fname
3428
&& !stream->intern->printable_fname_inuse)
3430
mem_free (stream->intern->printable_fname);
3431
stream->intern->printable_fname = NULL;
3433
if (stream->intern->printable_fname)
3434
return; /* Can't change because it is in use. */
3441
stream->intern->printable_fname = mem_alloc (strlen (fname) + quote + 1);
3445
stream->intern->printable_fname[0] = '\\';
3446
strcpy (stream->intern->printable_fname+quote, fname);
3451
/* Set the filename attribute of STREAM. There is no error return.
3452
as long as STREAM is valid. This function is called internally by
3453
functions which open a filename. */
3455
es_fname_set (estream_t stream, const char *fname)
3459
ESTREAM_LOCK (stream);
3460
fname_set_internal (stream, fname, 1);
3461
ESTREAM_UNLOCK (stream);
3466
/* Return the filename attribute of STREAM. In case no filename has
3467
been set, "[?]" will be returned. The returned file name is valid
3468
as long as STREAM is valid. */
3470
es_fname_get (estream_t stream)
3474
ESTREAM_LOCK (stream);
3475
fname = stream->intern->printable_fname;
3477
stream->intern->printable_fname_inuse = 1;
3478
ESTREAM_UNLOCK (stream);
3149
3485
/* Print a BUFFER to STREAM while replacing all control characters and
3150
3486
the characters in DELIMITERS by standard C escape sequences.
3151
3487
Returns 0 on success or -1 on error. If BYTES_WRITTEN is not NULL