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