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