LCOV - code coverage report
Current view: top level - src - estream.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 392 1307 30.0 %
Date: 2015-11-05 17:04:23 Functions: 41 138 29.7 %

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

Generated by: LCOV version 1.11