Blame src/estream.c

Packit fc043f
/* estream.c - Extended Stream I/O Library
Packit fc043f
 * Copyright (C) 2004, 2005, 2006, 2007, 2009, 2010, 2011,
Packit fc043f
 *               2014, 2015, 2016, 2017 g10 Code GmbH
Packit fc043f
 *
Packit fc043f
 * This file is part of Libestream.
Packit fc043f
 *
Packit fc043f
 * Libestream is free software; you can redistribute it and/or modify
Packit fc043f
 * it under the terms of the GNU Lesser General Public License as
Packit fc043f
 * published by the Free Software Foundation; either version 2.1 of
Packit fc043f
 * the License, or (at your option) any later version.
Packit fc043f
 *
Packit fc043f
 * Libestream is distributed in the hope that it will be useful, but
Packit fc043f
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit fc043f
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit fc043f
 * Lesser General Public License for more details.
Packit fc043f
 *
Packit fc043f
 * You should have received a copy of the GNU Lesser General Public
Packit fc043f
 * License along with Libestream; if not, see <https://www.gnu.org/licenses/>.
Packit fc043f
 *
Packit fc043f
 * ALTERNATIVELY, Libestream may be distributed under the terms of the
Packit fc043f
 * following license, in which case the provisions of this license are
Packit fc043f
 * required INSTEAD OF the GNU General Public License. If you wish to
Packit fc043f
 * allow use of your version of this file only under the terms of the
Packit fc043f
 * GNU General Public License, and not to allow others to use your
Packit fc043f
 * version of this file under the terms of the following license,
Packit fc043f
 * indicate your decision by deleting this paragraph and the license
Packit fc043f
 * below.
Packit fc043f
 *
Packit fc043f
 * Redistribution and use in source and binary forms, with or without
Packit fc043f
 * modification, are permitted provided that the following conditions
Packit fc043f
 * are met:
Packit fc043f
 * 1. Redistributions of source code must retain the above copyright
Packit fc043f
 *    notice, and the entire permission notice in its entirety,
Packit fc043f
 *    including the disclaimer of warranties.
Packit fc043f
 * 2. Redistributions in binary form must reproduce the above copyright
Packit fc043f
 *    notice, this list of conditions and the following disclaimer in the
Packit fc043f
 *    documentation and/or other materials provided with the distribution.
Packit fc043f
 * 3. The name of the author may not be used to endorse or promote
Packit fc043f
 *    products derived from this software without specific prior
Packit fc043f
 *    written permission.
Packit fc043f
 *
Packit fc043f
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
Packit fc043f
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
Packit fc043f
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
Packit fc043f
 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
Packit fc043f
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
Packit fc043f
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
Packit fc043f
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
Packit fc043f
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
Packit fc043f
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
Packit fc043f
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
Packit fc043f
 * OF THE POSSIBILITY OF SUCH DAMAGE.
Packit fc043f
 */
Packit fc043f
Packit fc043f
#ifdef USE_ESTREAM_SUPPORT_H
Packit fc043f
# include <estream-support.h>
Packit fc043f
#endif
Packit fc043f
Packit fc043f
#ifdef HAVE_CONFIG_H
Packit fc043f
# include <config.h>
Packit fc043f
#endif
Packit fc043f
Packit fc043f
#if defined(_WIN32) && !defined(HAVE_W32_SYSTEM)
Packit fc043f
# define HAVE_W32_SYSTEM 1
Packit fc043f
# if defined(__MINGW32CE__) && !defined (HAVE_W32CE_SYSTEM)
Packit fc043f
#  define HAVE_W32CE_SYSTEM
Packit fc043f
# endif
Packit fc043f
#endif
Packit fc043f
Packit fc043f
#ifdef HAVE_SYS_SELECT_H
Packit fc043f
# include <sys/select.h>
Packit fc043f
#endif
Packit fc043f
#ifdef HAVE_SYS_TIME_H
Packit fc043f
# include <sys/time.h>
Packit fc043f
#endif
Packit fc043f
#include <sys/types.h>
Packit fc043f
#include <sys/file.h>
Packit fc043f
#include <sys/stat.h>
Packit fc043f
#include <stdio.h>
Packit fc043f
#include <stdlib.h>
Packit fc043f
#include <string.h>
Packit fc043f
#include <unistd.h>
Packit fc043f
#include <stdarg.h>
Packit fc043f
#include <fcntl.h>
Packit fc043f
#include <errno.h>
Packit fc043f
#include <stddef.h>
Packit fc043f
#include <assert.h>
Packit fc043f
#ifdef HAVE_W32_SYSTEM
Packit fc043f
# ifdef HAVE_WINSOCK2_H
Packit fc043f
#  include <winsock2.h>
Packit fc043f
# endif
Packit fc043f
# include <windows.h>
Packit fc043f
#endif
Packit fc043f
Packit fc043f
/* Enable tracing.  The value is the module name to be printed.  */
Packit fc043f
/*#define ENABLE_TRACING "estream"*/
Packit fc043f
Packit fc043f
#include "gpgrt-int.h"
Packit fc043f
#include "estream-printf.h"
Packit fc043f
#include "thread.h"
Packit fc043f
#include "lock.h"
Packit fc043f
Packit fc043f
Packit fc043f
#ifndef O_BINARY
Packit fc043f
# define O_BINARY 0
Packit fc043f
#endif
Packit fc043f
#ifndef HAVE_DOSISH_SYSTEM
Packit fc043f
# ifdef HAVE_W32_SYSTEM
Packit fc043f
#  define HAVE_DOSISH_SYSTEM 1
Packit fc043f
# endif
Packit fc043f
#endif
Packit fc043f
Packit fc043f
Packit fc043f
#ifdef HAVE_W32_SYSTEM
Packit fc043f
# ifndef  S_IRGRP
Packit fc043f
#  define S_IRGRP S_IRUSR
Packit fc043f
# endif
Packit fc043f
# ifndef  S_IROTH
Packit fc043f
#  define S_IROTH S_IRUSR
Packit fc043f
# endif
Packit fc043f
# ifndef  S_IWGRP
Packit fc043f
#  define S_IWGRP S_IWUSR
Packit fc043f
# endif
Packit fc043f
# ifndef  S_IWOTH
Packit fc043f
#  define S_IWOTH S_IWUSR
Packit fc043f
# endif
Packit fc043f
# ifndef  S_IXGRP
Packit fc043f
#  define S_IXGRP S_IXUSR
Packit fc043f
# endif
Packit fc043f
# ifndef  S_IXOTH
Packit fc043f
#  define S_IXOTH S_IXUSR
Packit fc043f
# endif
Packit fc043f
#endif
Packit fc043f
Packit fc043f
#if !defined (EWOULDBLOCK) && defined (HAVE_W32_SYSTEM)
Packit fc043f
/* Compatibility with errno.h from mingw-2.0 */
Packit fc043f
# define EWOULDBLOCK 140
Packit fc043f
#endif
Packit fc043f
Packit fc043f
#ifndef EAGAIN
Packit fc043f
# define EAGAIN  EWOULDBLOCK
Packit fc043f
#endif
Packit fc043f
Packit fc043f
Packit fc043f
#ifdef HAVE_W32CE_SYSTEM
Packit fc043f
# define _set_errno(a)  gpg_err_set_errno ((a))
Packit fc043f
/* Setmode is missing in cegcc but available since CE 5.0.  */
Packit fc043f
int _setmode (int handle, int mode);
Packit fc043f
# define setmode(a,b)   _setmode ((a),(b))
Packit fc043f
#else
Packit fc043f
# define _set_errno(a)  do { errno = (a); } while (0)
Packit fc043f
#endif
Packit fc043f
Packit fc043f
#ifdef HAVE_W32_SYSTEM
Packit fc043f
# define IS_INVALID_FD(a)    ((void*)(a) == (void*)(-1)) /* ?? FIXME.  */
Packit fc043f
#else
Packit fc043f
# define IS_INVALID_FD(a)    ((a) == -1)
Packit fc043f
#endif
Packit fc043f
Packit fc043f
/* Calculate array dimension.  */
Packit fc043f
#ifndef DIM
Packit fc043f
#define DIM(array) (sizeof (array) / sizeof (*array))
Packit fc043f
#endif
Packit fc043f
Packit fc043f
/* A helper macro used to convert to a hex string.  */
Packit fc043f
#define tohex(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'A'))
Packit fc043f
Packit fc043f
Packit fc043f
/* Generally used types.  */
Packit fc043f
Packit fc043f
typedef void *(*func_realloc_t) (void *mem, size_t size);
Packit fc043f
typedef void (*func_free_t) (void *mem);
Packit fc043f
Packit fc043f
Packit fc043f

Packit fc043f
Packit fc043f
/*
Packit fc043f
 * A linked list to hold active stream objects.
Packit fc043f
 * Protected by ESTREAM_LIST_LOCK.
Packit fc043f
 */
Packit fc043f
struct estream_list_s
Packit fc043f
{
Packit fc043f
  struct estream_list_s *next;
Packit fc043f
  estream_t stream;  /* Entry is not used if NULL.  */
Packit fc043f
};
Packit fc043f
typedef struct estream_list_s *estream_list_t;
Packit fc043f
static estream_list_t estream_list;
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * File descriptors registered for use as the standard file handles.
Packit fc043f
 * Protected by ESTREAM_LIST_LOCK.
Packit fc043f
 */
Packit fc043f
static int custom_std_fds[3];
Packit fc043f
static unsigned char custom_std_fds_valid[3];
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * A lock object to protect ESTREAM LIST, CUSTOM_STD_FDS and
Packit fc043f
 * CUSTOM_STD_FDS_VALID.  Used by lock_list() and unlock_list().
Packit fc043f
 */
Packit fc043f
GPGRT_LOCK_DEFINE (estream_list_lock);
Packit fc043f
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * Error code replacements.
Packit fc043f
 */
Packit fc043f
#ifndef EOPNOTSUPP
Packit fc043f
# define EOPNOTSUPP ENOSYS
Packit fc043f
#endif
Packit fc043f
Packit fc043f
Packit fc043f
/* Local prototypes.  */
Packit fc043f
static void fname_set_internal (estream_t stream, const char *fname, int quote);
Packit fc043f
Packit fc043f
Packit fc043f
Packit fc043f

Packit fc043f
/*
Packit fc043f
 * Memory allocation wrappers used in this file.
Packit fc043f
 */
Packit fc043f
static void *
Packit fc043f
mem_alloc (size_t n)
Packit fc043f
{
Packit fc043f
  return _gpgrt_malloc (n);
Packit fc043f
}
Packit fc043f
Packit fc043f
static void *
Packit fc043f
mem_realloc (void *p, size_t n)
Packit fc043f
{
Packit fc043f
  return _gpgrt_realloc (p, n);
Packit fc043f
}
Packit fc043f
Packit fc043f
static void
Packit fc043f
mem_free (void *p)
Packit fc043f
{
Packit fc043f
  if (p)
Packit fc043f
    _gpgrt_free (p);
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * A Windows helper function to map a W32 API error code to a standard
Packit fc043f
 * system error code.
Packit fc043f
 */
Packit fc043f
#ifdef HAVE_W32_SYSTEM
Packit fc043f
static int
Packit fc043f
map_w32_to_errno (DWORD w32_err)
Packit fc043f
{
Packit fc043f
  switch (w32_err)
Packit fc043f
    {
Packit fc043f
    case 0:
Packit fc043f
      return 0;
Packit fc043f
Packit fc043f
    case ERROR_FILE_NOT_FOUND:
Packit fc043f
      return ENOENT;
Packit fc043f
Packit fc043f
    case ERROR_PATH_NOT_FOUND:
Packit fc043f
      return ENOENT;
Packit fc043f
Packit fc043f
    case ERROR_ACCESS_DENIED:
Packit fc043f
      return EPERM;
Packit fc043f
Packit fc043f
    case ERROR_INVALID_HANDLE:
Packit fc043f
    case ERROR_INVALID_BLOCK:
Packit fc043f
      return EINVAL;
Packit fc043f
Packit fc043f
    case ERROR_NOT_ENOUGH_MEMORY:
Packit fc043f
      return ENOMEM;
Packit fc043f
Packit fc043f
    case ERROR_NO_DATA:
Packit fc043f
      return EPIPE;
Packit fc043f
Packit fc043f
    default:
Packit fc043f
      return EIO;
Packit fc043f
    }
Packit fc043f
}
Packit fc043f
#endif /*HAVE_W32_SYSTEM*/
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * Replacement for a missing memrchr.
Packit fc043f
 */
Packit fc043f
#ifndef HAVE_MEMRCHR
Packit fc043f
static void *
Packit fc043f
memrchr (const void *buffer, int c, size_t n)
Packit fc043f
{
Packit fc043f
  const unsigned char *p = buffer;
Packit fc043f
Packit fc043f
  for (p += n; n ; n--)
Packit fc043f
    if (*--p == c)
Packit fc043f
      return (void *)p;
Packit fc043f
  return NULL;
Packit fc043f
}
Packit fc043f
#endif /*HAVE_MEMRCHR*/
Packit fc043f
Packit fc043f
Packit fc043f

Packit fc043f
/*
Packit fc043f
 * Wrappers to lock a stream or the list of streams.
Packit fc043f
 */
Packit fc043f
#if 0
Packit fc043f
# define dbg_lock_0(f)        fprintf (stderr, "estream: " f);
Packit fc043f
# define dbg_lock_1(f, a)     fprintf (stderr, "estream: " f, (a));
Packit fc043f
# define dbg_lock_2(f, a, b)  fprintf (stderr, "estream: " f, (a), (b));
Packit fc043f
#else
Packit fc043f
# define dbg_lock_0(f)
Packit fc043f
# define dbg_lock_1(f, a)
Packit fc043f
# define dbg_lock_2(f, a, b)
Packit fc043f
#endif
Packit fc043f
Packit fc043f
static int
Packit fc043f
init_stream_lock (estream_t _GPGRT__RESTRICT stream)
Packit fc043f
{
Packit fc043f
  int rc;
Packit fc043f
Packit fc043f
  if (!stream->intern->samethread)
Packit fc043f
    {
Packit fc043f
      dbg_lock_1 ("enter init_stream_lock for %p\n", stream);
Packit fc043f
      memset (&stream->intern->lock, 0 , sizeof stream->intern->lock);
Packit fc043f
      rc = _gpgrt_lock_init (&stream->intern->lock);
Packit fc043f
      dbg_lock_2 ("leave init_stream_lock for %p: rc=%d\n", stream, rc);
Packit fc043f
    }
Packit fc043f
  else
Packit fc043f
    rc = 0;
Packit fc043f
  return rc;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
static void
Packit fc043f
destroy_stream_lock (estream_t _GPGRT__RESTRICT stream)
Packit fc043f
{
Packit fc043f
  if (!stream->intern->samethread)
Packit fc043f
    {
Packit fc043f
      dbg_lock_1 ("enter destroy_stream_lock for %p\n", stream);
Packit fc043f
      _gpgrt_lock_destroy (&stream->intern->lock);
Packit fc043f
      dbg_lock_1 ("leave destroy_stream_lock for %p\n", stream);
Packit fc043f
    }
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
static void
Packit fc043f
lock_stream (estream_t _GPGRT__RESTRICT stream)
Packit fc043f
{
Packit fc043f
  if (!stream->intern->samethread)
Packit fc043f
    {
Packit fc043f
      dbg_lock_1 ("enter lock_stream for %p\n", stream);
Packit fc043f
      _gpgrt_lock_lock (&stream->intern->lock);
Packit fc043f
      dbg_lock_1 ("leave lock_stream for %p\n", stream);
Packit fc043f
    }
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
static int
Packit fc043f
trylock_stream (estream_t _GPGRT__RESTRICT stream)
Packit fc043f
{
Packit fc043f
  int rc;
Packit fc043f
Packit fc043f
  if (!stream->intern->samethread)
Packit fc043f
    {
Packit fc043f
      dbg_lock_1 ("enter trylock_stream for %p\n", stream);
Packit fc043f
      rc = _gpgrt_lock_trylock (&stream->intern->lock)? 0 : -1;
Packit fc043f
      dbg_lock_2 ("leave trylock_stream for %p: rc=%d\n", stream, rc);
Packit fc043f
    }
Packit fc043f
  else
Packit fc043f
    rc = 0;
Packit fc043f
  return rc;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
static void
Packit fc043f
unlock_stream (estream_t _GPGRT__RESTRICT stream)
Packit fc043f
{
Packit fc043f
  if (!stream->intern->samethread)
Packit fc043f
    {
Packit fc043f
      dbg_lock_1 ("enter unlock_stream for %p\n", stream);
Packit fc043f
      _gpgrt_lock_unlock (&stream->intern->lock);
Packit fc043f
      dbg_lock_1 ("leave unlock_stream for %p\n", stream);
Packit fc043f
    }
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
static void
Packit fc043f
lock_list (void)
Packit fc043f
{
Packit fc043f
  dbg_lock_0 ("enter lock_list\n");
Packit fc043f
  _gpgrt_lock_lock (&estream_list_lock);
Packit fc043f
  dbg_lock_0 ("leave lock_list\n");
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
static void
Packit fc043f
unlock_list (void)
Packit fc043f
{
Packit fc043f
  dbg_lock_0 ("enter unlock_list\n");
Packit fc043f
  _gpgrt_lock_unlock (&estream_list_lock);
Packit fc043f
  dbg_lock_0 ("leave unlock_list\n");
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
#undef dbg_lock_0
Packit fc043f
#undef dbg_lock_1
Packit fc043f
#undef dbg_lock_2
Packit fc043f
Packit fc043f
Packit fc043f

Packit fc043f
/*
Packit fc043f
 * Manipulation of the list of stream.
Packit fc043f
 */
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * Add STREAM to the list of registered stream objects.  If
Packit fc043f
 * WITH_LOCKED_LIST is true it is assumed that the list of streams is
Packit fc043f
 * already locked.  The implementation is straightforward: We first
Packit fc043f
 * look for an unused entry in the list and use that; if none is
Packit fc043f
 * available we put a new item at the head.  We drawback of the
Packit fc043f
 * strategy never to shorten the list is that a one time allocation of
Packit fc043f
 * many streams will lead to scanning unused entries later.  If that
Packit fc043f
 * turns out to be a problem, we may either free some items from the
Packit fc043f
 * list or append new entries at the end; or use a table.  Returns 0
Packit fc043f
 * on success; on error or non-zero is returned and ERRNO set.
Packit fc043f
 */
Packit fc043f
static int
Packit fc043f
do_list_add (estream_t stream, int with_locked_list)
Packit fc043f
{
Packit fc043f
  estream_list_t item;
Packit fc043f
Packit fc043f
  if (!with_locked_list)
Packit fc043f
    lock_list ();
Packit fc043f
Packit fc043f
  for (item = estream_list; item && item->stream; item = item->next)
Packit fc043f
    ;
Packit fc043f
  if (!item)
Packit fc043f
    {
Packit fc043f
      item = mem_alloc (sizeof *item);
Packit fc043f
      if (item)
Packit fc043f
        {
Packit fc043f
          item->next = estream_list;
Packit fc043f
          estream_list = item;
Packit fc043f
        }
Packit fc043f
    }
Packit fc043f
  if (item)
Packit fc043f
    item->stream = stream;
Packit fc043f
Packit fc043f
  if (!with_locked_list)
Packit fc043f
    unlock_list ();
Packit fc043f
Packit fc043f
  return item? 0 : -1;
Packit fc043f
}
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * Remove STREAM from the list of registered stream objects.
Packit fc043f
 */
Packit fc043f
static void
Packit fc043f
do_list_remove (estream_t stream, int with_locked_list)
Packit fc043f
{
Packit fc043f
  estream_list_t item, item_prev = NULL;
Packit fc043f
Packit fc043f
  if (!with_locked_list)
Packit fc043f
    lock_list ();
Packit fc043f
Packit fc043f
  for (item = estream_list; item; item = item->next)
Packit fc043f
    if (item->stream == stream)
Packit fc043f
      break;
Packit fc043f
    else
Packit fc043f
      item_prev = item;
Packit fc043f
Packit fc043f
  if (item_prev)
Packit fc043f
    {
Packit fc043f
      item_prev->next = item->next;
Packit fc043f
      mem_free (item);
Packit fc043f
    }
Packit fc043f
  else
Packit fc043f
    {
Packit fc043f
      if (item)
Packit fc043f
        {
Packit fc043f
          estream_list = item->next;
Packit fc043f
          mem_free (item);
Packit fc043f
        }
Packit fc043f
    }
Packit fc043f
Packit fc043f
  if (!with_locked_list)
Packit fc043f
    unlock_list ();
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f

Packit fc043f
/*
Packit fc043f
 * The atexit handler for the entire gpgrt.
Packit fc043f
 */
Packit fc043f
static void
Packit fc043f
do_deinit (void)
Packit fc043f
{
Packit fc043f
  /* Flush all streams. */
Packit fc043f
  _gpgrt_fflush (NULL);
Packit fc043f
Packit fc043f
  /* We should release the estream_list.  However there is one
Packit fc043f
     problem: That list is also used to search for the standard
Packit fc043f
     estream file descriptors.  If we would remove the entire list,
Packit fc043f
     any use of es_foo in another atexit function may re-create the
Packit fc043f
     list and the streams with possible undesirable effects.  Given
Packit fc043f
     that we don't close the stream either, it should not matter that
Packit fc043f
     we keep the list and let the OS clean it up at process end.  */
Packit fc043f
Packit fc043f
  /* Reset the syscall clamp.  */
Packit fc043f
  _gpgrt_set_syscall_clamp (NULL, NULL);
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * Initialization of the estream module.
Packit fc043f
 */
Packit fc043f
int
Packit fc043f
_gpgrt_estream_init (void)
Packit fc043f
{
Packit fc043f
  static int initialized;
Packit fc043f
Packit fc043f
  if (!initialized)
Packit fc043f
    {
Packit fc043f
      initialized = 1;
Packit fc043f
      atexit (do_deinit);
Packit fc043f
    }
Packit fc043f
  return 0;
Packit fc043f
}
Packit fc043f
Packit fc043f

Packit fc043f
/*
Packit fc043f
 * Implementation of memory based I/O.
Packit fc043f
 */
Packit fc043f
Packit fc043f
/* Cookie for memory objects.  */
Packit fc043f
typedef struct estream_cookie_mem
Packit fc043f
{
Packit fc043f
  unsigned int modeflags;	/* Open flags.  */
Packit fc043f
  unsigned char *memory;	/* Allocated data buffer.  */
Packit fc043f
  size_t memory_size;		/* Allocated size of MEMORY.  */
Packit fc043f
  size_t memory_limit;          /* Caller supplied maximum allowed
Packit fc043f
                                   allocation size or 0 for no limit.  */
Packit fc043f
  size_t offset;		/* Current offset in MEMORY.  */
Packit fc043f
  size_t data_len;		/* Used length of data in MEMORY.  */
Packit fc043f
  size_t block_size;		/* Block size.  */
Packit fc043f
  struct {
Packit fc043f
    unsigned int grow: 1;	/* MEMORY is allowed to grow.  */
Packit fc043f
  } flags;
Packit fc043f
  func_realloc_t func_realloc;
Packit fc043f
  func_free_t func_free;
Packit fc043f
} *estream_cookie_mem_t;
Packit fc043f
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * Create function for memory objects.  DATA is either NULL or a user
Packit fc043f
 * supplied buffer with the initial conetnt of the memory buffer.  If
Packit fc043f
 * DATA is NULL, DATA_N and DATA_LEN need to be 0 as well.  If DATA is
Packit fc043f
 * not NULL, DATA_N gives the allocated size of DATA and DATA_LEN the
Packit fc043f
 * used length in DATA.  If this function succeeds DATA is now owned
Packit fc043f
 * by this function.  If GROW is false FUNC_REALLOC is not
Packit fc043f
 * required.
Packit fc043f
 */
Packit fc043f
static int
Packit fc043f
func_mem_create (void *_GPGRT__RESTRICT *_GPGRT__RESTRICT cookie,
Packit fc043f
                 unsigned char *_GPGRT__RESTRICT data, size_t data_n,
Packit fc043f
                 size_t data_len,
Packit fc043f
                 size_t block_size, unsigned int grow,
Packit fc043f
                 func_realloc_t func_realloc, func_free_t func_free,
Packit fc043f
                 unsigned int modeflags,
Packit fc043f
                 size_t memory_limit)
Packit fc043f
{
Packit fc043f
  estream_cookie_mem_t mem_cookie;
Packit fc043f
  int err;
Packit fc043f
Packit fc043f
  if (!data && (data_n || data_len))
Packit fc043f
    {
Packit fc043f
      _set_errno (EINVAL);
Packit fc043f
      return -1;
Packit fc043f
    }
Packit fc043f
  if (grow && func_free && !func_realloc)
Packit fc043f
    {
Packit fc043f
      _set_errno (EINVAL);
Packit fc043f
      return -1;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  /* Round a memory limit up to the next block length.  */
Packit fc043f
  if (memory_limit && block_size)
Packit fc043f
    {
Packit fc043f
      memory_limit += block_size - 1;
Packit fc043f
      memory_limit /= block_size;
Packit fc043f
      memory_limit *= block_size;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  mem_cookie = mem_alloc (sizeof (*mem_cookie));
Packit fc043f
  if (!mem_cookie)
Packit fc043f
    err = -1;
Packit fc043f
  else
Packit fc043f
    {
Packit fc043f
      mem_cookie->modeflags = modeflags;
Packit fc043f
      mem_cookie->memory = data;
Packit fc043f
      mem_cookie->memory_size = data_n;
Packit fc043f
      mem_cookie->memory_limit = memory_limit;
Packit fc043f
      mem_cookie->offset = 0;
Packit fc043f
      mem_cookie->data_len = data_len;
Packit fc043f
      mem_cookie->block_size = block_size;
Packit fc043f
      mem_cookie->flags.grow = !!grow;
Packit fc043f
      mem_cookie->func_realloc
Packit fc043f
        = grow? (func_realloc ? func_realloc : mem_realloc) : NULL;
Packit fc043f
      mem_cookie->func_free = func_free ? func_free : mem_free;
Packit fc043f
      *cookie = mem_cookie;
Packit fc043f
      err = 0;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  return err;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * Read function for memory objects.
Packit fc043f
 */
Packit fc043f
static gpgrt_ssize_t
Packit fc043f
func_mem_read (void *cookie, void *buffer, size_t size)
Packit fc043f
{
Packit fc043f
  estream_cookie_mem_t mem_cookie = cookie;
Packit fc043f
  gpgrt_ssize_t ret;
Packit fc043f
Packit fc043f
  if (!size)  /* Just the pending data check.  */
Packit fc043f
    return (mem_cookie->data_len - mem_cookie->offset)? 0 : -1;
Packit fc043f
Packit fc043f
  if (size > mem_cookie->data_len - mem_cookie->offset)
Packit fc043f
    size = mem_cookie->data_len - mem_cookie->offset;
Packit fc043f
Packit fc043f
  if (size)
Packit fc043f
    {
Packit fc043f
      memcpy (buffer, mem_cookie->memory + mem_cookie->offset, size);
Packit fc043f
      mem_cookie->offset += size;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  ret = size;
Packit fc043f
  return ret;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * Write function for memory objects.
Packit fc043f
 */
Packit fc043f
static gpgrt_ssize_t
Packit fc043f
func_mem_write (void *cookie, const void *buffer, size_t size)
Packit fc043f
{
Packit fc043f
  estream_cookie_mem_t mem_cookie = cookie;
Packit fc043f
  gpgrt_ssize_t ret;
Packit fc043f
  size_t nleft;
Packit fc043f
Packit fc043f
  if (!size)
Packit fc043f
    return 0;  /* A flush is a NOP for memory objects.  */
Packit fc043f
Packit fc043f
  if (mem_cookie->modeflags & O_APPEND)
Packit fc043f
    {
Packit fc043f
      /* Append to data.  */
Packit fc043f
      mem_cookie->offset = mem_cookie->data_len;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  assert (mem_cookie->memory_size >= mem_cookie->offset);
Packit fc043f
  nleft = mem_cookie->memory_size - mem_cookie->offset;
Packit fc043f
Packit fc043f
  /* If we are not allowed to grow the buffer, limit the size to the
Packit fc043f
     left space.  */
Packit fc043f
  if (!mem_cookie->flags.grow && size > nleft)
Packit fc043f
    size = nleft;
Packit fc043f
Packit fc043f
  /* Enlarge the memory buffer if needed.  */
Packit fc043f
  if (size > nleft)
Packit fc043f
    {
Packit fc043f
      unsigned char *newbuf;
Packit fc043f
      size_t newsize;
Packit fc043f
Packit fc043f
      if (!mem_cookie->memory_size)
Packit fc043f
        newsize = size;  /* Not yet allocated.  */
Packit fc043f
      else
Packit fc043f
        newsize = mem_cookie->memory_size + (size - nleft);
Packit fc043f
      if (newsize < mem_cookie->offset)
Packit fc043f
        {
Packit fc043f
          _set_errno (EINVAL);
Packit fc043f
          return -1;
Packit fc043f
        }
Packit fc043f
Packit fc043f
      /* Round up to the next block length.  BLOCK_SIZE should always
Packit fc043f
         be set; we check anyway.  */
Packit fc043f
      if (mem_cookie->block_size)
Packit fc043f
        {
Packit fc043f
          newsize += mem_cookie->block_size - 1;
Packit fc043f
          if (newsize < mem_cookie->offset)
Packit fc043f
            {
Packit fc043f
              _set_errno (EINVAL);
Packit fc043f
              return -1;
Packit fc043f
            }
Packit fc043f
          newsize /= mem_cookie->block_size;
Packit fc043f
          newsize *= mem_cookie->block_size;
Packit fc043f
        }
Packit fc043f
Packit fc043f
      /* Check for a total limit.  */
Packit fc043f
      if (mem_cookie->memory_limit && newsize > mem_cookie->memory_limit)
Packit fc043f
        {
Packit fc043f
          _set_errno (ENOSPC);
Packit fc043f
          return -1;
Packit fc043f
        }
Packit fc043f
Packit fc043f
      assert (mem_cookie->func_realloc);
Packit fc043f
      newbuf = mem_cookie->func_realloc (mem_cookie->memory, newsize);
Packit fc043f
      if (!newbuf)
Packit fc043f
        return -1;
Packit fc043f
Packit fc043f
      mem_cookie->memory = newbuf;
Packit fc043f
      mem_cookie->memory_size = newsize;
Packit fc043f
Packit fc043f
      assert (mem_cookie->memory_size >= mem_cookie->offset);
Packit fc043f
      nleft = mem_cookie->memory_size - mem_cookie->offset;
Packit fc043f
Packit fc043f
      assert (size <= nleft);
Packit fc043f
    }
Packit fc043f
Packit fc043f
  memcpy (mem_cookie->memory + mem_cookie->offset, buffer, size);
Packit fc043f
  if (mem_cookie->offset + size > mem_cookie->data_len)
Packit fc043f
    mem_cookie->data_len = mem_cookie->offset + size;
Packit fc043f
  mem_cookie->offset += size;
Packit fc043f
Packit fc043f
  ret = size;
Packit fc043f
  return ret;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * Seek function for memory objects.
Packit fc043f
 */
Packit fc043f
static int
Packit fc043f
func_mem_seek (void *cookie, gpgrt_off_t *offset, int whence)
Packit fc043f
{
Packit fc043f
  estream_cookie_mem_t mem_cookie = cookie;
Packit fc043f
  gpgrt_off_t pos_new;
Packit fc043f
Packit fc043f
  switch (whence)
Packit fc043f
    {
Packit fc043f
    case SEEK_SET:
Packit fc043f
      pos_new = *offset;
Packit fc043f
      break;
Packit fc043f
Packit fc043f
    case SEEK_CUR:
Packit fc043f
      pos_new = mem_cookie->offset += *offset;
Packit fc043f
      break;
Packit fc043f
Packit fc043f
    case SEEK_END:
Packit fc043f
      pos_new = mem_cookie->data_len += *offset;
Packit fc043f
      break;
Packit fc043f
Packit fc043f
    default:
Packit fc043f
      _set_errno (EINVAL);
Packit fc043f
      return -1;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  if (pos_new > mem_cookie->memory_size)
Packit fc043f
    {
Packit fc043f
      size_t newsize;
Packit fc043f
      void *newbuf;
Packit fc043f
Packit fc043f
      if (!mem_cookie->flags.grow)
Packit fc043f
	{
Packit fc043f
	  _set_errno (ENOSPC);
Packit fc043f
	  return -1;
Packit fc043f
        }
Packit fc043f
Packit fc043f
      newsize = pos_new + mem_cookie->block_size - 1;
Packit fc043f
      if (newsize < pos_new)
Packit fc043f
        {
Packit fc043f
          _set_errno (EINVAL);
Packit fc043f
          return -1;
Packit fc043f
        }
Packit fc043f
      newsize /= mem_cookie->block_size;
Packit fc043f
      newsize *= mem_cookie->block_size;
Packit fc043f
Packit fc043f
      if (mem_cookie->memory_limit && newsize > mem_cookie->memory_limit)
Packit fc043f
        {
Packit fc043f
          _set_errno (ENOSPC);
Packit fc043f
          return -1;
Packit fc043f
        }
Packit fc043f
Packit fc043f
      assert (mem_cookie->func_realloc);
Packit fc043f
      newbuf = mem_cookie->func_realloc (mem_cookie->memory, newsize);
Packit fc043f
      if (!newbuf)
Packit fc043f
        return -1;
Packit fc043f
Packit fc043f
      mem_cookie->memory = newbuf;
Packit fc043f
      mem_cookie->memory_size = newsize;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  if (pos_new > mem_cookie->data_len)
Packit fc043f
    {
Packit fc043f
      /* Fill spare space with zeroes.  */
Packit fc043f
      memset (mem_cookie->memory + mem_cookie->data_len,
Packit fc043f
              0, pos_new - mem_cookie->data_len);
Packit fc043f
      mem_cookie->data_len = pos_new;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  mem_cookie->offset = pos_new;
Packit fc043f
  *offset = pos_new;
Packit fc043f
Packit fc043f
  return 0;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * The IOCTL function for memory objects.
Packit fc043f
 */
Packit fc043f
static int
Packit fc043f
func_mem_ioctl (void *cookie, int cmd, void *ptr, size_t *len)
Packit fc043f
{
Packit fc043f
  estream_cookie_mem_t mem_cookie = cookie;
Packit fc043f
  int ret;
Packit fc043f
Packit fc043f
  if (cmd == COOKIE_IOCTL_SNATCH_BUFFER)
Packit fc043f
    {
Packit fc043f
      /* Return the internal buffer of the stream to the caller and
Packit fc043f
         invalidate it for the stream.  */
Packit fc043f
      *(void**)ptr = mem_cookie->memory;
Packit fc043f
      *len = mem_cookie->data_len;
Packit fc043f
      mem_cookie->memory = NULL;
Packit fc043f
      mem_cookie->memory_size = 0;
Packit fc043f
      mem_cookie->offset = 0;
Packit fc043f
      ret = 0;
Packit fc043f
    }
Packit fc043f
  else
Packit fc043f
    {
Packit fc043f
      _set_errno (EINVAL);
Packit fc043f
      ret = -1;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  return ret;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * The destroy function for memory objects.
Packit fc043f
 */
Packit fc043f
static int
Packit fc043f
func_mem_destroy (void *cookie)
Packit fc043f
{
Packit fc043f
  estream_cookie_mem_t mem_cookie = cookie;
Packit fc043f
Packit fc043f
  if (cookie)
Packit fc043f
    {
Packit fc043f
      mem_cookie->func_free (mem_cookie->memory);
Packit fc043f
      mem_free (mem_cookie);
Packit fc043f
    }
Packit fc043f
  return 0;
Packit fc043f
}
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * Access object for the memory functions.
Packit fc043f
 */
Packit fc043f
static struct cookie_io_functions_s estream_functions_mem =
Packit fc043f
  {
Packit fc043f
    {
Packit fc043f
      func_mem_read,
Packit fc043f
      func_mem_write,
Packit fc043f
      func_mem_seek,
Packit fc043f
      func_mem_destroy,
Packit fc043f
    },
Packit fc043f
    func_mem_ioctl,
Packit fc043f
  };
Packit fc043f
Packit fc043f
Packit fc043f

Packit fc043f
/*
Packit fc043f
 * Implementation of file descriptor based I/O.
Packit fc043f
 */
Packit fc043f
Packit fc043f
/* Cookie for fd objects.  */
Packit fc043f
typedef struct estream_cookie_fd
Packit fc043f
{
Packit fc043f
  int fd;        /* The file descriptor we are using for actual output.  */
Packit fc043f
  int no_close;  /* If set we won't close the file descriptor.  */
Packit fc043f
  int nonblock;  /* Non-blocking mode is enabled.  */
Packit fc043f
} *estream_cookie_fd_t;
Packit fc043f
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * Create function for objects indentified by a libc file descriptor.
Packit fc043f
 */
Packit fc043f
static int
Packit fc043f
func_fd_create (void **cookie, int fd, unsigned int modeflags, int no_close)
Packit fc043f
{
Packit fc043f
  estream_cookie_fd_t fd_cookie;
Packit fc043f
  int err;
Packit fc043f
Packit fc043f
  trace (("enter: fd=%d mf=%x nc=%d", fd, modeflags, no_close));
Packit fc043f
Packit fc043f
  fd_cookie = mem_alloc (sizeof (*fd_cookie));
Packit fc043f
  if (! fd_cookie)
Packit fc043f
    err = -1;
Packit fc043f
  else
Packit fc043f
    {
Packit fc043f
#ifdef HAVE_DOSISH_SYSTEM
Packit fc043f
      /* Make sure it is in binary mode if requested.  */
Packit fc043f
      if ( (modeflags & O_BINARY) )
Packit fc043f
        setmode (fd, O_BINARY);
Packit fc043f
#endif
Packit fc043f
      fd_cookie->fd = fd;
Packit fc043f
      fd_cookie->no_close = no_close;
Packit fc043f
      fd_cookie->nonblock = !!(modeflags & O_NONBLOCK);
Packit fc043f
      *cookie = fd_cookie;
Packit fc043f
      err = 0;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  trace_errno (err, ("leave: cookie=%p err=%d", *cookie, err));
Packit fc043f
  return err;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * Read function for fd objects.
Packit fc043f
 */
Packit fc043f
static gpgrt_ssize_t
Packit fc043f
func_fd_read (void *cookie, void *buffer, size_t size)
Packit fc043f
Packit fc043f
{
Packit fc043f
  estream_cookie_fd_t file_cookie = cookie;
Packit fc043f
  gpgrt_ssize_t bytes_read;
Packit fc043f
Packit fc043f
  trace (("enter: cookie=%p buffer=%p size=%d", cookie, buffer, (int)size));
Packit fc043f
Packit fc043f
  if (!size)
Packit fc043f
    bytes_read = -1; /* We don't know whether anything is pending.  */
Packit fc043f
  else if (IS_INVALID_FD (file_cookie->fd))
Packit fc043f
    {
Packit fc043f
      _gpgrt_yield ();
Packit fc043f
      bytes_read = 0;
Packit fc043f
    }
Packit fc043f
  else
Packit fc043f
    {
Packit fc043f
      _gpgrt_pre_syscall ();
Packit fc043f
      do
Packit fc043f
        {
Packit fc043f
          bytes_read = read (file_cookie->fd, buffer, size);
Packit fc043f
        }
Packit fc043f
      while (bytes_read == -1 && errno == EINTR);
Packit fc043f
      _gpgrt_post_syscall ();
Packit fc043f
    }
Packit fc043f
Packit fc043f
  trace_errno (bytes_read == -1, ("leave: bytes_read=%d", (int)bytes_read));
Packit fc043f
  return bytes_read;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * Write function for fd objects.
Packit fc043f
 */
Packit fc043f
static gpgrt_ssize_t
Packit fc043f
func_fd_write (void *cookie, const void *buffer, size_t size)
Packit fc043f
{
Packit fc043f
  estream_cookie_fd_t file_cookie = cookie;
Packit fc043f
  gpgrt_ssize_t bytes_written;
Packit fc043f
Packit fc043f
  trace (("enter: cookie=%p buffer=%p size=%d", cookie, buffer, (int)size));
Packit fc043f
Packit fc043f
  if (IS_INVALID_FD (file_cookie->fd))
Packit fc043f
    {
Packit fc043f
      _gpgrt_yield ();
Packit fc043f
      bytes_written = size; /* Yeah:  Success writing to the bit bucket.  */
Packit fc043f
    }
Packit fc043f
  else if (buffer)
Packit fc043f
    {
Packit fc043f
      _gpgrt_pre_syscall ();
Packit fc043f
      do
Packit fc043f
        {
Packit fc043f
          bytes_written = write (file_cookie->fd, buffer, size);
Packit fc043f
        }
Packit fc043f
      while (bytes_written == -1 && errno == EINTR);
Packit fc043f
      _gpgrt_post_syscall ();
Packit fc043f
    }
Packit fc043f
  else
Packit fc043f
    bytes_written = size; /* Note that for a flush SIZE should be 0.  */
Packit fc043f
Packit fc043f
  trace_errno (bytes_written == -1,
Packit fc043f
               ("leave: bytes_written=%d", (int)bytes_written));
Packit fc043f
  return bytes_written;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * Seek function for fd objects.
Packit fc043f
 */
Packit fc043f
static int
Packit fc043f
func_fd_seek (void *cookie, gpgrt_off_t *offset, int whence)
Packit fc043f
{
Packit fc043f
  estream_cookie_fd_t file_cookie = cookie;
Packit fc043f
  gpgrt_off_t offset_new;
Packit fc043f
  int err;
Packit fc043f
Packit fc043f
  if (IS_INVALID_FD (file_cookie->fd))
Packit fc043f
    {
Packit fc043f
      _set_errno (ESPIPE);
Packit fc043f
      err = -1;
Packit fc043f
    }
Packit fc043f
  else
Packit fc043f
    {
Packit fc043f
      _gpgrt_pre_syscall ();
Packit fc043f
      offset_new = lseek (file_cookie->fd, *offset, whence);
Packit fc043f
      _gpgrt_post_syscall ();
Packit fc043f
      if (offset_new == -1)
Packit fc043f
        err = -1;
Packit fc043f
      else
Packit fc043f
        {
Packit fc043f
          *offset = offset_new;
Packit fc043f
          err = 0;
Packit fc043f
        }
Packit fc043f
    }
Packit fc043f
Packit fc043f
  return err;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * The IOCTL function for fd objects.
Packit fc043f
 */
Packit fc043f
static int
Packit fc043f
func_fd_ioctl (void *cookie, int cmd, void *ptr, size_t *len)
Packit fc043f
{
Packit fc043f
  estream_cookie_fd_t fd_cookie = cookie;
Packit fc043f
  int ret;
Packit fc043f
Packit fc043f
  if (cmd == COOKIE_IOCTL_NONBLOCK && !len)
Packit fc043f
    {
Packit fc043f
      fd_cookie->nonblock = !!ptr;
Packit fc043f
      if (IS_INVALID_FD (fd_cookie->fd))
Packit fc043f
        {
Packit fc043f
          _set_errno (EINVAL);
Packit fc043f
          ret = -1;
Packit fc043f
        }
Packit fc043f
      else
Packit fc043f
        {
Packit fc043f
#ifdef _WIN32
Packit fc043f
          _set_errno (EOPNOTSUPP); /* FIXME: Implement for Windows.  */
Packit fc043f
          ret = -1;
Packit fc043f
#else
Packit fc043f
          _set_errno (0);
Packit fc043f
          ret = fcntl (fd_cookie->fd, F_GETFL, 0);
Packit fc043f
          if (ret == -1 && errno)
Packit fc043f
            ;
Packit fc043f
          else if (fd_cookie->nonblock)
Packit fc043f
            ret = fcntl (fd_cookie->fd, F_SETFL, (ret | O_NONBLOCK));
Packit fc043f
          else
Packit fc043f
            ret = fcntl (fd_cookie->fd, F_SETFL, (ret & ~O_NONBLOCK));
Packit fc043f
#endif
Packit fc043f
        }
Packit fc043f
    }
Packit fc043f
  else
Packit fc043f
    {
Packit fc043f
      _set_errno (EINVAL);
Packit fc043f
      ret = -1;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  return ret;
Packit fc043f
}
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * The destroy function for fd objects.
Packit fc043f
 */
Packit fc043f
static int
Packit fc043f
func_fd_destroy (void *cookie)
Packit fc043f
{
Packit fc043f
  estream_cookie_fd_t fd_cookie = cookie;
Packit fc043f
  int err;
Packit fc043f
Packit fc043f
  trace (("enter: cookie=%p", cookie));
Packit fc043f
Packit fc043f
  if (fd_cookie)
Packit fc043f
    {
Packit fc043f
      if (IS_INVALID_FD (fd_cookie->fd))
Packit fc043f
        err = 0;
Packit fc043f
      else
Packit fc043f
        err = fd_cookie->no_close? 0 : close (fd_cookie->fd);
Packit fc043f
      mem_free (fd_cookie);
Packit fc043f
    }
Packit fc043f
  else
Packit fc043f
    err = 0;
Packit fc043f
Packit fc043f
  trace_errno (err,("leave: err=%d", err));
Packit fc043f
  return err;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * Access object for the fd functions.
Packit fc043f
 */
Packit fc043f
static struct cookie_io_functions_s estream_functions_fd =
Packit fc043f
  {
Packit fc043f
    {
Packit fc043f
      func_fd_read,
Packit fc043f
      func_fd_write,
Packit fc043f
      func_fd_seek,
Packit fc043f
      func_fd_destroy,
Packit fc043f
    },
Packit fc043f
    func_fd_ioctl,
Packit fc043f
  };
Packit fc043f
Packit fc043f
Packit fc043f
Packit fc043f

Packit fc043f
/*
Packit fc043f
 * Implementation of W32 handle based I/O.
Packit fc043f
 */
Packit fc043f
#ifdef HAVE_W32_SYSTEM
Packit fc043f
Packit fc043f
/* Cookie for fd objects.  */
Packit fc043f
typedef struct estream_cookie_w32
Packit fc043f
{
Packit fc043f
  HANDLE hd;     /* The handle we are using for actual output.  */
Packit fc043f
  int no_close;  /* If set we won't close the handle.  */
Packit fc043f
  int no_syscall_clamp; /* Do not use the syscall clamp. */
Packit fc043f
} *estream_cookie_w32_t;
Packit fc043f
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * Create function for w32 handle objects.
Packit fc043f
 */
Packit fc043f
static int
Packit fc043f
func_w32_create (void **cookie, HANDLE hd,
Packit fc043f
                 unsigned int modeflags, int no_close, int no_syscall_clamp)
Packit fc043f
{
Packit fc043f
  estream_cookie_w32_t w32_cookie;
Packit fc043f
  int err;
Packit fc043f
Packit fc043f
  trace (("enter: hd=%p mf=%x nc=%d nsc=%d",
Packit fc043f
          hd, modeflags, no_close, no_syscall_clamp));
Packit fc043f
  w32_cookie = mem_alloc (sizeof (*w32_cookie));
Packit fc043f
  if (!w32_cookie)
Packit fc043f
    err = -1;
Packit fc043f
  else
Packit fc043f
    {
Packit fc043f
      /* CR/LF translations are not supported when using the bare W32
Packit fc043f
         API.  If that is really required we need to implemented that
Packit fc043f
         in the upper layer.  */
Packit fc043f
      (void)modeflags;
Packit fc043f
Packit fc043f
      w32_cookie->hd = hd;
Packit fc043f
      w32_cookie->no_close = no_close;
Packit fc043f
      w32_cookie->no_syscall_clamp = no_syscall_clamp;
Packit fc043f
      *cookie = w32_cookie;
Packit fc043f
      err = 0;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  trace_errno (err, ("leave: cookie=%p err=%d", *cookie, err));
Packit fc043f
  return err;
Packit fc043f
}
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * Read function for W32 handle objects.
Packit fc043f
 *
Packit fc043f
 * Note that this function may also be used by the reader thread of
Packit fc043f
 * w32-stream.  In that case the NO_SYSCALL_CLAMP is set.
Packit fc043f
 */
Packit fc043f
static gpgrt_ssize_t
Packit fc043f
func_w32_read (void *cookie, void *buffer, size_t size)
Packit fc043f
{
Packit fc043f
  estream_cookie_w32_t w32_cookie = cookie;
Packit fc043f
  gpgrt_ssize_t bytes_read;
Packit fc043f
Packit fc043f
  trace (("enter: cookie=%p buffer=%p size=%d", cookie, buffer, (int)size));
Packit fc043f
Packit fc043f
  if (!size)
Packit fc043f
    bytes_read = -1; /* We don't know whether anything is pending.  */
Packit fc043f
  else if (w32_cookie->hd == INVALID_HANDLE_VALUE)
Packit fc043f
    {
Packit fc043f
      _gpgrt_yield ();
Packit fc043f
      bytes_read = 0;
Packit fc043f
    }
Packit fc043f
  else
Packit fc043f
    {
Packit fc043f
      if (!w32_cookie->no_syscall_clamp)
Packit fc043f
        _gpgrt_pre_syscall ();
Packit fc043f
      do
Packit fc043f
        {
Packit fc043f
          DWORD nread, ec;
Packit fc043f
Packit fc043f
          trace (("cookie=%p calling ReadFile", cookie));
Packit fc043f
          if (!ReadFile (w32_cookie->hd, buffer, size, &nread, NULL))
Packit fc043f
            {
Packit fc043f
              ec = GetLastError ();
Packit fc043f
              trace (("cookie=%p ReadFile failed: ec=%ld", cookie,ec));
Packit fc043f
              if (ec == ERROR_BROKEN_PIPE)
Packit fc043f
                bytes_read = 0; /* Like our pth_read we handle this as EOF.  */
Packit fc043f
              else
Packit fc043f
                {
Packit fc043f
                  _set_errno (map_w32_to_errno (ec));
Packit fc043f
                  bytes_read = -1;
Packit fc043f
                }
Packit fc043f
            }
Packit fc043f
          else
Packit fc043f
            bytes_read = (int)nread;
Packit fc043f
        }
Packit fc043f
      while (bytes_read == -1 && errno == EINTR);
Packit fc043f
      if (!w32_cookie->no_syscall_clamp)
Packit fc043f
        _gpgrt_post_syscall ();
Packit fc043f
    }
Packit fc043f
Packit fc043f
  trace_errno (bytes_read==-1,("leave: bytes_read=%d", (int)bytes_read));
Packit fc043f
  return bytes_read;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * Write function for W32 handle objects.
Packit fc043f
 *
Packit fc043f
 * Note that this function may also be used by the writer thread of
Packit fc043f
 * w32-stream.  In that case the NO_SYSCALL_CLAMP is set.
Packit fc043f
 */
Packit fc043f
static gpgrt_ssize_t
Packit fc043f
func_w32_write (void *cookie, const void *buffer, size_t size)
Packit fc043f
{
Packit fc043f
  estream_cookie_w32_t w32_cookie = cookie;
Packit fc043f
  gpgrt_ssize_t bytes_written;
Packit fc043f
Packit fc043f
  trace (("enter: cookie=%p buffer=%p size=%d", cookie, buffer, (int)size));
Packit fc043f
Packit fc043f
  if (w32_cookie->hd == INVALID_HANDLE_VALUE)
Packit fc043f
    {
Packit fc043f
      _gpgrt_yield ();
Packit fc043f
      bytes_written = size; /* Yeah:  Success writing to the bit bucket.  */
Packit fc043f
    }
Packit fc043f
  else if (buffer)
Packit fc043f
    {
Packit fc043f
      if (!w32_cookie->no_syscall_clamp)
Packit fc043f
        _gpgrt_pre_syscall ();
Packit fc043f
      do
Packit fc043f
        {
Packit fc043f
          DWORD nwritten;
Packit fc043f
Packit fc043f
          trace (("cookie=%p calling WriteFile", cookie));
Packit fc043f
	  if (!WriteFile (w32_cookie->hd, buffer, size, &nwritten, NULL))
Packit fc043f
	    {
Packit fc043f
              DWORD ec = GetLastError ();
Packit fc043f
              trace (("cookie=%p WriteFile failed: ec=%ld", cookie, ec));
Packit fc043f
	      _set_errno (map_w32_to_errno (ec));
Packit fc043f
	      bytes_written = -1;
Packit fc043f
	    }
Packit fc043f
	  else
Packit fc043f
	    bytes_written = (int)nwritten;
Packit fc043f
        }
Packit fc043f
      while (bytes_written == -1 && errno == EINTR);
Packit fc043f
      if (!w32_cookie->no_syscall_clamp)
Packit fc043f
        _gpgrt_post_syscall ();
Packit fc043f
    }
Packit fc043f
  else
Packit fc043f
    bytes_written = size; /* Note that for a flush SIZE should be 0.  */
Packit fc043f
Packit fc043f
  trace_errno (bytes_written==-1,
Packit fc043f
               ("leave: bytes_written=%d", (int)bytes_written));
Packit fc043f
  return bytes_written;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * Seek function for W32 handle objects.
Packit fc043f
 */
Packit fc043f
static int
Packit fc043f
func_w32_seek (void *cookie, gpgrt_off_t *offset, int whence)
Packit fc043f
{
Packit fc043f
  estream_cookie_w32_t w32_cookie = cookie;
Packit fc043f
  DWORD method;
Packit fc043f
  LARGE_INTEGER distance, newoff;
Packit fc043f
Packit fc043f
  if (w32_cookie->hd == INVALID_HANDLE_VALUE)
Packit fc043f
    {
Packit fc043f
      _set_errno (ESPIPE);
Packit fc043f
      return -1;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  if (whence == SEEK_SET)
Packit fc043f
    {
Packit fc043f
      method = FILE_BEGIN;
Packit fc043f
      distance.QuadPart = (unsigned long long)(*offset);
Packit fc043f
    }
Packit fc043f
  else if (whence == SEEK_CUR)
Packit fc043f
    {
Packit fc043f
      method = FILE_CURRENT;
Packit fc043f
      distance.QuadPart = (long long)(*offset);
Packit fc043f
    }
Packit fc043f
  else if (whence == SEEK_END)
Packit fc043f
    {
Packit fc043f
      method = FILE_END;
Packit fc043f
      distance.QuadPart = (long long)(*offset);
Packit fc043f
    }
Packit fc043f
  else
Packit fc043f
    {
Packit fc043f
      _set_errno (EINVAL);
Packit fc043f
      return -1;
Packit fc043f
    }
Packit fc043f
#ifdef HAVE_W32CE_SYSTEM
Packit fc043f
# warning need to use SetFilePointer
Packit fc043f
#else
Packit fc043f
  if (!w32_cookie->no_syscall_clamp)
Packit fc043f
    _gpgrt_pre_syscall ();
Packit fc043f
  if (!SetFilePointerEx (w32_cookie->hd, distance, &newoff, method))
Packit fc043f
    {
Packit fc043f
      _set_errno (map_w32_to_errno (GetLastError ()));
Packit fc043f
      _gpgrt_post_syscall ();
Packit fc043f
      return -1;
Packit fc043f
    }
Packit fc043f
  if (!w32_cookie->no_syscall_clamp)
Packit fc043f
    _gpgrt_post_syscall ();
Packit fc043f
#endif
Packit fc043f
  /* Note that gpgrt_off_t is always 64 bit.  */
Packit fc043f
  *offset = (gpgrt_off_t)newoff.QuadPart;
Packit fc043f
  return 0;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * Destroy function for W32 handle objects.
Packit fc043f
 */
Packit fc043f
static int
Packit fc043f
func_w32_destroy (void *cookie)
Packit fc043f
{
Packit fc043f
  estream_cookie_w32_t w32_cookie = cookie;
Packit fc043f
  int err;
Packit fc043f
Packit fc043f
  trace (("enter: cookie=%p", cookie));
Packit fc043f
Packit fc043f
  if (w32_cookie)
Packit fc043f
    {
Packit fc043f
      if (w32_cookie->hd == INVALID_HANDLE_VALUE)
Packit fc043f
        err = 0;
Packit fc043f
      else if (w32_cookie->no_close)
Packit fc043f
        err = 0;
Packit fc043f
      else
Packit fc043f
        {
Packit fc043f
          trace (("cookie=%p closing handle %p", cookie, w32_cookie->hd));
Packit fc043f
          if (!CloseHandle (w32_cookie->hd))
Packit fc043f
            {
Packit fc043f
              DWORD ec = GetLastError ();
Packit fc043f
              trace (("cookie=%p CloseHandle failed: ec=%ld", cookie,ec));
Packit fc043f
	      _set_errno (map_w32_to_errno (ec));
Packit fc043f
              err = -1;
Packit fc043f
            }
Packit fc043f
          else
Packit fc043f
            err = 0;
Packit fc043f
        }
Packit fc043f
      mem_free (w32_cookie);
Packit fc043f
    }
Packit fc043f
  else
Packit fc043f
    err = 0;
Packit fc043f
Packit fc043f
  trace_errno (err, ("leave: err=%d", err));
Packit fc043f
  return err;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * Access object for the W32 handle based objects.
Packit fc043f
 */
Packit fc043f
static struct cookie_io_functions_s estream_functions_w32 =
Packit fc043f
  {
Packit fc043f
    {
Packit fc043f
      func_w32_read,
Packit fc043f
      func_w32_write,
Packit fc043f
      func_w32_seek,
Packit fc043f
      func_w32_destroy,
Packit fc043f
    },
Packit fc043f
    NULL,
Packit fc043f
  };
Packit fc043f
#endif /*HAVE_W32_SYSTEM*/
Packit fc043f
Packit fc043f
Packit fc043f
Packit fc043f

Packit fc043f
/*
Packit fc043f
 * Implementation of stdio based I/O.
Packit fc043f
 */
Packit fc043f
Packit fc043f
/* Cookie for fp objects.  */
Packit fc043f
typedef struct estream_cookie_fp
Packit fc043f
{
Packit fc043f
  FILE *fp;      /* The file pointer we are using for actual output.  */
Packit fc043f
  int no_close;  /* If set we won't close the file pointer.  */
Packit fc043f
} *estream_cookie_fp_t;
Packit fc043f
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * Create function for stdio based objects.
Packit fc043f
 */
Packit fc043f
static int
Packit fc043f
func_fp_create (void **cookie, FILE *fp,
Packit fc043f
                unsigned int modeflags, int no_close)
Packit fc043f
{
Packit fc043f
  estream_cookie_fp_t fp_cookie;
Packit fc043f
  int err;
Packit fc043f
Packit fc043f
  fp_cookie = mem_alloc (sizeof *fp_cookie);
Packit fc043f
  if (!fp_cookie)
Packit fc043f
    err = -1;
Packit fc043f
  else
Packit fc043f
    {
Packit fc043f
#ifdef HAVE_DOSISH_SYSTEM
Packit fc043f
      /* Make sure it is in binary mode if requested.  */
Packit fc043f
      if ( (modeflags & O_BINARY) )
Packit fc043f
        setmode (fileno (fp), O_BINARY);
Packit fc043f
#else
Packit fc043f
      (void)modeflags;
Packit fc043f
#endif
Packit fc043f
      fp_cookie->fp = fp;
Packit fc043f
      fp_cookie->no_close = no_close;
Packit fc043f
      *cookie = fp_cookie;
Packit fc043f
      err = 0;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  return err;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * Read function for stdio based objects.
Packit fc043f
 */
Packit fc043f
static gpgrt_ssize_t
Packit fc043f
func_fp_read (void *cookie, void *buffer, size_t size)
Packit fc043f
Packit fc043f
{
Packit fc043f
  estream_cookie_fp_t file_cookie = cookie;
Packit fc043f
  gpgrt_ssize_t bytes_read;
Packit fc043f
Packit fc043f
  if (!size)
Packit fc043f
    return -1; /* We don't know whether anything is pending.  */
Packit fc043f
Packit fc043f
  if (file_cookie->fp)
Packit fc043f
    {
Packit fc043f
      _gpgrt_pre_syscall ();
Packit fc043f
      bytes_read = fread (buffer, 1, size, file_cookie->fp);
Packit fc043f
      _gpgrt_post_syscall ();
Packit fc043f
    }
Packit fc043f
  else
Packit fc043f
    bytes_read = 0;
Packit fc043f
  if (!bytes_read && ferror (file_cookie->fp))
Packit fc043f
    return -1;
Packit fc043f
  return bytes_read;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * Write function for stdio bases objects.
Packit fc043f
 */
Packit fc043f
static gpgrt_ssize_t
Packit fc043f
func_fp_write (void *cookie, const void *buffer, size_t size)
Packit fc043f
{
Packit fc043f
  estream_cookie_fp_t file_cookie = cookie;
Packit fc043f
  size_t bytes_written;
Packit fc043f
Packit fc043f
  if (file_cookie->fp)
Packit fc043f
    {
Packit fc043f
      _gpgrt_pre_syscall ();
Packit fc043f
      if (buffer)
Packit fc043f
        {
Packit fc043f
#ifdef HAVE_W32_SYSTEM
Packit fc043f
          /* Using an fwrite to stdout connected to the console fails
Packit fc043f
             with the error "Not enough space" for an fwrite size of
Packit fc043f
             >= 52KB (tested on Windows XP SP2).  To solve this we
Packit fc043f
             always chunk the writes up into smaller blocks.  */
Packit fc043f
          bytes_written = 0;
Packit fc043f
          while (bytes_written < size)
Packit fc043f
            {
Packit fc043f
              size_t cnt = size - bytes_written;
Packit fc043f
Packit fc043f
              if (cnt > 32*1024)
Packit fc043f
                cnt = 32*1024;
Packit fc043f
              if (fwrite ((const char*)buffer + bytes_written,
Packit fc043f
                          cnt, 1, file_cookie->fp) != 1)
Packit fc043f
                break; /* Write error.  */
Packit fc043f
              bytes_written += cnt;
Packit fc043f
            }
Packit fc043f
#else
Packit fc043f
          bytes_written = fwrite (buffer, 1, size, file_cookie->fp);
Packit fc043f
#endif
Packit fc043f
        }
Packit fc043f
      else /* Only flush requested.  */
Packit fc043f
        bytes_written = size;
Packit fc043f
Packit fc043f
      fflush (file_cookie->fp);
Packit fc043f
      _gpgrt_post_syscall ();
Packit fc043f
    }
Packit fc043f
  else
Packit fc043f
    bytes_written = size; /* Successfully written to the bit bucket.  */
Packit fc043f
Packit fc043f
  if (bytes_written != size)
Packit fc043f
    return -1;
Packit fc043f
  return bytes_written;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * Seek function for stdio based objects.
Packit fc043f
 */
Packit fc043f
static int
Packit fc043f
func_fp_seek (void *cookie, gpgrt_off_t *offset, int whence)
Packit fc043f
{
Packit fc043f
  estream_cookie_fp_t file_cookie = cookie;
Packit fc043f
  long int offset_new;
Packit fc043f
Packit fc043f
  if (!file_cookie->fp)
Packit fc043f
    {
Packit fc043f
      _set_errno (ESPIPE);
Packit fc043f
      return -1;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  _gpgrt_pre_syscall ();
Packit fc043f
  if ( fseek (file_cookie->fp, (long int)*offset, whence) )
Packit fc043f
    {
Packit fc043f
      /* fprintf (stderr, "\nfseek failed: errno=%d (%s)\n", */
Packit fc043f
      /*          errno,strerror (errno)); */
Packit fc043f
      _gpgrt_post_syscall ();
Packit fc043f
      return -1;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  offset_new = ftell (file_cookie->fp);
Packit fc043f
  _gpgrt_post_syscall ();
Packit fc043f
  if (offset_new == -1)
Packit fc043f
    {
Packit fc043f
      /* fprintf (stderr, "\nftell failed: errno=%d (%s)\n",  */
Packit fc043f
      /*          errno,strerror (errno)); */
Packit fc043f
      return -1;
Packit fc043f
    }
Packit fc043f
  *offset = offset_new;
Packit fc043f
  return 0;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * Destroy function for stdio based objects.
Packit fc043f
 */
Packit fc043f
static int
Packit fc043f
func_fp_destroy (void *cookie)
Packit fc043f
{
Packit fc043f
  estream_cookie_fp_t fp_cookie = cookie;
Packit fc043f
  int err;
Packit fc043f
Packit fc043f
  if (fp_cookie)
Packit fc043f
    {
Packit fc043f
      if (fp_cookie->fp)
Packit fc043f
        {
Packit fc043f
          _gpgrt_pre_syscall ();
Packit fc043f
          fflush (fp_cookie->fp);
Packit fc043f
          _gpgrt_post_syscall ();
Packit fc043f
          err = fp_cookie->no_close? 0 : fclose (fp_cookie->fp);
Packit fc043f
        }
Packit fc043f
      else
Packit fc043f
        err = 0;
Packit fc043f
      mem_free (fp_cookie);
Packit fc043f
    }
Packit fc043f
  else
Packit fc043f
    err = 0;
Packit fc043f
Packit fc043f
  return err;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * Access object for stdio based objects.
Packit fc043f
 */
Packit fc043f
static struct cookie_io_functions_s estream_functions_fp =
Packit fc043f
  {
Packit fc043f
    {
Packit fc043f
      func_fp_read,
Packit fc043f
      func_fp_write,
Packit fc043f
      func_fp_seek,
Packit fc043f
      func_fp_destroy,
Packit fc043f
    },
Packit fc043f
    NULL,
Packit fc043f
  };
Packit fc043f
Packit fc043f
Packit fc043f
Packit fc043f

Packit fc043f
/*
Packit fc043f
 * Implementation of file name based I/O.
Packit fc043f
 *
Packit fc043f
 * Note that only a create function is required because the other
Packit fc043f
 * operations ares handled by file descriptor based I/O.
Packit fc043f
 */
Packit fc043f
Packit fc043f
/* Create function for objects identified by a file name.  */
Packit fc043f
static int
Packit fc043f
func_file_create (void **cookie, int *filedes,
Packit fc043f
                  const char *path, unsigned int modeflags, unsigned int cmode)
Packit fc043f
{
Packit fc043f
  estream_cookie_fd_t file_cookie;
Packit fc043f
  int err;
Packit fc043f
  int fd;
Packit fc043f
Packit fc043f
  err = 0;
Packit fc043f
Packit fc043f
  file_cookie = mem_alloc (sizeof (*file_cookie));
Packit fc043f
  if (! file_cookie)
Packit fc043f
    {
Packit fc043f
      err = -1;
Packit fc043f
      goto out;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  fd = open (path, modeflags, cmode);
Packit fc043f
  if (fd == -1)
Packit fc043f
    {
Packit fc043f
      err = -1;
Packit fc043f
      goto out;
Packit fc043f
    }
Packit fc043f
#ifdef HAVE_DOSISH_SYSTEM
Packit fc043f
  /* Make sure it is in binary mode if requested.  */
Packit fc043f
  if ( (modeflags & O_BINARY) )
Packit fc043f
    setmode (fd, O_BINARY);
Packit fc043f
#endif
Packit fc043f
Packit fc043f
  file_cookie->fd = fd;
Packit fc043f
  file_cookie->no_close = 0;
Packit fc043f
  *cookie = file_cookie;
Packit fc043f
  *filedes = fd;
Packit fc043f
Packit fc043f
 out:
Packit fc043f
Packit fc043f
  if (err)
Packit fc043f
    mem_free (file_cookie);
Packit fc043f
Packit fc043f
  return err;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f

Packit fc043f
/* Flags used by parse_mode and friends.  */
Packit fc043f
#define X_SAMETHREAD	(1 << 0)
Packit fc043f
#define X_SYSOPEN	(1 << 1)
Packit fc043f
#define X_POLLABLE	(1 << 2)
Packit fc043f
Packit fc043f
/* Parse the mode flags of fopen et al.  In addition to the POSIX
Packit fc043f
 * defined mode flags keyword parameters are supported.  These are
Packit fc043f
 * key/value pairs delimited by comma and optional white spaces.
Packit fc043f
 * Keywords and values may not contain a comma or white space; unknown
Packit fc043f
 * keywords are skipped. Supported keywords are:
Packit fc043f
 *
Packit fc043f
 * mode=<string>
Packit fc043f
 *
Packit fc043f
 *    Creates a file and gives the new file read and write permissions
Packit fc043f
 *    for the user and read permission for the group.  The format of
Packit fc043f
 *    the string is the same as shown by the -l option of the ls(1)
Packit fc043f
 *    command.  However the first letter must be a dash and it is
Packit fc043f
 *    allowed to leave out trailing dashes.  If this keyword parameter
Packit fc043f
 *    is not given the default mode for creating files is "-rw-rw-r--"
Packit fc043f
 *    (664).  Note that the system still applies the current umask to
Packit fc043f
 *    the mode when creating a file.  Example:
Packit fc043f
 *
Packit fc043f
 *       "wb,mode=-rw-r--"
Packit fc043f
 *
Packit fc043f
 * samethread
Packit fc043f
 *
Packit fc043f
 *    Assumes that the object is only used by the creating thread and
Packit fc043f
 *    disables any internal locking.  This keyword is also found on
Packit fc043f
 *    IBM systems.
Packit fc043f
 *
Packit fc043f
 * nonblock
Packit fc043f
 *
Packit fc043f
 *    The object is opened in non-blocking mode.  This is the same as
Packit fc043f
 *    calling gpgrt_set_nonblock on the file.
Packit fc043f
 *
Packit fc043f
 * sysopen
Packit fc043f
 *
Packit fc043f
 *    The object is opened in sysmode.  On POSIX this is a NOP but
Packit fc043f
 *    under Windows the direct W32 API functions (HANDLE) are used
Packit fc043f
 *    instead of their libc counterparts (fd).
Packit fc043f
 *    FIXME: The functionality is not yet implemented.
Packit fc043f
 *
Packit fc043f
 * pollable
Packit fc043f
 *
Packit fc043f
 *    The object is opened in a way suitable for use with es_poll.  On
Packit fc043f
 *    POSIX this is a NOP but under Windows we create up to two
Packit fc043f
 *    threads, one for reading and one for writing, do any I/O there,
Packit fc043f
 *    and synchronize with them in order to support es_poll.
Packit fc043f
 *
Packit fc043f
 * Note: R_CMODE is optional because is only required by functions
Packit fc043f
 * which are able to creat a file.
Packit fc043f
 */
Packit fc043f
static int
Packit fc043f
parse_mode (const char *modestr,
Packit fc043f
            unsigned int *modeflags,
Packit fc043f
            unsigned int *r_xmode,
Packit fc043f
            unsigned int *r_cmode)
Packit fc043f
{
Packit fc043f
  unsigned int omode, oflags, cmode;
Packit fc043f
  int got_cmode = 0;
Packit fc043f
Packit fc043f
  *r_xmode = 0;
Packit fc043f
Packit fc043f
  switch (*modestr)
Packit fc043f
    {
Packit fc043f
    case 'r':
Packit fc043f
      omode = O_RDONLY;
Packit fc043f
      oflags = 0;
Packit fc043f
      break;
Packit fc043f
    case 'w':
Packit fc043f
      omode = O_WRONLY;
Packit fc043f
      oflags = O_TRUNC | O_CREAT;
Packit fc043f
      break;
Packit fc043f
    case 'a':
Packit fc043f
      omode = O_WRONLY;
Packit fc043f
      oflags = O_APPEND | O_CREAT;
Packit fc043f
      break;
Packit fc043f
    default:
Packit fc043f
      _set_errno (EINVAL);
Packit fc043f
      return -1;
Packit fc043f
    }
Packit fc043f
  for (modestr++; *modestr; modestr++)
Packit fc043f
    {
Packit fc043f
      switch (*modestr)
Packit fc043f
        {
Packit fc043f
        case '+':
Packit fc043f
          omode = O_RDWR;
Packit fc043f
          break;
Packit fc043f
        case 'b':
Packit fc043f
          oflags |= O_BINARY;
Packit fc043f
          break;
Packit fc043f
        case 'x':
Packit fc043f
          oflags |= O_EXCL;
Packit fc043f
          break;
Packit fc043f
        case ',':
Packit fc043f
          goto keyvalue;
Packit fc043f
        default: /* Ignore unknown flags.  */
Packit fc043f
          break;
Packit fc043f
        }
Packit fc043f
    }
Packit fc043f
Packit fc043f
 keyvalue:
Packit fc043f
  /* Parse key/value pairs (similar to fopen on mainframes).  */
Packit fc043f
  for (cmode=0; *modestr == ','; modestr += strcspn (modestr, ","))
Packit fc043f
    {
Packit fc043f
      modestr++;
Packit fc043f
      modestr += strspn (modestr, " \t");
Packit fc043f
      if (!strncmp (modestr, "mode=", 5))
Packit fc043f
        {
Packit fc043f
          static struct {
Packit fc043f
            char letter;
Packit fc043f
            unsigned int value;
Packit fc043f
          } table[] = { { '-', 0 },
Packit fc043f
                        { 'r', S_IRUSR }, { 'w', S_IWUSR }, { 'x', S_IXUSR },
Packit fc043f
                        { 'r', S_IRGRP }, { 'w', S_IWGRP }, { 'x', S_IXGRP },
Packit fc043f
                        { 'r', S_IROTH }, { 'w', S_IWOTH }, { 'x', S_IXOTH }};
Packit fc043f
          int idx;
Packit fc043f
Packit fc043f
          got_cmode = 1;
Packit fc043f
          modestr += 5;
Packit fc043f
          /* For now we only support a string as used by ls(1) and no
Packit fc043f
             octal numbers.  The first character must be a dash.  */
Packit fc043f
          for (idx=0; idx < 10 && *modestr; idx++, modestr++)
Packit fc043f
            {
Packit fc043f
              if (*modestr == table[idx].letter)
Packit fc043f
                cmode |= table[idx].value;
Packit fc043f
              else if (*modestr != '-')
Packit fc043f
                break;
Packit fc043f
            }
Packit fc043f
          if (*modestr && !strchr (" \t,", *modestr))
Packit fc043f
            {
Packit fc043f
              _set_errno (EINVAL);
Packit fc043f
              return -1;
Packit fc043f
            }
Packit fc043f
        }
Packit fc043f
      else if (!strncmp (modestr, "samethread", 10))
Packit fc043f
        {
Packit fc043f
          modestr += 10;
Packit fc043f
          if (*modestr && !strchr (" \t,", *modestr))
Packit fc043f
            {
Packit fc043f
              _set_errno (EINVAL);
Packit fc043f
              return -1;
Packit fc043f
            }
Packit fc043f
          *r_xmode |= X_SAMETHREAD;
Packit fc043f
        }
Packit fc043f
      else if (!strncmp (modestr, "nonblock", 8))
Packit fc043f
        {
Packit fc043f
          modestr += 8;
Packit fc043f
          if (*modestr && !strchr (" \t,", *modestr))
Packit fc043f
            {
Packit fc043f
              _set_errno (EINVAL);
Packit fc043f
              return -1;
Packit fc043f
            }
Packit fc043f
          oflags |= O_NONBLOCK;
Packit fc043f
#if HAVE_W32_SYSTEM
Packit fc043f
          /* Currently, nonblock implies pollable on Windows.  */
Packit fc043f
          *r_xmode |= X_POLLABLE;
Packit fc043f
#endif
Packit fc043f
        }
Packit fc043f
      else if (!strncmp (modestr, "sysopen", 7))
Packit fc043f
        {
Packit fc043f
          modestr += 7;
Packit fc043f
          if (*modestr && !strchr (" \t,", *modestr))
Packit fc043f
            {
Packit fc043f
              _set_errno (EINVAL);
Packit fc043f
              return -1;
Packit fc043f
            }
Packit fc043f
          *r_xmode |= X_SYSOPEN;
Packit fc043f
        }
Packit fc043f
      else if (!strncmp (modestr, "pollable", 8))
Packit fc043f
        {
Packit fc043f
          modestr += 8;
Packit fc043f
          if (*modestr && !strchr (" \t,", *modestr))
Packit fc043f
            {
Packit fc043f
              _set_errno (EINVAL);
Packit fc043f
              return -1;
Packit fc043f
            }
Packit fc043f
          *r_xmode |= X_POLLABLE;
Packit fc043f
        }
Packit fc043f
    }
Packit fc043f
  if (!got_cmode)
Packit fc043f
    cmode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
Packit fc043f
Packit fc043f
  *modeflags = (omode | oflags);
Packit fc043f
  if (r_cmode)
Packit fc043f
    *r_cmode = cmode;
Packit fc043f
  return 0;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f

Packit fc043f
/*
Packit fc043f
 * Low level stream functionality.
Packit fc043f
 */
Packit fc043f
Packit fc043f
static int
Packit fc043f
fill_stream (estream_t stream)
Packit fc043f
{
Packit fc043f
  size_t bytes_read = 0;
Packit fc043f
  int err;
Packit fc043f
Packit fc043f
  if (!stream->intern->func_read)
Packit fc043f
    {
Packit fc043f
      _set_errno (EOPNOTSUPP);
Packit fc043f
      err = -1;
Packit fc043f
    }
Packit fc043f
  else if (!stream->buffer_size)
Packit fc043f
    err = 0;
Packit fc043f
  else
Packit fc043f
    {
Packit fc043f
      gpgrt_cookie_read_function_t func_read = stream->intern->func_read;
Packit fc043f
      gpgrt_ssize_t ret;
Packit fc043f
Packit fc043f
      ret = (*func_read) (stream->intern->cookie,
Packit fc043f
			  stream->buffer, stream->buffer_size);
Packit fc043f
      if (ret == -1)
Packit fc043f
	{
Packit fc043f
	  bytes_read = 0;
Packit fc043f
	  err = -1;
Packit fc043f
#if EWOULDBLOCK != EAGAIN
Packit fc043f
          if (errno == EWOULDBLOCK)
Packit fc043f
            _set_errno (EAGAIN);
Packit fc043f
#endif
Packit fc043f
	}
Packit fc043f
      else
Packit fc043f
	{
Packit fc043f
	  bytes_read = ret;
Packit fc043f
	  err = 0;
Packit fc043f
	}
Packit fc043f
    }
Packit fc043f
Packit fc043f
  if (err)
Packit fc043f
    {
Packit fc043f
      if (errno != EAGAIN)
Packit fc043f
        {
Packit fc043f
          if (errno == EPIPE)
Packit fc043f
            stream->intern->indicators.hup = 1;
Packit fc043f
          stream->intern->indicators.err = 1;
Packit fc043f
        }
Packit fc043f
    }
Packit fc043f
  else if (!bytes_read)
Packit fc043f
    stream->intern->indicators.eof = 1;
Packit fc043f
Packit fc043f
  stream->intern->offset += stream->data_len;
Packit fc043f
  stream->data_len = bytes_read;
Packit fc043f
  stream->data_offset = 0;
Packit fc043f
Packit fc043f
  return err;
Packit fc043f
}
Packit fc043f
Packit fc043f
static int
Packit fc043f
flush_stream (estream_t stream)
Packit fc043f
{
Packit fc043f
  gpgrt_cookie_write_function_t func_write = stream->intern->func_write;
Packit fc043f
  int err;
Packit fc043f
Packit fc043f
  assert (stream->flags.writing);
Packit fc043f
Packit fc043f
  if (stream->data_offset)
Packit fc043f
    {
Packit fc043f
      size_t bytes_written;
Packit fc043f
      size_t data_flushed;
Packit fc043f
      gpgrt_ssize_t ret;
Packit fc043f
Packit fc043f
      if (! func_write)
Packit fc043f
	{
Packit fc043f
          _set_errno (EOPNOTSUPP);
Packit fc043f
          err = -1;
Packit fc043f
	  goto out;
Packit fc043f
	}
Packit fc043f
Packit fc043f
      /* Note: to prevent an endless loop caused by user-provided
Packit fc043f
	 write-functions that pretend to have written more bytes than
Packit fc043f
	 they were asked to write, we have to check for
Packit fc043f
	 "(stream->data_offset - data_flushed) > 0" instead of
Packit fc043f
	 "stream->data_offset - data_flushed".  */
Packit fc043f
Packit fc043f
      data_flushed = 0;
Packit fc043f
      err = 0;
Packit fc043f
Packit fc043f
      while ((((gpgrt_ssize_t) (stream->data_offset - data_flushed)) > 0)
Packit fc043f
             && !err)
Packit fc043f
	{
Packit fc043f
	  ret = (*func_write) (stream->intern->cookie,
Packit fc043f
			       stream->buffer + data_flushed,
Packit fc043f
			       stream->data_offset - data_flushed);
Packit fc043f
	  if (ret == -1)
Packit fc043f
	    {
Packit fc043f
	      bytes_written = 0;
Packit fc043f
	      err = -1;
Packit fc043f
#if EWOULDBLOCK != EAGAIN
Packit fc043f
              if (errno == EWOULDBLOCK)
Packit fc043f
                _set_errno (EAGAIN);
Packit fc043f
#endif
Packit fc043f
	    }
Packit fc043f
	  else
Packit fc043f
	    bytes_written = ret;
Packit fc043f
Packit fc043f
	  data_flushed += bytes_written;
Packit fc043f
	  if (err)
Packit fc043f
	    break;
Packit fc043f
	}
Packit fc043f
Packit fc043f
      stream->data_flushed += data_flushed;
Packit fc043f
      if (stream->data_offset == data_flushed)
Packit fc043f
	{
Packit fc043f
	  stream->intern->offset += stream->data_offset;
Packit fc043f
	  stream->data_offset = 0;
Packit fc043f
	  stream->data_flushed = 0;
Packit fc043f
Packit fc043f
	  /* Propagate flush event.  */
Packit fc043f
	  (*func_write) (stream->intern->cookie, NULL, 0);
Packit fc043f
	}
Packit fc043f
    }
Packit fc043f
  else
Packit fc043f
    err = 0;
Packit fc043f
Packit fc043f
 out:
Packit fc043f
Packit fc043f
  if (err && errno != EAGAIN)
Packit fc043f
    {
Packit fc043f
      if (errno == EPIPE)
Packit fc043f
        stream->intern->indicators.hup = 1;
Packit fc043f
      stream->intern->indicators.err = 1;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  return err;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * Discard buffered data for STREAM.
Packit fc043f
 */
Packit fc043f
static void
Packit fc043f
es_empty (estream_t stream)
Packit fc043f
{
Packit fc043f
  assert (!stream->flags.writing);
Packit fc043f
  stream->data_len = 0;
Packit fc043f
  stream->data_offset = 0;
Packit fc043f
  stream->unread_data_len = 0;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * Initialize STREAM.
Packit fc043f
 */
Packit fc043f
static void
Packit fc043f
init_stream_obj (estream_t stream,
Packit fc043f
                 void *cookie, es_syshd_t *syshd,
Packit fc043f
                 gpgrt_stream_backend_kind_t kind,
Packit fc043f
                 struct cookie_io_functions_s functions,
Packit fc043f
                 unsigned int modeflags, unsigned int xmode)
Packit fc043f
{
Packit fc043f
  stream->intern->kind = kind;
Packit fc043f
  stream->intern->cookie = cookie;
Packit fc043f
  stream->intern->opaque = NULL;
Packit fc043f
  stream->intern->offset = 0;
Packit fc043f
  stream->intern->func_read = functions.public.func_read;
Packit fc043f
  stream->intern->func_write = functions.public.func_write;
Packit fc043f
  stream->intern->func_seek = functions.public.func_seek;
Packit fc043f
  stream->intern->func_ioctl = functions.func_ioctl;
Packit fc043f
  stream->intern->func_close = functions.public.func_close;
Packit fc043f
  stream->intern->strategy = _IOFBF;
Packit fc043f
  stream->intern->syshd = *syshd;
Packit fc043f
  stream->intern->print_ntotal = 0;
Packit fc043f
  stream->intern->indicators.err = 0;
Packit fc043f
  stream->intern->indicators.eof = 0;
Packit fc043f
  stream->intern->indicators.hup = 0;
Packit fc043f
  stream->intern->is_stdstream = 0;
Packit fc043f
  stream->intern->stdstream_fd = 0;
Packit fc043f
  stream->intern->deallocate_buffer = 0;
Packit fc043f
  stream->intern->printable_fname = NULL;
Packit fc043f
  stream->intern->printable_fname_inuse = 0;
Packit fc043f
  stream->intern->samethread = !! (xmode & X_SAMETHREAD);
Packit fc043f
  stream->intern->onclose = NULL;
Packit fc043f
Packit fc043f
  stream->data_len = 0;
Packit fc043f
  stream->data_offset = 0;
Packit fc043f
  stream->data_flushed = 0;
Packit fc043f
  stream->unread_data_len = 0;
Packit fc043f
  /* Depending on the modeflags we set whether we start in writing or
Packit fc043f
     reading mode.  This is required in case we are working on a
Packit fc043f
     stream which is not seeekable (like stdout).  Without this
Packit fc043f
     pre-initialization we would do a seek at the first write call and
Packit fc043f
     as this will fail no output will be delivered. */
Packit fc043f
  if ((modeflags & O_WRONLY) || (modeflags & O_RDWR) )
Packit fc043f
    stream->flags.writing = 1;
Packit fc043f
  else
Packit fc043f
    stream->flags.writing = 0;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * Deinitialize the STREAM object.  This does _not_ free the memory,
Packit fc043f
 * destroys the lock, or closes the underlying descriptor.
Packit fc043f
 */
Packit fc043f
static int
Packit fc043f
deinit_stream_obj (estream_t stream)
Packit fc043f
{
Packit fc043f
  gpgrt_cookie_close_function_t func_close;
Packit fc043f
  int err, tmp_err;
Packit fc043f
Packit fc043f
  trace (("enter: stream %p", stream));
Packit fc043f
  func_close = stream->intern->func_close;
Packit fc043f
Packit fc043f
  err = 0;
Packit fc043f
  if (stream->flags.writing)
Packit fc043f
    {
Packit fc043f
      tmp_err = flush_stream (stream);
Packit fc043f
      if (!err)
Packit fc043f
        err = tmp_err;
Packit fc043f
    }
Packit fc043f
  if (func_close)
Packit fc043f
    {
Packit fc043f
      trace (("stream %p calling func_close", stream));
Packit fc043f
      tmp_err = func_close (stream->intern->cookie);
Packit fc043f
      if (!err)
Packit fc043f
        err = tmp_err;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  mem_free (stream->intern->printable_fname);
Packit fc043f
  stream->intern->printable_fname = NULL;
Packit fc043f
  stream->intern->printable_fname_inuse = 0;
Packit fc043f
  while (stream->intern->onclose)
Packit fc043f
    {
Packit fc043f
      notify_list_t tmp = stream->intern->onclose->next;
Packit fc043f
      mem_free (stream->intern->onclose);
Packit fc043f
      stream->intern->onclose = tmp;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  trace_errno (err, ("leave: stream %p err=%d", stream, err));
Packit fc043f
  return err;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * Create a new stream and initialize it.  On success the new stream
Packit fc043f
 * handle is tsored at R_STREAM.  On failure NULL is stored at
Packit fc043f
 * R_STREAM.
Packit fc043f
 */
Packit fc043f
static int
Packit fc043f
create_stream (estream_t *r_stream, void *cookie, es_syshd_t *syshd,
Packit fc043f
               gpgrt_stream_backend_kind_t kind,
Packit fc043f
               struct cookie_io_functions_s functions, unsigned int modeflags,
Packit fc043f
               unsigned int xmode, int with_locked_list)
Packit fc043f
{
Packit fc043f
  estream_internal_t stream_internal_new;
Packit fc043f
  estream_t stream_new;
Packit fc043f
  int err;
Packit fc043f
#if HAVE_W32_SYSTEM
Packit fc043f
  void *old_cookie = NULL;
Packit fc043f
#endif
Packit fc043f
Packit fc043f
  stream_new = NULL;
Packit fc043f
  stream_internal_new = NULL;
Packit fc043f
Packit fc043f
#if HAVE_W32_SYSTEM
Packit fc043f
  if ((xmode & X_POLLABLE) && kind != BACKEND_W32)
Packit fc043f
    {
Packit fc043f
      /* We require the W32 backend, because only that allows us to
Packit fc043f
       * write directly using the native W32 API and to disable the
Packit fc043f
       * system clamp.  Note that func_w32_create has already been
Packit fc043f
       * called with the flag to disable the system call clamp.  */
Packit fc043f
      _set_errno (EINVAL);
Packit fc043f
      err = -1;
Packit fc043f
      goto out;
Packit fc043f
    }
Packit fc043f
#endif /*HAVE_W32_SYSTEM*/
Packit fc043f
Packit fc043f
  stream_new = mem_alloc (sizeof (*stream_new));
Packit fc043f
  if (! stream_new)
Packit fc043f
    {
Packit fc043f
      err = -1;
Packit fc043f
      goto out;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  stream_internal_new = mem_alloc (sizeof (*stream_internal_new));
Packit fc043f
  if (! stream_internal_new)
Packit fc043f
    {
Packit fc043f
      err = -1;
Packit fc043f
      goto out;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  stream_new->buffer = stream_internal_new->buffer;
Packit fc043f
  stream_new->buffer_size = sizeof (stream_internal_new->buffer);
Packit fc043f
  stream_new->unread_buffer = stream_internal_new->unread_buffer;
Packit fc043f
  stream_new->unread_buffer_size = sizeof (stream_internal_new->unread_buffer);
Packit fc043f
  stream_new->intern = stream_internal_new;
Packit fc043f
Packit fc043f
#if HAVE_W32_SYSTEM
Packit fc043f
  if ((xmode & X_POLLABLE))
Packit fc043f
    {
Packit fc043f
      void *new_cookie;
Packit fc043f
Packit fc043f
      err = _gpgrt_w32_pollable_create (&new_cookie, modeflags,
Packit fc043f
                                        functions, cookie);
Packit fc043f
      if (err)
Packit fc043f
        goto out;
Packit fc043f
Packit fc043f
      modeflags &= ~O_NONBLOCK;
Packit fc043f
      old_cookie = cookie;
Packit fc043f
      cookie = new_cookie;
Packit fc043f
      kind = BACKEND_W32_POLLABLE;
Packit fc043f
      functions = _gpgrt_functions_w32_pollable;
Packit fc043f
    }
Packit fc043f
#endif /*HAVE_W32_SYSTEM*/
Packit fc043f
Packit fc043f
  init_stream_obj (stream_new, cookie, syshd, kind, functions, modeflags,
Packit fc043f
                   xmode);
Packit fc043f
  init_stream_lock (stream_new);
Packit fc043f
Packit fc043f
  err = do_list_add (stream_new, with_locked_list);
Packit fc043f
  if (err)
Packit fc043f
    goto out;
Packit fc043f
Packit fc043f
  *r_stream = stream_new;
Packit fc043f
Packit fc043f
 out:
Packit fc043f
Packit fc043f
  if (err)
Packit fc043f
    {
Packit fc043f
      trace_errno (err, ("leave: err=%d", err));
Packit fc043f
      if (stream_new)
Packit fc043f
	{
Packit fc043f
	  deinit_stream_obj (stream_new);
Packit fc043f
          destroy_stream_lock (stream_new);
Packit fc043f
	  mem_free (stream_new->intern);
Packit fc043f
	  mem_free (stream_new);
Packit fc043f
	}
Packit fc043f
    }
Packit fc043f
#if HAVE_W32_SYSTEM
Packit fc043f
  else if (old_cookie)
Packit fc043f
    trace (("leave: success stream=%p cookie=%p,%p",
Packit fc043f
            *r_stream, old_cookie, cookie));
Packit fc043f
#endif
Packit fc043f
  else
Packit fc043f
    trace (("leave: success stream=%p cookie=%p", *r_stream, cookie));
Packit fc043f
Packit fc043f
  return err;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * Deinitialize a stream object and destroy it.
Packit fc043f
 */
Packit fc043f
static int
Packit fc043f
do_close (estream_t stream, int with_locked_list)
Packit fc043f
{
Packit fc043f
  int err;
Packit fc043f
Packit fc043f
  trace (("stream %p %s", stream, with_locked_list? "(with locked list)":""));
Packit fc043f
Packit fc043f
  if (stream)
Packit fc043f
    {
Packit fc043f
      do_list_remove (stream, with_locked_list);
Packit fc043f
      while (stream->intern->onclose)
Packit fc043f
        {
Packit fc043f
          notify_list_t tmp = stream->intern->onclose->next;
Packit fc043f
Packit fc043f
          if (stream->intern->onclose->fnc)
Packit fc043f
            stream->intern->onclose->fnc (stream,
Packit fc043f
                                          stream->intern->onclose->fnc_value);
Packit fc043f
          mem_free (stream->intern->onclose);
Packit fc043f
          stream->intern->onclose = tmp;
Packit fc043f
        }
Packit fc043f
      err = deinit_stream_obj (stream);
Packit fc043f
      destroy_stream_lock (stream);
Packit fc043f
      if (stream->intern->deallocate_buffer)
Packit fc043f
        mem_free (stream->buffer);
Packit fc043f
      mem_free (stream->intern);
Packit fc043f
      mem_free (stream);
Packit fc043f
    }
Packit fc043f
  else
Packit fc043f
    err = 0;
Packit fc043f
Packit fc043f
  trace_errno (err, ("stream %p err=%d", stream, err));
Packit fc043f
  return err;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * The onclose worker function which is called with a locked
Packit fc043f
 * stream.
Packit fc043f
 */
Packit fc043f
static int
Packit fc043f
do_onclose (estream_t stream, int mode,
Packit fc043f
            void (*fnc) (estream_t, void*), void *fnc_value)
Packit fc043f
{
Packit fc043f
  notify_list_t item;
Packit fc043f
Packit fc043f
  if (!mode)
Packit fc043f
    {
Packit fc043f
      for (item = stream->intern->onclose; item; item = item->next)
Packit fc043f
        if (item->fnc && item->fnc == fnc && item->fnc_value == fnc_value)
Packit fc043f
          item->fnc = NULL; /* Disable this notification.  */
Packit fc043f
    }
Packit fc043f
  else
Packit fc043f
    {
Packit fc043f
      item = mem_alloc (sizeof *item);
Packit fc043f
      if (!item)
Packit fc043f
        return -1;
Packit fc043f
      item->fnc = fnc;
Packit fc043f
      item->fnc_value = fnc_value;
Packit fc043f
      item->next = stream->intern->onclose;
Packit fc043f
      stream->intern->onclose = item;
Packit fc043f
    }
Packit fc043f
  return 0;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * Try to read BYTES_TO_READ bytes from STREAM into BUFFER in
Packit fc043f
 * unbuffered-mode, storing the amount of bytes read at BYTES_READ.
Packit fc043f
 */
Packit fc043f
static int
Packit fc043f
do_read_nbf (estream_t _GPGRT__RESTRICT stream,
Packit fc043f
	     unsigned char *_GPGRT__RESTRICT buffer,
Packit fc043f
	     size_t bytes_to_read, size_t *_GPGRT__RESTRICT bytes_read)
Packit fc043f
{
Packit fc043f
  gpgrt_cookie_read_function_t func_read = stream->intern->func_read;
Packit fc043f
  size_t data_read;
Packit fc043f
  gpgrt_ssize_t ret;
Packit fc043f
  int err;
Packit fc043f
Packit fc043f
  data_read = 0;
Packit fc043f
  err = 0;
Packit fc043f
Packit fc043f
  while (bytes_to_read - data_read)
Packit fc043f
    {
Packit fc043f
      ret = (*func_read) (stream->intern->cookie,
Packit fc043f
			  buffer + data_read, bytes_to_read - data_read);
Packit fc043f
      if (ret == -1)
Packit fc043f
	{
Packit fc043f
	  err = -1;
Packit fc043f
#if EWOULDBLOCK != EAGAIN
Packit fc043f
          if (errno == EWOULDBLOCK)
Packit fc043f
            _set_errno (EAGAIN);
Packit fc043f
#endif
Packit fc043f
	  break;
Packit fc043f
	}
Packit fc043f
      else if (ret)
Packit fc043f
	data_read += ret;
Packit fc043f
      else
Packit fc043f
	break;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  stream->intern->offset += data_read;
Packit fc043f
  *bytes_read = data_read;
Packit fc043f
Packit fc043f
  return err;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * Helper for check_pending.
Packit fc043f
 */
Packit fc043f
static int
Packit fc043f
check_pending_nbf (estream_t _GPGRT__RESTRICT stream)
Packit fc043f
{
Packit fc043f
  gpgrt_cookie_read_function_t func_read = stream->intern->func_read;
Packit fc043f
  char buffer[1];
Packit fc043f
Packit fc043f
  if (!(*func_read) (stream->intern->cookie, buffer, 0))
Packit fc043f
    return 1; /* Pending bytes.  */
Packit fc043f
  return 0; /* No pending bytes or error.  */
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * Try to read BYTES_TO_READ bytes from STREAM into BUFFER in
Packit fc043f
 * fully-buffered-mode, storing the amount of bytes read at
Packit fc043f
 * BYTES_READ.
Packit fc043f
 */
Packit fc043f
static int
Packit fc043f
do_read_fbf (estream_t _GPGRT__RESTRICT stream,
Packit fc043f
	     unsigned char *_GPGRT__RESTRICT buffer,
Packit fc043f
	     size_t bytes_to_read, size_t *_GPGRT__RESTRICT bytes_read)
Packit fc043f
{
Packit fc043f
  size_t data_available;
Packit fc043f
  size_t data_to_read;
Packit fc043f
  size_t data_read;
Packit fc043f
  int err;
Packit fc043f
Packit fc043f
  data_read = 0;
Packit fc043f
  err = 0;
Packit fc043f
Packit fc043f
  while ((bytes_to_read - data_read) && (! err))
Packit fc043f
    {
Packit fc043f
      if (stream->data_offset == stream->data_len)
Packit fc043f
	{
Packit fc043f
	  /* Nothing more to read in current container, try to
Packit fc043f
	     fill container with new data.  */
Packit fc043f
	  err = fill_stream (stream);
Packit fc043f
	  if (! err)
Packit fc043f
	    if (! stream->data_len)
Packit fc043f
	      /* Filling did not result in any data read.  */
Packit fc043f
	      break;
Packit fc043f
	}
Packit fc043f
Packit fc043f
      if (! err)
Packit fc043f
	{
Packit fc043f
	  /* Filling resulted in some new data.  */
Packit fc043f
Packit fc043f
	  data_to_read = bytes_to_read - data_read;
Packit fc043f
	  data_available = stream->data_len - stream->data_offset;
Packit fc043f
	  if (data_to_read > data_available)
Packit fc043f
	    data_to_read = data_available;
Packit fc043f
Packit fc043f
	  memcpy (buffer + data_read,
Packit fc043f
		  stream->buffer + stream->data_offset, data_to_read);
Packit fc043f
	  stream->data_offset += data_to_read;
Packit fc043f
	  data_read += data_to_read;
Packit fc043f
	}
Packit fc043f
    }
Packit fc043f
Packit fc043f
  *bytes_read = data_read;
Packit fc043f
Packit fc043f
  return err;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * Helper for check_pending.
Packit fc043f
 */
Packit fc043f
static int
Packit fc043f
check_pending_fbf (estream_t _GPGRT__RESTRICT stream)
Packit fc043f
{
Packit fc043f
  gpgrt_cookie_read_function_t func_read = stream->intern->func_read;
Packit fc043f
  char buffer[1];
Packit fc043f
Packit fc043f
  if (stream->data_offset == stream->data_len)
Packit fc043f
    {
Packit fc043f
      /* Nothing more to read in current container, check whether it
Packit fc043f
         would be possible to fill the container with new data.  */
Packit fc043f
      if (!(*func_read) (stream->intern->cookie, buffer, 0))
Packit fc043f
        return 1; /* Pending bytes.  */
Packit fc043f
    }
Packit fc043f
  else
Packit fc043f
    return 1;
Packit fc043f
  return 0;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * Try to read BYTES_TO_READ bytes from STREAM into BUFFER in
Packit fc043f
 * line-buffered-mode, storing the amount of bytes read at BYTES_READ.
Packit fc043f
 */
Packit fc043f
static int
Packit fc043f
do_read_lbf (estream_t _GPGRT__RESTRICT stream,
Packit fc043f
	     unsigned char *_GPGRT__RESTRICT buffer,
Packit fc043f
	     size_t bytes_to_read, size_t *_GPGRT__RESTRICT bytes_read)
Packit fc043f
{
Packit fc043f
  int err;
Packit fc043f
Packit fc043f
  err = do_read_fbf (stream, buffer, bytes_to_read, bytes_read);
Packit fc043f
Packit fc043f
  return err;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * Try to read BYTES_TO_READ bytes from STREAM into BUFFER, storing
Packit fc043f
 * the amount of bytes read at BYTES_READ.
Packit fc043f
 */
Packit fc043f
static int
Packit fc043f
es_readn (estream_t _GPGRT__RESTRICT stream,
Packit fc043f
	  void *_GPGRT__RESTRICT buffer_arg,
Packit fc043f
	  size_t bytes_to_read, size_t *_GPGRT__RESTRICT bytes_read)
Packit fc043f
{
Packit fc043f
  unsigned char *buffer = (unsigned char *)buffer_arg;
Packit fc043f
  size_t data_read_unread, data_read;
Packit fc043f
  int err;
Packit fc043f
Packit fc043f
  data_read_unread = 0;
Packit fc043f
  data_read = 0;
Packit fc043f
  err = 0;
Packit fc043f
Packit fc043f
  if (stream->flags.writing)
Packit fc043f
    {
Packit fc043f
      /* Switching to reading mode -> flush output.  */
Packit fc043f
      err = flush_stream (stream);
Packit fc043f
      if (err)
Packit fc043f
	goto out;
Packit fc043f
      stream->flags.writing = 0;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  /* Read unread data first.  */
Packit fc043f
  while ((bytes_to_read - data_read_unread) && stream->unread_data_len)
Packit fc043f
    {
Packit fc043f
      buffer[data_read_unread]
Packit fc043f
	= stream->unread_buffer[stream->unread_data_len - 1];
Packit fc043f
      stream->unread_data_len--;
Packit fc043f
      data_read_unread++;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  switch (stream->intern->strategy)
Packit fc043f
    {
Packit fc043f
    case _IONBF:
Packit fc043f
      err = do_read_nbf (stream,
Packit fc043f
			 buffer + data_read_unread,
Packit fc043f
			 bytes_to_read - data_read_unread, &data_read);
Packit fc043f
      break;
Packit fc043f
    case _IOLBF:
Packit fc043f
      err = do_read_lbf (stream,
Packit fc043f
			 buffer + data_read_unread,
Packit fc043f
			 bytes_to_read - data_read_unread, &data_read);
Packit fc043f
      break;
Packit fc043f
    case _IOFBF:
Packit fc043f
      err = do_read_fbf (stream,
Packit fc043f
			 buffer + data_read_unread,
Packit fc043f
			 bytes_to_read - data_read_unread, &data_read);
Packit fc043f
      break;
Packit fc043f
    }
Packit fc043f
Packit fc043f
 out:
Packit fc043f
Packit fc043f
  if (bytes_read)
Packit fc043f
    *bytes_read = data_read_unread + data_read;
Packit fc043f
Packit fc043f
  return err;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * Return true if at least one byte is pending for read.  This is a
Packit fc043f
 * best effort check and it it possible that bytes are still pending
Packit fc043f
 * even if false is returned.  If the stream is in writing mode it is
Packit fc043f
 * switched to read mode.
Packit fc043f
 */
Packit fc043f
static int
Packit fc043f
check_pending (estream_t _GPGRT__RESTRICT stream)
Packit fc043f
{
Packit fc043f
  if (stream->flags.writing)
Packit fc043f
    {
Packit fc043f
      /* Switching to reading mode -> flush output.  */
Packit fc043f
      if (flush_stream (stream))
Packit fc043f
	return 0; /* Better return 0 on error.  */
Packit fc043f
      stream->flags.writing = 0;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  /* Check unread data first.  */
Packit fc043f
  if (stream->unread_data_len)
Packit fc043f
    return 1;
Packit fc043f
Packit fc043f
  switch (stream->intern->strategy)
Packit fc043f
    {
Packit fc043f
    case _IONBF:
Packit fc043f
      return check_pending_nbf (stream);
Packit fc043f
    case _IOLBF:
Packit fc043f
    case _IOFBF:
Packit fc043f
      return check_pending_fbf (stream);
Packit fc043f
    }
Packit fc043f
Packit fc043f
  return 0;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * Try to unread DATA_N bytes from DATA into STREAM, storing the
Packit fc043f
 * amount of bytes successfully unread at BYTES_UNREAD.
Packit fc043f
 */
Packit fc043f
static void
Packit fc043f
es_unreadn (estream_t _GPGRT__RESTRICT stream,
Packit fc043f
	    const unsigned char *_GPGRT__RESTRICT data, size_t data_n,
Packit fc043f
	    size_t *_GPGRT__RESTRICT bytes_unread)
Packit fc043f
{
Packit fc043f
  size_t space_left;
Packit fc043f
Packit fc043f
  space_left = stream->unread_buffer_size - stream->unread_data_len;
Packit fc043f
Packit fc043f
  if (data_n > space_left)
Packit fc043f
    data_n = space_left;
Packit fc043f
Packit fc043f
  if (! data_n)
Packit fc043f
    goto out;
Packit fc043f
Packit fc043f
  memcpy (stream->unread_buffer + stream->unread_data_len, data, data_n);
Packit fc043f
  stream->unread_data_len += data_n;
Packit fc043f
  stream->intern->indicators.eof = 0;
Packit fc043f
Packit fc043f
 out:
Packit fc043f
Packit fc043f
  if (bytes_unread)
Packit fc043f
    *bytes_unread = data_n;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * Seek in STREAM.
Packit fc043f
 */
Packit fc043f
static int
Packit fc043f
es_seek (estream_t _GPGRT__RESTRICT stream, gpgrt_off_t offset, int whence,
Packit fc043f
	 gpgrt_off_t *_GPGRT__RESTRICT offset_new)
Packit fc043f
{
Packit fc043f
  gpgrt_cookie_seek_function_t func_seek = stream->intern->func_seek;
Packit fc043f
  int err, ret;
Packit fc043f
  gpgrt_off_t off;
Packit fc043f
Packit fc043f
  if (! func_seek)
Packit fc043f
    {
Packit fc043f
      _set_errno (EOPNOTSUPP);
Packit fc043f
      err = -1;
Packit fc043f
      goto out;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  if (stream->flags.writing)
Packit fc043f
    {
Packit fc043f
      /* Flush data first in order to prevent flushing it to the wrong
Packit fc043f
	 offset.  */
Packit fc043f
      err = flush_stream (stream);
Packit fc043f
      if (err)
Packit fc043f
	goto out;
Packit fc043f
      stream->flags.writing = 0;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  off = offset;
Packit fc043f
  if (whence == SEEK_CUR)
Packit fc043f
    {
Packit fc043f
      off = off - stream->data_len + stream->data_offset;
Packit fc043f
      off -= stream->unread_data_len;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  ret = (*func_seek) (stream->intern->cookie, &off, whence);
Packit fc043f
  if (ret == -1)
Packit fc043f
    {
Packit fc043f
      err = -1;
Packit fc043f
#if EWOULDBLOCK != EAGAIN
Packit fc043f
      if (errno == EWOULDBLOCK)
Packit fc043f
        _set_errno (EAGAIN);
Packit fc043f
#endif
Packit fc043f
      goto out;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  err = 0;
Packit fc043f
  es_empty (stream);
Packit fc043f
Packit fc043f
  if (offset_new)
Packit fc043f
    *offset_new = off;
Packit fc043f
Packit fc043f
  stream->intern->indicators.eof = 0;
Packit fc043f
  stream->intern->offset = off;
Packit fc043f
Packit fc043f
 out:
Packit fc043f
Packit fc043f
  if (err)
Packit fc043f
    {
Packit fc043f
      if (errno == EPIPE)
Packit fc043f
        stream->intern->indicators.hup = 1;
Packit fc043f
      stream->intern->indicators.err = 1;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  return err;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
Packit fc043f
 * unbuffered-mode, storing the amount of bytes written at
Packit fc043f
 * BYTES_WRITTEN.
Packit fc043f
 */
Packit fc043f
static int
Packit fc043f
es_write_nbf (estream_t _GPGRT__RESTRICT stream,
Packit fc043f
	      const unsigned char *_GPGRT__RESTRICT buffer,
Packit fc043f
	      size_t bytes_to_write, size_t *_GPGRT__RESTRICT bytes_written)
Packit fc043f
{
Packit fc043f
  gpgrt_cookie_write_function_t func_write = stream->intern->func_write;
Packit fc043f
  size_t data_written;
Packit fc043f
  gpgrt_ssize_t ret;
Packit fc043f
  int err;
Packit fc043f
Packit fc043f
  if (bytes_to_write && (! func_write))
Packit fc043f
    {
Packit fc043f
      _set_errno (EOPNOTSUPP);
Packit fc043f
      err = -1;
Packit fc043f
      goto out;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  data_written = 0;
Packit fc043f
  err = 0;
Packit fc043f
Packit fc043f
  while (bytes_to_write - data_written)
Packit fc043f
    {
Packit fc043f
      ret = (*func_write) (stream->intern->cookie,
Packit fc043f
			   buffer + data_written,
Packit fc043f
			   bytes_to_write - data_written);
Packit fc043f
      if (ret == -1)
Packit fc043f
	{
Packit fc043f
	  err = -1;
Packit fc043f
#if EWOULDBLOCK != EAGAIN
Packit fc043f
          if (errno == EWOULDBLOCK)
Packit fc043f
            _set_errno (EAGAIN);
Packit fc043f
#endif
Packit fc043f
	  break;
Packit fc043f
	}
Packit fc043f
      else
Packit fc043f
	data_written += ret;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  stream->intern->offset += data_written;
Packit fc043f
  *bytes_written = data_written;
Packit fc043f
Packit fc043f
 out:
Packit fc043f
Packit fc043f
  return err;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
Packit fc043f
 * fully-buffered-mode, storing the amount of bytes written at
Packit fc043f
 * BYTES_WRITTEN.
Packit fc043f
 */
Packit fc043f
static int
Packit fc043f
es_write_fbf (estream_t _GPGRT__RESTRICT stream,
Packit fc043f
	      const unsigned char *_GPGRT__RESTRICT buffer,
Packit fc043f
	      size_t bytes_to_write, size_t *_GPGRT__RESTRICT bytes_written)
Packit fc043f
{
Packit fc043f
  size_t space_available;
Packit fc043f
  size_t data_to_write;
Packit fc043f
  size_t data_written;
Packit fc043f
  int err;
Packit fc043f
Packit fc043f
  data_written = 0;
Packit fc043f
  err = 0;
Packit fc043f
Packit fc043f
  while ((bytes_to_write - data_written) && (! err))
Packit fc043f
    {
Packit fc043f
      if (stream->data_offset == stream->buffer_size)
Packit fc043f
	/* Container full, flush buffer.  */
Packit fc043f
	err = flush_stream (stream);
Packit fc043f
Packit fc043f
      if (! err)
Packit fc043f
	{
Packit fc043f
	  /* Flushing resulted in empty container.  */
Packit fc043f
Packit fc043f
	  data_to_write = bytes_to_write - data_written;
Packit fc043f
	  space_available = stream->buffer_size - stream->data_offset;
Packit fc043f
	  if (data_to_write > space_available)
Packit fc043f
	    data_to_write = space_available;
Packit fc043f
Packit fc043f
	  memcpy (stream->buffer + stream->data_offset,
Packit fc043f
		  buffer + data_written, data_to_write);
Packit fc043f
	  stream->data_offset += data_to_write;
Packit fc043f
	  data_written += data_to_write;
Packit fc043f
	}
Packit fc043f
    }
Packit fc043f
Packit fc043f
  *bytes_written = data_written;
Packit fc043f
Packit fc043f
  return err;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
Packit fc043f
   line-buffered-mode, storing the amount of bytes written in
Packit fc043f
   *BYTES_WRITTEN.  */
Packit fc043f
static int
Packit fc043f
es_write_lbf (estream_t _GPGRT__RESTRICT stream,
Packit fc043f
	      const unsigned char *_GPGRT__RESTRICT buffer,
Packit fc043f
	      size_t bytes_to_write, size_t *_GPGRT__RESTRICT bytes_written)
Packit fc043f
{
Packit fc043f
  size_t data_flushed = 0;
Packit fc043f
  size_t data_buffered = 0;
Packit fc043f
  unsigned char *nlp;
Packit fc043f
  int err = 0;
Packit fc043f
Packit fc043f
  nlp = memrchr (buffer, '\n', bytes_to_write);
Packit fc043f
  if (nlp)
Packit fc043f
    {
Packit fc043f
      /* Found a newline, directly write up to (including) this
Packit fc043f
	 character.  */
Packit fc043f
      err = flush_stream (stream);
Packit fc043f
      if (!err)
Packit fc043f
	err = es_write_nbf (stream, buffer, nlp - buffer + 1, &data_flushed);
Packit fc043f
    }
Packit fc043f
Packit fc043f
  if (!err)
Packit fc043f
    {
Packit fc043f
      /* Write remaining data fully buffered.  */
Packit fc043f
      err = es_write_fbf (stream, buffer + data_flushed,
Packit fc043f
			  bytes_to_write - data_flushed, &data_buffered);
Packit fc043f
    }
Packit fc043f
Packit fc043f
  *bytes_written = data_flushed + data_buffered;
Packit fc043f
  return err;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in, storing the
Packit fc043f
   amount of bytes written in BYTES_WRITTEN.  */
Packit fc043f
static int
Packit fc043f
es_writen (estream_t _GPGRT__RESTRICT stream,
Packit fc043f
	   const void *_GPGRT__RESTRICT buffer,
Packit fc043f
	   size_t bytes_to_write, size_t *_GPGRT__RESTRICT bytes_written)
Packit fc043f
{
Packit fc043f
  size_t data_written;
Packit fc043f
  int err;
Packit fc043f
Packit fc043f
  data_written = 0;
Packit fc043f
  err = 0;
Packit fc043f
Packit fc043f
  if (!stream->flags.writing)
Packit fc043f
    {
Packit fc043f
      /* Switching to writing mode -> discard input data and seek to
Packit fc043f
	 position at which reading has stopped.  We can do this only
Packit fc043f
	 if a seek function has been registered. */
Packit fc043f
      if (stream->intern->func_seek)
Packit fc043f
        {
Packit fc043f
          err = es_seek (stream, 0, SEEK_CUR, NULL);
Packit fc043f
          if (err)
Packit fc043f
            {
Packit fc043f
              if (errno == ESPIPE)
Packit fc043f
                err = 0;
Packit fc043f
              else
Packit fc043f
                goto out;
Packit fc043f
            }
Packit fc043f
          stream->flags.writing = 1;
Packit fc043f
        }
Packit fc043f
    }
Packit fc043f
Packit fc043f
  switch (stream->intern->strategy)
Packit fc043f
    {
Packit fc043f
    case _IONBF:
Packit fc043f
      err = es_write_nbf (stream, buffer, bytes_to_write, &data_written);
Packit fc043f
      break;
Packit fc043f
Packit fc043f
    case _IOLBF:
Packit fc043f
      err = es_write_lbf (stream, buffer, bytes_to_write, &data_written);
Packit fc043f
      break;
Packit fc043f
Packit fc043f
    case _IOFBF:
Packit fc043f
      err = es_write_fbf (stream, buffer, bytes_to_write, &data_written);
Packit fc043f
      break;
Packit fc043f
    }
Packit fc043f
Packit fc043f
 out:
Packit fc043f
Packit fc043f
  if (bytes_written)
Packit fc043f
    *bytes_written = data_written;
Packit fc043f
Packit fc043f
  return err;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
static int
Packit fc043f
peek_stream (estream_t _GPGRT__RESTRICT stream,
Packit fc043f
             unsigned char **_GPGRT__RESTRICT data,
Packit fc043f
             size_t *_GPGRT__RESTRICT data_len)
Packit fc043f
{
Packit fc043f
  int err;
Packit fc043f
Packit fc043f
  if (stream->flags.writing)
Packit fc043f
    {
Packit fc043f
      /* Switching to reading mode -> flush output.  */
Packit fc043f
      err = flush_stream (stream);
Packit fc043f
      if (err)
Packit fc043f
	goto out;
Packit fc043f
      stream->flags.writing = 0;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  if (stream->data_offset == stream->data_len)
Packit fc043f
    {
Packit fc043f
      /* Refill container.  */
Packit fc043f
      err = fill_stream (stream);
Packit fc043f
      if (err)
Packit fc043f
	goto out;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  if (data)
Packit fc043f
    *data = stream->buffer + stream->data_offset;
Packit fc043f
  if (data_len)
Packit fc043f
    *data_len = stream->data_len - stream->data_offset;
Packit fc043f
  err = 0;
Packit fc043f
Packit fc043f
 out:
Packit fc043f
Packit fc043f
  return err;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/* Skip SIZE bytes of input data contained in buffer.  */
Packit fc043f
static int
Packit fc043f
skip_stream (estream_t stream, size_t size)
Packit fc043f
{
Packit fc043f
  int err;
Packit fc043f
Packit fc043f
  if (stream->data_offset + size > stream->data_len)
Packit fc043f
    {
Packit fc043f
      _set_errno (EINVAL);
Packit fc043f
      err = -1;
Packit fc043f
    }
Packit fc043f
  else
Packit fc043f
    {
Packit fc043f
      stream->data_offset += size;
Packit fc043f
      err = 0;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  return err;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
static int
Packit fc043f
doreadline (estream_t _GPGRT__RESTRICT stream, size_t max_length,
Packit fc043f
            char *_GPGRT__RESTRICT *_GPGRT__RESTRICT line,
Packit fc043f
            size_t *_GPGRT__RESTRICT line_length)
Packit fc043f
{
Packit fc043f
  size_t line_size;
Packit fc043f
  estream_t line_stream;
Packit fc043f
  char *line_new;
Packit fc043f
  void *line_stream_cookie;
Packit fc043f
  char *newline;
Packit fc043f
  unsigned char *data;
Packit fc043f
  size_t data_len;
Packit fc043f
  int err;
Packit fc043f
  es_syshd_t syshd;
Packit fc043f
Packit fc043f
  line_new = NULL;
Packit fc043f
  line_stream = NULL;
Packit fc043f
  line_stream_cookie = NULL;
Packit fc043f
Packit fc043f
  err = func_mem_create (&line_stream_cookie, NULL, 0, 0,
Packit fc043f
                         BUFFER_BLOCK_SIZE, 1,
Packit fc043f
                         mem_realloc, mem_free,
Packit fc043f
                         O_RDWR,
Packit fc043f
                         0);
Packit fc043f
  if (err)
Packit fc043f
    goto out;
Packit fc043f
Packit fc043f
  memset (&syshd, 0, sizeof syshd);
Packit fc043f
  err = create_stream (&line_stream, line_stream_cookie,
Packit fc043f
                       &syshd, BACKEND_MEM,
Packit fc043f
                       estream_functions_mem, O_RDWR, 1, 0);
Packit fc043f
  if (err)
Packit fc043f
    goto out;
Packit fc043f
Packit fc043f
  {
Packit fc043f
    size_t space_left = max_length;
Packit fc043f
Packit fc043f
    line_size = 0;
Packit fc043f
    for (;;)
Packit fc043f
      {
Packit fc043f
        if (max_length && (space_left == 1))
Packit fc043f
          break;
Packit fc043f
Packit fc043f
        err = peek_stream (stream, &data, &data_len);
Packit fc043f
        if (err || (! data_len))
Packit fc043f
          break;
Packit fc043f
Packit fc043f
        if (data_len > (space_left - 1))
Packit fc043f
          data_len = space_left - 1;
Packit fc043f
Packit fc043f
        newline = memchr (data, '\n', data_len);
Packit fc043f
        if (newline)
Packit fc043f
          {
Packit fc043f
            data_len = (newline - (char *) data) + 1;
Packit fc043f
            err = _gpgrt_write (line_stream, data, data_len, NULL);
Packit fc043f
            if (! err)
Packit fc043f
              {
Packit fc043f
                /* Not needed: space_left -= data_len */
Packit fc043f
                line_size += data_len;
Packit fc043f
                skip_stream (stream, data_len);
Packit fc043f
                break; /* endless loop */
Packit fc043f
              }
Packit fc043f
          }
Packit fc043f
        else
Packit fc043f
          {
Packit fc043f
            err = _gpgrt_write (line_stream, data, data_len, NULL);
Packit fc043f
            if (! err)
Packit fc043f
              {
Packit fc043f
                space_left -= data_len;
Packit fc043f
                line_size += data_len;
Packit fc043f
                skip_stream (stream, data_len);
Packit fc043f
              }
Packit fc043f
          }
Packit fc043f
        if (err)
Packit fc043f
          break;
Packit fc043f
      }
Packit fc043f
  }
Packit fc043f
  if (err)
Packit fc043f
    goto out;
Packit fc043f
Packit fc043f
  /* Complete line has been written to line_stream.  */
Packit fc043f
Packit fc043f
  if ((max_length > 1) && (! line_size))
Packit fc043f
    {
Packit fc043f
      stream->intern->indicators.eof = 1;
Packit fc043f
      goto out;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  err = es_seek (line_stream, 0, SEEK_SET, NULL);
Packit fc043f
  if (err)
Packit fc043f
    goto out;
Packit fc043f
Packit fc043f
  if (! *line)
Packit fc043f
    {
Packit fc043f
      line_new = mem_alloc (line_size + 1);
Packit fc043f
      if (! line_new)
Packit fc043f
	{
Packit fc043f
	  err = -1;
Packit fc043f
	  goto out;
Packit fc043f
	}
Packit fc043f
    }
Packit fc043f
  else
Packit fc043f
    line_new = *line;
Packit fc043f
Packit fc043f
  err = _gpgrt_read (line_stream, line_new, line_size, NULL);
Packit fc043f
  if (err)
Packit fc043f
    goto out;
Packit fc043f
Packit fc043f
  line_new[line_size] = '\0';
Packit fc043f
Packit fc043f
  if (! *line)
Packit fc043f
    *line = line_new;
Packit fc043f
  if (line_length)
Packit fc043f
    *line_length = line_size;
Packit fc043f
Packit fc043f
 out:
Packit fc043f
Packit fc043f
  if (line_stream)
Packit fc043f
    do_close (line_stream, 0);
Packit fc043f
  else if (line_stream_cookie)
Packit fc043f
    func_mem_destroy (line_stream_cookie);
Packit fc043f
Packit fc043f
  if (err)
Packit fc043f
    {
Packit fc043f
      if (! *line)
Packit fc043f
	mem_free (line_new);
Packit fc043f
      stream->intern->indicators.err = 1;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  return err;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/* Output function used by estream_format.  */
Packit fc043f
static int
Packit fc043f
print_writer (void *outfncarg, const char *buf, size_t buflen)
Packit fc043f
{
Packit fc043f
  estream_t stream = outfncarg;
Packit fc043f
  size_t nwritten;
Packit fc043f
  int rc;
Packit fc043f
Packit fc043f
  nwritten = 0;
Packit fc043f
  rc = es_writen (stream, buf, buflen, &nwritten);
Packit fc043f
  stream->intern->print_ntotal += nwritten;
Packit fc043f
  return rc;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/* The core of our printf function.  This is called in locked state. */
Packit fc043f
static int
Packit fc043f
do_print_stream (estream_t _GPGRT__RESTRICT stream,
Packit fc043f
                 const char *_GPGRT__RESTRICT format, va_list ap)
Packit fc043f
{
Packit fc043f
  int rc;
Packit fc043f
Packit fc043f
  stream->intern->print_ntotal = 0;
Packit fc043f
  rc = _gpgrt_estream_format (print_writer, stream, format, ap);
Packit fc043f
  if (rc)
Packit fc043f
    return -1;
Packit fc043f
  return (int)stream->intern->print_ntotal;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
static int
Packit fc043f
es_set_buffering (estream_t _GPGRT__RESTRICT stream,
Packit fc043f
		  char *_GPGRT__RESTRICT buffer, int mode, size_t size)
Packit fc043f
{
Packit fc043f
  int err;
Packit fc043f
Packit fc043f
  /* Flush or empty buffer depending on mode.  */
Packit fc043f
  if (stream->flags.writing)
Packit fc043f
    {
Packit fc043f
      err = flush_stream (stream);
Packit fc043f
      if (err)
Packit fc043f
	goto out;
Packit fc043f
    }
Packit fc043f
  else
Packit fc043f
    es_empty (stream);
Packit fc043f
Packit fc043f
  stream->intern->indicators.eof = 0;
Packit fc043f
Packit fc043f
  /* Free old buffer in case that was allocated by this function.  */
Packit fc043f
  if (stream->intern->deallocate_buffer)
Packit fc043f
    {
Packit fc043f
      stream->intern->deallocate_buffer = 0;
Packit fc043f
      mem_free (stream->buffer);
Packit fc043f
      stream->buffer = NULL;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  if (mode == _IONBF)
Packit fc043f
    stream->buffer_size = 0;
Packit fc043f
  else
Packit fc043f
    {
Packit fc043f
      void *buffer_new;
Packit fc043f
Packit fc043f
      if (buffer)
Packit fc043f
	buffer_new = buffer;
Packit fc043f
      else
Packit fc043f
	{
Packit fc043f
          if (!size)
Packit fc043f
            size = BUFSIZ;
Packit fc043f
	  buffer_new = mem_alloc (size);
Packit fc043f
	  if (! buffer_new)
Packit fc043f
	    {
Packit fc043f
	      err = -1;
Packit fc043f
	      goto out;
Packit fc043f
	    }
Packit fc043f
	}
Packit fc043f
Packit fc043f
      stream->buffer = buffer_new;
Packit fc043f
      stream->buffer_size = size;
Packit fc043f
      if (! buffer)
Packit fc043f
	stream->intern->deallocate_buffer = 1;
Packit fc043f
    }
Packit fc043f
  stream->intern->strategy = mode;
Packit fc043f
  err = 0;
Packit fc043f
Packit fc043f
 out:
Packit fc043f
Packit fc043f
  return err;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
static gpgrt_off_t
Packit fc043f
es_offset_calculate (estream_t stream)
Packit fc043f
{
Packit fc043f
  gpgrt_off_t offset;
Packit fc043f
Packit fc043f
  offset = stream->intern->offset + stream->data_offset;
Packit fc043f
  if (offset < stream->unread_data_len)
Packit fc043f
    /* Offset undefined.  */
Packit fc043f
    offset = 0;
Packit fc043f
  else
Packit fc043f
    offset -= stream->unread_data_len;
Packit fc043f
Packit fc043f
  return offset;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
static void
Packit fc043f
es_opaque_ctrl (estream_t _GPGRT__RESTRICT stream,
Packit fc043f
                void *_GPGRT__RESTRICT opaque_new,
Packit fc043f
		void **_GPGRT__RESTRICT opaque_old)
Packit fc043f
{
Packit fc043f
  if (opaque_old)
Packit fc043f
    *opaque_old = stream->intern->opaque;
Packit fc043f
  if (opaque_new)
Packit fc043f
    stream->intern->opaque = opaque_new;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/* API.  */
Packit fc043f

Packit fc043f
estream_t
Packit fc043f
_gpgrt_fopen (const char *_GPGRT__RESTRICT path,
Packit fc043f
              const char *_GPGRT__RESTRICT mode)
Packit fc043f
{
Packit fc043f
  unsigned int modeflags, cmode, xmode;
Packit fc043f
  int create_called;
Packit fc043f
  estream_t stream;
Packit fc043f
  void *cookie;
Packit fc043f
  int err;
Packit fc043f
  int fd;
Packit fc043f
  es_syshd_t syshd;
Packit fc043f
Packit fc043f
  stream = NULL;
Packit fc043f
  cookie = NULL;
Packit fc043f
  create_called = 0;
Packit fc043f
Packit fc043f
  err = parse_mode (mode, &modeflags, &xmode, &cmode);
Packit fc043f
  if (err)
Packit fc043f
    goto out;
Packit fc043f
Packit fc043f
  err = func_file_create (&cookie, &fd, path, modeflags, cmode);
Packit fc043f
  if (err)
Packit fc043f
    goto out;
Packit fc043f
Packit fc043f
  syshd.type = ES_SYSHD_FD;
Packit fc043f
  syshd.u.fd = fd;
Packit fc043f
  create_called = 1;
Packit fc043f
  err = create_stream (&stream, cookie, &syshd, BACKEND_FD,
Packit fc043f
                       estream_functions_fd, modeflags, xmode, 0);
Packit fc043f
  if (err)
Packit fc043f
    goto out;
Packit fc043f
Packit fc043f
  if (stream && path)
Packit fc043f
    fname_set_internal (stream, path, 1);
Packit fc043f
Packit fc043f
 out:
Packit fc043f
Packit fc043f
  if (err && create_called)
Packit fc043f
    (*estream_functions_fd.public.func_close) (cookie);
Packit fc043f
Packit fc043f
  return stream;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f

Packit fc043f
/* Create a new estream object in memory.  If DATA is not NULL this
Packit fc043f
   buffer will be used as the memory buffer; thus after this functions
Packit fc043f
   returns with the success the the memory at DATA belongs to the new
Packit fc043f
   estream.  The allocated length of DATA is given by DATA_LEN and its
Packit fc043f
   used length by DATA_N.  Usually this is malloced buffer; if a
Packit fc043f
   static buffer is provided, the caller must pass false for GROW and
Packit fc043f
   provide a dummy function for FUNC_FREE.  FUNC_FREE and FUNC_REALLOC
Packit fc043f
   allow the caller to provide custom functions for realloc and free
Packit fc043f
   to be used by the new estream object.  Note that the realloc
Packit fc043f
   function is also used for initial allocation.  If DATA is NULL a
Packit fc043f
   buffer is internally allocated; either using internal function or
Packit fc043f
   those provide by the caller.  It is an error to provide a realloc
Packit fc043f
   function but no free function.  Providing only a free function is
Packit fc043f
   allowed as long as GROW is false.  */
Packit fc043f
estream_t
Packit fc043f
_gpgrt_mopen (void *_GPGRT__RESTRICT data, size_t data_n, size_t data_len,
Packit fc043f
              unsigned int grow,
Packit fc043f
              func_realloc_t func_realloc, func_free_t func_free,
Packit fc043f
              const char *_GPGRT__RESTRICT mode)
Packit fc043f
{
Packit fc043f
  int create_called = 0;
Packit fc043f
  estream_t stream = NULL;
Packit fc043f
  void *cookie = NULL;
Packit fc043f
  unsigned int modeflags, xmode;
Packit fc043f
  int err;
Packit fc043f
  es_syshd_t syshd;
Packit fc043f
Packit fc043f
  err = parse_mode (mode, &modeflags, &xmode, NULL);
Packit fc043f
  if (err)
Packit fc043f
    goto out;
Packit fc043f
Packit fc043f
  err = func_mem_create (&cookie, data, data_n, data_len,
Packit fc043f
                         BUFFER_BLOCK_SIZE, grow,
Packit fc043f
                         func_realloc, func_free, modeflags, 0);
Packit fc043f
  if (err)
Packit fc043f
    goto out;
Packit fc043f
Packit fc043f
  memset (&syshd, 0, sizeof syshd);
Packit fc043f
  create_called = 1;
Packit fc043f
  err = create_stream (&stream, cookie, &syshd, BACKEND_MEM,
Packit fc043f
                       estream_functions_mem, modeflags, xmode, 0);
Packit fc043f
Packit fc043f
 out:
Packit fc043f
Packit fc043f
  if (err && create_called)
Packit fc043f
    (*estream_functions_mem.public.func_close) (cookie);
Packit fc043f
Packit fc043f
  return stream;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f

Packit fc043f
estream_t
Packit fc043f
_gpgrt_fopenmem (size_t memlimit, const char *_GPGRT__RESTRICT mode)
Packit fc043f
{
Packit fc043f
  unsigned int modeflags, xmode;
Packit fc043f
  estream_t stream = NULL;
Packit fc043f
  void *cookie = NULL;
Packit fc043f
  es_syshd_t syshd;
Packit fc043f
Packit fc043f
  /* Memory streams are always read/write.  We use MODE only to get
Packit fc043f
     the append flag.  */
Packit fc043f
  if (parse_mode (mode, &modeflags, &xmode, NULL))
Packit fc043f
    return NULL;
Packit fc043f
  modeflags |= O_RDWR;
Packit fc043f
Packit fc043f
  if (func_mem_create (&cookie, NULL, 0, 0,
Packit fc043f
                       BUFFER_BLOCK_SIZE, 1,
Packit fc043f
                       mem_realloc, mem_free, modeflags,
Packit fc043f
                       memlimit))
Packit fc043f
    return NULL;
Packit fc043f
Packit fc043f
  memset (&syshd, 0, sizeof syshd);
Packit fc043f
  if (create_stream (&stream, cookie, &syshd, BACKEND_MEM,
Packit fc043f
                     estream_functions_mem, modeflags, xmode, 0))
Packit fc043f
    (*estream_functions_mem.public.func_close) (cookie);
Packit fc043f
Packit fc043f
  return stream;
Packit fc043f
}
Packit fc043f
Packit fc043f

Packit fc043f
/* This is the same as es_fopenmem but intializes the memory with a
Packit fc043f
   copy of (DATA,DATALEN).  The stream is initially set to the
Packit fc043f
   beginning.  If MEMLIMIT is not 0 but shorter than DATALEN it
Packit fc043f
   DATALEN will be used as the value for MEMLIMIT.  */
Packit fc043f
estream_t
Packit fc043f
_gpgrt_fopenmem_init (size_t memlimit, const char *_GPGRT__RESTRICT mode,
Packit fc043f
                      const void *data, size_t datalen)
Packit fc043f
{
Packit fc043f
  estream_t stream;
Packit fc043f
Packit fc043f
  if (memlimit && memlimit < datalen)
Packit fc043f
    memlimit = datalen;
Packit fc043f
Packit fc043f
  stream = _gpgrt_fopenmem (memlimit, mode);
Packit fc043f
  if (stream && data && datalen)
Packit fc043f
    {
Packit fc043f
      if (es_writen (stream, data, datalen, NULL))
Packit fc043f
        {
Packit fc043f
          int saveerrno = errno;
Packit fc043f
          _gpgrt_fclose (stream);
Packit fc043f
          stream = NULL;
Packit fc043f
          _set_errno (saveerrno);
Packit fc043f
        }
Packit fc043f
      else
Packit fc043f
        {
Packit fc043f
          es_seek (stream, 0L, SEEK_SET, NULL);
Packit fc043f
          stream->intern->indicators.eof = 0;
Packit fc043f
          stream->intern->indicators.err = 0;
Packit fc043f
        }
Packit fc043f
    }
Packit fc043f
  return stream;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f

Packit fc043f
estream_t
Packit fc043f
_gpgrt_fopencookie (void *_GPGRT__RESTRICT cookie,
Packit fc043f
                    const char *_GPGRT__RESTRICT mode,
Packit fc043f
                    gpgrt_cookie_io_functions_t functions)
Packit fc043f
{
Packit fc043f
  unsigned int modeflags, xmode;
Packit fc043f
  estream_t stream;
Packit fc043f
  int err;
Packit fc043f
  es_syshd_t syshd;
Packit fc043f
  struct cookie_io_functions_s io_functions = { functions, NULL, };
Packit fc043f
Packit fc043f
  stream = NULL;
Packit fc043f
  modeflags = 0;
Packit fc043f
Packit fc043f
  err = parse_mode (mode, &modeflags, &xmode, NULL);
Packit fc043f
  if (err)
Packit fc043f
    goto out;
Packit fc043f
Packit fc043f
  memset (&syshd, 0, sizeof syshd);
Packit fc043f
  err = create_stream (&stream, cookie, &syshd, BACKEND_USER, io_functions,
Packit fc043f
                       modeflags, xmode, 0);
Packit fc043f
  if (err)
Packit fc043f
    goto out;
Packit fc043f
Packit fc043f
 out:
Packit fc043f
  return stream;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f

Packit fc043f
static estream_t
Packit fc043f
do_fdopen (int filedes, const char *mode, int no_close, int with_locked_list)
Packit fc043f
{
Packit fc043f
  int create_called = 0;
Packit fc043f
  estream_t stream = NULL;
Packit fc043f
  void *cookie = NULL;
Packit fc043f
  unsigned int modeflags, xmode;
Packit fc043f
  int err;
Packit fc043f
  es_syshd_t syshd;
Packit fc043f
Packit fc043f
  err = parse_mode (mode, &modeflags, &xmode, NULL);
Packit fc043f
  if (err)
Packit fc043f
    goto out;
Packit fc043f
  if ((xmode & X_SYSOPEN))
Packit fc043f
    {
Packit fc043f
      /* Not allowed for fdopen.  */
Packit fc043f
      _set_errno (EINVAL);
Packit fc043f
      err = -1;
Packit fc043f
      goto out;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  err = func_fd_create (&cookie, filedes, modeflags, no_close);
Packit fc043f
  if (err)
Packit fc043f
    goto out;
Packit fc043f
Packit fc043f
  syshd.type = ES_SYSHD_FD;
Packit fc043f
  syshd.u.fd = filedes;
Packit fc043f
  create_called = 1;
Packit fc043f
  err = create_stream (&stream, cookie, &syshd,
Packit fc043f
                       BACKEND_FD, estream_functions_fd,
Packit fc043f
                       modeflags, xmode, with_locked_list);
Packit fc043f
Packit fc043f
  if (!err && stream)
Packit fc043f
    {
Packit fc043f
      if ((modeflags & O_NONBLOCK))
Packit fc043f
        err = stream->intern->func_ioctl (cookie, COOKIE_IOCTL_NONBLOCK,
Packit fc043f
                                          "", NULL);
Packit fc043f
    }
Packit fc043f
Packit fc043f
 out:
Packit fc043f
  if (err && create_called)
Packit fc043f
    (*estream_functions_fd.public.func_close) (cookie);
Packit fc043f
Packit fc043f
  return stream;
Packit fc043f
}
Packit fc043f
Packit fc043f
estream_t
Packit fc043f
_gpgrt_fdopen (int filedes, const char *mode)
Packit fc043f
{
Packit fc043f
  return do_fdopen (filedes, mode, 0, 0);
Packit fc043f
}
Packit fc043f
Packit fc043f
/* A variant of es_fdopen which does not close FILEDES at the end.  */
Packit fc043f
estream_t
Packit fc043f
_gpgrt_fdopen_nc (int filedes, const char *mode)
Packit fc043f
{
Packit fc043f
  return do_fdopen (filedes, mode, 1, 0);
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f

Packit fc043f
static estream_t
Packit fc043f
do_fpopen (FILE *fp, const char *mode, int no_close, int with_locked_list)
Packit fc043f
{
Packit fc043f
  unsigned int modeflags, cmode, xmode;
Packit fc043f
  int create_called = 0;
Packit fc043f
  estream_t stream = NULL;
Packit fc043f
  void *cookie = NULL;
Packit fc043f
  int err;
Packit fc043f
  es_syshd_t syshd;
Packit fc043f
Packit fc043f
  err = parse_mode (mode, &modeflags, &xmode, &cmode);
Packit fc043f
  if (err)
Packit fc043f
    goto out;
Packit fc043f
  if ((xmode & X_SYSOPEN))
Packit fc043f
    {
Packit fc043f
      /* Not allowed for fpopen.  */
Packit fc043f
      _set_errno (EINVAL);
Packit fc043f
      err = -1;
Packit fc043f
      goto out;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  if (fp)
Packit fc043f
    fflush (fp);
Packit fc043f
  err = func_fp_create (&cookie, fp, modeflags, no_close);
Packit fc043f
  if (err)
Packit fc043f
    goto out;
Packit fc043f
Packit fc043f
  syshd.type = ES_SYSHD_FD;
Packit fc043f
  syshd.u.fd = fp? fileno (fp): -1;
Packit fc043f
  create_called = 1;
Packit fc043f