LCOV - code coverage report
Current view: top level - src - estream.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 402 1307 30.8 %
Date: 2017-03-02 16:37:58 Functions: 39 122 32.0 %

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

Generated by: LCOV version 1.13