LCOV - code coverage report
Current view: top level - src - estream.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 406 1335 30.4 %
Date: 2016-11-29 14:52:46 Functions: 41 139 29.5 %

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

Generated by: LCOV version 1.11