|
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 |
|