Line data Source code
1 : /* estream.c - Extended Stream I/O Library
2 : * Copyright (C) 2004, 2005, 2006, 2007, 2009, 2010, 2011,
3 : * 2014, 2015 g10 Code GmbH
4 : *
5 : * This file is part of Libestream.
6 : *
7 : * Libestream is free software; you can redistribute it and/or modify
8 : * it under the terms of the GNU Lesser General Public License as
9 : * published by the Free Software Foundation; either version 2.1 of
10 : * the License, or (at your option) any later version.
11 : *
12 : * Libestream is distributed in the hope that it will be useful, but
13 : * WITHOUT ANY WARRANTY; without even the implied warranty of
14 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : * Lesser General Public License for more details.
16 : *
17 : * You should have received a copy of the GNU Lesser General Public
18 : * License along with Libestream; if not, see <http://www.gnu.org/licenses/>.
19 : *
20 : * ALTERNATIVELY, Libestream may be distributed under the terms of the
21 : * following license, in which case the provisions of this license are
22 : * required INSTEAD OF the GNU General Public License. If you wish to
23 : * allow use of your version of this file only under the terms of the
24 : * GNU General Public License, and not to allow others to use your
25 : * version of this file under the terms of the following license,
26 : * indicate your decision by deleting this paragraph and the license
27 : * below.
28 : *
29 : * Redistribution and use in source and binary forms, with or without
30 : * modification, are permitted provided that the following conditions
31 : * are met:
32 : * 1. Redistributions of source code must retain the above copyright
33 : * notice, and the entire permission notice in its entirety,
34 : * including the disclaimer of warranties.
35 : * 2. Redistributions in binary form must reproduce the above copyright
36 : * notice, this list of conditions and the following disclaimer in the
37 : * documentation and/or other materials provided with the distribution.
38 : * 3. The name of the author may not be used to endorse or promote
39 : * products derived from this software without specific prior
40 : * written permission.
41 : *
42 : * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
43 : * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
44 : * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
45 : * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
46 : * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
47 : * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
48 : * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
49 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
50 : * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
51 : * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
52 : * OF THE POSSIBILITY OF SUCH DAMAGE.
53 : */
54 :
55 : #ifdef USE_ESTREAM_SUPPORT_H
56 : # include <estream-support.h>
57 : #endif
58 :
59 : #ifdef HAVE_CONFIG_H
60 : # include <config.h>
61 : #endif
62 :
63 : #if defined(_WIN32) && !defined(HAVE_W32_SYSTEM)
64 : # define HAVE_W32_SYSTEM 1
65 : # if defined(__MINGW32CE__) && !defined (HAVE_W32CE_SYSTEM)
66 : # define HAVE_W32CE_SYSTEM
67 : # endif
68 : #endif
69 :
70 : #ifdef HAVE_SYS_SELECT_H
71 : # include <sys/select.h>
72 : #endif
73 : #ifdef HAVE_SYS_TIME_H
74 : # include <sys/time.h>
75 : #endif
76 : #include <sys/types.h>
77 : #include <sys/file.h>
78 : #include <sys/stat.h>
79 : #include <stdio.h>
80 : #include <stdlib.h>
81 : #include <string.h>
82 : #include <unistd.h>
83 : #include <stdarg.h>
84 : #include <fcntl.h>
85 : #include <errno.h>
86 : #include <stddef.h>
87 : #include <assert.h>
88 : #ifdef HAVE_W32_SYSTEM
89 : # ifdef HAVE_WINSOCK2_H
90 : # include <winsock2.h>
91 : # endif
92 : # include <windows.h>
93 : #endif
94 :
95 :
96 : #include "gpgrt-int.h"
97 : #include "estream-printf.h"
98 :
99 :
100 : #ifndef O_BINARY
101 : # define O_BINARY 0
102 : #endif
103 : #ifndef HAVE_DOSISH_SYSTEM
104 : # ifdef HAVE_W32_SYSTEM
105 : # define HAVE_DOSISH_SYSTEM 1
106 : # endif
107 : #endif
108 :
109 :
110 : #ifdef HAVE_W32_SYSTEM
111 : # define S_IRGRP S_IRUSR
112 : # define S_IROTH S_IRUSR
113 : # define S_IWGRP S_IWUSR
114 : # define S_IWOTH S_IWUSR
115 : # define S_IXGRP S_IXUSR
116 : # define S_IXOTH S_IXUSR
117 : # define O_NONBLOCK 0 /* FIXME: Not yet supported. */
118 : #endif
119 :
120 : #ifndef EAGAIN
121 : # define EAGAIN EWOULDBLOCK
122 : #endif
123 :
124 :
125 : #ifdef HAVE_W32CE_SYSTEM
126 : # define _set_errno(a) gpg_err_set_errno ((a))
127 : /* Setmode is missing in cegcc but available since CE 5.0. */
128 : int _setmode (int handle, int mode);
129 : # define setmode(a,b) _setmode ((a),(b))
130 : #else
131 : # define _set_errno(a) do { errno = (a); } while (0)
132 : #endif
133 :
134 : #ifdef HAVE_W32_SYSTEM
135 : # define IS_INVALID_FD(a) ((void*)(a) == (void*)(-1)) /* ?? FIXME. */
136 : #else
137 : # define IS_INVALID_FD(a) ((a) == -1)
138 : #endif
139 :
140 :
141 : /* Generally used types. */
142 :
143 : typedef void *(*func_realloc_t) (void *mem, size_t size);
144 : typedef void (*func_free_t) (void *mem);
145 :
146 :
147 :
148 :
149 : /* Buffer management layer. */
150 :
151 : #define BUFFER_BLOCK_SIZE BUFSIZ
152 : #define BUFFER_UNREAD_SIZE 16
153 :
154 :
155 : /* A linked list to hold notification functions. */
156 : struct notify_list_s
157 : {
158 : struct notify_list_s *next;
159 : void (*fnc) (estream_t, void*); /* The notification function. */
160 : void *fnc_value; /* The value to be passed to FNC. */
161 : };
162 : typedef struct notify_list_s *notify_list_t;
163 :
164 :
165 : /* A private cookie function to implement an internal IOCTL
166 : service. */
167 : typedef int (*cookie_ioctl_function_t) (void *cookie, int cmd,
168 : void *ptr, size_t *len);
169 : /* IOCTL commands for the private cookie function. */
170 : #define COOKIE_IOCTL_SNATCH_BUFFER 1
171 : #define COOKIE_IOCTL_NONBLOCK 2
172 :
173 :
174 : /* The internal stream object. */
175 : struct _gpgrt_stream_internal
176 : {
177 : unsigned char buffer[BUFFER_BLOCK_SIZE];
178 : unsigned char unread_buffer[BUFFER_UNREAD_SIZE];
179 :
180 : gpgrt_lock_t lock; /* Lock. */
181 :
182 : void *cookie; /* Cookie. */
183 : void *opaque; /* Opaque data. */
184 : unsigned int modeflags; /* Flags for the backend. */
185 : char *printable_fname; /* Malloced filename for es_fname_get. */
186 : gpgrt_off_t offset;
187 : gpgrt_cookie_read_function_t func_read;
188 : gpgrt_cookie_write_function_t func_write;
189 : gpgrt_cookie_seek_function_t func_seek;
190 : gpgrt_cookie_close_function_t func_close;
191 : cookie_ioctl_function_t func_ioctl;
192 : int strategy;
193 : es_syshd_t syshd; /* A copy of the sytem handle. */
194 : struct
195 : {
196 : unsigned int err: 1;
197 : unsigned int eof: 1;
198 : unsigned int hup: 1;
199 : } indicators;
200 : unsigned int deallocate_buffer: 1;
201 : unsigned int is_stdstream:1; /* This is a standard stream. */
202 : unsigned int stdstream_fd:2; /* 0, 1 or 2 for a standard stream. */
203 : unsigned int printable_fname_inuse: 1; /* es_fname_get has been used. */
204 : unsigned int samethread: 1; /* The "samethread" mode keyword. */
205 : size_t print_ntotal; /* Bytes written from in print_writer. */
206 : notify_list_t onclose; /* On close notify function list. */
207 : };
208 : typedef struct _gpgrt_stream_internal *estream_internal_t;
209 :
210 : /* A linked list to hold active stream objects. */
211 : struct estream_list_s
212 : {
213 : struct estream_list_s *next;
214 : estream_t stream; /* Entry is not used if NULL. */
215 : };
216 : typedef struct estream_list_s *estream_list_t;
217 : static estream_list_t estream_list;
218 : /* A lock object for the estream list and the custom_std_fds array. */
219 : GPGRT_LOCK_DEFINE (estream_list_lock);
220 :
221 : /* File descriptors registered to be used as the standard file handles. */
222 : static int custom_std_fds[3];
223 : static unsigned char custom_std_fds_valid[3];
224 :
225 : /* Functions called before and after blocking syscalls. */
226 : static void (*pre_syscall_func)(void);
227 : static void (*post_syscall_func)(void);
228 :
229 : /* Error code replacements. */
230 : #ifndef EOPNOTSUPP
231 : # define EOPNOTSUPP ENOSYS
232 : #endif
233 :
234 :
235 : /* Local prototypes. */
236 : static void fname_set_internal (estream_t stream, const char *fname, int quote);
237 :
238 :
239 :
240 :
241 : /* Macros. */
242 :
243 : /* Calculate array dimension. */
244 : #ifndef DIM
245 : #define DIM(array) (sizeof (array) / sizeof (*array))
246 : #endif
247 :
248 : #define tohex(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'A'))
249 :
250 :
251 : /* Evaluate EXPRESSION, setting VARIABLE to the return code, if
252 : VARIABLE is zero. */
253 : #define SET_UNLESS_NONZERO(variable, tmp_variable, expression) \
254 : do \
255 : { \
256 : tmp_variable = expression; \
257 : if ((! variable) && tmp_variable) \
258 : variable = tmp_variable; \
259 : } \
260 : while (0)
261 :
262 :
263 :
264 : static void *
265 : mem_alloc (size_t n)
266 : {
267 24 : return _gpgrt_malloc (n);
268 : }
269 :
270 : static void *
271 0 : mem_realloc (void *p, size_t n)
272 : {
273 0 : return _gpgrt_realloc (p, n);
274 : }
275 :
276 : static void
277 0 : mem_free (void *p)
278 : {
279 24 : if (p)
280 18 : _gpgrt_free (p);
281 0 : }
282 :
283 : #ifdef HAVE_W32_SYSTEM
284 : static int
285 : map_w32_to_errno (DWORD w32_err)
286 : {
287 : switch (w32_err)
288 : {
289 : case 0:
290 : return 0;
291 :
292 : case ERROR_FILE_NOT_FOUND:
293 : return ENOENT;
294 :
295 : case ERROR_PATH_NOT_FOUND:
296 : return ENOENT;
297 :
298 : case ERROR_ACCESS_DENIED:
299 : return EPERM;
300 :
301 : case ERROR_INVALID_HANDLE:
302 : case ERROR_INVALID_BLOCK:
303 : return EINVAL;
304 :
305 : case ERROR_NOT_ENOUGH_MEMORY:
306 : return ENOMEM;
307 :
308 : case ERROR_NO_DATA:
309 : return EPIPE;
310 :
311 : default:
312 : return EIO;
313 : }
314 : }
315 : #endif /*HAVE_W32_SYSTEM*/
316 :
317 : /* Replacement fucntions. */
318 :
319 : #ifndef HAVE_MEMRCHR
320 : static void *
321 : memrchr (const void *buffer, int c, size_t n)
322 : {
323 : const unsigned char *p = buffer;
324 :
325 : for (p += n; n ; n--)
326 : if (*--p == c)
327 : return (void *)p;
328 : return NULL;
329 : }
330 : #endif /*HAVE_MEMRCHR*/
331 :
332 :
333 : /*
334 : * Lock wrappers
335 : */
336 : #if 0
337 : # define dbg_lock_0(f) fprintf (stderr, "estream: " f);
338 : # define dbg_lock_1(f, a) fprintf (stderr, "estream: " f, (a));
339 : # define dbg_lock_2(f, a, b) fprintf (stderr, "estream: " f, (a), (b));
340 : #else
341 : # define dbg_lock_0(f)
342 : # define dbg_lock_1(f, a)
343 : # define dbg_lock_2(f, a, b)
344 : #endif
345 :
346 : static int
347 6 : init_stream_lock (estream_t _GPGRT__RESTRICT stream)
348 : {
349 : int rc;
350 :
351 6 : if (!stream->intern->samethread)
352 : {
353 : dbg_lock_1 ("enter init_stream_lock for %p\n", stream);
354 6 : memset (&stream->intern->lock, 0 , sizeof stream->intern->lock);
355 6 : rc = _gpgrt_lock_init (&stream->intern->lock);
356 : dbg_lock_2 ("leave init_stream_lock for %p: rc=%d\n", stream, rc);
357 : }
358 : else
359 : rc = 0;
360 6 : return rc;
361 : }
362 :
363 :
364 : static void
365 0 : destroy_stream_lock (estream_t _GPGRT__RESTRICT stream)
366 : {
367 6 : if (!stream->intern->samethread)
368 : {
369 : dbg_lock_1 ("enter destroy_stream_lock for %p\n", stream);
370 6 : _gpgrt_lock_destroy (&stream->intern->lock);
371 : dbg_lock_1 ("leave destroy_stream_lock for %p\n", stream);
372 : }
373 0 : }
374 :
375 :
376 : static void
377 0 : lock_stream (estream_t _GPGRT__RESTRICT stream)
378 : {
379 161 : if (!stream->intern->samethread)
380 : {
381 : dbg_lock_1 ("enter lock_stream for %p\n", stream);
382 161 : _gpgrt_lock_lock (&stream->intern->lock);
383 : dbg_lock_1 ("leave lock_stream for %p\n", stream);
384 : }
385 0 : }
386 :
387 :
388 : static int
389 0 : trylock_stream (estream_t _GPGRT__RESTRICT stream)
390 : {
391 : int rc;
392 :
393 0 : if (!stream->intern->samethread)
394 : {
395 : dbg_lock_1 ("enter trylock_stream for %p\n", stream);
396 0 : rc = _gpgrt_lock_trylock (&stream->intern->lock)? 0 : -1;
397 : dbg_lock_2 ("leave trylock_stream for %p: rc=%d\n", stream, rc);
398 : }
399 : else
400 : rc = 0;
401 0 : return rc;
402 : }
403 :
404 :
405 : static void
406 0 : unlock_stream (estream_t _GPGRT__RESTRICT stream)
407 : {
408 161 : if (!stream->intern->samethread)
409 : {
410 : dbg_lock_1 ("enter unlock_stream for %p\n", stream);
411 161 : _gpgrt_lock_unlock (&stream->intern->lock);
412 : dbg_lock_1 ("leave unlock_stream for %p\n", stream);
413 : }
414 0 : }
415 :
416 :
417 : static void
418 : lock_list (void)
419 : {
420 : dbg_lock_0 ("enter lock_list\n");
421 18 : _gpgrt_lock_lock (&estream_list_lock);
422 : dbg_lock_0 ("leave lock_list\n");
423 : }
424 :
425 :
426 : static void
427 : unlock_list (void)
428 : {
429 : dbg_lock_0 ("enter unlock_list\n");
430 18 : _gpgrt_lock_unlock (&estream_list_lock);
431 : dbg_lock_0 ("leave unlock_list\n");
432 : }
433 :
434 :
435 : #undef dbg_lock_0
436 : #undef dbg_lock_1
437 : #undef dbg_lock_2
438 :
439 :
440 :
441 : /*
442 : * List manipulation.
443 : */
444 :
445 : /* Add STREAM to the list of registered stream objects. If
446 : WITH_LOCKED_LIST is true it is assumed that the list of streams is
447 : already locked. The implementation is straightforward: We first
448 : look for an unused entry in the list and use that; if none is
449 : available we put a new item at the head. We drawback of the
450 : strategy never to shorten the list is that a one time allocation of
451 : many streams will lead to scanning unused entries later. If that
452 : turns out to be a problem, we may either free some items from the
453 : list or append new entries at the end; or use a table. Returns 0
454 : on success; on error or non-zero is returned and ERRNO set. */
455 : static int
456 6 : do_list_add (estream_t stream, int with_locked_list)
457 : {
458 : estream_list_t item;
459 :
460 6 : if (!with_locked_list)
461 : lock_list ();
462 :
463 6 : for (item = estream_list; item && item->stream; item = item->next)
464 : ;
465 6 : if (!item)
466 : {
467 : item = mem_alloc (sizeof *item);
468 6 : if (item)
469 : {
470 6 : item->next = estream_list;
471 6 : estream_list = item;
472 : }
473 : }
474 6 : if (item)
475 6 : item->stream = stream;
476 :
477 6 : if (!with_locked_list)
478 : unlock_list ();
479 :
480 6 : return item? 0 : -1;
481 : }
482 :
483 : /* Remove STREAM from the list of registered stream objects. */
484 : static void
485 6 : do_list_remove (estream_t stream, int with_locked_list)
486 : {
487 : estream_list_t item;
488 :
489 6 : if (!with_locked_list)
490 : lock_list ();
491 :
492 21 : for (item = estream_list; item; item = item->next)
493 21 : if (item->stream == stream)
494 : {
495 6 : item->stream = NULL;
496 6 : break;
497 : }
498 :
499 6 : if (!with_locked_list)
500 : unlock_list ();
501 6 : }
502 :
503 :
504 :
505 : static void
506 6 : do_deinit (void)
507 : {
508 : /* Flush all streams. */
509 6 : _gpgrt_fflush (NULL);
510 :
511 : /* We should release the estream_list. However there is one
512 : problem: That list is also used to search for the standard
513 : estream file descriptors. If we would remove the entire list,
514 : any use of es_foo in another atexit function may re-create the
515 : list and the streams with possible undesirable effects. Given
516 : that we don't close the stream either, it should not matter that
517 : we keep the list and let the OS clean it up at process end. */
518 :
519 : /* Reset the syscall clamp. */
520 6 : pre_syscall_func = NULL;
521 6 : post_syscall_func = NULL;
522 6 : }
523 :
524 :
525 : /*
526 : * Initialization.
527 : */
528 :
529 : int
530 6 : _gpgrt_es_init (void)
531 : {
532 : static int initialized;
533 :
534 6 : if (!initialized)
535 : {
536 6 : initialized = 1;
537 6 : atexit (do_deinit);
538 : }
539 6 : return 0;
540 : }
541 :
542 : /* Register the syscall clamp. These two functions are called
543 : immediately before and after a possible blocking system call. This
544 : should be used before any I/O happens. The function is commonly
545 : used with the nPth library:
546 :
547 : gpgrt_set_syscall_clamp (npth_unprotect, npth_protect);
548 :
549 : These functions may not modify ERRNO.
550 : */
551 : void
552 0 : _gpgrt_set_syscall_clamp (void (*pre)(void), void (*post)(void))
553 : {
554 0 : pre_syscall_func = pre;
555 0 : post_syscall_func = post;
556 0 : }
557 :
558 :
559 :
560 :
561 : /*
562 : * I/O methods.
563 : */
564 :
565 : /* Implementation of Memory I/O. */
566 :
567 : /* Cookie for memory objects. */
568 : typedef struct estream_cookie_mem
569 : {
570 : unsigned int modeflags; /* Open flags. */
571 : unsigned char *memory; /* Allocated data buffer. */
572 : size_t memory_size; /* Allocated size of MEMORY. */
573 : size_t memory_limit; /* Caller supplied maximum allowed
574 : allocation size or 0 for no limit. */
575 : size_t offset; /* Current offset in MEMORY. */
576 : size_t data_len; /* Used length of data in MEMORY. */
577 : size_t block_size; /* Block size. */
578 : struct {
579 : unsigned int grow: 1; /* MEMORY is allowed to grow. */
580 : } flags;
581 : func_realloc_t func_realloc;
582 : func_free_t func_free;
583 : } *estream_cookie_mem_t;
584 :
585 :
586 : /* Create function for memory objects. DATA is either NULL or a user
587 : supplied buffer with the initial conetnt of the memory buffer. If
588 : DATA is NULL, DATA_N and DATA_LEN need to be 0 as well. If DATA is
589 : not NULL, DATA_N gives the allocated size of DATA and DATA_LEN the
590 : used length in DATA. If this fucntion succeeds DATA is now owned
591 : by this function. If GROW is false FUNC_REALLOC is not
592 : required. */
593 : static int
594 0 : func_mem_create (void *_GPGRT__RESTRICT *_GPGRT__RESTRICT cookie,
595 : unsigned char *_GPGRT__RESTRICT data, size_t data_n,
596 : size_t data_len,
597 : size_t block_size, unsigned int grow,
598 : func_realloc_t func_realloc, func_free_t func_free,
599 : unsigned int modeflags,
600 : size_t memory_limit)
601 : {
602 : estream_cookie_mem_t mem_cookie;
603 : int err;
604 :
605 0 : if (!data && (data_n || data_len))
606 : {
607 0 : _set_errno (EINVAL);
608 0 : return -1;
609 : }
610 0 : if (grow && func_free && !func_realloc)
611 : {
612 0 : _set_errno (EINVAL);
613 0 : return -1;
614 : }
615 :
616 : mem_cookie = mem_alloc (sizeof (*mem_cookie));
617 0 : if (!mem_cookie)
618 : err = -1;
619 : else
620 : {
621 0 : mem_cookie->modeflags = modeflags;
622 0 : mem_cookie->memory = data;
623 0 : mem_cookie->memory_size = data_n;
624 0 : mem_cookie->memory_limit = memory_limit;
625 0 : mem_cookie->offset = 0;
626 0 : mem_cookie->data_len = data_len;
627 0 : mem_cookie->block_size = block_size;
628 0 : mem_cookie->flags.grow = !!grow;
629 : mem_cookie->func_realloc
630 0 : = grow? (func_realloc ? func_realloc : mem_realloc) : NULL;
631 0 : mem_cookie->func_free = func_free ? func_free : mem_free;
632 0 : *cookie = mem_cookie;
633 : err = 0;
634 : }
635 :
636 0 : return err;
637 : }
638 :
639 :
640 : /* Read function for memory objects. */
641 : static gpgrt_ssize_t
642 0 : es_func_mem_read (void *cookie, void *buffer, size_t size)
643 : {
644 : estream_cookie_mem_t mem_cookie = cookie;
645 : gpgrt_ssize_t ret;
646 :
647 0 : if (!size) /* Just the pending data check. */
648 0 : return (mem_cookie->data_len - mem_cookie->offset)? 0 : -1;
649 :
650 0 : if (size > mem_cookie->data_len - mem_cookie->offset)
651 : size = mem_cookie->data_len - mem_cookie->offset;
652 :
653 0 : if (size)
654 : {
655 0 : memcpy (buffer, mem_cookie->memory + mem_cookie->offset, size);
656 0 : mem_cookie->offset += size;
657 : }
658 :
659 0 : ret = size;
660 0 : return ret;
661 : }
662 :
663 :
664 : /* Write function for memory objects. */
665 : static gpgrt_ssize_t
666 0 : es_func_mem_write (void *cookie, const void *buffer, size_t size)
667 : {
668 : estream_cookie_mem_t mem_cookie = cookie;
669 : gpgrt_ssize_t ret;
670 : size_t nleft;
671 :
672 0 : if (!size)
673 : return 0; /* A flush is a NOP for memory objects. */
674 :
675 0 : if (mem_cookie->modeflags & O_APPEND)
676 : {
677 : /* Append to data. */
678 0 : mem_cookie->offset = mem_cookie->data_len;
679 : }
680 :
681 0 : assert (mem_cookie->memory_size >= mem_cookie->offset);
682 0 : nleft = mem_cookie->memory_size - mem_cookie->offset;
683 :
684 : /* If we are not allowed to grow the buffer, limit the size to the
685 : left space. */
686 0 : if (!mem_cookie->flags.grow && size > nleft)
687 : size = nleft;
688 :
689 : /* Enlarge the memory buffer if needed. */
690 0 : if (size > nleft)
691 : {
692 : unsigned char *newbuf;
693 : size_t newsize;
694 :
695 0 : if (!mem_cookie->memory_size)
696 : newsize = size; /* Not yet allocated. */
697 : else
698 0 : newsize = mem_cookie->memory_size + (size - nleft);
699 0 : if (newsize < mem_cookie->offset)
700 : {
701 0 : _set_errno (EINVAL);
702 0 : return -1;
703 : }
704 :
705 : /* Round up to the next block length. BLOCK_SIZE should always
706 : be set; we check anyway. */
707 0 : if (mem_cookie->block_size)
708 : {
709 0 : newsize += mem_cookie->block_size - 1;
710 0 : if (newsize < mem_cookie->offset)
711 : {
712 0 : _set_errno (EINVAL);
713 0 : return -1;
714 : }
715 0 : newsize /= mem_cookie->block_size;
716 0 : newsize *= mem_cookie->block_size;
717 : }
718 :
719 : /* Check for a total limit. */
720 0 : if (mem_cookie->memory_limit && newsize > mem_cookie->memory_limit)
721 : {
722 0 : _set_errno (ENOSPC);
723 0 : return -1;
724 : }
725 :
726 0 : assert (mem_cookie->func_realloc);
727 0 : newbuf = mem_cookie->func_realloc (mem_cookie->memory, newsize);
728 0 : if (!newbuf)
729 : return -1;
730 :
731 0 : mem_cookie->memory = newbuf;
732 0 : mem_cookie->memory_size = newsize;
733 :
734 0 : assert (mem_cookie->memory_size >= mem_cookie->offset);
735 0 : nleft = mem_cookie->memory_size - mem_cookie->offset;
736 :
737 0 : assert (size <= nleft);
738 : }
739 :
740 0 : memcpy (mem_cookie->memory + mem_cookie->offset, buffer, size);
741 0 : if (mem_cookie->offset + size > mem_cookie->data_len)
742 0 : mem_cookie->data_len = mem_cookie->offset + size;
743 0 : mem_cookie->offset += size;
744 :
745 0 : ret = size;
746 0 : return ret;
747 : }
748 :
749 :
750 : /* Seek function for memory objects. */
751 : static int
752 0 : es_func_mem_seek (void *cookie, gpgrt_off_t *offset, int whence)
753 : {
754 : estream_cookie_mem_t mem_cookie = cookie;
755 : gpgrt_off_t pos_new;
756 :
757 0 : switch (whence)
758 : {
759 : case SEEK_SET:
760 0 : pos_new = *offset;
761 0 : break;
762 :
763 : case SEEK_CUR:
764 0 : pos_new = mem_cookie->offset += *offset;
765 0 : break;
766 :
767 : case SEEK_END:
768 0 : pos_new = mem_cookie->data_len += *offset;
769 0 : break;
770 :
771 : default:
772 0 : _set_errno (EINVAL);
773 0 : return -1;
774 : }
775 :
776 0 : if (pos_new > mem_cookie->memory_size)
777 : {
778 : size_t newsize;
779 : void *newbuf;
780 :
781 0 : if (!mem_cookie->flags.grow)
782 : {
783 0 : _set_errno (ENOSPC);
784 0 : return -1;
785 : }
786 :
787 0 : newsize = pos_new + mem_cookie->block_size - 1;
788 0 : if (newsize < pos_new)
789 : {
790 0 : _set_errno (EINVAL);
791 0 : return -1;
792 : }
793 0 : newsize /= mem_cookie->block_size;
794 0 : newsize *= mem_cookie->block_size;
795 :
796 0 : if (mem_cookie->memory_limit && newsize > mem_cookie->memory_limit)
797 : {
798 0 : _set_errno (ENOSPC);
799 0 : return -1;
800 : }
801 :
802 0 : assert (mem_cookie->func_realloc);
803 0 : newbuf = mem_cookie->func_realloc (mem_cookie->memory, newsize);
804 0 : if (!newbuf)
805 : return -1;
806 :
807 0 : mem_cookie->memory = newbuf;
808 0 : mem_cookie->memory_size = newsize;
809 : }
810 :
811 0 : if (pos_new > mem_cookie->data_len)
812 : {
813 : /* Fill spare space with zeroes. */
814 0 : memset (mem_cookie->memory + mem_cookie->data_len,
815 : 0, pos_new - mem_cookie->data_len);
816 0 : mem_cookie->data_len = pos_new;
817 : }
818 :
819 0 : mem_cookie->offset = pos_new;
820 0 : *offset = pos_new;
821 :
822 0 : return 0;
823 : }
824 :
825 : /* An IOCTL function for memory objects. */
826 : static int
827 0 : es_func_mem_ioctl (void *cookie, int cmd, void *ptr, size_t *len)
828 : {
829 : estream_cookie_mem_t mem_cookie = cookie;
830 : int ret;
831 :
832 0 : if (cmd == COOKIE_IOCTL_SNATCH_BUFFER)
833 : {
834 : /* Return the internal buffer of the stream to the caller and
835 : invalidate it for the stream. */
836 0 : *(void**)ptr = mem_cookie->memory;
837 0 : *len = mem_cookie->offset;
838 0 : mem_cookie->memory = NULL;
839 0 : mem_cookie->memory_size = 0;
840 0 : mem_cookie->offset = 0;
841 : ret = 0;
842 : }
843 : else
844 : {
845 0 : _set_errno (EINVAL);
846 : ret = -1;
847 : }
848 :
849 0 : return ret;
850 : }
851 :
852 :
853 : /* Destroy function for memory objects. */
854 : static int
855 0 : es_func_mem_destroy (void *cookie)
856 : {
857 : estream_cookie_mem_t mem_cookie = cookie;
858 :
859 0 : if (cookie)
860 : {
861 0 : mem_cookie->func_free (mem_cookie->memory);
862 : mem_free (mem_cookie);
863 : }
864 0 : return 0;
865 : }
866 :
867 :
868 : static gpgrt_cookie_io_functions_t estream_functions_mem =
869 : {
870 : es_func_mem_read,
871 : es_func_mem_write,
872 : es_func_mem_seek,
873 : es_func_mem_destroy
874 : };
875 :
876 :
877 :
878 : /* Implementation of file descriptor based I/O. */
879 :
880 : /* Cookie for fd objects. */
881 : typedef struct estream_cookie_fd
882 : {
883 : int fd; /* The file descriptor we are using for actual output. */
884 : int no_close; /* If set we won't close the file descriptor. */
885 : int nonblock; /* Non-blocking mode is enabled. */
886 : } *estream_cookie_fd_t;
887 :
888 : /* Create function for objects indentified by a libc file descriptor. */
889 : static int
890 : func_fd_create (void **cookie, int fd, unsigned int modeflags, int no_close)
891 : {
892 : estream_cookie_fd_t fd_cookie;
893 : int err;
894 :
895 : fd_cookie = mem_alloc (sizeof (*fd_cookie));
896 6 : if (! fd_cookie)
897 : err = -1;
898 : else
899 : {
900 : #ifdef HAVE_DOSISH_SYSTEM
901 : /* Make sure it is in binary mode if requested. */
902 : if ( (modeflags & O_BINARY) )
903 : setmode (fd, O_BINARY);
904 : #endif
905 6 : fd_cookie->fd = fd;
906 6 : fd_cookie->no_close = no_close;
907 6 : fd_cookie->nonblock = !!(modeflags & O_NONBLOCK);
908 : *cookie = fd_cookie;
909 : err = 0;
910 : }
911 :
912 : return err;
913 : }
914 :
915 : /* Read function for fd objects. */
916 : static gpgrt_ssize_t
917 12 : es_func_fd_read (void *cookie, void *buffer, size_t size)
918 :
919 : {
920 : estream_cookie_fd_t file_cookie = cookie;
921 : gpgrt_ssize_t bytes_read;
922 :
923 12 : if (!size)
924 : bytes_read = -1; /* We don't know whether anything is pending. */
925 11 : else if (IS_INVALID_FD (file_cookie->fd))
926 : {
927 0 : _gpgrt_yield ();
928 : bytes_read = 0;
929 : }
930 : else
931 : {
932 11 : if (pre_syscall_func)
933 0 : pre_syscall_func ();
934 : do
935 : {
936 11 : bytes_read = read (file_cookie->fd, buffer, size);
937 : }
938 11 : while (bytes_read == -1 && errno == EINTR);
939 11 : if (post_syscall_func)
940 0 : post_syscall_func ();
941 : }
942 :
943 12 : return bytes_read;
944 : }
945 :
946 : /* Write function for fd objects. */
947 : static gpgrt_ssize_t
948 20 : es_func_fd_write (void *cookie, const void *buffer, size_t size)
949 : {
950 : estream_cookie_fd_t file_cookie = cookie;
951 : gpgrt_ssize_t bytes_written;
952 :
953 20 : if (IS_INVALID_FD (file_cookie->fd))
954 : {
955 0 : _gpgrt_yield ();
956 0 : bytes_written = size; /* Yeah: Success writing to the bit bucket. */
957 : }
958 20 : else if (buffer)
959 : {
960 10 : if (pre_syscall_func)
961 0 : pre_syscall_func ();
962 : do
963 : {
964 10 : bytes_written = write (file_cookie->fd, buffer, size);
965 : }
966 10 : while (bytes_written == -1 && errno == EINTR);
967 10 : if (post_syscall_func)
968 0 : post_syscall_func ();
969 : }
970 : else
971 10 : bytes_written = size; /* Note that for a flush SIZE should be 0. */
972 :
973 20 : return bytes_written;
974 : }
975 :
976 : /* Seek function for fd objects. */
977 : static int
978 0 : es_func_fd_seek (void *cookie, gpgrt_off_t *offset, int whence)
979 : {
980 : estream_cookie_fd_t file_cookie = cookie;
981 : gpgrt_off_t offset_new;
982 : int err;
983 :
984 0 : if (IS_INVALID_FD (file_cookie->fd))
985 : {
986 0 : _set_errno (ESPIPE);
987 : err = -1;
988 : }
989 : else
990 : {
991 0 : if (pre_syscall_func)
992 0 : pre_syscall_func ();
993 0 : offset_new = lseek (file_cookie->fd, *offset, whence);
994 0 : if (post_syscall_func)
995 0 : post_syscall_func ();
996 0 : if (offset_new == -1)
997 : err = -1;
998 : else
999 : {
1000 0 : *offset = offset_new;
1001 : err = 0;
1002 : }
1003 : }
1004 :
1005 0 : return err;
1006 : }
1007 :
1008 : /* An IOCTL function for fd objects. */
1009 : static int
1010 3 : es_func_fd_ioctl (void *cookie, int cmd, void *ptr, size_t *len)
1011 : {
1012 : estream_cookie_fd_t fd_cookie = cookie;
1013 : int ret;
1014 :
1015 3 : if (cmd == COOKIE_IOCTL_NONBLOCK && !len)
1016 : {
1017 3 : fd_cookie->nonblock = !!ptr;
1018 3 : if (IS_INVALID_FD (fd_cookie->fd))
1019 : {
1020 0 : _set_errno (EINVAL);
1021 : ret = -1;
1022 : }
1023 : else
1024 : {
1025 : #ifdef _WIN32
1026 : _set_errno (EOPNOTSUPP); /* FIXME: Implement for Windows. */
1027 : ret = -1;
1028 : #else
1029 3 : _set_errno (0);
1030 3 : ret = fcntl (fd_cookie->fd, F_GETFL, 0);
1031 3 : if (ret == -1 && errno)
1032 : ;
1033 3 : else if (fd_cookie->nonblock)
1034 3 : ret = fcntl (fd_cookie->fd, F_SETFL, (ret | O_NONBLOCK));
1035 : else
1036 0 : ret = fcntl (fd_cookie->fd, F_SETFL, (ret & ~O_NONBLOCK));
1037 : #endif
1038 : }
1039 : }
1040 : else
1041 : {
1042 0 : _set_errno (EINVAL);
1043 : ret = -1;
1044 : }
1045 :
1046 3 : return ret;
1047 : }
1048 :
1049 : /* Destroy function for fd objects. */
1050 : static int
1051 6 : es_func_fd_destroy (void *cookie)
1052 : {
1053 : estream_cookie_fd_t fd_cookie = cookie;
1054 : int err;
1055 :
1056 6 : if (fd_cookie)
1057 : {
1058 6 : if (IS_INVALID_FD (fd_cookie->fd))
1059 : err = 0;
1060 : else
1061 6 : err = fd_cookie->no_close? 0 : close (fd_cookie->fd);
1062 : mem_free (fd_cookie);
1063 : }
1064 : else
1065 : err = 0;
1066 :
1067 6 : return err;
1068 : }
1069 :
1070 :
1071 : static gpgrt_cookie_io_functions_t estream_functions_fd =
1072 : {
1073 : es_func_fd_read,
1074 : es_func_fd_write,
1075 : es_func_fd_seek,
1076 : es_func_fd_destroy
1077 : };
1078 :
1079 :
1080 :
1081 :
1082 : #ifdef HAVE_W32_SYSTEM
1083 : /* Implementation of W32 handle based I/O. */
1084 :
1085 : /* Cookie for fd objects. */
1086 : typedef struct estream_cookie_w32
1087 : {
1088 : HANDLE hd; /* The handle we are using for actual output. */
1089 : int no_close; /* If set we won't close the handle. */
1090 : } *estream_cookie_w32_t;
1091 :
1092 :
1093 : /* Create function for w32 handle objects. */
1094 : static int
1095 : es_func_w32_create (void **cookie, HANDLE hd,
1096 : unsigned int modeflags, int no_close)
1097 : {
1098 : estream_cookie_w32_t w32_cookie;
1099 : int err;
1100 :
1101 : w32_cookie = mem_alloc (sizeof (*w32_cookie));
1102 : if (!w32_cookie)
1103 : err = -1;
1104 : else
1105 : {
1106 : /* CR/LF translations are not supported when using the bare W32
1107 : API. If that is really required we need to implemented that
1108 : in the upper layer. */
1109 : (void)modeflags;
1110 :
1111 : w32_cookie->hd = hd;
1112 : w32_cookie->no_close = no_close;
1113 : *cookie = w32_cookie;
1114 : err = 0;
1115 : }
1116 :
1117 : return err;
1118 : }
1119 :
1120 : /* Read function for W32 handle objects. */
1121 : static gpgrt_ssize_t
1122 : es_func_w32_read (void *cookie, void *buffer, size_t size)
1123 : {
1124 : estream_cookie_w32_t w32_cookie = cookie;
1125 : gpgrt_ssize_t bytes_read;
1126 :
1127 : if (!size)
1128 : bytes_read = -1; /* We don't know whether anything is pending. */
1129 : else if (w32_cookie->hd == INVALID_HANDLE_VALUE)
1130 : {
1131 : _gpgrt_yield ();
1132 : bytes_read = 0;
1133 : }
1134 : else
1135 : {
1136 : if (pre_syscall_func)
1137 : pre_syscall_func ();
1138 : do
1139 : {
1140 : DWORD nread, ec;
1141 :
1142 : if (!ReadFile (w32_cookie->hd, buffer, size, &nread, NULL))
1143 : {
1144 : ec = GetLastError ();
1145 : if (ec == ERROR_BROKEN_PIPE)
1146 : bytes_read = 0; /* Like our pth_read we handle this as EOF. */
1147 : else
1148 : {
1149 : _set_errno (map_w32_to_errno (ec));
1150 : bytes_read = -1;
1151 : }
1152 : }
1153 : else
1154 : bytes_read = (int)nread;
1155 : }
1156 : while (bytes_read == -1 && errno == EINTR);
1157 : if (post_syscall_func)
1158 : post_syscall_func ();
1159 : }
1160 :
1161 : return bytes_read;
1162 : }
1163 :
1164 : /* Write function for W32 handle objects. */
1165 : static gpgrt_ssize_t
1166 : es_func_w32_write (void *cookie, const void *buffer, size_t size)
1167 : {
1168 : estream_cookie_w32_t w32_cookie = cookie;
1169 : gpgrt_ssize_t bytes_written;
1170 :
1171 : if (w32_cookie->hd == INVALID_HANDLE_VALUE)
1172 : {
1173 : _gpgrt_yield ();
1174 : bytes_written = size; /* Yeah: Success writing to the bit bucket. */
1175 : }
1176 : else if (buffer)
1177 : {
1178 : if (pre_syscall_func)
1179 : pre_syscall_func ();
1180 : do
1181 : {
1182 : DWORD nwritten;
1183 :
1184 : if (!WriteFile (w32_cookie->hd, buffer, size, &nwritten, NULL))
1185 : {
1186 : _set_errno (map_w32_to_errno (GetLastError ()));
1187 : bytes_written = -1;
1188 : }
1189 : else
1190 : bytes_written = (int)nwritten;
1191 : }
1192 : while (bytes_written == -1 && errno == EINTR);
1193 : if (post_syscall_func)
1194 : post_syscall_func ();
1195 : }
1196 : else
1197 : bytes_written = size; /* Note that for a flush SIZE should be 0. */
1198 :
1199 : return bytes_written;
1200 : }
1201 :
1202 : /* Seek function for W32 handle objects. */
1203 : static int
1204 : es_func_w32_seek (void *cookie, gpgrt_off_t *offset, int whence)
1205 : {
1206 : estream_cookie_w32_t w32_cookie = cookie;
1207 : DWORD method;
1208 : LARGE_INTEGER distance, newoff;
1209 :
1210 : if (w32_cookie->hd == INVALID_HANDLE_VALUE)
1211 : {
1212 : _set_errno (ESPIPE);
1213 : return -1;
1214 : }
1215 :
1216 : if (whence == SEEK_SET)
1217 : {
1218 : method = FILE_BEGIN;
1219 : distance.QuadPart = (unsigned long long)(*offset);
1220 : }
1221 : else if (whence == SEEK_CUR)
1222 : {
1223 : method = FILE_CURRENT;
1224 : distance.QuadPart = (long long)(*offset);
1225 : }
1226 : else if (whence == SEEK_END)
1227 : {
1228 : method = FILE_END;
1229 : distance.QuadPart = (long long)(*offset);
1230 : }
1231 : else
1232 : {
1233 : _set_errno (EINVAL);
1234 : return -1;
1235 : }
1236 : #ifdef HAVE_W32CE_SYSTEM
1237 : # warning need to use SetFilePointer
1238 : #else
1239 : if (pre_syscall_func)
1240 : pre_syscall_func ();
1241 : if (!SetFilePointerEx (w32_cookie->hd, distance, &newoff, method))
1242 : {
1243 : _set_errno (map_w32_to_errno (GetLastError ()));
1244 : if (post_syscall_func)
1245 : post_syscall_func ();
1246 : return -1;
1247 : }
1248 : if (post_syscall_func)
1249 : post_syscall_func ();
1250 : #endif
1251 : /* Note that gpgrt_off_t is always 64 bit. */
1252 : *offset = (gpgrt_off_t)newoff.QuadPart;
1253 : return 0;
1254 : }
1255 :
1256 : /* Destroy function for W32 handle objects. */
1257 : static int
1258 : es_func_w32_destroy (void *cookie)
1259 : {
1260 : estream_cookie_w32_t w32_cookie = cookie;
1261 : int err;
1262 :
1263 : if (w32_cookie)
1264 : {
1265 : if (w32_cookie->hd == INVALID_HANDLE_VALUE)
1266 : err = 0;
1267 : else if (w32_cookie->no_close)
1268 : err = 0;
1269 : else
1270 : {
1271 : if (!CloseHandle (w32_cookie->hd))
1272 : {
1273 : _set_errno (map_w32_to_errno (GetLastError ()));
1274 : err = -1;
1275 : }
1276 : else
1277 : err = 0;
1278 : }
1279 : mem_free (w32_cookie);
1280 : }
1281 : else
1282 : err = 0;
1283 :
1284 : return err;
1285 : }
1286 :
1287 :
1288 : static gpgrt_cookie_io_functions_t estream_functions_w32 =
1289 : {
1290 : es_func_w32_read,
1291 : es_func_w32_write,
1292 : es_func_w32_seek,
1293 : es_func_w32_destroy
1294 : };
1295 : #endif /*HAVE_W32_SYSTEM*/
1296 :
1297 :
1298 :
1299 :
1300 : /* Implementation of FILE* I/O. */
1301 :
1302 : /* Cookie for fp objects. */
1303 : typedef struct estream_cookie_fp
1304 : {
1305 : FILE *fp; /* The file pointer we are using for actual output. */
1306 : int no_close; /* If set we won't close the file pointer. */
1307 : } *estream_cookie_fp_t;
1308 :
1309 :
1310 : /* Create function for FILE objects. */
1311 : static int
1312 0 : func_fp_create (void **cookie, FILE *fp,
1313 : unsigned int modeflags, int no_close)
1314 : {
1315 : estream_cookie_fp_t fp_cookie;
1316 : int err;
1317 :
1318 : fp_cookie = mem_alloc (sizeof *fp_cookie);
1319 0 : if (!fp_cookie)
1320 : err = -1;
1321 : else
1322 : {
1323 : #ifdef HAVE_DOSISH_SYSTEM
1324 : /* Make sure it is in binary mode if requested. */
1325 : if ( (modeflags & O_BINARY) )
1326 : setmode (fileno (fp), O_BINARY);
1327 : #else
1328 : (void)modeflags;
1329 : #endif
1330 0 : fp_cookie->fp = fp;
1331 0 : fp_cookie->no_close = no_close;
1332 0 : *cookie = fp_cookie;
1333 : err = 0;
1334 : }
1335 :
1336 0 : return err;
1337 : }
1338 :
1339 : /* Read function for FILE* objects. */
1340 : static gpgrt_ssize_t
1341 0 : es_func_fp_read (void *cookie, void *buffer, size_t size)
1342 :
1343 : {
1344 : estream_cookie_fp_t file_cookie = cookie;
1345 : gpgrt_ssize_t bytes_read;
1346 :
1347 0 : if (!size)
1348 : return -1; /* We don't know whether anything is pending. */
1349 :
1350 0 : if (file_cookie->fp)
1351 : {
1352 0 : if (pre_syscall_func)
1353 0 : pre_syscall_func ();
1354 0 : bytes_read = fread (buffer, 1, size, file_cookie->fp);
1355 0 : if (post_syscall_func)
1356 0 : post_syscall_func ();
1357 : }
1358 : else
1359 : bytes_read = 0;
1360 0 : if (!bytes_read && ferror (file_cookie->fp))
1361 : return -1;
1362 0 : return bytes_read;
1363 : }
1364 :
1365 : /* Write function for FILE* objects. */
1366 : static gpgrt_ssize_t
1367 0 : es_func_fp_write (void *cookie, const void *buffer, size_t size)
1368 : {
1369 : estream_cookie_fp_t file_cookie = cookie;
1370 : size_t bytes_written;
1371 :
1372 0 : if (file_cookie->fp)
1373 : {
1374 0 : if (pre_syscall_func)
1375 0 : pre_syscall_func ();
1376 0 : if (buffer)
1377 : {
1378 : #ifdef HAVE_W32_SYSTEM
1379 : /* Using an fwrite to stdout connected to the console fails
1380 : with the error "Not enough space" for an fwrite size of
1381 : >= 52KB (tested on Windows XP SP2). To solve this we
1382 : always chunk the writes up into smaller blocks. */
1383 : bytes_written = 0;
1384 : while (bytes_written < size)
1385 : {
1386 : size_t cnt = size - bytes_written;
1387 :
1388 : if (cnt > 32*1024)
1389 : cnt = 32*1024;
1390 : if (fwrite ((const char*)buffer + bytes_written,
1391 : cnt, 1, file_cookie->fp) != 1)
1392 : break; /* Write error. */
1393 : bytes_written += cnt;
1394 : }
1395 : #else
1396 0 : bytes_written = fwrite (buffer, 1, size, file_cookie->fp);
1397 : #endif
1398 : }
1399 : else /* Only flush requested. */
1400 : bytes_written = size;
1401 :
1402 0 : fflush (file_cookie->fp);
1403 0 : if (post_syscall_func)
1404 0 : post_syscall_func ();
1405 : }
1406 : else
1407 : bytes_written = size; /* Successfully written to the bit bucket. */
1408 :
1409 0 : if (bytes_written != size)
1410 : return -1;
1411 0 : return bytes_written;
1412 : }
1413 :
1414 : /* Seek function for FILE* objects. */
1415 : static int
1416 0 : es_func_fp_seek (void *cookie, gpgrt_off_t *offset, int whence)
1417 : {
1418 : estream_cookie_fp_t file_cookie = cookie;
1419 : long int offset_new;
1420 :
1421 0 : if (!file_cookie->fp)
1422 : {
1423 0 : _set_errno (ESPIPE);
1424 0 : return -1;
1425 : }
1426 :
1427 0 : if (pre_syscall_func)
1428 0 : pre_syscall_func ();
1429 0 : if ( fseek (file_cookie->fp, (long int)*offset, whence) )
1430 : {
1431 : /* fprintf (stderr, "\nfseek failed: errno=%d (%s)\n", */
1432 : /* errno,strerror (errno)); */
1433 0 : if (post_syscall_func)
1434 0 : post_syscall_func ();
1435 : return -1;
1436 : }
1437 :
1438 0 : offset_new = ftell (file_cookie->fp);
1439 0 : if (post_syscall_func)
1440 0 : post_syscall_func ();
1441 0 : if (offset_new == -1)
1442 : {
1443 : /* fprintf (stderr, "\nftell failed: errno=%d (%s)\n", */
1444 : /* errno,strerror (errno)); */
1445 : return -1;
1446 : }
1447 0 : *offset = offset_new;
1448 0 : return 0;
1449 : }
1450 :
1451 : /* Destroy function for FILE* objects. */
1452 : static int
1453 0 : es_func_fp_destroy (void *cookie)
1454 : {
1455 : estream_cookie_fp_t fp_cookie = cookie;
1456 : int err;
1457 :
1458 0 : if (fp_cookie)
1459 : {
1460 0 : if (fp_cookie->fp)
1461 : {
1462 0 : if (pre_syscall_func)
1463 0 : pre_syscall_func ();
1464 0 : fflush (fp_cookie->fp);
1465 0 : if (post_syscall_func)
1466 0 : post_syscall_func ();
1467 0 : err = fp_cookie->no_close? 0 : fclose (fp_cookie->fp);
1468 : }
1469 : else
1470 : err = 0;
1471 : mem_free (fp_cookie);
1472 : }
1473 : else
1474 : err = 0;
1475 :
1476 0 : return err;
1477 : }
1478 :
1479 :
1480 : static gpgrt_cookie_io_functions_t estream_functions_fp =
1481 : {
1482 : es_func_fp_read,
1483 : es_func_fp_write,
1484 : es_func_fp_seek,
1485 : es_func_fp_destroy
1486 : };
1487 :
1488 :
1489 :
1490 :
1491 : /* Implementation of file I/O. */
1492 :
1493 : /* Create function for objects identified by a file name. */
1494 : static int
1495 0 : func_file_create (void **cookie, int *filedes,
1496 : const char *path, unsigned int modeflags, unsigned int cmode)
1497 : {
1498 : estream_cookie_fd_t file_cookie;
1499 : int err;
1500 : int fd;
1501 :
1502 : err = 0;
1503 : fd = -1;
1504 :
1505 : file_cookie = mem_alloc (sizeof (*file_cookie));
1506 0 : if (! file_cookie)
1507 : {
1508 : err = -1;
1509 : goto out;
1510 : }
1511 :
1512 0 : fd = open (path, modeflags, cmode);
1513 0 : if (fd == -1)
1514 : {
1515 : err = -1;
1516 : goto out;
1517 : }
1518 : #ifdef HAVE_DOSISH_SYSTEM
1519 : /* Make sure it is in binary mode if requested. */
1520 : if ( (modeflags & O_BINARY) )
1521 : setmode (fd, O_BINARY);
1522 : #endif
1523 :
1524 0 : file_cookie->fd = fd;
1525 0 : file_cookie->no_close = 0;
1526 0 : *cookie = file_cookie;
1527 0 : *filedes = fd;
1528 :
1529 : out:
1530 :
1531 0 : if (err)
1532 : mem_free (file_cookie);
1533 :
1534 0 : return err;
1535 : }
1536 :
1537 :
1538 :
1539 : /* Parse the mode flags of fopen et al. In addition to the POSIX
1540 : defined mode flags keyword parameters are supported. These are
1541 : key/value pairs delimited by comma and optional white spaces.
1542 : Keywords and values may not contain a comma or white space; unknown
1543 : keywords are skipped. Supported keywords are:
1544 :
1545 : mode=<string>
1546 :
1547 : Creates a file and gives the new file read and write permissions
1548 : for the user and read permission for the group. The format of
1549 : the string is the same as shown by the -l option of the ls(1)
1550 : command. However the first letter must be a dash and it is
1551 : allowed to leave out trailing dashes. If this keyword parameter
1552 : is not given the default mode for creating files is "-rw-rw-r--"
1553 : (664). Note that the system still applies the current umask to
1554 : the mode when crating a file. Example:
1555 :
1556 : "wb,mode=-rw-r--"
1557 :
1558 : samethread
1559 :
1560 : Assumes that the object is only used by the creating thread and
1561 : disables any internal locking. This keyword is also found on
1562 : IBM systems.
1563 :
1564 : nonblock
1565 :
1566 : The object is opened in non-blocking mode. This is the same as
1567 : calling gpgrt_set_nonblock on the file.
1568 :
1569 : Note: R_CMODE is optional because is only required by functions
1570 : which are able to creat a file. */
1571 : static int
1572 6 : parse_mode (const char *modestr,
1573 : unsigned int *modeflags, int *samethread,
1574 : unsigned int *r_cmode)
1575 : {
1576 : unsigned int omode, oflags, cmode;
1577 : int got_cmode = 0;
1578 :
1579 6 : *samethread = 0;
1580 :
1581 6 : switch (*modestr)
1582 : {
1583 : case 'r':
1584 : omode = O_RDONLY;
1585 : oflags = 0;
1586 : break;
1587 : case 'w':
1588 : omode = O_WRONLY;
1589 : oflags = O_TRUNC | O_CREAT;
1590 3 : break;
1591 : case 'a':
1592 : omode = O_WRONLY;
1593 : oflags = O_APPEND | O_CREAT;
1594 0 : break;
1595 : default:
1596 0 : _set_errno (EINVAL);
1597 0 : return -1;
1598 : }
1599 6 : for (modestr++; *modestr; modestr++)
1600 : {
1601 0 : switch (*modestr)
1602 : {
1603 : case '+':
1604 : omode = O_RDWR;
1605 0 : break;
1606 : case 'b':
1607 : oflags |= O_BINARY;
1608 : break;
1609 : case 'x':
1610 0 : oflags |= O_EXCL;
1611 0 : break;
1612 : case ',':
1613 : goto keyvalue;
1614 : default: /* Ignore unknown flags. */
1615 : break;
1616 : }
1617 : }
1618 :
1619 : keyvalue:
1620 : /* Parse key/value pairs (similar to fopen on mainframes). */
1621 0 : for (cmode=0; *modestr == ','; modestr += strcspn (modestr, ","))
1622 : {
1623 0 : modestr++;
1624 0 : modestr += strspn (modestr, " \t");
1625 0 : if (!strncmp (modestr, "mode=", 5))
1626 : {
1627 : static struct {
1628 : char letter;
1629 : unsigned int value;
1630 : } table[] = { { '-', 0 },
1631 : { 'r', S_IRUSR }, { 'w', S_IWUSR }, { 'x', S_IXUSR },
1632 : { 'r', S_IRGRP }, { 'w', S_IWGRP }, { 'x', S_IXGRP },
1633 : { 'r', S_IROTH }, { 'w', S_IWOTH }, { 'x', S_IXOTH }};
1634 : int idx;
1635 :
1636 : got_cmode = 1;
1637 0 : modestr += 5;
1638 : /* For now we only support a string as used by ls(1) and no
1639 : octal numbers. The first character must be a dash. */
1640 0 : for (idx=0; idx < 10 && *modestr; idx++, modestr++)
1641 : {
1642 0 : if (*modestr == table[idx].letter)
1643 0 : cmode |= table[idx].value;
1644 0 : else if (*modestr != '-')
1645 : break;
1646 : }
1647 0 : if (*modestr && !strchr (" \t,", *modestr))
1648 : {
1649 0 : _set_errno (EINVAL);
1650 0 : return -1;
1651 : }
1652 : }
1653 0 : else if (!strncmp (modestr, "samethread", 10))
1654 : {
1655 0 : modestr += 10;
1656 0 : if (*modestr && !strchr (" \t,", *modestr))
1657 : {
1658 0 : _set_errno (EINVAL);
1659 0 : return -1;
1660 : }
1661 0 : *samethread = 1;
1662 : }
1663 0 : else if (!strncmp (modestr, "nonblock", 8))
1664 : {
1665 0 : modestr += 8;
1666 0 : if (*modestr && !strchr (" \t,", *modestr))
1667 : {
1668 0 : _set_errno (EINVAL);
1669 0 : return -1;
1670 : }
1671 0 : oflags |= O_NONBLOCK;
1672 : }
1673 : }
1674 6 : if (!got_cmode)
1675 : cmode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
1676 :
1677 6 : *modeflags = (omode | oflags);
1678 6 : if (r_cmode)
1679 0 : *r_cmode = cmode;
1680 : return 0;
1681 : }
1682 :
1683 :
1684 :
1685 : /*
1686 : * Low level stream functionality.
1687 : */
1688 :
1689 : static int
1690 11 : es_fill (estream_t stream)
1691 : {
1692 : size_t bytes_read = 0;
1693 : int err;
1694 :
1695 11 : if (!stream->intern->func_read)
1696 : {
1697 0 : _set_errno (EOPNOTSUPP);
1698 : err = -1;
1699 : }
1700 11 : else if (!stream->buffer_size)
1701 : err = 0;
1702 : else
1703 : {
1704 : gpgrt_cookie_read_function_t func_read = stream->intern->func_read;
1705 : gpgrt_ssize_t ret;
1706 :
1707 11 : ret = (*func_read) (stream->intern->cookie,
1708 11 : stream->buffer, stream->buffer_size);
1709 11 : if (ret == -1)
1710 : {
1711 : bytes_read = 0;
1712 : err = -1;
1713 : #if EWOULDBLOCK != EAGAIN
1714 : if (errno == EWOULDBLOCK)
1715 : _set_errno (EAGAIN);
1716 : #endif
1717 : }
1718 : else
1719 : {
1720 11 : bytes_read = ret;
1721 : err = 0;
1722 : }
1723 : }
1724 :
1725 11 : if (err)
1726 : {
1727 0 : if (errno != EAGAIN)
1728 : {
1729 0 : if (errno == EPIPE)
1730 0 : stream->intern->indicators.hup = 1;
1731 0 : stream->intern->indicators.err = 1;
1732 : }
1733 : }
1734 11 : else if (!bytes_read)
1735 3 : stream->intern->indicators.eof = 1;
1736 :
1737 11 : stream->intern->offset += stream->data_len;
1738 11 : stream->data_len = bytes_read;
1739 11 : stream->data_offset = 0;
1740 :
1741 11 : return err;
1742 : }
1743 :
1744 : static int
1745 13 : es_flush (estream_t stream)
1746 : {
1747 13 : gpgrt_cookie_write_function_t func_write = stream->intern->func_write;
1748 : int err;
1749 :
1750 13 : assert (stream->flags.writing);
1751 :
1752 13 : if (stream->data_offset)
1753 : {
1754 : size_t bytes_written;
1755 : size_t data_flushed;
1756 : gpgrt_ssize_t ret;
1757 :
1758 10 : if (! func_write)
1759 : {
1760 : err = EOPNOTSUPP;
1761 : goto out;
1762 : }
1763 :
1764 : /* Note: to prevent an endless loop caused by user-provided
1765 : write-functions that pretend to have written more bytes than
1766 : they were asked to write, we have to check for
1767 : "(stream->data_offset - data_flushed) > 0" instead of
1768 : "stream->data_offset - data_flushed". */
1769 :
1770 : data_flushed = 0;
1771 : err = 0;
1772 :
1773 20 : while ((((gpgrt_ssize_t) (stream->data_offset - data_flushed)) > 0)
1774 10 : && !err)
1775 : {
1776 10 : ret = (*func_write) (stream->intern->cookie,
1777 10 : stream->buffer + data_flushed,
1778 : stream->data_offset - data_flushed);
1779 10 : if (ret == -1)
1780 : {
1781 : bytes_written = 0;
1782 : err = -1;
1783 : #if EWOULDBLOCK != EAGAIN
1784 : if (errno == EWOULDBLOCK)
1785 : _set_errno (EAGAIN);
1786 : #endif
1787 : }
1788 : else
1789 10 : bytes_written = ret;
1790 :
1791 10 : data_flushed += bytes_written;
1792 10 : if (err)
1793 : break;
1794 : }
1795 :
1796 10 : stream->data_flushed += data_flushed;
1797 10 : if (stream->data_offset == data_flushed)
1798 : {
1799 10 : stream->intern->offset += stream->data_offset;
1800 10 : stream->data_offset = 0;
1801 10 : stream->data_flushed = 0;
1802 :
1803 : /* Propagate flush event. */
1804 10 : (*func_write) (stream->intern->cookie, NULL, 0);
1805 : }
1806 : }
1807 : else
1808 : err = 0;
1809 :
1810 : out:
1811 :
1812 13 : if (err && errno != EAGAIN)
1813 : {
1814 0 : if (errno == EPIPE)
1815 0 : stream->intern->indicators.hup = 1;
1816 0 : stream->intern->indicators.err = 1;
1817 : }
1818 :
1819 13 : return err;
1820 : }
1821 :
1822 : /* Discard buffered data for STREAM. */
1823 : static void
1824 0 : es_empty (estream_t stream)
1825 : {
1826 0 : assert (!stream->flags.writing);
1827 0 : stream->data_len = 0;
1828 0 : stream->data_offset = 0;
1829 0 : stream->unread_data_len = 0;
1830 0 : }
1831 :
1832 : /* Initialize STREAM. */
1833 : static void
1834 6 : init_stream_obj (estream_t stream,
1835 : void *cookie, es_syshd_t *syshd,
1836 : gpgrt_cookie_io_functions_t functions,
1837 : unsigned int modeflags, int samethread)
1838 : {
1839 6 : stream->intern->cookie = cookie;
1840 6 : stream->intern->opaque = NULL;
1841 6 : stream->intern->offset = 0;
1842 6 : stream->intern->func_read = functions.func_read;
1843 6 : stream->intern->func_write = functions.func_write;
1844 6 : stream->intern->func_seek = functions.func_seek;
1845 6 : stream->intern->func_ioctl = NULL;
1846 6 : stream->intern->func_close = functions.func_close;
1847 6 : stream->intern->strategy = _IOFBF;
1848 6 : stream->intern->syshd = *syshd;
1849 6 : stream->intern->print_ntotal = 0;
1850 6 : stream->intern->indicators.err = 0;
1851 6 : stream->intern->indicators.eof = 0;
1852 6 : stream->intern->indicators.hup = 0;
1853 6 : stream->intern->is_stdstream = 0;
1854 6 : stream->intern->stdstream_fd = 0;
1855 6 : stream->intern->deallocate_buffer = 0;
1856 6 : stream->intern->printable_fname = NULL;
1857 6 : stream->intern->printable_fname_inuse = 0;
1858 6 : stream->intern->samethread = !!samethread;
1859 6 : stream->intern->onclose = NULL;
1860 :
1861 6 : stream->data_len = 0;
1862 6 : stream->data_offset = 0;
1863 6 : stream->data_flushed = 0;
1864 6 : stream->unread_data_len = 0;
1865 : /* Depending on the modeflags we set whether we start in writing or
1866 : reading mode. This is required in case we are working on a
1867 : stream which is not seeekable (like stdout). Without this
1868 : pre-initialization we would do a seek at the first write call and
1869 : as this will fail no output will be delivered. */
1870 6 : if ((modeflags & O_WRONLY) || (modeflags & O_RDWR) )
1871 3 : stream->flags.writing = 1;
1872 : else
1873 3 : stream->flags.writing = 0;
1874 6 : }
1875 :
1876 : /* Deinitialize STREAM. */
1877 : static int
1878 6 : es_deinitialize (estream_t stream)
1879 : {
1880 : gpgrt_cookie_close_function_t func_close;
1881 : int err, tmp_err;
1882 :
1883 6 : func_close = stream->intern->func_close;
1884 :
1885 : err = 0;
1886 6 : if (stream->flags.writing)
1887 3 : SET_UNLESS_NONZERO (err, tmp_err, es_flush (stream));
1888 6 : if (func_close)
1889 6 : SET_UNLESS_NONZERO (err, tmp_err, (*func_close) (stream->intern->cookie));
1890 :
1891 6 : mem_free (stream->intern->printable_fname);
1892 6 : stream->intern->printable_fname = NULL;
1893 6 : stream->intern->printable_fname_inuse = 0;
1894 12 : while (stream->intern->onclose)
1895 : {
1896 0 : notify_list_t tmp = stream->intern->onclose->next;
1897 : mem_free (stream->intern->onclose);
1898 0 : stream->intern->onclose = tmp;
1899 : }
1900 :
1901 6 : return err;
1902 : }
1903 :
1904 : /* Create a new stream object, initialize it. */
1905 : static int
1906 6 : es_create (estream_t *stream, void *cookie, es_syshd_t *syshd,
1907 : gpgrt_cookie_io_functions_t functions, unsigned int modeflags,
1908 : int samethread, int with_locked_list)
1909 : {
1910 : estream_internal_t stream_internal_new;
1911 : estream_t stream_new;
1912 : int err;
1913 :
1914 : stream_new = NULL;
1915 : stream_internal_new = NULL;
1916 :
1917 : stream_new = mem_alloc (sizeof (*stream_new));
1918 6 : if (! stream_new)
1919 : {
1920 : err = -1;
1921 : goto out;
1922 : }
1923 :
1924 : stream_internal_new = mem_alloc (sizeof (*stream_internal_new));
1925 6 : if (! stream_internal_new)
1926 : {
1927 : err = -1;
1928 : goto out;
1929 : }
1930 :
1931 6 : stream_new->buffer = stream_internal_new->buffer;
1932 6 : stream_new->buffer_size = sizeof (stream_internal_new->buffer);
1933 6 : stream_new->unread_buffer = stream_internal_new->unread_buffer;
1934 6 : stream_new->unread_buffer_size = sizeof (stream_internal_new->unread_buffer);
1935 6 : stream_new->intern = stream_internal_new;
1936 :
1937 6 : init_stream_obj (stream_new, cookie, syshd, functions, modeflags, samethread);
1938 6 : init_stream_lock (stream_new);
1939 :
1940 6 : err = do_list_add (stream_new, with_locked_list);
1941 6 : if (err)
1942 : goto out;
1943 :
1944 6 : *stream = stream_new;
1945 :
1946 : out:
1947 :
1948 6 : if (err)
1949 : {
1950 0 : if (stream_new)
1951 : {
1952 0 : es_deinitialize (stream_new);
1953 : destroy_stream_lock (stream_new);
1954 0 : mem_free (stream_new->intern);
1955 : mem_free (stream_new);
1956 : }
1957 : }
1958 :
1959 6 : return err;
1960 : }
1961 :
1962 : /* Deinitialize a stream object and destroy it. */
1963 : static int
1964 6 : do_close (estream_t stream, int with_locked_list)
1965 : {
1966 : int err;
1967 :
1968 6 : if (stream)
1969 : {
1970 6 : do_list_remove (stream, with_locked_list);
1971 12 : while (stream->intern->onclose)
1972 : {
1973 0 : notify_list_t tmp = stream->intern->onclose->next;
1974 :
1975 0 : if (stream->intern->onclose->fnc)
1976 0 : stream->intern->onclose->fnc (stream,
1977 : stream->intern->onclose->fnc_value);
1978 0 : mem_free (stream->intern->onclose);
1979 0 : stream->intern->onclose = tmp;
1980 : }
1981 6 : err = es_deinitialize (stream);
1982 : destroy_stream_lock (stream);
1983 6 : mem_free (stream->intern);
1984 : mem_free (stream);
1985 : }
1986 : else
1987 : err = 0;
1988 :
1989 6 : return err;
1990 : }
1991 :
1992 :
1993 : /* This worker function is called with a locked stream. */
1994 : static int
1995 0 : do_onclose (estream_t stream, int mode,
1996 : void (*fnc) (estream_t, void*), void *fnc_value)
1997 : {
1998 : notify_list_t item;
1999 :
2000 0 : if (!mode)
2001 : {
2002 0 : for (item = stream->intern->onclose; item; item = item->next)
2003 0 : if (item->fnc && item->fnc == fnc && item->fnc_value == fnc_value)
2004 0 : item->fnc = NULL; /* Disable this notification. */
2005 : }
2006 : else
2007 : {
2008 : item = mem_alloc (sizeof *item);
2009 0 : if (!item)
2010 : return -1;
2011 0 : item->fnc = fnc;
2012 0 : item->fnc_value = fnc_value;
2013 0 : item->next = stream->intern->onclose;
2014 0 : stream->intern->onclose = item;
2015 : }
2016 : return 0;
2017 : }
2018 :
2019 :
2020 : /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in
2021 : unbuffered-mode, storing the amount of bytes read in
2022 : *BYTES_READ. */
2023 : static int
2024 0 : es_read_nbf (estream_t _GPGRT__RESTRICT stream,
2025 : unsigned char *_GPGRT__RESTRICT buffer,
2026 : size_t bytes_to_read, size_t *_GPGRT__RESTRICT bytes_read)
2027 : {
2028 0 : gpgrt_cookie_read_function_t func_read = stream->intern->func_read;
2029 : size_t data_read;
2030 : gpgrt_ssize_t ret;
2031 : int err;
2032 :
2033 : data_read = 0;
2034 : err = 0;
2035 :
2036 0 : while (bytes_to_read - data_read)
2037 : {
2038 0 : ret = (*func_read) (stream->intern->cookie,
2039 : buffer + data_read, bytes_to_read - data_read);
2040 0 : if (ret == -1)
2041 : {
2042 : err = -1;
2043 : #if EWOULDBLOCK != EAGAIN
2044 : if (errno == EWOULDBLOCK)
2045 : _set_errno (EAGAIN);
2046 : #endif
2047 : break;
2048 : }
2049 0 : else if (ret)
2050 0 : data_read += ret;
2051 : else
2052 : break;
2053 : }
2054 :
2055 0 : stream->intern->offset += data_read;
2056 0 : *bytes_read = data_read;
2057 :
2058 0 : return err;
2059 : }
2060 :
2061 : static int
2062 0 : check_pending_nbf (estream_t _GPGRT__RESTRICT stream)
2063 : {
2064 0 : gpgrt_cookie_read_function_t func_read = stream->intern->func_read;
2065 : char buffer[1];
2066 :
2067 0 : if (!(*func_read) (stream->intern->cookie, buffer, 0))
2068 : return 1; /* Pending bytes. */
2069 0 : return 0; /* No pending bytes or error. */
2070 : }
2071 :
2072 :
2073 : /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in
2074 : fully-buffered-mode, storing the amount of bytes read in
2075 : *BYTES_READ. */
2076 : static int
2077 11 : es_read_fbf (estream_t _GPGRT__RESTRICT stream,
2078 : unsigned char *_GPGRT__RESTRICT buffer,
2079 : size_t bytes_to_read, size_t *_GPGRT__RESTRICT bytes_read)
2080 : {
2081 : size_t data_available;
2082 : size_t data_to_read;
2083 : size_t data_read;
2084 : int err;
2085 :
2086 : data_read = 0;
2087 : err = 0;
2088 :
2089 30 : while ((bytes_to_read - data_read) && (! err))
2090 : {
2091 11 : if (stream->data_offset == stream->data_len)
2092 : {
2093 : /* Nothing more to read in current container, try to
2094 : fill container with new data. */
2095 11 : err = es_fill (stream);
2096 11 : if (! err)
2097 11 : if (! stream->data_len)
2098 : /* Filling did not result in any data read. */
2099 : break;
2100 : }
2101 :
2102 8 : if (! err)
2103 : {
2104 : /* Filling resulted in some new data. */
2105 :
2106 8 : data_to_read = bytes_to_read - data_read;
2107 8 : data_available = stream->data_len - stream->data_offset;
2108 8 : if (data_to_read > data_available)
2109 : data_to_read = data_available;
2110 :
2111 8 : memcpy (buffer + data_read,
2112 8 : stream->buffer + stream->data_offset, data_to_read);
2113 8 : stream->data_offset += data_to_read;
2114 8 : data_read += data_to_read;
2115 : }
2116 : }
2117 :
2118 11 : *bytes_read = data_read;
2119 :
2120 11 : return err;
2121 : }
2122 :
2123 :
2124 : static int
2125 7 : check_pending_fbf (estream_t _GPGRT__RESTRICT stream)
2126 : {
2127 7 : gpgrt_cookie_read_function_t func_read = stream->intern->func_read;
2128 : char buffer[1];
2129 :
2130 7 : if (stream->data_offset == stream->data_len)
2131 : {
2132 : /* Nothing more to read in current container, check whether it
2133 : would be possible to fill the container with new data. */
2134 1 : if (!(*func_read) (stream->intern->cookie, buffer, 0))
2135 : return 1; /* Pending bytes. */
2136 : }
2137 : else
2138 : return 1;
2139 1 : return 0;
2140 : }
2141 :
2142 :
2143 : /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in
2144 : line-buffered-mode, storing the amount of bytes read in
2145 : *BYTES_READ. */
2146 : static int
2147 : es_read_lbf (estream_t _GPGRT__RESTRICT stream,
2148 : unsigned char *_GPGRT__RESTRICT buffer,
2149 : size_t bytes_to_read, size_t *_GPGRT__RESTRICT bytes_read)
2150 : {
2151 : int err;
2152 :
2153 0 : err = es_read_fbf (stream, buffer, bytes_to_read, bytes_read);
2154 :
2155 : return err;
2156 : }
2157 :
2158 : /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER, storing
2159 : the amount of bytes read in BYTES_READ. */
2160 : static int
2161 11 : es_readn (estream_t _GPGRT__RESTRICT stream,
2162 : void *_GPGRT__RESTRICT buffer_arg,
2163 : size_t bytes_to_read, size_t *_GPGRT__RESTRICT bytes_read)
2164 : {
2165 : unsigned char *buffer = (unsigned char *)buffer_arg;
2166 : size_t data_read_unread, data_read;
2167 : int err;
2168 :
2169 : data_read_unread = 0;
2170 11 : data_read = 0;
2171 : err = 0;
2172 :
2173 11 : if (stream->flags.writing)
2174 : {
2175 : /* Switching to reading mode -> flush output. */
2176 0 : err = es_flush (stream);
2177 0 : if (err)
2178 : goto out;
2179 0 : stream->flags.writing = 0;
2180 : }
2181 :
2182 : /* Read unread data first. */
2183 11 : while ((bytes_to_read - data_read_unread) && stream->unread_data_len)
2184 : {
2185 0 : buffer[data_read_unread]
2186 0 : = stream->unread_buffer[stream->unread_data_len - 1];
2187 0 : stream->unread_data_len--;
2188 0 : data_read_unread++;
2189 : }
2190 :
2191 11 : switch (stream->intern->strategy)
2192 : {
2193 : case _IONBF:
2194 0 : err = es_read_nbf (stream,
2195 : buffer + data_read_unread,
2196 : bytes_to_read - data_read_unread, &data_read);
2197 0 : break;
2198 : case _IOLBF:
2199 0 : err = es_read_lbf (stream,
2200 : buffer + data_read_unread,
2201 : bytes_to_read - data_read_unread, &data_read);
2202 0 : break;
2203 : case _IOFBF:
2204 11 : err = es_read_fbf (stream,
2205 : buffer + data_read_unread,
2206 : bytes_to_read - data_read_unread, &data_read);
2207 11 : break;
2208 : }
2209 :
2210 : out:
2211 :
2212 11 : if (bytes_read)
2213 11 : *bytes_read = data_read_unread + data_read;
2214 :
2215 11 : return err;
2216 : }
2217 :
2218 :
2219 : /* Return true if at least one byte is pending for read. This is a
2220 : best effort check and it it possible that bytes are still pending
2221 : even if false is returned. If the stream is in writing mode it is
2222 : switched to read mode. */
2223 : static int
2224 7 : check_pending (estream_t _GPGRT__RESTRICT stream)
2225 : {
2226 7 : if (stream->flags.writing)
2227 : {
2228 : /* Switching to reading mode -> flush output. */
2229 0 : if (es_flush (stream))
2230 : return 0; /* Better return 0 on error. */
2231 0 : stream->flags.writing = 0;
2232 : }
2233 :
2234 : /* Check unread data first. */
2235 7 : if (stream->unread_data_len)
2236 : return 1;
2237 :
2238 7 : switch (stream->intern->strategy)
2239 : {
2240 : case _IONBF:
2241 0 : return check_pending_nbf (stream);
2242 : case _IOLBF:
2243 : case _IOFBF:
2244 7 : return check_pending_fbf (stream);
2245 : }
2246 :
2247 : return 0;
2248 : }
2249 :
2250 :
2251 : /* Try to unread DATA_N bytes from DATA into STREAM, storing the
2252 : amount of bytes successfully unread in *BYTES_UNREAD. */
2253 : static void
2254 0 : es_unreadn (estream_t _GPGRT__RESTRICT stream,
2255 : const unsigned char *_GPGRT__RESTRICT data, size_t data_n,
2256 : size_t *_GPGRT__RESTRICT bytes_unread)
2257 : {
2258 : size_t space_left;
2259 :
2260 0 : space_left = stream->unread_buffer_size - stream->unread_data_len;
2261 :
2262 0 : if (data_n > space_left)
2263 : data_n = space_left;
2264 :
2265 0 : if (! data_n)
2266 : goto out;
2267 :
2268 0 : memcpy (stream->unread_buffer + stream->unread_data_len, data, data_n);
2269 0 : stream->unread_data_len += data_n;
2270 0 : stream->intern->indicators.eof = 0;
2271 :
2272 : out:
2273 :
2274 0 : if (bytes_unread)
2275 0 : *bytes_unread = data_n;
2276 0 : }
2277 :
2278 : /* Seek in STREAM. */
2279 : static int
2280 0 : es_seek (estream_t _GPGRT__RESTRICT stream, gpgrt_off_t offset, int whence,
2281 : gpgrt_off_t *_GPGRT__RESTRICT offset_new)
2282 : {
2283 0 : gpgrt_cookie_seek_function_t func_seek = stream->intern->func_seek;
2284 : int err, ret;
2285 : gpgrt_off_t off;
2286 :
2287 0 : if (! func_seek)
2288 : {
2289 0 : _set_errno (EOPNOTSUPP);
2290 : err = -1;
2291 0 : goto out;
2292 : }
2293 :
2294 0 : if (stream->flags.writing)
2295 : {
2296 : /* Flush data first in order to prevent flushing it to the wrong
2297 : offset. */
2298 0 : err = es_flush (stream);
2299 0 : if (err)
2300 : goto out;
2301 0 : stream->flags.writing = 0;
2302 : }
2303 :
2304 0 : off = offset;
2305 0 : if (whence == SEEK_CUR)
2306 : {
2307 0 : off = off - stream->data_len + stream->data_offset;
2308 0 : off -= stream->unread_data_len;
2309 : }
2310 :
2311 0 : ret = (*func_seek) (stream->intern->cookie, &off, whence);
2312 0 : if (ret == -1)
2313 : {
2314 : err = -1;
2315 : #if EWOULDBLOCK != EAGAIN
2316 : if (errno == EWOULDBLOCK)
2317 : _set_errno (EAGAIN);
2318 : #endif
2319 : goto out;
2320 : }
2321 :
2322 : err = 0;
2323 0 : es_empty (stream);
2324 :
2325 0 : if (offset_new)
2326 0 : *offset_new = off;
2327 :
2328 0 : stream->intern->indicators.eof = 0;
2329 0 : stream->intern->offset = off;
2330 :
2331 : out:
2332 :
2333 0 : if (err)
2334 : {
2335 0 : if (errno == EPIPE)
2336 0 : stream->intern->indicators.hup = 1;
2337 0 : stream->intern->indicators.err = 1;
2338 : }
2339 :
2340 0 : return err;
2341 : }
2342 :
2343 : /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
2344 : unbuffered-mode, storing the amount of bytes written in
2345 : *BYTES_WRITTEN. */
2346 : static int
2347 0 : es_write_nbf (estream_t _GPGRT__RESTRICT stream,
2348 : const unsigned char *_GPGRT__RESTRICT buffer,
2349 : size_t bytes_to_write, size_t *_GPGRT__RESTRICT bytes_written)
2350 : {
2351 0 : gpgrt_cookie_write_function_t func_write = stream->intern->func_write;
2352 : size_t data_written;
2353 : gpgrt_ssize_t ret;
2354 : int err;
2355 :
2356 0 : if (bytes_to_write && (! func_write))
2357 : {
2358 : err = EOPNOTSUPP;
2359 : goto out;
2360 : }
2361 :
2362 : data_written = 0;
2363 : err = 0;
2364 :
2365 0 : while (bytes_to_write - data_written)
2366 : {
2367 0 : ret = (*func_write) (stream->intern->cookie,
2368 : buffer + data_written,
2369 : bytes_to_write - data_written);
2370 0 : if (ret == -1)
2371 : {
2372 : err = -1;
2373 : #if EWOULDBLOCK != EAGAIN
2374 : if (errno == EWOULDBLOCK)
2375 : _set_errno (EAGAIN);
2376 : #endif
2377 : break;
2378 : }
2379 : else
2380 0 : data_written += ret;
2381 : }
2382 :
2383 0 : stream->intern->offset += data_written;
2384 0 : *bytes_written = data_written;
2385 :
2386 : out:
2387 :
2388 0 : return err;
2389 : }
2390 :
2391 : /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
2392 : fully-buffered-mode, storing the amount of bytes written in
2393 : *BYTES_WRITTEN. */
2394 : static int
2395 22 : es_write_fbf (estream_t _GPGRT__RESTRICT stream,
2396 : const unsigned char *_GPGRT__RESTRICT buffer,
2397 : size_t bytes_to_write, size_t *_GPGRT__RESTRICT bytes_written)
2398 : {
2399 : size_t space_available;
2400 : size_t data_to_write;
2401 : size_t data_written;
2402 : int err;
2403 :
2404 : data_written = 0;
2405 : err = 0;
2406 :
2407 66 : while ((bytes_to_write - data_written) && (! err))
2408 : {
2409 22 : if (stream->data_offset == stream->buffer_size)
2410 : /* Container full, flush buffer. */
2411 0 : err = es_flush (stream);
2412 :
2413 22 : if (! err)
2414 : {
2415 : /* Flushing resulted in empty container. */
2416 :
2417 22 : data_to_write = bytes_to_write - data_written;
2418 22 : space_available = stream->buffer_size - stream->data_offset;
2419 22 : if (data_to_write > space_available)
2420 : data_to_write = space_available;
2421 :
2422 22 : memcpy (stream->buffer + stream->data_offset,
2423 : buffer + data_written, data_to_write);
2424 22 : stream->data_offset += data_to_write;
2425 22 : data_written += data_to_write;
2426 : }
2427 : }
2428 :
2429 22 : *bytes_written = data_written;
2430 :
2431 22 : return err;
2432 : }
2433 :
2434 :
2435 : /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
2436 : line-buffered-mode, storing the amount of bytes written in
2437 : *BYTES_WRITTEN. */
2438 : static int
2439 0 : es_write_lbf (estream_t _GPGRT__RESTRICT stream,
2440 : const unsigned char *_GPGRT__RESTRICT buffer,
2441 : size_t bytes_to_write, size_t *_GPGRT__RESTRICT bytes_written)
2442 : {
2443 0 : size_t data_flushed = 0;
2444 0 : size_t data_buffered = 0;
2445 : unsigned char *nlp;
2446 : int err = 0;
2447 :
2448 0 : nlp = memrchr (buffer, '\n', bytes_to_write);
2449 0 : if (nlp)
2450 : {
2451 : /* Found a newline, directly write up to (including) this
2452 : character. */
2453 0 : err = es_flush (stream);
2454 0 : if (!err)
2455 0 : err = es_write_nbf (stream, buffer, nlp - buffer + 1, &data_flushed);
2456 : }
2457 :
2458 0 : if (!err)
2459 : {
2460 : /* Write remaining data fully buffered. */
2461 0 : err = es_write_fbf (stream, buffer + data_flushed,
2462 : bytes_to_write - data_flushed, &data_buffered);
2463 : }
2464 :
2465 0 : *bytes_written = data_flushed + data_buffered;
2466 0 : return err;
2467 : }
2468 :
2469 :
2470 : /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in, storing the
2471 : amount of bytes written in BYTES_WRITTEN. */
2472 : static int
2473 22 : es_writen (estream_t _GPGRT__RESTRICT stream,
2474 : const void *_GPGRT__RESTRICT buffer,
2475 : size_t bytes_to_write, size_t *_GPGRT__RESTRICT bytes_written)
2476 : {
2477 : size_t data_written;
2478 : int err;
2479 :
2480 22 : data_written = 0;
2481 : err = 0;
2482 :
2483 22 : if (!stream->flags.writing)
2484 : {
2485 : /* Switching to writing mode -> discard input data and seek to
2486 : position at which reading has stopped. We can do this only
2487 : if a seek function has been registered. */
2488 0 : if (stream->intern->func_seek)
2489 : {
2490 0 : err = es_seek (stream, 0, SEEK_CUR, NULL);
2491 0 : if (err)
2492 : {
2493 0 : if (errno == ESPIPE)
2494 : err = 0;
2495 : else
2496 : goto out;
2497 : }
2498 : }
2499 : }
2500 :
2501 22 : switch (stream->intern->strategy)
2502 : {
2503 : case _IONBF:
2504 0 : err = es_write_nbf (stream, buffer, bytes_to_write, &data_written);
2505 0 : break;
2506 :
2507 : case _IOLBF:
2508 0 : err = es_write_lbf (stream, buffer, bytes_to_write, &data_written);
2509 0 : break;
2510 :
2511 : case _IOFBF:
2512 22 : err = es_write_fbf (stream, buffer, bytes_to_write, &data_written);
2513 22 : break;
2514 : }
2515 :
2516 : out:
2517 :
2518 22 : if (bytes_written)
2519 22 : *bytes_written = data_written;
2520 22 : if (data_written)
2521 22 : if (!stream->flags.writing)
2522 0 : stream->flags.writing = 1;
2523 :
2524 22 : return err;
2525 : }
2526 :
2527 :
2528 : static int
2529 0 : es_peek (estream_t _GPGRT__RESTRICT stream,
2530 : unsigned char **_GPGRT__RESTRICT data,
2531 : size_t *_GPGRT__RESTRICT data_len)
2532 : {
2533 : int err;
2534 :
2535 0 : if (stream->flags.writing)
2536 : {
2537 : /* Switching to reading mode -> flush output. */
2538 0 : err = es_flush (stream);
2539 0 : if (err)
2540 : goto out;
2541 0 : stream->flags.writing = 0;
2542 : }
2543 :
2544 0 : if (stream->data_offset == stream->data_len)
2545 : {
2546 : /* Refill container. */
2547 0 : err = es_fill (stream);
2548 0 : if (err)
2549 : goto out;
2550 : }
2551 :
2552 0 : if (data)
2553 0 : *data = stream->buffer + stream->data_offset;
2554 0 : if (data_len)
2555 0 : *data_len = stream->data_len - stream->data_offset;
2556 : err = 0;
2557 :
2558 : out:
2559 :
2560 0 : return err;
2561 : }
2562 :
2563 :
2564 : /* Skip SIZE bytes of input data contained in buffer. */
2565 : static int
2566 0 : es_skip (estream_t stream, size_t size)
2567 : {
2568 : int err;
2569 :
2570 0 : if (stream->data_offset + size > stream->data_len)
2571 : {
2572 0 : _set_errno (EINVAL);
2573 : err = -1;
2574 : }
2575 : else
2576 : {
2577 0 : stream->data_offset += size;
2578 : err = 0;
2579 : }
2580 :
2581 0 : return err;
2582 : }
2583 :
2584 :
2585 : static int
2586 0 : doreadline (estream_t _GPGRT__RESTRICT stream, size_t max_length,
2587 : char *_GPGRT__RESTRICT *_GPGRT__RESTRICT line,
2588 : size_t *_GPGRT__RESTRICT line_length)
2589 : {
2590 : size_t space_left;
2591 : size_t line_size;
2592 : estream_t line_stream;
2593 : char *line_new;
2594 : void *line_stream_cookie;
2595 : char *newline;
2596 : unsigned char *data;
2597 : size_t data_len;
2598 : int err;
2599 : es_syshd_t syshd;
2600 :
2601 : line_new = NULL;
2602 0 : line_stream = NULL;
2603 0 : line_stream_cookie = NULL;
2604 :
2605 0 : err = func_mem_create (&line_stream_cookie, NULL, 0, 0,
2606 : BUFFER_BLOCK_SIZE, 1,
2607 : mem_realloc, mem_free,
2608 : O_RDWR,
2609 : 0);
2610 0 : if (err)
2611 : goto out;
2612 :
2613 0 : memset (&syshd, 0, sizeof syshd);
2614 0 : err = es_create (&line_stream, line_stream_cookie, &syshd,
2615 : estream_functions_mem, O_RDWR, 1, 0);
2616 0 : if (err)
2617 : goto out;
2618 :
2619 : space_left = max_length;
2620 : line_size = 0;
2621 : while (1)
2622 : {
2623 0 : if (max_length && (space_left == 1))
2624 : break;
2625 :
2626 0 : err = es_peek (stream, &data, &data_len);
2627 0 : if (err || (! data_len))
2628 : break;
2629 :
2630 0 : if (data_len > (space_left - 1))
2631 0 : data_len = space_left - 1;
2632 :
2633 0 : newline = memchr (data, '\n', data_len);
2634 0 : if (newline)
2635 : {
2636 0 : data_len = (newline - (char *) data) + 1;
2637 0 : err = _gpgrt_write (line_stream, data, data_len, NULL);
2638 0 : if (! err)
2639 : {
2640 : space_left -= data_len;
2641 0 : line_size += data_len;
2642 : es_skip (stream, data_len);
2643 : break;
2644 : }
2645 : }
2646 : else
2647 : {
2648 0 : err = _gpgrt_write (line_stream, data, data_len, NULL);
2649 0 : if (! err)
2650 : {
2651 0 : space_left -= data_len;
2652 0 : line_size += data_len;
2653 : es_skip (stream, data_len);
2654 : }
2655 : }
2656 0 : if (err)
2657 : break;
2658 : }
2659 0 : if (err)
2660 : goto out;
2661 :
2662 : /* Complete line has been written to line_stream. */
2663 :
2664 0 : if ((max_length > 1) && (! line_size))
2665 : {
2666 0 : stream->intern->indicators.eof = 1;
2667 0 : goto out;
2668 : }
2669 :
2670 0 : err = es_seek (line_stream, 0, SEEK_SET, NULL);
2671 0 : if (err)
2672 : goto out;
2673 :
2674 0 : if (! *line)
2675 : {
2676 0 : line_new = mem_alloc (line_size + 1);
2677 0 : if (! line_new)
2678 : {
2679 : err = -1;
2680 : goto out;
2681 : }
2682 : }
2683 : else
2684 : line_new = *line;
2685 :
2686 0 : err = _gpgrt_read (line_stream, line_new, line_size, NULL);
2687 0 : if (err)
2688 : goto out;
2689 :
2690 0 : line_new[line_size] = '\0';
2691 :
2692 0 : if (! *line)
2693 0 : *line = line_new;
2694 0 : if (line_length)
2695 0 : *line_length = line_size;
2696 :
2697 : out:
2698 :
2699 0 : if (line_stream)
2700 0 : do_close (line_stream, 0);
2701 0 : else if (line_stream_cookie)
2702 0 : es_func_mem_destroy (line_stream_cookie);
2703 :
2704 0 : if (err)
2705 : {
2706 0 : if (! *line)
2707 : mem_free (line_new);
2708 0 : stream->intern->indicators.err = 1;
2709 : }
2710 :
2711 0 : return err;
2712 : }
2713 :
2714 :
2715 : /* Output function used by estream_format. */
2716 : static int
2717 15 : print_writer (void *outfncarg, const char *buf, size_t buflen)
2718 : {
2719 : estream_t stream = outfncarg;
2720 : size_t nwritten;
2721 : int rc;
2722 :
2723 15 : nwritten = 0;
2724 15 : rc = es_writen (stream, buf, buflen, &nwritten);
2725 15 : stream->intern->print_ntotal += nwritten;
2726 15 : return rc;
2727 : }
2728 :
2729 :
2730 : /* The core of our printf function. This is called in locked state. */
2731 : static int
2732 3 : es_print (estream_t _GPGRT__RESTRICT stream,
2733 : const char *_GPGRT__RESTRICT format, va_list ap)
2734 : {
2735 : int rc;
2736 :
2737 3 : stream->intern->print_ntotal = 0;
2738 3 : rc = _gpgrt_estream_format (print_writer, stream, format, ap);
2739 3 : if (rc)
2740 : return -1;
2741 3 : return (int)stream->intern->print_ntotal;
2742 : }
2743 :
2744 :
2745 : static int
2746 0 : es_set_buffering (estream_t _GPGRT__RESTRICT stream,
2747 : char *_GPGRT__RESTRICT buffer, int mode, size_t size)
2748 : {
2749 : int err;
2750 :
2751 : /* Flush or empty buffer depending on mode. */
2752 0 : if (stream->flags.writing)
2753 : {
2754 0 : err = es_flush (stream);
2755 0 : if (err)
2756 : goto out;
2757 : }
2758 : else
2759 0 : es_empty (stream);
2760 :
2761 0 : stream->intern->indicators.eof = 0;
2762 :
2763 : /* Free old buffer in case that was allocated by this function. */
2764 0 : if (stream->intern->deallocate_buffer)
2765 : {
2766 0 : stream->intern->deallocate_buffer = 0;
2767 0 : mem_free (stream->buffer);
2768 0 : stream->buffer = NULL;
2769 : }
2770 :
2771 0 : if (mode == _IONBF)
2772 0 : stream->buffer_size = 0;
2773 : else
2774 : {
2775 : void *buffer_new;
2776 :
2777 0 : if (buffer)
2778 : buffer_new = buffer;
2779 : else
2780 : {
2781 0 : if (!size)
2782 : size = BUFSIZ;
2783 : buffer_new = mem_alloc (size);
2784 0 : if (! buffer_new)
2785 : {
2786 : err = -1;
2787 : goto out;
2788 : }
2789 : }
2790 :
2791 0 : stream->buffer = buffer_new;
2792 0 : stream->buffer_size = size;
2793 0 : if (! buffer)
2794 0 : stream->intern->deallocate_buffer = 1;
2795 : }
2796 0 : stream->intern->strategy = mode;
2797 : err = 0;
2798 :
2799 : out:
2800 :
2801 0 : return err;
2802 : }
2803 :
2804 :
2805 : static gpgrt_off_t
2806 : es_offset_calculate (estream_t stream)
2807 : {
2808 : gpgrt_off_t offset;
2809 :
2810 0 : offset = stream->intern->offset + stream->data_offset;
2811 0 : if (offset < stream->unread_data_len)
2812 : /* Offset undefined. */
2813 : offset = 0;
2814 : else
2815 0 : offset -= stream->unread_data_len;
2816 :
2817 : return offset;
2818 : }
2819 :
2820 :
2821 : static void
2822 0 : es_opaque_ctrl (estream_t _GPGRT__RESTRICT stream,
2823 : void *_GPGRT__RESTRICT opaque_new,
2824 : void **_GPGRT__RESTRICT opaque_old)
2825 : {
2826 0 : if (opaque_old)
2827 0 : *opaque_old = stream->intern->opaque;
2828 0 : if (opaque_new)
2829 0 : stream->intern->opaque = opaque_new;
2830 0 : }
2831 :
2832 :
2833 : /* API. */
2834 :
2835 : estream_t
2836 0 : _gpgrt_fopen (const char *_GPGRT__RESTRICT path,
2837 : const char *_GPGRT__RESTRICT mode)
2838 : {
2839 : unsigned int modeflags, cmode;
2840 : int samethread, create_called;
2841 : estream_t stream;
2842 : void *cookie;
2843 : int err;
2844 : int fd;
2845 : es_syshd_t syshd;
2846 :
2847 0 : stream = NULL;
2848 0 : cookie = NULL;
2849 : create_called = 0;
2850 :
2851 0 : err = parse_mode (mode, &modeflags, &samethread, &cmode);
2852 0 : if (err)
2853 : goto out;
2854 :
2855 0 : err = func_file_create (&cookie, &fd, path, modeflags, cmode);
2856 0 : if (err)
2857 : goto out;
2858 :
2859 0 : syshd.type = ES_SYSHD_FD;
2860 0 : syshd.u.fd = fd;
2861 :
2862 : create_called = 1;
2863 0 : err = es_create (&stream, cookie, &syshd, estream_functions_fd, modeflags,
2864 : samethread, 0);
2865 0 : if (err)
2866 : goto out;
2867 :
2868 0 : if (stream && path)
2869 0 : fname_set_internal (stream, path, 1);
2870 :
2871 : out:
2872 :
2873 0 : if (err && create_called)
2874 0 : (*estream_functions_fd.func_close) (cookie);
2875 :
2876 0 : return stream;
2877 : }
2878 :
2879 :
2880 :
2881 : /* Create a new estream object in memory. If DATA is not NULL this
2882 : buffer will be used as the memory buffer; thus after this functions
2883 : returns with the success the the memory at DATA belongs to the new
2884 : estream. The allocated length of DATA is given by DATA_LEN and its
2885 : used length by DATA_N. Usually this is malloced buffer; if a
2886 : static buffer is provided, the caller must pass false for GROW and
2887 : provide a dummy function for FUNC_FREE. FUNC_FREE and FUNC_REALLOC
2888 : allow the caller to provide custom functions for realloc and free
2889 : to be used by the new estream object. Note that the realloc
2890 : function is also used for initial allocation. If DATA is NULL a
2891 : buffer is internally allocated; either using internal function or
2892 : those provide by the caller. It is an error to provide a realloc
2893 : function but no free function. Providing only a free function is
2894 : allowed as long as GROW is false. */
2895 : estream_t
2896 0 : _gpgrt_mopen (void *_GPGRT__RESTRICT data, size_t data_n, size_t data_len,
2897 : unsigned int grow,
2898 : func_realloc_t func_realloc, func_free_t func_free,
2899 : const char *_GPGRT__RESTRICT mode)
2900 : {
2901 : int create_called = 0;
2902 0 : estream_t stream = NULL;
2903 0 : void *cookie = NULL;
2904 : unsigned int modeflags;
2905 : int samethread;
2906 : int err;
2907 : es_syshd_t syshd;
2908 :
2909 0 : err = parse_mode (mode, &modeflags, &samethread, NULL);
2910 0 : if (err)
2911 : goto out;
2912 :
2913 0 : err = func_mem_create (&cookie, data, data_n, data_len,
2914 : BUFFER_BLOCK_SIZE, grow,
2915 : func_realloc, func_free, modeflags, 0);
2916 0 : if (err)
2917 : goto out;
2918 :
2919 0 : memset (&syshd, 0, sizeof syshd);
2920 : create_called = 1;
2921 0 : err = es_create (&stream, cookie, &syshd,
2922 : estream_functions_mem, modeflags, samethread, 0);
2923 :
2924 : out:
2925 :
2926 0 : if (err && create_called)
2927 0 : (*estream_functions_mem.func_close) (cookie);
2928 :
2929 0 : return stream;
2930 : }
2931 :
2932 :
2933 :
2934 : estream_t
2935 0 : _gpgrt_fopenmem (size_t memlimit, const char *_GPGRT__RESTRICT mode)
2936 : {
2937 : unsigned int modeflags;
2938 : int samethread;
2939 0 : estream_t stream = NULL;
2940 0 : void *cookie = NULL;
2941 : es_syshd_t syshd;
2942 :
2943 : /* Memory streams are always read/write. We use MODE only to get
2944 : the append flag. */
2945 0 : if (parse_mode (mode, &modeflags, &samethread, NULL))
2946 : return NULL;
2947 0 : modeflags |= O_RDWR;
2948 :
2949 0 : if (func_mem_create (&cookie, NULL, 0, 0,
2950 : BUFFER_BLOCK_SIZE, 1,
2951 : mem_realloc, mem_free, modeflags,
2952 : memlimit))
2953 : return NULL;
2954 :
2955 0 : memset (&syshd, 0, sizeof syshd);
2956 0 : if (es_create (&stream, cookie, &syshd, estream_functions_mem, modeflags,
2957 : samethread, 0))
2958 0 : (*estream_functions_mem.func_close) (cookie);
2959 :
2960 0 : if (stream)
2961 0 : stream->intern->func_ioctl = es_func_mem_ioctl;
2962 :
2963 0 : return stream;
2964 : }
2965 :
2966 :
2967 : /* This is the same as es_fopenmem but intializes the memory with a
2968 : copy of (DATA,DATALEN). The stream is initally set to the
2969 : beginning. If MEMLIMIT is not 0 but shorter than DATALEN it
2970 : DATALEN will be used as the value for MEMLIMIT. */
2971 : estream_t
2972 0 : _gpgrt_fopenmem_init (size_t memlimit, const char *_GPGRT__RESTRICT mode,
2973 : const void *data, size_t datalen)
2974 : {
2975 : estream_t stream;
2976 :
2977 0 : if (memlimit && memlimit < datalen)
2978 : memlimit = datalen;
2979 :
2980 0 : stream = _gpgrt_fopenmem (memlimit, mode);
2981 0 : if (stream && data && datalen)
2982 : {
2983 0 : if (es_writen (stream, data, datalen, NULL))
2984 : {
2985 0 : int saveerrno = errno;
2986 : _gpgrt_fclose (stream);
2987 : stream = NULL;
2988 0 : _set_errno (saveerrno);
2989 : }
2990 : else
2991 : {
2992 0 : es_seek (stream, 0L, SEEK_SET, NULL);
2993 0 : stream->intern->indicators.eof = 0;
2994 0 : stream->intern->indicators.err = 0;
2995 : }
2996 : }
2997 0 : return stream;
2998 : }
2999 :
3000 :
3001 :
3002 : estream_t
3003 0 : _gpgrt_fopencookie (void *_GPGRT__RESTRICT cookie,
3004 : const char *_GPGRT__RESTRICT mode,
3005 : gpgrt_cookie_io_functions_t functions)
3006 : {
3007 : unsigned int modeflags;
3008 : int samethread;
3009 : estream_t stream;
3010 : int err;
3011 : es_syshd_t syshd;
3012 :
3013 0 : stream = NULL;
3014 0 : modeflags = 0;
3015 :
3016 0 : err = parse_mode (mode, &modeflags, &samethread, NULL);
3017 0 : if (err)
3018 : goto out;
3019 :
3020 0 : memset (&syshd, 0, sizeof syshd);
3021 0 : err = es_create (&stream, cookie, &syshd, functions, modeflags,
3022 : samethread, 0);
3023 : if (err)
3024 : goto out;
3025 :
3026 : out:
3027 0 : return stream;
3028 : }
3029 :
3030 :
3031 :
3032 : static estream_t
3033 6 : do_fdopen (int filedes, const char *mode, int no_close, int with_locked_list)
3034 : {
3035 : unsigned int modeflags;
3036 : int samethread, create_called;
3037 : estream_t stream;
3038 : void *cookie;
3039 : int err;
3040 : es_syshd_t syshd;
3041 :
3042 6 : stream = NULL;
3043 : cookie = NULL;
3044 : create_called = 0;
3045 :
3046 6 : err = parse_mode (mode, &modeflags, &samethread, NULL);
3047 6 : if (err)
3048 : goto out;
3049 :
3050 6 : err = func_fd_create (&cookie, filedes, modeflags, no_close);
3051 6 : if (err)
3052 : goto out;
3053 :
3054 6 : syshd.type = ES_SYSHD_FD;
3055 6 : syshd.u.fd = filedes;
3056 : create_called = 1;
3057 6 : err = es_create (&stream, cookie, &syshd, estream_functions_fd,
3058 : modeflags, samethread, with_locked_list);
3059 :
3060 6 : if (!err && stream)
3061 : {
3062 6 : stream->intern->func_ioctl = es_func_fd_ioctl;
3063 6 : if ((modeflags & O_NONBLOCK))
3064 0 : err = es_func_fd_ioctl (cookie, COOKIE_IOCTL_NONBLOCK, "", NULL);
3065 : }
3066 :
3067 : out:
3068 6 : if (err && create_called)
3069 0 : (*estream_functions_fd.func_close) (cookie);
3070 :
3071 6 : return stream;
3072 : }
3073 :
3074 : estream_t
3075 6 : _gpgrt_fdopen (int filedes, const char *mode)
3076 : {
3077 6 : return do_fdopen (filedes, mode, 0, 0);
3078 : }
3079 :
3080 : /* A variant of es_fdopen which does not close FILEDES at the end. */
3081 : estream_t
3082 0 : _gpgrt_fdopen_nc (int filedes, const char *mode)
3083 : {
3084 0 : return do_fdopen (filedes, mode, 1, 0);
3085 : }
3086 :
3087 :
3088 :
3089 : static estream_t
3090 0 : do_fpopen (FILE *fp, const char *mode, int no_close, int with_locked_list)
3091 : {
3092 : unsigned int modeflags, cmode;
3093 : int samethread, create_called;
3094 : estream_t stream;
3095 : void *cookie;
3096 : int err;
3097 : es_syshd_t syshd;
3098 :
3099 0 : stream = NULL;
3100 : cookie = NULL;
3101 : create_called = 0;
3102 :
3103 0 : err = parse_mode (mode, &modeflags, &samethread, &cmode);
3104 0 : if (err)
3105 : goto out;
3106 :
3107 0 : if (fp)
3108 0 : fflush (fp);
3109 : err = func_fp_create (&cookie, fp, modeflags, no_close);
3110 0 : if (err)
3111 : goto out;
3112 :
3113 0 : syshd.type = ES_SYSHD_FD;
3114 0 : syshd.u.fd = fp? fileno (fp): -1;
3115 : create_called = 1;
3116 0 : err = es_create (&stream, cookie, &syshd, estream_functions_fp,
3117 : modeflags, samethread, with_locked_list);
3118 :
3119 : out:
3120 :
3121 0 : if (err && create_called)
3122 0 : (*estream_functions_fp.func_close) (cookie);
3123 :
3124 0 : return stream;
3125 : }
3126 :
3127 :
3128 : /* Create an estream from the stdio stream FP. This mechanism is
3129 : useful in case the stdio streams have special properties and may
3130 : not be mixed with fd based functions. This is for example the case
3131 : under Windows where the 3 standard streams are associated with the
3132 : console whereas a duped and fd-opened stream of one of this stream
3133 : won't be associated with the console. As this messes things up it
3134 : is easier to keep on using the standard I/O stream as a backend for
3135 : estream. */
3136 : estream_t
3137 0 : _gpgrt_fpopen (FILE *fp, const char *mode)
3138 : {
3139 0 : return do_fpopen (fp, mode, 0, 0);
3140 : }
3141 :
3142 :
3143 : /* Same as es_fpopen but does not close FP at the end. */
3144 : estream_t
3145 0 : _gpgrt_fpopen_nc (FILE *fp, const char *mode)
3146 : {
3147 0 : return do_fpopen (fp, mode, 1, 0);
3148 : }
3149 :
3150 :
3151 :
3152 : #ifdef HAVE_W32_SYSTEM
3153 : estream_t
3154 : do_w32open (HANDLE hd, const char *mode,
3155 : int no_close, int with_locked_list)
3156 : {
3157 : unsigned int modeflags, cmode;
3158 : int samethread;
3159 : int create_called = 0;
3160 : estream_t stream = NULL;
3161 : void *cookie = NULL;
3162 : int err;
3163 : es_syshd_t syshd;
3164 :
3165 : err = parse_mode (mode, &modeflags, &samethread, &cmode);
3166 : if (err)
3167 : goto leave;
3168 :
3169 : err = es_func_w32_create (&cookie, hd, modeflags, no_close);
3170 : if (err)
3171 : goto leave;
3172 :
3173 : syshd.type = ES_SYSHD_HANDLE;
3174 : syshd.u.handle = hd;
3175 : create_called = 1;
3176 : err = es_create (&stream, cookie, &syshd, estream_functions_w32,
3177 : modeflags, samethread, with_locked_list);
3178 :
3179 : leave:
3180 : if (err && create_called)
3181 : (*estream_functions_w32.func_close) (cookie);
3182 :
3183 : return stream;
3184 : }
3185 : #endif /*HAVE_W32_SYSTEM*/
3186 :
3187 : static estream_t
3188 0 : do_sysopen (es_syshd_t *syshd, const char *mode, int no_close)
3189 : {
3190 : estream_t stream;
3191 :
3192 0 : switch (syshd->type)
3193 : {
3194 : case ES_SYSHD_FD:
3195 : case ES_SYSHD_SOCK:
3196 0 : stream = do_fdopen (syshd->u.fd, mode, no_close, 0);
3197 0 : break;
3198 :
3199 : #ifdef HAVE_W32_SYSTEM
3200 : case ES_SYSHD_HANDLE:
3201 : stream = do_w32open (syshd->u.handle, mode, no_close, 0);
3202 : break;
3203 : #endif
3204 :
3205 : /* FIXME: Support RVIDs under Wince? */
3206 :
3207 : default:
3208 0 : _set_errno (EINVAL);
3209 : stream = NULL;
3210 : }
3211 0 : return stream;
3212 : }
3213 :
3214 : /* On POSIX systems this function is an alias for es_fdopen. Under
3215 : Windows it uses the bare W32 API and thus a HANDLE instead of a
3216 : file descriptor. */
3217 : estream_t
3218 0 : _gpgrt_sysopen (es_syshd_t *syshd, const char *mode)
3219 : {
3220 0 : return do_sysopen (syshd, mode, 0);
3221 : }
3222 :
3223 : /* Same as es_sysopen but the handle/fd will not be closed by
3224 : es_fclose. */
3225 : estream_t
3226 0 : _gpgrt_sysopen_nc (es_syshd_t *syshd, const char *mode)
3227 : {
3228 0 : return do_sysopen (syshd, mode, 1);
3229 : }
3230 :
3231 :
3232 :
3233 : /* Set custom standard descriptors to be used for stdin, stdout and
3234 : stderr. This function needs to be called before any of the
3235 : standard streams are accessed. This internal version uses a double
3236 : dash inside its name. */
3237 : void
3238 0 : _gpgrt__set_std_fd (int no, int fd)
3239 : {
3240 : /* fprintf (stderr, "es_set_std_fd(%d, %d)\n", no, fd); */
3241 : lock_list ();
3242 0 : if (no >= 0 && no < 3 && !custom_std_fds_valid[no])
3243 : {
3244 0 : custom_std_fds[no] = fd;
3245 0 : custom_std_fds_valid[no] = 1;
3246 : }
3247 : unlock_list ();
3248 0 : }
3249 :
3250 :
3251 : /* Return the stream used for stdin, stdout or stderr.
3252 : This internal version uses a double dash inside its name. */
3253 : estream_t
3254 0 : _gpgrt__get_std_stream (int fd)
3255 : {
3256 : estream_list_t list_obj;
3257 : estream_t stream = NULL;
3258 :
3259 0 : fd %= 3; /* We only allow 0, 1 or 2 but we don't want to return an error. */
3260 :
3261 : lock_list ();
3262 :
3263 0 : for (list_obj = estream_list; list_obj; list_obj = list_obj->next)
3264 0 : if (list_obj->stream && list_obj->stream->intern->is_stdstream
3265 0 : && list_obj->stream->intern->stdstream_fd == fd)
3266 : {
3267 0 : stream = list_obj->stream;
3268 0 : break;
3269 : }
3270 0 : if (!stream)
3271 : {
3272 : /* Standard stream not yet created. We first try to create them
3273 : from registered file descriptors. */
3274 0 : if (!fd && custom_std_fds_valid[0])
3275 0 : stream = do_fdopen (custom_std_fds[0], "r", 1, 1);
3276 0 : else if (fd == 1 && custom_std_fds_valid[1])
3277 0 : stream = do_fdopen (custom_std_fds[1], "a", 1, 1);
3278 0 : else if (custom_std_fds_valid[2])
3279 0 : stream = do_fdopen (custom_std_fds[2], "a", 1, 1);
3280 :
3281 0 : if (!stream)
3282 : {
3283 : /* Second try is to use the standard C streams. */
3284 0 : if (!fd)
3285 0 : stream = do_fpopen (stdin, "r", 1, 1);
3286 0 : else if (fd == 1)
3287 0 : stream = do_fpopen (stdout, "a", 1, 1);
3288 : else
3289 0 : stream = do_fpopen (stderr, "a", 1, 1);
3290 : }
3291 :
3292 0 : if (!stream)
3293 : {
3294 : /* Last try: Create a bit bucket. */
3295 0 : stream = do_fpopen (NULL, fd? "a":"r", 0, 1);
3296 0 : if (!stream)
3297 : {
3298 0 : fprintf (stderr, "fatal: error creating a dummy estream"
3299 0 : " for %d: %s\n", fd, strerror (errno));
3300 0 : abort();
3301 : }
3302 : }
3303 :
3304 0 : stream->intern->is_stdstream = 1;
3305 0 : stream->intern->stdstream_fd = fd;
3306 0 : if (fd == 2)
3307 0 : es_set_buffering (stream, NULL, _IOLBF, 0);
3308 0 : fname_set_internal (stream,
3309 : fd == 0? "[stdin]" :
3310 : fd == 1? "[stdout]" : "[stderr]", 0);
3311 : }
3312 :
3313 : unlock_list ();
3314 0 : return stream;
3315 : }
3316 :
3317 : /* Note: A "samethread" keyword given in "mode" is ignored and the
3318 : value used by STREAM is used instead. */
3319 : estream_t
3320 0 : _gpgrt_freopen (const char *_GPGRT__RESTRICT path,
3321 : const char *_GPGRT__RESTRICT mode,
3322 : estream_t _GPGRT__RESTRICT stream)
3323 : {
3324 : int err;
3325 :
3326 0 : if (path)
3327 : {
3328 : unsigned int modeflags, cmode;
3329 : int dummy, samethread, create_called;
3330 : void *cookie;
3331 : int fd;
3332 : es_syshd_t syshd;
3333 :
3334 0 : cookie = NULL;
3335 : create_called = 0;
3336 :
3337 0 : samethread = stream->intern->samethread;
3338 :
3339 : lock_stream (stream);
3340 :
3341 0 : es_deinitialize (stream);
3342 :
3343 0 : err = parse_mode (mode, &modeflags, &dummy, &cmode);
3344 0 : if (err)
3345 : goto leave;
3346 : (void)dummy;
3347 :
3348 0 : err = func_file_create (&cookie, &fd, path, modeflags, cmode);
3349 0 : if (err)
3350 : goto leave;
3351 :
3352 0 : syshd.type = ES_SYSHD_FD;
3353 0 : syshd.u.fd = fd;
3354 : create_called = 1;
3355 0 : init_stream_obj (stream, cookie, &syshd, estream_functions_fd,
3356 : modeflags, samethread);
3357 :
3358 : leave:
3359 :
3360 0 : if (err)
3361 : {
3362 0 : if (create_called)
3363 0 : es_func_fd_destroy (cookie);
3364 :
3365 0 : do_close (stream, 0);
3366 : stream = NULL;
3367 : }
3368 : else
3369 : {
3370 0 : if (path)
3371 0 : fname_set_internal (stream, path, 1);
3372 : unlock_stream (stream);
3373 : }
3374 : }
3375 : else
3376 : {
3377 : /* FIXME? We don't support re-opening at the moment. */
3378 0 : _set_errno (EINVAL);
3379 0 : es_deinitialize (stream);
3380 0 : do_close (stream, 0);
3381 : stream = NULL;
3382 : }
3383 :
3384 0 : return stream;
3385 : }
3386 :
3387 :
3388 : int
3389 6 : _gpgrt_fclose (estream_t stream)
3390 : {
3391 : int err;
3392 :
3393 6 : err = do_close (stream, 0);
3394 :
3395 6 : return err;
3396 : }
3397 :
3398 :
3399 : /* This is a special version of es_fclose which can be used with
3400 : es_fopenmem to return the memory buffer. This is feature is useful
3401 : to write to a memory buffer using estream. Note that the function
3402 : does not close the stream if the stream does not support snatching
3403 : the buffer. On error NULL is stored at R_BUFFER. Note that if no
3404 : write operation has happened, NULL may also be stored at BUFFER on
3405 : success. The caller needs to release the returned memory using
3406 : gpgrt_free. */
3407 : int
3408 0 : _gpgrt_fclose_snatch (estream_t stream, void **r_buffer, size_t *r_buflen)
3409 : {
3410 : int err;
3411 :
3412 : /* Note: There is no need to lock the stream in a close call. The
3413 : object will be destroyed after the close and thus any other
3414 : contender for the lock would work on a closed stream. */
3415 :
3416 0 : if (r_buffer)
3417 : {
3418 0 : cookie_ioctl_function_t func_ioctl = stream->intern->func_ioctl;
3419 : size_t buflen;
3420 :
3421 0 : *r_buffer = NULL;
3422 :
3423 0 : if (!func_ioctl)
3424 : {
3425 0 : _set_errno (EOPNOTSUPP);
3426 : err = -1;
3427 0 : goto leave;
3428 : }
3429 :
3430 0 : if (stream->flags.writing)
3431 : {
3432 0 : err = es_flush (stream);
3433 0 : if (err)
3434 : goto leave;
3435 0 : stream->flags.writing = 0;
3436 : }
3437 :
3438 0 : err = func_ioctl (stream->intern->cookie, COOKIE_IOCTL_SNATCH_BUFFER,
3439 : r_buffer, &buflen);
3440 0 : if (err)
3441 : goto leave;
3442 0 : if (r_buflen)
3443 0 : *r_buflen = buflen;
3444 : }
3445 :
3446 0 : err = do_close (stream, 0);
3447 :
3448 : leave:
3449 0 : if (err && r_buffer)
3450 : {
3451 0 : mem_free (*r_buffer);
3452 0 : *r_buffer = NULL;
3453 : }
3454 0 : return err;
3455 : }
3456 :
3457 :
3458 : /* Register or unregister a close notification function for STREAM.
3459 : FNC is the function to call and FNC_VALUE the value passed as
3460 : second argument. To register the notification the value for MODE
3461 : must be 1. If mode is 0 the function tries to remove or disable an
3462 : already registered notification; for this to work the value of FNC
3463 : and FNC_VALUE must be the same as with the registration and
3464 : FNC_VALUE must be a unique value. No error will be returned if
3465 : MODE is 0.
3466 :
3467 : FIXME: I think the next comment is not anymore correct:
3468 : Unregister should only be used in the error case because it may not
3469 : be able to remove memory internally allocated for the onclose
3470 : handler.
3471 :
3472 : FIXME: Unregister is not thread safe.
3473 :
3474 : The notification will be called right before the stream is closed.
3475 : It may not call any estream function for STREAM, neither direct nor
3476 : indirectly. */
3477 : int
3478 0 : _gpgrt_onclose (estream_t stream, int mode,
3479 : void (*fnc) (estream_t, void*), void *fnc_value)
3480 : {
3481 : int err;
3482 :
3483 : lock_stream (stream);
3484 0 : err = do_onclose (stream, mode, fnc, fnc_value);
3485 : unlock_stream (stream);
3486 :
3487 0 : return err;
3488 : }
3489 :
3490 :
3491 : int
3492 19 : _gpgrt_fileno_unlocked (estream_t stream)
3493 : {
3494 : es_syshd_t syshd;
3495 :
3496 19 : if (_gpgrt_syshd_unlocked (stream, &syshd))
3497 : return -1;
3498 19 : switch (syshd.type)
3499 : {
3500 19 : case ES_SYSHD_FD: return syshd.u.fd;
3501 0 : case ES_SYSHD_SOCK: return syshd.u.sock;
3502 : default:
3503 0 : _set_errno (EINVAL);
3504 0 : return -1;
3505 : }
3506 : }
3507 :
3508 :
3509 : /* Return the handle of a stream which has been opened by es_sysopen.
3510 : The caller needs to pass a structure which will be filled with the
3511 : sys handle. Return 0 on success or true on error and sets errno.
3512 : This is the unlocked version. */
3513 : int
3514 19 : _gpgrt_syshd_unlocked (estream_t stream, es_syshd_t *syshd)
3515 : {
3516 19 : if (!stream || !syshd || stream->intern->syshd.type == ES_SYSHD_NONE)
3517 : {
3518 0 : if (syshd)
3519 0 : syshd->type = ES_SYSHD_NONE;
3520 0 : _set_errno (EINVAL);
3521 0 : return -1;
3522 : }
3523 :
3524 19 : *syshd = stream->intern->syshd;
3525 19 : return 0;
3526 : }
3527 :
3528 :
3529 : void
3530 0 : _gpgrt_flockfile (estream_t stream)
3531 : {
3532 : lock_stream (stream);
3533 0 : }
3534 :
3535 :
3536 : int
3537 0 : _gpgrt_ftrylockfile (estream_t stream)
3538 : {
3539 0 : return trylock_stream (stream);
3540 : }
3541 :
3542 :
3543 : void
3544 0 : _gpgrt_funlockfile (estream_t stream)
3545 : {
3546 : unlock_stream (stream);
3547 0 : }
3548 :
3549 :
3550 : int
3551 19 : _gpgrt_fileno (estream_t stream)
3552 : {
3553 : int ret;
3554 :
3555 : lock_stream (stream);
3556 19 : ret = _gpgrt_fileno_unlocked (stream);
3557 : unlock_stream (stream);
3558 :
3559 19 : return ret;
3560 : }
3561 :
3562 :
3563 : /* Return the handle of a stream which has been opened by es_sysopen.
3564 : The caller needs to pass a structure which will be filled with the
3565 : sys handle. Return 0 on success or true on error and sets errno.
3566 : This is the unlocked version. */
3567 : int
3568 0 : _gpgrt_syshd (estream_t stream, es_syshd_t *syshd)
3569 : {
3570 : int ret;
3571 :
3572 : lock_stream (stream);
3573 0 : ret = _gpgrt_syshd_unlocked (stream, syshd);
3574 : unlock_stream (stream);
3575 :
3576 0 : return ret;
3577 : }
3578 :
3579 :
3580 : int
3581 0 : _gpgrt__pending_unlocked (estream_t stream)
3582 : {
3583 7 : return check_pending (stream);
3584 : }
3585 :
3586 :
3587 : /* Return true if there is at least one byte pending for read on
3588 : STREAM. This does only work if the backend supports checking for
3589 : pending bytes and is thus mostly useful with cookie based backends.
3590 :
3591 : Note that if this function is used with cookie based functions, the
3592 : read cookie may be called with 0 for the SIZE argument. If bytes
3593 : are pending the function is expected to return -1 in this case and
3594 : thus deviates from the standard behavior of read(2). */
3595 : int
3596 7 : _gpgrt__pending (estream_t stream)
3597 : {
3598 : int ret;
3599 :
3600 : lock_stream (stream);
3601 : ret = _gpgrt__pending_unlocked (stream);
3602 : unlock_stream (stream);
3603 :
3604 7 : return ret;
3605 : }
3606 :
3607 :
3608 : int
3609 0 : _gpgrt_feof_unlocked (estream_t stream)
3610 : {
3611 1 : return stream->intern->indicators.eof;
3612 : }
3613 :
3614 :
3615 : int
3616 1 : _gpgrt_feof (estream_t stream)
3617 : {
3618 : int ret;
3619 :
3620 : lock_stream (stream);
3621 : ret = _gpgrt_feof_unlocked (stream);
3622 : unlock_stream (stream);
3623 :
3624 1 : return ret;
3625 : }
3626 :
3627 :
3628 : int
3629 0 : _gpgrt_ferror_unlocked (estream_t stream)
3630 : {
3631 0 : return stream->intern->indicators.err;
3632 : }
3633 :
3634 :
3635 : int
3636 0 : _gpgrt_ferror (estream_t stream)
3637 : {
3638 : int ret;
3639 :
3640 : lock_stream (stream);
3641 : ret = _gpgrt_ferror_unlocked (stream);
3642 : unlock_stream (stream);
3643 :
3644 0 : return ret;
3645 : }
3646 :
3647 :
3648 : void
3649 0 : _gpgrt_clearerr_unlocked (estream_t stream)
3650 : {
3651 0 : stream->intern->indicators.eof = 0;
3652 0 : stream->intern->indicators.err = 0;
3653 : /* We do not reset the HUP indicator because there is no way to
3654 : get out of this state. */
3655 0 : }
3656 :
3657 :
3658 : void
3659 0 : _gpgrt_clearerr (estream_t stream)
3660 : {
3661 : lock_stream (stream);
3662 : _gpgrt_clearerr_unlocked (stream);
3663 : unlock_stream (stream);
3664 0 : }
3665 :
3666 :
3667 : static int
3668 10 : do_fflush (estream_t stream)
3669 : {
3670 : int err;
3671 :
3672 10 : if (stream->flags.writing)
3673 10 : err = es_flush (stream);
3674 : else
3675 : {
3676 0 : es_empty (stream);
3677 : err = 0;
3678 : }
3679 :
3680 10 : return err;
3681 : }
3682 :
3683 :
3684 : int
3685 16 : _gpgrt_fflush (estream_t stream)
3686 : {
3687 : int err;
3688 :
3689 16 : if (stream)
3690 : {
3691 : lock_stream (stream);
3692 10 : err = do_fflush (stream);
3693 : unlock_stream (stream);
3694 : }
3695 : else
3696 : {
3697 : estream_list_t item;
3698 :
3699 : err = 0;
3700 : lock_list ();
3701 12 : for (item = estream_list; item; item = item->next)
3702 6 : if (item->stream)
3703 : {
3704 : lock_stream (item->stream);
3705 0 : err |= do_fflush (item->stream);
3706 0 : unlock_stream (item->stream);
3707 : }
3708 : unlock_list ();
3709 : }
3710 16 : return err ? EOF : 0;
3711 : }
3712 :
3713 :
3714 : int
3715 0 : _gpgrt_fseek (estream_t stream, long int offset, int whence)
3716 : {
3717 : int err;
3718 :
3719 : lock_stream (stream);
3720 0 : err = es_seek (stream, offset, whence, NULL);
3721 : unlock_stream (stream);
3722 :
3723 0 : return err;
3724 : }
3725 :
3726 :
3727 : int
3728 0 : _gpgrt_fseeko (estream_t stream, gpgrt_off_t offset, int whence)
3729 : {
3730 : int err;
3731 :
3732 : lock_stream (stream);
3733 0 : err = es_seek (stream, offset, whence, NULL);
3734 : unlock_stream (stream);
3735 :
3736 0 : return err;
3737 : }
3738 :
3739 :
3740 : long int
3741 0 : _gpgrt_ftell (estream_t stream)
3742 : {
3743 : long int ret;
3744 :
3745 : lock_stream (stream);
3746 : ret = es_offset_calculate (stream);
3747 : unlock_stream (stream);
3748 :
3749 0 : return ret;
3750 : }
3751 :
3752 :
3753 : gpgrt_off_t
3754 0 : _gpgrt_ftello (estream_t stream)
3755 : {
3756 : gpgrt_off_t ret = -1;
3757 :
3758 : lock_stream (stream);
3759 : ret = es_offset_calculate (stream);
3760 : unlock_stream (stream);
3761 :
3762 0 : return ret;
3763 : }
3764 :
3765 :
3766 : void
3767 0 : _gpgrt_rewind (estream_t stream)
3768 : {
3769 : lock_stream (stream);
3770 0 : es_seek (stream, 0L, SEEK_SET, NULL);
3771 : /* Note that es_seek already cleared the EOF flag. */
3772 0 : stream->intern->indicators.err = 0;
3773 : unlock_stream (stream);
3774 0 : }
3775 :
3776 :
3777 : int
3778 11 : _gpgrt__getc_underflow (estream_t stream)
3779 : {
3780 : int err;
3781 : unsigned char c;
3782 : size_t bytes_read;
3783 :
3784 11 : err = es_readn (stream, &c, 1, &bytes_read);
3785 :
3786 11 : return (err || (! bytes_read)) ? EOF : c;
3787 : }
3788 :
3789 :
3790 : int
3791 0 : _gpgrt__putc_overflow (int c, estream_t stream)
3792 : {
3793 0 : unsigned char d = c;
3794 : int err;
3795 :
3796 0 : err = es_writen (stream, &d, 1, NULL);
3797 :
3798 0 : return err ? EOF : c;
3799 : }
3800 :
3801 :
3802 : int
3803 100 : _gpgrt_fgetc (estream_t stream)
3804 : {
3805 : int ret;
3806 :
3807 : lock_stream (stream);
3808 100 : ret = _gpgrt_getc_unlocked (stream);
3809 : unlock_stream (stream);
3810 :
3811 100 : return ret;
3812 : }
3813 :
3814 :
3815 : int
3816 0 : _gpgrt_fputc (int c, estream_t stream)
3817 : {
3818 : int ret;
3819 :
3820 : lock_stream (stream);
3821 0 : ret = _gpgrt_putc_unlocked (c, stream);
3822 : unlock_stream (stream);
3823 :
3824 0 : return ret;
3825 : }
3826 :
3827 :
3828 : int
3829 0 : _gpgrt_ungetc (int c, estream_t stream)
3830 : {
3831 0 : unsigned char data = (unsigned char) c;
3832 : size_t data_unread;
3833 :
3834 : lock_stream (stream);
3835 0 : es_unreadn (stream, &data, 1, &data_unread);
3836 : unlock_stream (stream);
3837 :
3838 0 : return data_unread ? c : EOF;
3839 : }
3840 :
3841 :
3842 : int
3843 0 : _gpgrt_read (estream_t _GPGRT__RESTRICT stream,
3844 : void *_GPGRT__RESTRICT buffer, size_t bytes_to_read,
3845 : size_t *_GPGRT__RESTRICT bytes_read)
3846 : {
3847 : int err;
3848 :
3849 0 : if (bytes_to_read)
3850 : {
3851 : lock_stream (stream);
3852 0 : err = es_readn (stream, buffer, bytes_to_read, bytes_read);
3853 : unlock_stream (stream);
3854 : }
3855 : else
3856 : err = 0;
3857 :
3858 0 : return err;
3859 : }
3860 :
3861 :
3862 : int
3863 7 : _gpgrt_write (estream_t _GPGRT__RESTRICT stream,
3864 : const void *_GPGRT__RESTRICT buffer, size_t bytes_to_write,
3865 : size_t *_GPGRT__RESTRICT bytes_written)
3866 : {
3867 : int err;
3868 :
3869 7 : if (bytes_to_write)
3870 : {
3871 : lock_stream (stream);
3872 7 : err = es_writen (stream, buffer, bytes_to_write, bytes_written);
3873 : unlock_stream (stream);
3874 : }
3875 : else
3876 : err = 0;
3877 :
3878 7 : return err;
3879 : }
3880 :
3881 :
3882 : size_t
3883 0 : _gpgrt_fread (void *_GPGRT__RESTRICT ptr, size_t size, size_t nitems,
3884 : estream_t _GPGRT__RESTRICT stream)
3885 : {
3886 : size_t ret, bytes;
3887 :
3888 0 : if (size * nitems)
3889 : {
3890 : lock_stream (stream);
3891 0 : es_readn (stream, ptr, size * nitems, &bytes);
3892 : unlock_stream (stream);
3893 :
3894 0 : ret = bytes / size;
3895 : }
3896 : else
3897 : ret = 0;
3898 :
3899 0 : return ret;
3900 : }
3901 :
3902 :
3903 : size_t
3904 0 : _gpgrt_fwrite (const void *_GPGRT__RESTRICT ptr, size_t size, size_t nitems,
3905 : estream_t _GPGRT__RESTRICT stream)
3906 : {
3907 : size_t ret, bytes;
3908 :
3909 0 : if (size * nitems)
3910 : {
3911 : lock_stream (stream);
3912 0 : es_writen (stream, ptr, size * nitems, &bytes);
3913 : unlock_stream (stream);
3914 :
3915 0 : ret = bytes / size;
3916 : }
3917 : else
3918 : ret = 0;
3919 :
3920 0 : return ret;
3921 : }
3922 :
3923 :
3924 : char *
3925 11 : _gpgrt_fgets (char *_GPGRT__RESTRICT buffer, int length,
3926 : estream_t _GPGRT__RESTRICT stream)
3927 : {
3928 : unsigned char *s = (unsigned char*)buffer;
3929 : int c;
3930 :
3931 11 : if (!length)
3932 : return NULL;
3933 :
3934 : c = EOF;
3935 : lock_stream (stream);
3936 107 : while (length > 1 && (c = _gpgrt_getc_unlocked (stream)) != EOF && c != '\n')
3937 : {
3938 96 : *s++ = c;
3939 96 : length--;
3940 : }
3941 : unlock_stream (stream);
3942 :
3943 11 : if (c == EOF && s == (unsigned char*)buffer)
3944 : return NULL; /* Nothing read. */
3945 :
3946 9 : if (c != EOF && length > 1)
3947 3 : *s++ = c;
3948 :
3949 9 : *s = 0;
3950 9 : return buffer;
3951 : }
3952 :
3953 :
3954 : int
3955 0 : _gpgrt_fputs_unlocked (const char *_GPGRT__RESTRICT s,
3956 : estream_t _GPGRT__RESTRICT stream)
3957 : {
3958 : size_t length;
3959 : int err;
3960 :
3961 0 : length = strlen (s);
3962 0 : err = es_writen (stream, s, length, NULL);
3963 0 : return err ? EOF : 0;
3964 : }
3965 :
3966 : int
3967 0 : _gpgrt_fputs (const char *_GPGRT__RESTRICT s, estream_t _GPGRT__RESTRICT stream)
3968 : {
3969 : size_t length;
3970 : int err;
3971 :
3972 0 : length = strlen (s);
3973 : lock_stream (stream);
3974 0 : err = es_writen (stream, s, length, NULL);
3975 : unlock_stream (stream);
3976 :
3977 0 : return err ? EOF : 0;
3978 : }
3979 :
3980 :
3981 : gpgrt_ssize_t
3982 0 : _gpgrt_getline (char *_GPGRT__RESTRICT *_GPGRT__RESTRICT lineptr,
3983 : size_t *_GPGRT__RESTRICT n, estream_t _GPGRT__RESTRICT stream)
3984 : {
3985 0 : char *line = NULL;
3986 0 : size_t line_n = 0;
3987 : int err;
3988 :
3989 : lock_stream (stream);
3990 0 : err = doreadline (stream, 0, &line, &line_n);
3991 : unlock_stream (stream);
3992 0 : if (err)
3993 : goto out;
3994 :
3995 0 : if (*n)
3996 : {
3997 : /* Caller wants us to use his buffer. */
3998 :
3999 0 : if (*n < (line_n + 1))
4000 : {
4001 : /* Provided buffer is too small -> resize. */
4002 :
4003 : void *p;
4004 :
4005 0 : p = mem_realloc (*lineptr, line_n + 1);
4006 0 : if (! p)
4007 : err = -1;
4008 : else
4009 : {
4010 0 : if (*lineptr != p)
4011 0 : *lineptr = p;
4012 : }
4013 : }
4014 :
4015 0 : if (! err)
4016 : {
4017 0 : memcpy (*lineptr, line, line_n + 1);
4018 0 : if (*n != line_n)
4019 0 : *n = line_n;
4020 : }
4021 0 : mem_free (line);
4022 : }
4023 : else
4024 : {
4025 : /* Caller wants new buffers. */
4026 0 : *lineptr = line;
4027 0 : *n = line_n;
4028 : }
4029 :
4030 : out:
4031 :
4032 0 : return err ? err : (gpgrt_ssize_t)line_n;
4033 : }
4034 :
4035 :
4036 :
4037 : /* Same as fgets() but if the provided buffer is too short a larger
4038 : one will be allocated. This is similar to getline. A line is
4039 : considered a byte stream ending in a LF.
4040 :
4041 : If MAX_LENGTH is not NULL, it shall point to a value with the
4042 : maximum allowed allocation.
4043 :
4044 : Returns the length of the line. EOF is indicated by a line of
4045 : length zero. A truncated line is indicated my setting the value at
4046 : MAX_LENGTH to 0. If the returned value is less then 0 not enough
4047 : memory was enable or another error occurred; ERRNO is then set
4048 : accordingly.
4049 :
4050 : If a line has been truncated, the file pointer is moved forward to
4051 : the end of the line so that the next read starts with the next
4052 : line. Note that MAX_LENGTH must be re-initialzied in this case.
4053 :
4054 : The caller initially needs to provide the address of a variable,
4055 : initialized to NULL, at ADDR_OF_BUFFER and don't change this value
4056 : anymore with the following invocations. LENGTH_OF_BUFFER should be
4057 : the address of a variable, initialized to 0, which is also
4058 : maintained by this function. Thus, both paramaters should be
4059 : considered the state of this function.
4060 :
4061 : Note: The returned buffer is allocated with enough extra space to
4062 : allow the caller to append a CR,LF,Nul. The buffer should be
4063 : released using gpgrt_free.
4064 : */
4065 : gpgrt_ssize_t
4066 0 : _gpgrt_read_line (estream_t stream,
4067 : char **addr_of_buffer, size_t *length_of_buffer,
4068 : size_t *max_length)
4069 : {
4070 : int c;
4071 0 : char *buffer = *addr_of_buffer;
4072 0 : size_t length = *length_of_buffer;
4073 : size_t nbytes = 0;
4074 0 : size_t maxlen = max_length? *max_length : 0;
4075 : char *p;
4076 :
4077 0 : if (!buffer)
4078 : {
4079 : /* No buffer given - allocate a new one. */
4080 : length = 256;
4081 : buffer = mem_alloc (length);
4082 0 : *addr_of_buffer = buffer;
4083 0 : if (!buffer)
4084 : {
4085 0 : *length_of_buffer = 0;
4086 0 : if (max_length)
4087 0 : *max_length = 0;
4088 : return -1;
4089 : }
4090 0 : *length_of_buffer = length;
4091 : }
4092 :
4093 0 : if (length < 4)
4094 : {
4095 : /* This should never happen. If it does, the function has been
4096 : called with wrong arguments. */
4097 0 : _set_errno (EINVAL);
4098 0 : return -1;
4099 : }
4100 0 : length -= 3; /* Reserve 3 bytes for CR,LF,EOL. */
4101 :
4102 : lock_stream (stream);
4103 : p = buffer;
4104 0 : while ((c = _gpgrt_getc_unlocked (stream)) != EOF)
4105 : {
4106 0 : if (nbytes == length)
4107 : {
4108 : /* Enlarge the buffer. */
4109 0 : if (maxlen && length > maxlen)
4110 : {
4111 : /* We are beyond our limit: Skip the rest of the line. */
4112 0 : while (c != '\n' && (c=_gpgrt_getc_unlocked (stream)) != EOF)
4113 : ;
4114 0 : *p++ = '\n'; /* Always append a LF (we reserved some space). */
4115 0 : nbytes++;
4116 0 : if (max_length)
4117 0 : *max_length = 0; /* Indicate truncation. */
4118 : break; /* the while loop. */
4119 : }
4120 0 : length += 3; /* Adjust for the reserved bytes. */
4121 0 : length += length < 1024? 256 : 1024;
4122 0 : *addr_of_buffer = mem_realloc (buffer, length);
4123 0 : if (!*addr_of_buffer)
4124 : {
4125 0 : int save_errno = errno;
4126 : mem_free (buffer);
4127 0 : *length_of_buffer = 0;
4128 0 : if (max_length)
4129 0 : *max_length = 0;
4130 : unlock_stream (stream);
4131 0 : _set_errno (save_errno);
4132 0 : return -1;
4133 : }
4134 : buffer = *addr_of_buffer;
4135 0 : *length_of_buffer = length;
4136 0 : length -= 3;
4137 0 : p = buffer + nbytes;
4138 : }
4139 0 : *p++ = c;
4140 0 : nbytes++;
4141 0 : if (c == '\n')
4142 : break;
4143 : }
4144 0 : *p = 0; /* Make sure the line is a string. */
4145 : unlock_stream (stream);
4146 :
4147 0 : return nbytes;
4148 : }
4149 :
4150 : /* Wrapper around free() to match the memory allocation system used by
4151 : estream. Should be used for all buffers returned to the caller by
4152 : libestream. If a custom allocation handler has been set with
4153 : gpgrt_set_alloc_func that register function may be used
4154 : instead. This function has been moved to init.c. */
4155 : /* void */
4156 : /* _gpgrt_free (void *a) */
4157 : /* { */
4158 : /* mem_free (a); */
4159 : /* } */
4160 :
4161 :
4162 : int
4163 0 : _gpgrt_vfprintf_unlocked (estream_t _GPGRT__RESTRICT stream,
4164 : const char *_GPGRT__RESTRICT format,
4165 : va_list ap)
4166 : {
4167 0 : return es_print (stream, format, ap);
4168 : }
4169 :
4170 :
4171 : int
4172 3 : _gpgrt_vfprintf (estream_t _GPGRT__RESTRICT stream,
4173 : const char *_GPGRT__RESTRICT format,
4174 : va_list ap)
4175 : {
4176 : int ret;
4177 :
4178 : lock_stream (stream);
4179 3 : ret = es_print (stream, format, ap);
4180 : unlock_stream (stream);
4181 :
4182 3 : return ret;
4183 : }
4184 :
4185 :
4186 : int
4187 0 : _gpgrt_fprintf_unlocked (estream_t _GPGRT__RESTRICT stream,
4188 : const char *_GPGRT__RESTRICT format, ...)
4189 : {
4190 : int ret;
4191 :
4192 : va_list ap;
4193 0 : va_start (ap, format);
4194 0 : ret = es_print (stream, format, ap);
4195 0 : va_end (ap);
4196 :
4197 0 : return ret;
4198 : }
4199 :
4200 :
4201 : int
4202 0 : _gpgrt_fprintf (estream_t _GPGRT__RESTRICT stream,
4203 : const char *_GPGRT__RESTRICT format, ...)
4204 : {
4205 : int ret;
4206 :
4207 : va_list ap;
4208 0 : va_start (ap, format);
4209 : lock_stream (stream);
4210 0 : ret = es_print (stream, format, ap);
4211 : unlock_stream (stream);
4212 0 : va_end (ap);
4213 :
4214 0 : return ret;
4215 : }
4216 :
4217 :
4218 : static int
4219 0 : tmpfd (void)
4220 : {
4221 : #ifdef HAVE_W32_SYSTEM
4222 : int attempts, n;
4223 : #ifdef HAVE_W32CE_SYSTEM
4224 : wchar_t buffer[MAX_PATH+9+12+1];
4225 : # define mystrlen(a) wcslen (a)
4226 : wchar_t *name, *p;
4227 : #else
4228 : char buffer[MAX_PATH+9+12+1];
4229 : # define mystrlen(a) strlen (a)
4230 : char *name, *p;
4231 : #endif
4232 : HANDLE file;
4233 : int pid = GetCurrentProcessId ();
4234 : unsigned int value;
4235 : int i;
4236 :
4237 : n = GetTempPath (MAX_PATH+1, buffer);
4238 : if (!n || n > MAX_PATH || mystrlen (buffer) > MAX_PATH)
4239 : {
4240 : _set_errno (ENOENT);
4241 : return -1;
4242 : }
4243 : p = buffer + mystrlen (buffer);
4244 : #ifdef HAVE_W32CE_SYSTEM
4245 : wcscpy (p, L"_estream");
4246 : #else
4247 : strcpy (p, "_estream");
4248 : #endif
4249 : p += 8;
4250 : /* We try to create the directory but don't care about an error as
4251 : it may already exist and the CreateFile would throw an error
4252 : anyway. */
4253 : CreateDirectory (buffer, NULL);
4254 : *p++ = '\\';
4255 : name = p;
4256 : for (attempts=0; attempts < 10; attempts++)
4257 : {
4258 : p = name;
4259 : value = (GetTickCount () ^ ((pid<<16) & 0xffff0000));
4260 : for (i=0; i < 8; i++)
4261 : {
4262 : *p++ = tohex (((value >> 28) & 0x0f));
4263 : value <<= 4;
4264 : }
4265 : #ifdef HAVE_W32CE_SYSTEM
4266 : wcscpy (p, L".tmp");
4267 : #else
4268 : strcpy (p, ".tmp");
4269 : #endif
4270 : file = CreateFile (buffer,
4271 : GENERIC_READ | GENERIC_WRITE,
4272 : 0,
4273 : NULL,
4274 : CREATE_NEW,
4275 : FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
4276 : NULL);
4277 : if (file != INVALID_HANDLE_VALUE)
4278 : {
4279 : #ifdef HAVE_W32CE_SYSTEM
4280 : int fd = (int)file;
4281 : #else
4282 : int fd = _open_osfhandle ((long)file, 0);
4283 : if (fd == -1)
4284 : {
4285 : CloseHandle (file);
4286 : return -1;
4287 : }
4288 : #endif
4289 : return fd;
4290 : }
4291 : Sleep (1); /* One ms as this is the granularity of GetTickCount. */
4292 : }
4293 : _set_errno (ENOENT);
4294 : return -1;
4295 : #else /*!HAVE_W32_SYSTEM*/
4296 : FILE *fp;
4297 : int fp_fd;
4298 : int fd;
4299 :
4300 : fp = NULL;
4301 : fd = -1;
4302 :
4303 0 : fp = tmpfile ();
4304 0 : if (! fp)
4305 : goto out;
4306 :
4307 0 : fp_fd = fileno (fp);
4308 0 : fd = dup (fp_fd);
4309 :
4310 : out:
4311 :
4312 0 : if (fp)
4313 0 : fclose (fp);
4314 :
4315 0 : return fd;
4316 : #endif /*!HAVE_W32_SYSTEM*/
4317 : }
4318 :
4319 : estream_t
4320 0 : _gpgrt_tmpfile (void)
4321 : {
4322 : unsigned int modeflags;
4323 : int create_called;
4324 : estream_t stream;
4325 : void *cookie;
4326 : int err;
4327 : int fd;
4328 : es_syshd_t syshd;
4329 :
4330 : create_called = 0;
4331 0 : stream = NULL;
4332 : modeflags = O_RDWR | O_TRUNC | O_CREAT;
4333 : cookie = NULL;
4334 :
4335 0 : fd = tmpfd ();
4336 0 : if (fd == -1)
4337 : {
4338 : err = -1;
4339 : goto out;
4340 : }
4341 :
4342 : err = func_fd_create (&cookie, fd, modeflags, 0);
4343 0 : if (err)
4344 : goto out;
4345 :
4346 0 : syshd.type = ES_SYSHD_FD;
4347 0 : syshd.u.fd = fd;
4348 : create_called = 1;
4349 0 : err = es_create (&stream, cookie, &syshd, estream_functions_fd, modeflags,
4350 : 0, 0);
4351 :
4352 : out:
4353 0 : if (err)
4354 : {
4355 0 : if (create_called)
4356 0 : es_func_fd_destroy (cookie);
4357 0 : else if (fd != -1)
4358 0 : close (fd);
4359 0 : stream = NULL;
4360 : }
4361 :
4362 0 : return stream;
4363 : }
4364 :
4365 :
4366 : int
4367 0 : _gpgrt_setvbuf (estream_t _GPGRT__RESTRICT stream,
4368 : char *_GPGRT__RESTRICT buf, int type, size_t size)
4369 : {
4370 : int err;
4371 :
4372 0 : if ((type == _IOFBF || type == _IOLBF || type == _IONBF)
4373 0 : && (!buf || size || type == _IONBF))
4374 : {
4375 : lock_stream (stream);
4376 0 : err = es_set_buffering (stream, buf, type, size);
4377 : unlock_stream (stream);
4378 : }
4379 : else
4380 : {
4381 0 : _set_errno (EINVAL);
4382 : err = -1;
4383 : }
4384 :
4385 0 : return err;
4386 : }
4387 :
4388 :
4389 : /* Put a stream into binary mode. This is only needed for the
4390 : standard streams if they are to be used in a binary way. On Unix
4391 : systems it is never needed but MSDOS based systems require such a
4392 : call. It needs to be called before any I/O is done on STREAM. */
4393 : void
4394 0 : _gpgrt_set_binary (estream_t stream)
4395 : {
4396 : lock_stream (stream);
4397 : if (!(stream->intern->modeflags & O_BINARY))
4398 : {
4399 0 : stream->intern->modeflags |= O_BINARY;
4400 : #ifdef HAVE_DOSISH_SYSTEM
4401 : if (stream->intern->func_read == es_func_fd_read)
4402 : {
4403 : estream_cookie_fd_t fd_cookie = stream->intern->cookie;
4404 :
4405 : if (!IS_INVALID_FD (fd_cookie->fd))
4406 : setmode (fd_cookie->fd, O_BINARY);
4407 : }
4408 : else if (stream->intern->func_read == es_func_fp_read)
4409 : {
4410 : estream_cookie_fp_t fp_cookie = stream->intern->cookie;
4411 :
4412 : if (fp_cookie->fp)
4413 : setmode (fileno (fp_cookie->fp), O_BINARY);
4414 : }
4415 : #endif
4416 : }
4417 : unlock_stream (stream);
4418 0 : }
4419 :
4420 :
4421 : /* Set non-blocking mode for STREAM. Use true for ONOFF to enable and
4422 : false to disable non-blocking mode. Returns 0 on success or -1 on
4423 : error and sets ERRNO. Note that not all backends support
4424 : non-blocking mode.
4425 :
4426 : In non-blocking mode a system call will not block but return an
4427 : error and set errno to EAGAIN. The estream API always uses EAGAIN
4428 : and not EWOULDBLOCK. If a buffered function like es_fgetc() or
4429 : es_fgets() returns an error and both, feof() and ferror() return
4430 : false the caller may assume that the error condition was EAGAIN.
4431 :
4432 : Switching back from non-blocking to blocking may raise problems
4433 : with buffering, thus care should be taken. Although read+write
4434 : sockets are supported in theory, switching from write to read may
4435 : result into problems because estream may first flush the write
4436 : buffers and there is no way to handle that non-blocking (EAGAIN)
4437 : case. Explicit flushing should thus be done before before
4438 : switching to read. */
4439 : int
4440 3 : _gpgrt_set_nonblock (estream_t stream, int onoff)
4441 : {
4442 : cookie_ioctl_function_t func_ioctl;
4443 : int ret;
4444 :
4445 : lock_stream (stream);
4446 3 : func_ioctl = stream->intern->func_ioctl;
4447 3 : if (!func_ioctl)
4448 : {
4449 0 : _set_errno (EOPNOTSUPP);
4450 : ret = -1;
4451 : }
4452 : else
4453 : {
4454 3 : unsigned int save_flags = stream->intern->modeflags;
4455 :
4456 3 : if (onoff)
4457 3 : stream->intern->modeflags |= O_NONBLOCK;
4458 : else
4459 0 : stream->intern->modeflags &= ~O_NONBLOCK;
4460 :
4461 3 : ret = func_ioctl (stream->intern->cookie, COOKIE_IOCTL_NONBLOCK,
4462 : onoff?"":NULL, NULL);
4463 3 : if (ret)
4464 0 : stream->intern->modeflags = save_flags;
4465 : }
4466 : unlock_stream (stream);
4467 3 : return ret;
4468 : }
4469 :
4470 :
4471 : /* Return true if STREAM is in non-blocking mode. */
4472 : int
4473 0 : _gpgrt_get_nonblock (estream_t stream)
4474 : {
4475 : int ret;
4476 :
4477 : lock_stream (stream);
4478 0 : ret = !!(stream->intern->modeflags & O_NONBLOCK);
4479 : unlock_stream (stream);
4480 0 : return ret;
4481 : }
4482 :
4483 :
4484 : /* A version of poll(2) working on estream handles. Note that not all
4485 : estream types work with this function. In contrast to the standard
4486 : poll function the gpgrt_poll_t object uses a set of names bit flags
4487 : instead of the EVENTS and REVENTS members. An item with the IGNORE
4488 : flag set is entirely ignored. The TIMEOUT values is given in
4489 : milliseconds, a value of -1 waits indefinitely, and a value of 0
4490 : returns immediately.
4491 :
4492 : A positive return value gives the number of fds with new
4493 : information. A return value of 0 indicates a timeout and -1
4494 : indicates an error in which case ERRNO is set. */
4495 : int
4496 13 : _gpgrt_poll (gpgrt_poll_t *fds, unsigned int nfds, int timeout)
4497 : {
4498 : gpgrt_poll_t *item;
4499 : int count = 0;
4500 : fd_set readfds, writefds, exceptfds;
4501 : int any_readfd, any_writefd, any_exceptfd;
4502 : int idx;
4503 : int max_fd;
4504 : int fd, ret, any;
4505 :
4506 13 : if (!fds)
4507 : {
4508 0 : _set_errno (EINVAL);
4509 0 : return -1;
4510 : }
4511 :
4512 : /* Clear all response fields (even for ignored items). */
4513 39 : for (item = fds, idx = 0; idx < nfds; item++, idx++)
4514 : {
4515 39 : item->got_read = 0;
4516 39 : item->got_write = 0;
4517 39 : item->got_oob = 0;
4518 39 : item->got_rdhup = 0;
4519 39 : item->got_err = 0;
4520 39 : item->got_hup = 0;
4521 39 : item->got_nval = 0;
4522 : }
4523 :
4524 : /* Check for pending reads. */
4525 39 : for (item = fds, idx = 0; idx < nfds; item++, idx++)
4526 : {
4527 39 : if (item->ignore)
4528 25 : continue;
4529 14 : if (!item->want_read)
4530 7 : continue;
4531 7 : if (_gpgrt__pending (item->stream))
4532 : {
4533 6 : item->got_read = 1;
4534 6 : count++;
4535 : }
4536 : }
4537 :
4538 : /* Check for space in the write buffers. */
4539 : for (item = fds, idx = 0; idx < nfds; item++, idx++)
4540 : {
4541 : if (item->ignore)
4542 : continue;
4543 : if (!item->want_write)
4544 : continue;
4545 : /* FIXME */
4546 : }
4547 :
4548 13 : if (count)
4549 6 : return count; /* Early return without waiting. */
4550 :
4551 : /* Now do the real select. */
4552 : any_readfd = any_writefd = any_exceptfd = 0;
4553 : max_fd = 0;
4554 21 : for (item = fds, idx = 0; idx < nfds; item++, idx++)
4555 : {
4556 21 : if (item->ignore)
4557 13 : continue;
4558 8 : fd = _gpgrt_fileno (item->stream);
4559 8 : if (fd == -1)
4560 0 : continue; /* Stream does not support polling. */
4561 :
4562 8 : if (item->want_read)
4563 : {
4564 1 : if (!any_readfd)
4565 : {
4566 1 : FD_ZERO (&readfds);
4567 : any_readfd = 1;
4568 : }
4569 1 : FD_SET (fd, &readfds);
4570 1 : if (fd > max_fd)
4571 : max_fd = fd;
4572 : }
4573 8 : if (item->want_write)
4574 : {
4575 7 : if (!any_writefd)
4576 : {
4577 7 : FD_ZERO (&writefds);
4578 : any_writefd = 1;
4579 : }
4580 7 : FD_SET (fd, &writefds);
4581 7 : if (fd > max_fd)
4582 : max_fd = fd;
4583 : }
4584 8 : if (item->want_oob)
4585 : {
4586 0 : if (!any_exceptfd)
4587 : {
4588 0 : FD_ZERO (&exceptfds);
4589 : any_exceptfd = 1;
4590 : }
4591 0 : FD_SET (fd, &exceptfds);
4592 0 : if (fd > max_fd)
4593 : max_fd = fd;
4594 : }
4595 : }
4596 :
4597 : #ifdef _WIN32
4598 : (void)timeout;
4599 : ret = -1;
4600 : _set_errno (EOPNOTSUPP);
4601 : #else
4602 7 : if (pre_syscall_func)
4603 0 : pre_syscall_func ();
4604 : do
4605 : {
4606 : struct timeval timeout_val;
4607 :
4608 7 : timeout_val.tv_sec = timeout / 1000;
4609 7 : timeout_val.tv_usec = (timeout % 1000) * 1000;
4610 7 : ret = select (max_fd+1,
4611 : any_readfd? &readfds : NULL,
4612 : any_writefd? &writefds : NULL,
4613 : any_exceptfd? &exceptfds : NULL,
4614 : timeout == -1 ? NULL : &timeout_val);
4615 : }
4616 7 : while (ret == -1 && errno == EINTR);
4617 7 : if (post_syscall_func)
4618 0 : post_syscall_func ();
4619 : #endif
4620 :
4621 7 : if (ret == -1)
4622 : return -1;
4623 7 : if (!ret)
4624 : return 0; /* Timeout. Note that in this case we can't return
4625 : got_err for an invalid stream. */
4626 :
4627 21 : for (item = fds, idx = 0; idx < nfds; item++, idx++)
4628 : {
4629 21 : if (item->ignore)
4630 13 : continue;
4631 8 : fd = _gpgrt_fileno (item->stream);
4632 8 : if (fd == -1)
4633 : {
4634 0 : item->got_err = 1; /* Stream does not support polling. */
4635 0 : count++;
4636 0 : continue;
4637 : }
4638 :
4639 : any = 0;
4640 8 : if (item->stream->intern->indicators.hup)
4641 : {
4642 0 : item->got_hup = 1;
4643 : any = 1;
4644 : }
4645 8 : if (item->want_read && FD_ISSET (fd, &readfds))
4646 : {
4647 1 : item->got_read = 1;
4648 : any = 1;
4649 : }
4650 8 : if (item->want_write && FD_ISSET (fd, &writefds))
4651 : {
4652 7 : item->got_write = 1;
4653 : any = 1;
4654 : }
4655 8 : if (item->want_oob && FD_ISSET (fd, &exceptfds))
4656 : {
4657 0 : item->got_oob = 1;
4658 : any = 1;
4659 : }
4660 :
4661 8 : if (any)
4662 8 : count++;
4663 : }
4664 :
4665 7 : return count;
4666 : }
4667 :
4668 :
4669 : void
4670 0 : _gpgrt_opaque_set (estream_t stream, void *opaque)
4671 : {
4672 : lock_stream (stream);
4673 : es_opaque_ctrl (stream, opaque, NULL);
4674 : unlock_stream (stream);
4675 0 : }
4676 :
4677 :
4678 : void *
4679 0 : _gpgrt_opaque_get (estream_t stream)
4680 : {
4681 : void *opaque;
4682 :
4683 : lock_stream (stream);
4684 : es_opaque_ctrl (stream, NULL, &opaque);
4685 : unlock_stream (stream);
4686 :
4687 0 : return opaque;
4688 : }
4689 :
4690 :
4691 : static void
4692 0 : fname_set_internal (estream_t stream, const char *fname, int quote)
4693 : {
4694 0 : if (stream->intern->printable_fname
4695 0 : && !stream->intern->printable_fname_inuse)
4696 : {
4697 : mem_free (stream->intern->printable_fname);
4698 0 : stream->intern->printable_fname = NULL;
4699 : }
4700 0 : if (stream->intern->printable_fname)
4701 0 : return; /* Can't change because it is in use. */
4702 :
4703 0 : if (*fname != '[')
4704 : quote = 0;
4705 : else
4706 0 : quote = !!quote;
4707 :
4708 0 : stream->intern->printable_fname = mem_alloc (strlen (fname) + quote + 1);
4709 0 : if (quote)
4710 0 : stream->intern->printable_fname[0] = '\\';
4711 0 : strcpy (stream->intern->printable_fname+quote, fname);
4712 : }
4713 :
4714 :
4715 : /* Set the filename attribute of STREAM. There is no error return.
4716 : as long as STREAM is valid. This function is called internally by
4717 : functions which open a filename. */
4718 : void
4719 0 : _gpgrt_fname_set (estream_t stream, const char *fname)
4720 : {
4721 0 : if (fname)
4722 : {
4723 : lock_stream (stream);
4724 0 : fname_set_internal (stream, fname, 1);
4725 : unlock_stream (stream);
4726 : }
4727 0 : }
4728 :
4729 :
4730 : /* Return the filename attribute of STREAM. In case no filename has
4731 : been set, "[?]" will be returned. The returned file name is valid
4732 : as long as STREAM is valid. */
4733 : const char *
4734 0 : _gpgrt_fname_get (estream_t stream)
4735 : {
4736 : const char *fname;
4737 :
4738 : lock_stream (stream);
4739 0 : fname = stream->intern->printable_fname;
4740 0 : if (fname)
4741 0 : stream->intern->printable_fname_inuse = 1;
4742 : unlock_stream (stream);
4743 0 : if (!fname)
4744 : fname = "[?]";
4745 0 : return fname;
4746 : }
4747 :
4748 :
4749 :
4750 : /* Print a BUFFER to STREAM while replacing all control characters and
4751 : the characters in DELIMITERS by standard C escape sequences.
4752 : Returns 0 on success or -1 on error. If BYTES_WRITTEN is not NULL
4753 : the number of bytes actually written are stored at this
4754 : address. */
4755 : int
4756 0 : _gpgrt_write_sanitized (estream_t _GPGRT__RESTRICT stream,
4757 : const void * _GPGRT__RESTRICT buffer, size_t length,
4758 : const char * delimiters,
4759 : size_t * _GPGRT__RESTRICT bytes_written)
4760 : {
4761 : const unsigned char *p = buffer;
4762 : size_t count = 0;
4763 : int ret;
4764 :
4765 : lock_stream (stream);
4766 0 : for (; length; length--, p++, count++)
4767 : {
4768 0 : if (*p < 0x20
4769 0 : || *p == 0x7f
4770 0 : || (delimiters
4771 0 : && (strchr (delimiters, *p) || *p == '\\')))
4772 : {
4773 0 : _gpgrt_putc_unlocked ('\\', stream);
4774 : count++;
4775 0 : if (*p == '\n')
4776 : {
4777 0 : _gpgrt_putc_unlocked ('n', stream);
4778 0 : count++;
4779 : }
4780 0 : else if (*p == '\r')
4781 : {
4782 0 : _gpgrt_putc_unlocked ('r', stream);
4783 0 : count++;
4784 : }
4785 0 : else if (*p == '\f')
4786 : {
4787 0 : _gpgrt_putc_unlocked ('f', stream);
4788 0 : count++;
4789 : }
4790 0 : else if (*p == '\v')
4791 : {
4792 0 : _gpgrt_putc_unlocked ('v', stream);
4793 0 : count++;
4794 : }
4795 0 : else if (*p == '\b')
4796 : {
4797 0 : _gpgrt_putc_unlocked ('b', stream);
4798 0 : count++;
4799 : }
4800 0 : else if (!*p)
4801 : {
4802 0 : _gpgrt_putc_unlocked('0', stream);
4803 0 : count++;
4804 : }
4805 : else
4806 : {
4807 0 : _gpgrt_fprintf_unlocked (stream, "x%02x", *p);
4808 0 : count += 3;
4809 : }
4810 : }
4811 : else
4812 : {
4813 0 : _gpgrt_putc_unlocked (*p, stream);
4814 0 : count++;
4815 : }
4816 : }
4817 :
4818 0 : if (bytes_written)
4819 0 : *bytes_written = count;
4820 0 : ret = _gpgrt_ferror_unlocked (stream)? -1 : 0;
4821 : unlock_stream (stream);
4822 :
4823 0 : return ret;
4824 : }
4825 :
4826 :
4827 : /* Write LENGTH bytes of BUFFER to STREAM as a hex encoded string.
4828 : RESERVED must be 0. Returns 0 on success or -1 on error. If
4829 : BYTES_WRITTEN is not NULL the number of bytes actually written are
4830 : stored at this address. */
4831 : int
4832 0 : _gpgrt_write_hexstring (estream_t _GPGRT__RESTRICT stream,
4833 : const void *_GPGRT__RESTRICT buffer, size_t length,
4834 : int reserved, size_t *_GPGRT__RESTRICT bytes_written )
4835 : {
4836 : int ret;
4837 : const unsigned char *s;
4838 : size_t count = 0;
4839 :
4840 : (void)reserved;
4841 :
4842 : #define tohex(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'A'))
4843 :
4844 0 : if (!length)
4845 : return 0;
4846 :
4847 : lock_stream (stream);
4848 :
4849 0 : for (s = buffer; length; s++, length--)
4850 : {
4851 0 : _gpgrt_putc_unlocked ( tohex ((*s>>4)&15), stream);
4852 0 : _gpgrt_putc_unlocked ( tohex (*s&15), stream);
4853 0 : count += 2;
4854 : }
4855 :
4856 0 : if (bytes_written)
4857 0 : *bytes_written = count;
4858 0 : ret = _gpgrt_ferror_unlocked (stream)? -1 : 0;
4859 :
4860 : unlock_stream (stream);
4861 :
4862 0 : return ret;
4863 :
4864 : #undef tohex
4865 : }
|