Blame src/data.c

Packit Service 672cf4
/* data.c - An abstraction for data objects.
Packit Service 6c01f9
   Copyright (C) 2002, 2003, 2004, 2005, 2007 g10 Code GmbH
Packit Service 6c01f9
Packit Service 6c01f9
   This file is part of GPGME.
Packit Service 6c01f9
Packit Service 6c01f9
   GPGME is free software; you can redistribute it and/or modify it
Packit Service 6c01f9
   under the terms of the GNU Lesser General Public License as
Packit Service 6c01f9
   published by the Free Software Foundation; either version 2.1 of
Packit Service 6c01f9
   the License, or (at your option) any later version.
Packit Service 6c01f9
Packit Service 6c01f9
   GPGME is distributed in the hope that it will be useful, but
Packit Service 6c01f9
   WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 6c01f9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 6c01f9
   Lesser General Public License for more details.
Packit Service 6c01f9
Packit Service 6c01f9
   You should have received a copy of the GNU Lesser General Public
Packit Service 6c01f9
   License along with this program; if not, write to the Free Software
Packit Service 6c01f9
   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
Packit Service 6c01f9
   02111-1307, USA.  */
Packit Service 672cf4
Packit Service 672cf4
#if HAVE_CONFIG_H
Packit Service 672cf4
#include <config.h>
Packit Service 672cf4
#endif
Packit Service 672cf4
Packit Service 672cf4
#include <stdlib.h>
Packit Service 672cf4
#ifdef HAVE_UNISTD_H
Packit Service 672cf4
# include <unistd.h>
Packit Service 672cf4
#endif
Packit Service 672cf4
#include <errno.h>
Packit Service 672cf4
#include <string.h>
Packit Service 672cf4
Packit Service 672cf4
#include "gpgme.h"
Packit Service 672cf4
#include "data.h"
Packit Service 672cf4
#include "util.h"
Packit Service 672cf4
#include "ops.h"
Packit Service 672cf4
#include "priv-io.h"
Packit Service 672cf4
#include "debug.h"
Packit Service 672cf4
Packit Service 672cf4

Packit Service 672cf4
gpgme_error_t
Packit Service 672cf4
_gpgme_data_new (gpgme_data_t *r_dh, struct _gpgme_data_cbs *cbs)
Packit Service 672cf4
{
Packit Service 672cf4
  gpgme_data_t dh;
Packit Service 672cf4
Packit Service 672cf4
  if (!r_dh)
Packit Service 672cf4
    return gpg_error (GPG_ERR_INV_VALUE);
Packit Service 672cf4
Packit Service 672cf4
  *r_dh = NULL;
Packit Service 672cf4
Packit Service 672cf4
  if (_gpgme_selftest)
Packit Service 672cf4
    return _gpgme_selftest;
Packit Service 672cf4
Packit Service 672cf4
  dh = calloc (1, sizeof (*dh));
Packit Service 672cf4
  if (!dh)
Packit Service 672cf4
    return gpg_error_from_syserror ();
Packit Service 672cf4
Packit Service 672cf4
  dh->cbs = cbs;
Packit Service 672cf4
Packit Service 672cf4
  *r_dh = dh;
Packit Service 672cf4
  return 0;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
void
Packit Service 672cf4
_gpgme_data_release (gpgme_data_t dh)
Packit Service 672cf4
{
Packit Service 672cf4
  if (!dh)
Packit Service 672cf4
    return;
Packit Service 672cf4
Packit Service 672cf4
  if (dh->file_name)
Packit Service 672cf4
    free (dh->file_name);
Packit Service 672cf4
  free (dh);
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4

Packit Service 672cf4
/* Read up to SIZE bytes into buffer BUFFER from the data object with
Packit Service 672cf4
   the handle DH.  Return the number of characters read, 0 on EOF and
Packit Service 672cf4
   -1 on error.  If an error occurs, errno is set.  */
Packit Service 672cf4
gpgme_ssize_t
Packit Service 672cf4
gpgme_data_read (gpgme_data_t dh, void *buffer, size_t size)
Packit Service 672cf4
{
Packit Service 672cf4
  gpgme_ssize_t res;
Packit Service 6c01f9
  TRACE_BEG2 (DEBUG_DATA, "gpgme_data_read", dh,
Packit Service 6c01f9
	      "buffer=%p, size=%u", buffer, size);
Packit Service 672cf4
Packit Service 672cf4
  if (!dh)
Packit Service 672cf4
    {
Packit Service 672cf4
      gpg_err_set_errno (EINVAL);
Packit Service 672cf4
      return TRACE_SYSRES (-1);
Packit Service 672cf4
    }
Packit Service 672cf4
  if (!dh->cbs->read)
Packit Service 672cf4
    {
Packit Service 672cf4
      gpg_err_set_errno (ENOSYS);
Packit Service 672cf4
      return TRACE_SYSRES (-1);
Packit Service 672cf4
    }
Packit Service 6c01f9
  do
Packit Service 6c01f9
    res = (*dh->cbs->read) (dh, buffer, size);
Packit Service 6c01f9
  while (res < 0 && errno == EINTR);
Packit Service 672cf4
Packit Service 6c01f9
  return TRACE_SYSRES (res);
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
/* Write up to SIZE bytes from buffer BUFFER to the data object with
Packit Service 672cf4
   the handle DH.  Return the number of characters written, or -1 on
Packit Service 672cf4
   error.  If an error occurs, errno is set.  */
Packit Service 672cf4
gpgme_ssize_t
Packit Service 672cf4
gpgme_data_write (gpgme_data_t dh, const void *buffer, size_t size)
Packit Service 672cf4
{
Packit Service 672cf4
  gpgme_ssize_t res;
Packit Service 6c01f9
  TRACE_BEG2 (DEBUG_DATA, "gpgme_data_write", dh,
Packit Service 6c01f9
	      "buffer=%p, size=%u", buffer, size);
Packit Service 672cf4
Packit Service 672cf4
  if (!dh)
Packit Service 672cf4
    {
Packit Service 672cf4
      gpg_err_set_errno (EINVAL);
Packit Service 672cf4
      return TRACE_SYSRES (-1);
Packit Service 672cf4
    }
Packit Service 672cf4
  if (!dh->cbs->write)
Packit Service 672cf4
    {
Packit Service 672cf4
      gpg_err_set_errno (ENOSYS);
Packit Service 672cf4
      return TRACE_SYSRES (-1);
Packit Service 672cf4
    }
Packit Service 672cf4
  do
Packit Service 672cf4
    res = (*dh->cbs->write) (dh, buffer, size);
Packit Service 672cf4
  while (res < 0 && errno == EINTR);
Packit Service 672cf4
Packit Service 6c01f9
  return TRACE_SYSRES (res);
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
/* Set the current position from where the next read or write starts
Packit Service 6c01f9
   in the data object with the handle DH to OFFSET, relativ to
Packit Service 672cf4
   WHENCE.  */
Packit Service 672cf4
gpgme_off_t
Packit Service 672cf4
gpgme_data_seek (gpgme_data_t dh, gpgme_off_t offset, int whence)
Packit Service 672cf4
{
Packit Service 6c01f9
  TRACE_BEG2 (DEBUG_DATA, "gpgme_data_seek", dh,
Packit Service 6c01f9
	      "offset=%lli, whence=%i", offset, whence);
Packit Service 672cf4
Packit Service 672cf4
  if (!dh)
Packit Service 672cf4
    {
Packit Service 672cf4
      gpg_err_set_errno (EINVAL);
Packit Service 672cf4
      return TRACE_SYSRES (-1);
Packit Service 672cf4
    }
Packit Service 672cf4
  if (!dh->cbs->seek)
Packit Service 672cf4
    {
Packit Service 672cf4
      gpg_err_set_errno (ENOSYS);
Packit Service 672cf4
      return TRACE_SYSRES (-1);
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  /* For relative movement, we must take into account the actual
Packit Service 672cf4
     position of the read counter.  */
Packit Service 672cf4
  if (whence == SEEK_CUR)
Packit Service 672cf4
    offset -= dh->pending_len;
Packit Service 672cf4
Packit Service 672cf4
  offset = (*dh->cbs->seek) (dh, offset, whence);
Packit Service 672cf4
  if (offset >= 0)
Packit Service 672cf4
    dh->pending_len = 0;
Packit Service 672cf4
Packit Service 6c01f9
  return TRACE_SYSRES (offset);
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
/* Convenience function to do a gpgme_data_seek (dh, 0, SEEK_SET).  */
Packit Service 672cf4
gpgme_error_t
Packit Service 672cf4
gpgme_data_rewind (gpgme_data_t dh)
Packit Service 672cf4
{
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 6c01f9
  TRACE_BEG (DEBUG_DATA, "gpgme_data_rewind", dh);
Packit Service 672cf4
Packit Service 672cf4
  err = ((gpgme_data_seek (dh, 0, SEEK_SET) == -1)
Packit Service 672cf4
         ? gpg_error_from_syserror () : 0);
Packit Service 672cf4
Packit Service 672cf4
  return TRACE_ERR (err);
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
/* Release the data object with the handle DH.  */
Packit Service 672cf4
void
Packit Service 672cf4
gpgme_data_release (gpgme_data_t dh)
Packit Service 672cf4
{
Packit Service 6c01f9
  TRACE (DEBUG_DATA, "gpgme_data_release", dh);
Packit Service 672cf4
Packit Service 672cf4
  if (!dh)
Packit Service 672cf4
    return;
Packit Service 672cf4
Packit Service 672cf4
  if (dh->cbs->release)
Packit Service 672cf4
    (*dh->cbs->release) (dh);
Packit Service 672cf4
  _gpgme_data_release (dh);
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
/* Get the current encoding meta information for the data object with
Packit Service 672cf4
   handle DH.  */
Packit Service 672cf4
gpgme_data_encoding_t
Packit Service 672cf4
gpgme_data_get_encoding (gpgme_data_t dh)
Packit Service 672cf4
{
Packit Service 6c01f9
  TRACE1 (DEBUG_DATA, "gpgme_data_get_encoding", dh,
Packit Service 6c01f9
	  "dh->encoding=%i", dh ? dh->encoding : GPGME_DATA_ENCODING_NONE);
Packit Service 672cf4
  return dh ? dh->encoding : GPGME_DATA_ENCODING_NONE;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
/* Set the encoding meta information for the data object with handle
Packit Service 672cf4
   DH to ENC.  */
Packit Service 672cf4
gpgme_error_t
Packit Service 672cf4
gpgme_data_set_encoding (gpgme_data_t dh, gpgme_data_encoding_t enc)
Packit Service 672cf4
{
Packit Service 6c01f9
  TRACE_BEG1 (DEBUG_DATA, "gpgme_data_set_encoding", dh,
Packit Service 672cf4
	      "encoding=%i", enc);
Packit Service 672cf4
  if (!dh)
Packit Service 672cf4
    return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
Packit Service 672cf4
  if (enc < 0 || enc > GPGME_DATA_ENCODING_MIME)
Packit Service 672cf4
    return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
Packit Service 672cf4
  dh->encoding = enc;
Packit Service 672cf4
  return TRACE_ERR (0);
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
/* Set the file name associated with the data object with handle DH to
Packit Service 672cf4
   FILE_NAME.  */
Packit Service 672cf4
gpgme_error_t
Packit Service 672cf4
gpgme_data_set_file_name (gpgme_data_t dh, const char *file_name)
Packit Service 672cf4
{
Packit Service 6c01f9
  TRACE_BEG1 (DEBUG_DATA, "gpgme_data_set_file_name", dh,
Packit Service 672cf4
	      "file_name=%s", file_name);
Packit Service 672cf4
Packit Service 672cf4
  if (!dh)
Packit Service 672cf4
    return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
Packit Service 672cf4
Packit Service 672cf4
  if (dh->file_name)
Packit Service 672cf4
    free (dh->file_name);
Packit Service 672cf4
Packit Service 672cf4
  if (file_name)
Packit Service 672cf4
    {
Packit Service 672cf4
      dh->file_name = strdup (file_name);
Packit Service 672cf4
      if (!dh->file_name)
Packit Service 672cf4
	return TRACE_ERR (gpg_error_from_syserror ());
Packit Service 672cf4
    }
Packit Service 672cf4
  else
Packit Service 672cf4
    dh->file_name = 0;
Packit Service 672cf4
Packit Service 672cf4
  return TRACE_ERR (0);
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
/* Get the file name associated with the data object with handle DH,
Packit Service 672cf4
   or NULL if there is none.  */
Packit Service 672cf4
char *
Packit Service 672cf4
gpgme_data_get_file_name (gpgme_data_t dh)
Packit Service 672cf4
{
Packit Service 672cf4
  if (!dh)
Packit Service 672cf4
    {
Packit Service 6c01f9
      TRACE (DEBUG_DATA, "gpgme_data_get_file_name", dh);
Packit Service 672cf4
      return NULL;
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 6c01f9
  TRACE1 (DEBUG_DATA, "gpgme_data_get_file_name", dh,
Packit Service 6c01f9
	  "dh->file_name=%s", dh->file_name);
Packit Service 672cf4
  return dh->file_name;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
/* Set a flag for the data object DH.  See the manual for details.  */
Packit Service 672cf4
gpg_error_t
Packit Service 672cf4
gpgme_data_set_flag (gpgme_data_t dh, const char *name, const char *value)
Packit Service 672cf4
{
Packit Service 6c01f9
  TRACE_BEG2 (DEBUG_DATA, "gpgme_data_set_flag", dh,
Packit Service 672cf4
	      "%s=%s", name, value);
Packit Service 672cf4
Packit Service 672cf4
  if (!dh)
Packit Service 672cf4
    return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
Packit Service 672cf4
Packit Service 672cf4
  if (!strcmp (name, "size-hint"))
Packit Service 672cf4
    {
Packit Service 672cf4
      dh->size_hint= value? _gpgme_string_to_off (value) : 0;
Packit Service 672cf4
    }
Packit Service 672cf4
  else
Packit Service 672cf4
    return gpg_error (GPG_ERR_UNKNOWN_NAME);
Packit Service 672cf4
Packit Service 672cf4
  return 0;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4

Packit Service 672cf4
/* Functions to support the wait interface.  */
Packit Service 672cf4
Packit Service 672cf4
gpgme_error_t
Packit Service 672cf4
_gpgme_data_inbound_handler (void *opaque, int fd)
Packit Service 672cf4
{
Packit Service 672cf4
  struct io_cb_data *data = (struct io_cb_data *) opaque;
Packit Service 672cf4
  gpgme_data_t dh = (gpgme_data_t) data->handler_value;
Packit Service 672cf4
  char buffer[BUFFER_SIZE];
Packit Service 672cf4
  char *bufp = buffer;
Packit Service 672cf4
  gpgme_ssize_t buflen;
Packit Service 6c01f9
  TRACE_BEG1 (DEBUG_CTX, "_gpgme_data_inbound_handler", dh,
Packit Service 6c01f9
	      "fd=0x%x", fd);
Packit Service 672cf4
Packit Service 672cf4
  buflen = _gpgme_io_read (fd, buffer, BUFFER_SIZE);
Packit Service 672cf4
  if (buflen < 0)
Packit Service 672cf4
    return gpg_error_from_syserror ();
Packit Service 672cf4
  if (buflen == 0)
Packit Service 672cf4
    {
Packit Service 672cf4
      _gpgme_io_close (fd);
Packit Service 672cf4
      return TRACE_ERR (0);
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  do
Packit Service 672cf4
    {
Packit Service 672cf4
      gpgme_ssize_t amt = gpgme_data_write (dh, bufp, buflen);
Packit Service 672cf4
      if (amt == 0 || (amt < 0 && errno != EINTR))
Packit Service 672cf4
	return TRACE_ERR (gpg_error_from_syserror ());
Packit Service 672cf4
      bufp += amt;
Packit Service 672cf4
      buflen -= amt;
Packit Service 672cf4
    }
Packit Service 672cf4
  while (buflen > 0);
Packit Service 672cf4
  return TRACE_ERR (0);
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
gpgme_error_t
Packit Service 672cf4
_gpgme_data_outbound_handler (void *opaque, int fd)
Packit Service 672cf4
{
Packit Service 672cf4
  struct io_cb_data *data = (struct io_cb_data *) opaque;
Packit Service 672cf4
  gpgme_data_t dh = (gpgme_data_t) data->handler_value;
Packit Service 672cf4
  gpgme_ssize_t nwritten;
Packit Service 6c01f9
  TRACE_BEG1 (DEBUG_CTX, "_gpgme_data_outbound_handler", dh,
Packit Service 6c01f9
	      "fd=0x%x", fd);
Packit Service 672cf4
Packit Service 672cf4
  if (!dh->pending_len)
Packit Service 672cf4
    {
Packit Service 672cf4
      gpgme_ssize_t amt = gpgme_data_read (dh, dh->pending, BUFFER_SIZE);
Packit Service 672cf4
      if (amt < 0)
Packit Service 672cf4
	return TRACE_ERR (gpg_error_from_syserror ());
Packit Service 672cf4
      if (amt == 0)
Packit Service 672cf4
	{
Packit Service 672cf4
	  _gpgme_io_close (fd);
Packit Service 672cf4
	  return TRACE_ERR (0);
Packit Service 672cf4
	}
Packit Service 672cf4
      dh->pending_len = amt;
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  nwritten = _gpgme_io_write (fd, dh->pending, dh->pending_len);
Packit Service 672cf4
  if (nwritten == -1 && errno == EAGAIN)
Packit Service 672cf4
    return TRACE_ERR (0);
Packit Service 672cf4
Packit Service 672cf4
  if (nwritten == -1 && errno == EPIPE)
Packit Service 672cf4
    {
Packit Service 672cf4
      /* Not much we can do.  The other end closed the pipe, but we
Packit Service 672cf4
	 still have data.  This should only ever happen if the other
Packit Service 672cf4
	 end is going to tell us what happened on some other channel.
Packit Service 672cf4
	 Silently close our end.  */
Packit Service 672cf4
      _gpgme_io_close (fd);
Packit Service 672cf4
      return TRACE_ERR (0);
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  if (nwritten <= 0)
Packit Service 672cf4
    return TRACE_ERR (gpg_error_from_syserror ());
Packit Service 672cf4
Packit Service 672cf4
  if (nwritten < dh->pending_len)
Packit Service 672cf4
    memmove (dh->pending, dh->pending + nwritten, dh->pending_len - nwritten);
Packit Service 672cf4
  dh->pending_len -= nwritten;
Packit Service 672cf4
  return TRACE_ERR (0);
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
/* Get the file descriptor associated with DH, if possible.  Otherwise
Packit Service 672cf4
   return -1.  */
Packit Service 672cf4
int
Packit Service 672cf4
_gpgme_data_get_fd (gpgme_data_t dh)
Packit Service 672cf4
{
Packit Service 672cf4
  if (!dh || !dh->cbs->get_fd)
Packit Service 672cf4
    return -1;
Packit Service 672cf4
  return (*dh->cbs->get_fd) (dh);
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
/* Get the size-hint value for DH or 0 if not available.  */
Packit Service 672cf4
gpgme_off_t
Packit Service 672cf4
_gpgme_data_get_size_hint (gpgme_data_t dh)
Packit Service 672cf4
{
Packit Service 672cf4
  return dh ? dh->size_hint : 0;
Packit Service 672cf4
}