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