Blame src/data.c

Packit d7e8d0
/* data.c - An abstraction for data objects.
Packit Service 30b792
 * Copyright (C) 2002, 2003, 2004, 2005, 2007 g10 Code GmbH
Packit Service 30b792
 *
Packit Service 30b792
 * This file is part of GPGME.
Packit Service 30b792
 *
Packit Service 30b792
 * GPGME is free software; you can redistribute it and/or modify it
Packit Service 30b792
 * under the terms of the GNU Lesser General Public License as
Packit Service 30b792
 * published by the Free Software Foundation; either version 2.1 of
Packit Service 30b792
 * the License, or (at your option) any later version.
Packit Service 30b792
 *
Packit Service 30b792
 * GPGME is distributed in the hope that it will be useful, but
Packit Service 30b792
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 30b792
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 30b792
 * Lesser General Public License for more details.
Packit Service 30b792
 *
Packit Service 30b792
 * You should have received a copy of the GNU Lesser General Public
Packit Service 30b792
 * License along with this program; if not, see <https://gnu.org/licenses/>.
Packit Service 30b792
 * SPDX-License-Identifier: LGPL-2.1-or-later
Packit Service 30b792
 */
Packit d7e8d0
Packit d7e8d0
#if HAVE_CONFIG_H
Packit d7e8d0
#include <config.h>
Packit d7e8d0
#endif
Packit d7e8d0
Packit d7e8d0
#include <stdlib.h>
Packit d7e8d0
#ifdef HAVE_UNISTD_H
Packit d7e8d0
# include <unistd.h>
Packit d7e8d0
#endif
Packit d7e8d0
#include <errno.h>
Packit d7e8d0
#include <string.h>
Packit Service 30b792
#include <assert.h>
Packit d7e8d0
Packit d7e8d0
#include "gpgme.h"
Packit d7e8d0
#include "data.h"
Packit d7e8d0
#include "util.h"
Packit d7e8d0
#include "ops.h"
Packit d7e8d0
#include "priv-io.h"
Packit d7e8d0
#include "debug.h"
Packit d7e8d0
Packit Service 30b792
Packit Service 30b792
/* The property table which has an entry for each active data object.
Packit Service 30b792
 * The data object itself uses an index into this table and the table
Packit Service 30b792
 * has a pointer back to the data object.  All access to that table is
Packit Service 30b792
 * controlled by the property_table_lock.
Packit Service 30b792
 *
Packit Service 30b792
 * We use a separate table instead of linking all data objects
Packit Service 30b792
 * together for faster locating properties of the data object using
Packit Service 30b792
 * the data objects serial number.  We use 64 bit for the serial
Packit Service 30b792
 * number which is good enough to create a new data object every
Packit Service 30b792
 * nanosecond for more than 500 years.  Thus no wrap around will ever
Packit Service 30b792
 * happen.
Packit Service 30b792
 */
Packit Service 30b792
struct property_s
Packit Service 30b792
{
Packit Service 30b792
  gpgme_data_t dh;   /* The data objcet or NULL if the slot is not used.  */
Packit Service 30b792
  uint64_t dserial;  /* The serial number of the data object.  */
Packit Service 30b792
  struct {
Packit Service 30b792
    unsigned int blankout : 1;  /* Void the held data.  */
Packit Service 30b792
  } flags;
Packit Service 30b792
};
Packit Service 30b792
typedef struct property_s *property_t;
Packit Service 30b792
Packit Service 30b792
static property_t property_table;
Packit Service 30b792
static unsigned int property_table_size;
Packit Service 30b792
DEFINE_STATIC_LOCK (property_table_lock);
Packit Service 30b792
#define PROPERTY_TABLE_ALLOCATION_CHUNK 32
Packit Service 30b792
Packit Service 30b792
Packit Service 30b792

Packit Service 30b792
/* Insert the newly created data object DH into the property table and
Packit Service 30b792
 * store the index of it at R_IDX.  An error code is returned on error
Packit Service 30b792
 * and the table is not changed.  */
Packit Service 30b792
static gpg_error_t
Packit Service 30b792
insert_into_property_table (gpgme_data_t dh, unsigned int *r_idx)
Packit Service 30b792
{
Packit Service 30b792
  static uint64_t last_dserial;
Packit Service 30b792
  gpg_error_t err;
Packit Service 30b792
  unsigned int idx;
Packit Service 30b792
Packit Service 30b792
  LOCK (property_table_lock);
Packit Service 30b792
  if (!property_table)
Packit Service 30b792
    {
Packit Service 30b792
      property_table_size = PROPERTY_TABLE_ALLOCATION_CHUNK;
Packit Service 30b792
      property_table = calloc (property_table_size, sizeof *property_table);
Packit Service 30b792
      if (!property_table)
Packit Service 30b792
        {
Packit Service 30b792
          err = gpg_error_from_syserror ();
Packit Service 30b792
          goto leave;
Packit Service 30b792
        }
Packit Service 30b792
    }
Packit Service 30b792
Packit Service 30b792
  /* Find an empty slot.  */
Packit Service 30b792
  for (idx = 0; idx < property_table_size; idx++)
Packit Service 30b792
    if (!property_table[idx].dh)
Packit Service 30b792
      break;
Packit Service 30b792
  if (!(idx < property_table_size))
Packit Service 30b792
    {
Packit Service 30b792
      /* No empty slot found.  Enlarge the table.  */
Packit Service 30b792
      property_t newtbl;
Packit Service 30b792
      unsigned int newsize;
Packit Service 30b792
Packit Service 30b792
      newsize = property_table_size + PROPERTY_TABLE_ALLOCATION_CHUNK;;
Packit Service 30b792
      if ((newsize * sizeof *property_table)
Packit Service 30b792
          < (property_table_size * sizeof *property_table))
Packit Service 30b792
        {
Packit Service 30b792
          err = gpg_error (GPG_ERR_ENOMEM);
Packit Service 30b792
          goto leave;
Packit Service 30b792
        }
Packit Service 30b792
      newtbl = realloc (property_table, newsize * sizeof *property_table);
Packit Service 30b792
      if (!newtbl)
Packit Service 30b792
        {
Packit Service 30b792
          err = gpg_error_from_syserror ();
Packit Service 30b792
          goto leave;
Packit Service 30b792
        }
Packit Service 30b792
      property_table = newtbl;
Packit Service 30b792
      for (idx = property_table_size; idx < newsize; idx++)
Packit Service 30b792
        property_table[idx].dh = NULL;
Packit Service 30b792
      idx = property_table_size;
Packit Service 30b792
      property_table_size = newsize;
Packit Service 30b792
    }
Packit Service 30b792
Packit Service 30b792
  /* Slot found. */
Packit Service 30b792
  property_table[idx].dh = dh;
Packit Service 30b792
  property_table[idx].dserial = ++last_dserial;
Packit Service 30b792
  memset (&property_table[idx].flags, 0, sizeof property_table[idx].flags);
Packit Service 30b792
  *r_idx = idx;
Packit Service 30b792
  err = 0;
Packit Service 30b792
Packit Service 30b792
 leave:
Packit Service 30b792
  UNLOCK (property_table_lock);
Packit Service 30b792
  return err;
Packit Service 30b792
}
Packit Service 30b792
Packit Service 30b792
Packit Service 30b792
/* Remove the data object at PROPIDX from the table.  DH is only used
Packit Service 30b792
 * for cross checking.  */
Packit Service 30b792
static void
Packit Service 30b792
remove_from_property_table (gpgme_data_t dh, unsigned int propidx)
Packit Service 30b792
{
Packit Service 30b792
  LOCK (property_table_lock);
Packit Service 30b792
  assert (property_table);
Packit Service 30b792
  assert (propidx < property_table_size);
Packit Service 30b792
  assert (property_table[propidx].dh == dh);
Packit Service 30b792
  property_table[propidx].dh = NULL;
Packit Service 30b792
  UNLOCK (property_table_lock);
Packit Service 30b792
}
Packit Service 30b792
Packit Service 30b792
Packit Service 30b792
/* Return the data object's serial number for handle DH.  This is a
Packit Service 30b792
 * unique serial number for each created data object.  */
Packit Service 30b792
uint64_t
Packit Service 30b792
_gpgme_data_get_dserial (gpgme_data_t dh)
Packit Service 30b792
{
Packit Service 30b792
  uint64_t dserial;
Packit Service 30b792
  unsigned int idx;
Packit Service 30b792
Packit Service 30b792
  if (!dh)
Packit Service 30b792
    return 0;
Packit Service 30b792
Packit Service 30b792
  idx = dh->propidx;
Packit Service 30b792
  LOCK (property_table_lock);
Packit Service 30b792
  assert (property_table);
Packit Service 30b792
  assert (idx < property_table_size);
Packit Service 30b792
  assert (property_table[idx].dh == dh);
Packit Service 30b792
  dserial = property_table[idx].dserial;
Packit Service 30b792
  UNLOCK (property_table_lock);
Packit Service 30b792
Packit Service 30b792
  return dserial;
Packit Service 30b792
}
Packit Service 30b792
Packit Service 30b792
Packit Service 30b792
/* Set an internal property of a data object.  The data object may
Packit Service 30b792
 * either be identified by the usual DH or by using the data serial
Packit Service 30b792
 * number DSERIAL.  */
Packit Service 30b792
gpg_error_t
Packit Service 30b792
_gpgme_data_set_prop (gpgme_data_t dh, uint64_t dserial,
Packit Service 30b792
                      data_prop_t name, int value)
Packit Service 30b792
{
Packit Service 30b792
  gpg_error_t err = 0;
Packit Service 30b792
  int idx;
Packit Service 30b792
  TRACE_BEG  (DEBUG_DATA, "gpgme_data_set_prop", dh,
Packit Service 30b792
	      "dserial=%llu %lu=%d",
Packit Service 30b792
              (unsigned long long)dserial,
Packit Service 30b792
              (unsigned long)name, value);
Packit Service 30b792
Packit Service 30b792
  LOCK (property_table_lock);
Packit Service 30b792
  if ((!dh && !dserial) || (dh && dserial))
Packit Service 30b792
    {
Packit Service 30b792
      err = gpg_error (GPG_ERR_INV_VALUE);
Packit Service 30b792
      goto leave;
Packit Service 30b792
    }
Packit Service 30b792
  if (dh) /* Lookup via handle.  */
Packit Service 30b792
    {
Packit Service 30b792
      idx = dh->propidx;
Packit Service 30b792
      assert (property_table);
Packit Service 30b792
      assert (idx < property_table_size);
Packit Service 30b792
      assert (property_table[idx].dh == dh);
Packit Service 30b792
    }
Packit Service 30b792
  else /* Lookup via DSERIAL.  */
Packit Service 30b792
    {
Packit Service 30b792
      if (!property_table)
Packit Service 30b792
        {
Packit Service 30b792
          err = gpg_error (GPG_ERR_NOT_FOUND);
Packit Service 30b792
          goto leave;
Packit Service 30b792
        }
Packit Service 30b792
      for (idx = 0; idx < property_table_size; idx++)
Packit Service 30b792
        if (property_table[idx].dh && property_table[idx].dserial == dserial)
Packit Service 30b792
          break;
Packit Service 30b792
      if (!(idx < property_table_size))
Packit Service 30b792
        {
Packit Service 30b792
          err = gpg_error (GPG_ERR_NOT_FOUND);
Packit Service 30b792
          goto leave;
Packit Service 30b792
        }
Packit Service 30b792
    }
Packit Service 30b792
Packit Service 30b792
  switch (name)
Packit Service 30b792
    {
Packit Service 30b792
    case DATA_PROP_NONE: /* Nothing to to do.  */
Packit Service 30b792
      break;
Packit Service 30b792
    case DATA_PROP_BLANKOUT:
Packit Service 30b792
      property_table[idx].flags.blankout = !!value;
Packit Service 30b792
      break;
Packit Service 30b792
Packit Service 30b792
    default:
Packit Service 30b792
      err = gpg_error (GPG_ERR_UNKNOWN_NAME);
Packit Service 30b792
      break;
Packit Service 30b792
    }
Packit Service 30b792
Packit Service 30b792
 leave:
Packit Service 30b792
  UNLOCK (property_table_lock);
Packit Service 30b792
  return TRACE_ERR (err);
Packit Service 30b792
}
Packit Service 30b792
Packit Service 30b792
Packit Service 30b792
/* Get an internal property of a data object.  This is the counter
Packit Service 30b792
 * part to _gpgme_data_set_property.  The value of the property is
Packit Service 30b792
 * stored at R_VALUE.  On error 0 is stored at R_VALUE.  */
Packit Service 30b792
gpg_error_t
Packit Service 30b792
_gpgme_data_get_prop (gpgme_data_t dh, uint64_t dserial,
Packit Service 30b792
                      data_prop_t name, int *r_value)
Packit Service 30b792
{
Packit Service 30b792
  gpg_error_t err = 0;
Packit Service 30b792
  int idx;
Packit Service 30b792
  TRACE_BEG  (DEBUG_DATA, "gpgme_data_get_prop", dh,
Packit Service 30b792
	      "dserial=%llu %lu",
Packit Service 30b792
              (unsigned long long)dserial,
Packit Service 30b792
              (unsigned long)name);
Packit Service 30b792
Packit Service 30b792
  *r_value = 0;
Packit Service 30b792
Packit Service 30b792
  LOCK (property_table_lock);
Packit Service 30b792
  if ((!dh && !dserial) || (dh && dserial))
Packit Service 30b792
    {
Packit Service 30b792
      err = gpg_error (GPG_ERR_INV_VALUE);
Packit Service 30b792
      goto leave;
Packit Service 30b792
    }
Packit Service 30b792
  if (dh) /* Lookup via handle.  */
Packit Service 30b792
    {
Packit Service 30b792
      idx = dh->propidx;
Packit Service 30b792
      assert (property_table);
Packit Service 30b792
      assert (idx < property_table_size);
Packit Service 30b792
      assert (property_table[idx].dh == dh);
Packit Service 30b792
    }
Packit Service 30b792
  else /* Lookup via DSERIAL.  */
Packit Service 30b792
    {
Packit Service 30b792
      if (!property_table)
Packit Service 30b792
        {
Packit Service 30b792
          err = gpg_error (GPG_ERR_NOT_FOUND);
Packit Service 30b792
          goto leave;
Packit Service 30b792
        }
Packit Service 30b792
      for (idx = 0; idx < property_table_size; idx++)
Packit Service 30b792
        if (property_table[idx].dh && property_table[idx].dserial == dserial)
Packit Service 30b792
          break;
Packit Service 30b792
      if (!(idx < property_table_size))
Packit Service 30b792
        {
Packit Service 30b792
          err = gpg_error (GPG_ERR_NOT_FOUND);
Packit Service 30b792
          goto leave;
Packit Service 30b792
        }
Packit Service 30b792
    }
Packit Service 30b792
Packit Service 30b792
  switch (name)
Packit Service 30b792
    {
Packit Service 30b792
    case DATA_PROP_NONE: /* Nothing to to do.  */
Packit Service 30b792
      break;
Packit Service 30b792
    case DATA_PROP_BLANKOUT:
Packit Service 30b792
      *r_value = property_table[idx].flags.blankout;
Packit Service 30b792
      break;
Packit Service 30b792
Packit Service 30b792
    default:
Packit Service 30b792
      err = gpg_error (GPG_ERR_UNKNOWN_NAME);
Packit Service 30b792
      break;
Packit Service 30b792
    }
Packit Service 30b792
Packit Service 30b792
 leave:
Packit Service 30b792
  UNLOCK (property_table_lock);
Packit Service 30b792
  return TRACE_ERR (err);
Packit Service 30b792
}
Packit Service 30b792
Packit Service 30b792
Packit d7e8d0

Packit d7e8d0
gpgme_error_t
Packit d7e8d0
_gpgme_data_new (gpgme_data_t *r_dh, struct _gpgme_data_cbs *cbs)
Packit d7e8d0
{
Packit Service 30b792
  gpgme_error_t err;
Packit d7e8d0
  gpgme_data_t dh;
Packit d7e8d0
Packit d7e8d0
  if (!r_dh)
Packit d7e8d0
    return gpg_error (GPG_ERR_INV_VALUE);
Packit d7e8d0
Packit d7e8d0
  *r_dh = NULL;
Packit d7e8d0
Packit d7e8d0
  if (_gpgme_selftest)
Packit d7e8d0
    return _gpgme_selftest;
Packit d7e8d0
Packit d7e8d0
  dh = calloc (1, sizeof (*dh));
Packit d7e8d0
  if (!dh)
Packit d7e8d0
    return gpg_error_from_syserror ();
Packit d7e8d0
Packit d7e8d0
  dh->cbs = cbs;
Packit d7e8d0
Packit Service 30b792
  err = insert_into_property_table (dh, &dh->propidx);
Packit Service 30b792
  if (err)
Packit Service 30b792
    {
Packit Service 30b792
      free (dh);
Packit Service 30b792
      return err;
Packit Service 30b792
    }
Packit Service 30b792
Packit d7e8d0
  *r_dh = dh;
Packit d7e8d0
  return 0;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
void
Packit d7e8d0
_gpgme_data_release (gpgme_data_t dh)
Packit d7e8d0
{
Packit d7e8d0
  if (!dh)
Packit d7e8d0
    return;
Packit d7e8d0
Packit Service 30b792
  remove_from_property_table (dh, dh->propidx);
Packit d7e8d0
  if (dh->file_name)
Packit d7e8d0
    free (dh->file_name);
Packit d7e8d0
  free (dh);
Packit d7e8d0
}
Packit d7e8d0
Packit Service 30b792
Packit d7e8d0

Packit d7e8d0
/* Read up to SIZE bytes into buffer BUFFER from the data object with
Packit d7e8d0
   the handle DH.  Return the number of characters read, 0 on EOF and
Packit d7e8d0
   -1 on error.  If an error occurs, errno is set.  */
Packit d7e8d0
gpgme_ssize_t
Packit d7e8d0
gpgme_data_read (gpgme_data_t dh, void *buffer, size_t size)
Packit d7e8d0
{
Packit d7e8d0
  gpgme_ssize_t res;
Packit Service 30b792
  int blankout;
Packit Service 30b792
  TRACE_BEG  (DEBUG_DATA, "gpgme_data_read", dh,
Packit Service 30b792
	      "buffer=%p, size=%zu", buffer, size);
Packit d7e8d0
Packit d7e8d0
  if (!dh)
Packit d7e8d0
    {
Packit d7e8d0
      gpg_err_set_errno (EINVAL);
Packit d7e8d0
      return TRACE_SYSRES (-1);
Packit d7e8d0
    }
Packit d7e8d0
  if (!dh->cbs->read)
Packit d7e8d0
    {
Packit d7e8d0
      gpg_err_set_errno (ENOSYS);
Packit d7e8d0
      return TRACE_SYSRES (-1);
Packit d7e8d0
    }
Packit d7e8d0
Packit Service 30b792
  if (_gpgme_data_get_prop (dh, 0, DATA_PROP_BLANKOUT, &blankout)
Packit Service 30b792
      || blankout)
Packit Service 30b792
    res = 0;
Packit Service 30b792
  else
Packit Service 30b792
    {
Packit Service 30b792
      do
Packit Service 30b792
        res = (*dh->cbs->read) (dh, buffer, size);
Packit Service 30b792
      while (res < 0 && errno == EINTR);
Packit Service 30b792
    }
Packit Service 30b792
Packit Service 30b792
  return TRACE_SYSRES ((int)res);
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
/* Write up to SIZE bytes from buffer BUFFER to the data object with
Packit d7e8d0
   the handle DH.  Return the number of characters written, or -1 on
Packit d7e8d0
   error.  If an error occurs, errno is set.  */
Packit d7e8d0
gpgme_ssize_t
Packit d7e8d0
gpgme_data_write (gpgme_data_t dh, const void *buffer, size_t size)
Packit d7e8d0
{
Packit d7e8d0
  gpgme_ssize_t res;
Packit Service 30b792
  TRACE_BEG  (DEBUG_DATA, "gpgme_data_write", dh,
Packit Service 30b792
	      "buffer=%p, size=%zu", buffer, size);
Packit d7e8d0
Packit d7e8d0
  if (!dh)
Packit d7e8d0
    {
Packit d7e8d0
      gpg_err_set_errno (EINVAL);
Packit d7e8d0
      return TRACE_SYSRES (-1);
Packit d7e8d0
    }
Packit d7e8d0
  if (!dh->cbs->write)
Packit d7e8d0
    {
Packit d7e8d0
      gpg_err_set_errno (ENOSYS);
Packit d7e8d0
      return TRACE_SYSRES (-1);
Packit d7e8d0
    }
Packit d7e8d0
  do
Packit d7e8d0
    res = (*dh->cbs->write) (dh, buffer, size);
Packit d7e8d0
  while (res < 0 && errno == EINTR);
Packit d7e8d0
Packit Service 30b792
  return TRACE_SYSRES ((int)res);
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
/* Set the current position from where the next read or write starts
Packit Service 30b792
   in the data object with the handle DH to OFFSET, relative to
Packit d7e8d0
   WHENCE.  */
Packit d7e8d0
gpgme_off_t
Packit d7e8d0
gpgme_data_seek (gpgme_data_t dh, gpgme_off_t offset, int whence)
Packit d7e8d0
{
Packit Service 30b792
  TRACE_BEG  (DEBUG_DATA, "gpgme_data_seek", dh,
Packit Service 30b792
	      "offset=%lli, whence=%i", (long long int)offset, whence);
Packit d7e8d0
Packit d7e8d0
  if (!dh)
Packit d7e8d0
    {
Packit d7e8d0
      gpg_err_set_errno (EINVAL);
Packit d7e8d0
      return TRACE_SYSRES (-1);
Packit d7e8d0
    }
Packit d7e8d0
  if (!dh->cbs->seek)
Packit d7e8d0
    {
Packit d7e8d0
      gpg_err_set_errno (ENOSYS);
Packit d7e8d0
      return TRACE_SYSRES (-1);
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  /* For relative movement, we must take into account the actual
Packit d7e8d0
     position of the read counter.  */
Packit d7e8d0
  if (whence == SEEK_CUR)
Packit d7e8d0
    offset -= dh->pending_len;
Packit d7e8d0
Packit d7e8d0
  offset = (*dh->cbs->seek) (dh, offset, whence);
Packit d7e8d0
  if (offset >= 0)
Packit d7e8d0
    dh->pending_len = 0;
Packit d7e8d0
Packit Service 30b792
  return TRACE_SYSRES ((int)offset);
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
/* Convenience function to do a gpgme_data_seek (dh, 0, SEEK_SET).  */
Packit d7e8d0
gpgme_error_t
Packit d7e8d0
gpgme_data_rewind (gpgme_data_t dh)
Packit d7e8d0
{
Packit d7e8d0
  gpgme_error_t err;
Packit Service 30b792
  TRACE_BEG  (DEBUG_DATA, "gpgme_data_rewind", dh, "");
Packit d7e8d0
Packit d7e8d0
  err = ((gpgme_data_seek (dh, 0, SEEK_SET) == -1)
Packit d7e8d0
         ? gpg_error_from_syserror () : 0);
Packit d7e8d0
Packit d7e8d0
  return TRACE_ERR (err);
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
/* Release the data object with the handle DH.  */
Packit d7e8d0
void
Packit d7e8d0
gpgme_data_release (gpgme_data_t dh)
Packit d7e8d0
{
Packit Service 30b792
  TRACE (DEBUG_DATA, "gpgme_data_release", dh, "");
Packit d7e8d0
Packit d7e8d0
  if (!dh)
Packit d7e8d0
    return;
Packit d7e8d0
Packit d7e8d0
  if (dh->cbs->release)
Packit d7e8d0
    (*dh->cbs->release) (dh);
Packit d7e8d0
  _gpgme_data_release (dh);
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
/* Get the current encoding meta information for the data object with
Packit d7e8d0
   handle DH.  */
Packit d7e8d0
gpgme_data_encoding_t
Packit d7e8d0
gpgme_data_get_encoding (gpgme_data_t dh)
Packit d7e8d0
{
Packit Service 30b792
  TRACE (DEBUG_DATA, "gpgme_data_get_encoding", dh,
Packit Service 30b792
         "dh->encoding=%i", dh ? dh->encoding : GPGME_DATA_ENCODING_NONE);
Packit d7e8d0
  return dh ? dh->encoding : GPGME_DATA_ENCODING_NONE;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
/* Set the encoding meta information for the data object with handle
Packit d7e8d0
   DH to ENC.  */
Packit d7e8d0
gpgme_error_t
Packit d7e8d0
gpgme_data_set_encoding (gpgme_data_t dh, gpgme_data_encoding_t enc)
Packit d7e8d0
{
Packit Service 30b792
  TRACE_BEG  (DEBUG_DATA, "gpgme_data_set_encoding", dh,
Packit d7e8d0
	      "encoding=%i", enc);
Packit d7e8d0
  if (!dh)
Packit d7e8d0
    return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
Packit d7e8d0
  if (enc < 0 || enc > GPGME_DATA_ENCODING_MIME)
Packit d7e8d0
    return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
Packit d7e8d0
  dh->encoding = enc;
Packit d7e8d0
  return TRACE_ERR (0);
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
/* Set the file name associated with the data object with handle DH to
Packit d7e8d0
   FILE_NAME.  */
Packit d7e8d0
gpgme_error_t
Packit d7e8d0
gpgme_data_set_file_name (gpgme_data_t dh, const char *file_name)
Packit d7e8d0
{
Packit Service 30b792
  TRACE_BEG  (DEBUG_DATA, "gpgme_data_set_file_name", dh,
Packit d7e8d0
	      "file_name=%s", file_name);
Packit d7e8d0
Packit d7e8d0
  if (!dh)
Packit d7e8d0
    return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
Packit d7e8d0
Packit d7e8d0
  if (dh->file_name)
Packit d7e8d0
    free (dh->file_name);
Packit d7e8d0
Packit d7e8d0
  if (file_name)
Packit d7e8d0
    {
Packit d7e8d0
      dh->file_name = strdup (file_name);
Packit d7e8d0
      if (!dh->file_name)
Packit d7e8d0
	return TRACE_ERR (gpg_error_from_syserror ());
Packit d7e8d0
    }
Packit d7e8d0
  else
Packit d7e8d0
    dh->file_name = 0;
Packit d7e8d0
Packit d7e8d0
  return TRACE_ERR (0);
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
/* Get the file name associated with the data object with handle DH,
Packit d7e8d0
   or NULL if there is none.  */
Packit d7e8d0
char *
Packit d7e8d0
gpgme_data_get_file_name (gpgme_data_t dh)
Packit d7e8d0
{
Packit d7e8d0
  if (!dh)
Packit d7e8d0
    {
Packit Service 30b792
      TRACE (DEBUG_DATA, "gpgme_data_get_file_name", dh, "");
Packit d7e8d0
      return NULL;
Packit d7e8d0
    }
Packit d7e8d0
Packit Service 30b792
  TRACE (DEBUG_DATA, "gpgme_data_get_file_name", dh,
Packit Service 30b792
         "dh->file_name=%s", dh->file_name);
Packit d7e8d0
  return dh->file_name;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
/* Set a flag for the data object DH.  See the manual for details.  */
Packit d7e8d0
gpg_error_t
Packit d7e8d0
gpgme_data_set_flag (gpgme_data_t dh, const char *name, const char *value)
Packit d7e8d0
{
Packit Service 30b792
  TRACE_BEG  (DEBUG_DATA, "gpgme_data_set_flag", dh,
Packit d7e8d0
	      "%s=%s", name, value);
Packit d7e8d0
Packit d7e8d0
  if (!dh)
Packit d7e8d0
    return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
Packit d7e8d0
Packit d7e8d0
  if (!strcmp (name, "size-hint"))
Packit d7e8d0
    {
Packit d7e8d0
      dh->size_hint= value? _gpgme_string_to_off (value) : 0;
Packit d7e8d0
    }
Packit d7e8d0
  else
Packit d7e8d0
    return gpg_error (GPG_ERR_UNKNOWN_NAME);
Packit d7e8d0
Packit d7e8d0
  return 0;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0

Packit d7e8d0
/* Functions to support the wait interface.  */
Packit d7e8d0
Packit d7e8d0
gpgme_error_t
Packit d7e8d0
_gpgme_data_inbound_handler (void *opaque, int fd)
Packit d7e8d0
{
Packit d7e8d0
  struct io_cb_data *data = (struct io_cb_data *) opaque;
Packit d7e8d0
  gpgme_data_t dh = (gpgme_data_t) data->handler_value;
Packit d7e8d0
  char buffer[BUFFER_SIZE];
Packit d7e8d0
  char *bufp = buffer;
Packit d7e8d0
  gpgme_ssize_t buflen;
Packit Service 30b792
  TRACE_BEG  (DEBUG_CTX, "_gpgme_data_inbound_handler", dh,
Packit Service 30b792
	      "fd=%d", fd);
Packit d7e8d0
Packit d7e8d0
  buflen = _gpgme_io_read (fd, buffer, BUFFER_SIZE);
Packit d7e8d0
  if (buflen < 0)
Packit d7e8d0
    return gpg_error_from_syserror ();
Packit d7e8d0
  if (buflen == 0)
Packit d7e8d0
    {
Packit d7e8d0
      _gpgme_io_close (fd);
Packit d7e8d0
      return TRACE_ERR (0);
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  do
Packit d7e8d0
    {
Packit d7e8d0
      gpgme_ssize_t amt = gpgme_data_write (dh, bufp, buflen);
Packit d7e8d0
      if (amt == 0 || (amt < 0 && errno != EINTR))
Packit d7e8d0
	return TRACE_ERR (gpg_error_from_syserror ());
Packit d7e8d0
      bufp += amt;
Packit d7e8d0
      buflen -= amt;
Packit d7e8d0
    }
Packit d7e8d0
  while (buflen > 0);
Packit d7e8d0
  return TRACE_ERR (0);
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
gpgme_error_t
Packit d7e8d0
_gpgme_data_outbound_handler (void *opaque, int fd)
Packit d7e8d0
{
Packit d7e8d0
  struct io_cb_data *data = (struct io_cb_data *) opaque;
Packit d7e8d0
  gpgme_data_t dh = (gpgme_data_t) data->handler_value;
Packit d7e8d0
  gpgme_ssize_t nwritten;
Packit Service 30b792
  TRACE_BEG  (DEBUG_CTX, "_gpgme_data_outbound_handler", dh,
Packit Service 30b792
	      "fd=%d", fd);
Packit d7e8d0
Packit d7e8d0
  if (!dh->pending_len)
Packit d7e8d0
    {
Packit d7e8d0
      gpgme_ssize_t amt = gpgme_data_read (dh, dh->pending, BUFFER_SIZE);
Packit d7e8d0
      if (amt < 0)
Packit d7e8d0
	return TRACE_ERR (gpg_error_from_syserror ());
Packit d7e8d0
      if (amt == 0)
Packit d7e8d0
	{
Packit d7e8d0
	  _gpgme_io_close (fd);
Packit d7e8d0
	  return TRACE_ERR (0);
Packit d7e8d0
	}
Packit d7e8d0
      dh->pending_len = amt;
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  nwritten = _gpgme_io_write (fd, dh->pending, dh->pending_len);
Packit d7e8d0
  if (nwritten == -1 && errno == EAGAIN)
Packit d7e8d0
    return TRACE_ERR (0);
Packit d7e8d0
Packit d7e8d0
  if (nwritten == -1 && errno == EPIPE)
Packit d7e8d0
    {
Packit d7e8d0
      /* Not much we can do.  The other end closed the pipe, but we
Packit d7e8d0
	 still have data.  This should only ever happen if the other
Packit d7e8d0
	 end is going to tell us what happened on some other channel.
Packit d7e8d0
	 Silently close our end.  */
Packit d7e8d0
      _gpgme_io_close (fd);
Packit d7e8d0
      return TRACE_ERR (0);
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  if (nwritten <= 0)
Packit d7e8d0
    return TRACE_ERR (gpg_error_from_syserror ());
Packit d7e8d0
Packit d7e8d0
  if (nwritten < dh->pending_len)
Packit d7e8d0
    memmove (dh->pending, dh->pending + nwritten, dh->pending_len - nwritten);
Packit d7e8d0
  dh->pending_len -= nwritten;
Packit d7e8d0
  return TRACE_ERR (0);
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
/* Get the file descriptor associated with DH, if possible.  Otherwise
Packit d7e8d0
   return -1.  */
Packit d7e8d0
int
Packit d7e8d0
_gpgme_data_get_fd (gpgme_data_t dh)
Packit d7e8d0
{
Packit d7e8d0
  if (!dh || !dh->cbs->get_fd)
Packit d7e8d0
    return -1;
Packit d7e8d0
  return (*dh->cbs->get_fd) (dh);
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
/* Get the size-hint value for DH or 0 if not available.  */
Packit d7e8d0
gpgme_off_t
Packit d7e8d0
_gpgme_data_get_size_hint (gpgme_data_t dh)
Packit d7e8d0
{
Packit d7e8d0
  return dh ? dh->size_hint : 0;
Packit d7e8d0
}