LCOV - code coverage report
Current view: top level - src - estream.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 394 1325 29.7 %
Date: 2016-09-12 12:19:50 Functions: 41 138 29.7 %

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

Generated by: LCOV version 1.11