Blame src/data-mem.c

Packit Service 672cf4
/* data-mem.c - A memory based data object.
Packit Service 6c01f9
   Copyright (C) 2002, 2003, 2004, 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 <errno.h>
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 <assert.h>
Packit Service 672cf4
#include <string.h>
Packit Service 672cf4
Packit Service 672cf4
#include "data.h"
Packit Service 672cf4
#include "util.h"
Packit Service 672cf4
#include "debug.h"
Packit Service 672cf4
Packit Service 672cf4

Packit Service 672cf4
static gpgme_ssize_t
Packit Service 672cf4
mem_read (gpgme_data_t dh, void *buffer, size_t size)
Packit Service 672cf4
{
Packit Service 672cf4
  size_t amt = dh->data.mem.length - dh->data.mem.offset;
Packit Service 672cf4
  const char *src;
Packit Service 672cf4
Packit Service 672cf4
  if (!amt)
Packit Service 672cf4
    return 0;
Packit Service 672cf4
Packit Service 672cf4
  if (size < amt)
Packit Service 672cf4
    amt = size;
Packit Service 672cf4
Packit Service 672cf4
  src = dh->data.mem.buffer ? dh->data.mem.buffer : dh->data.mem.orig_buffer;
Packit Service 672cf4
  memcpy (buffer, src + dh->data.mem.offset, amt);
Packit Service 672cf4
  dh->data.mem.offset += amt;
Packit Service 672cf4
  return amt;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_ssize_t
Packit Service 672cf4
mem_write (gpgme_data_t dh, const void *buffer, size_t size)
Packit Service 672cf4
{
Packit Service 672cf4
  size_t unused;
Packit Service 672cf4
Packit Service 672cf4
  if (!dh->data.mem.buffer && dh->data.mem.orig_buffer)
Packit Service 672cf4
    {
Packit Service 672cf4
      size_t new_size = dh->data.mem.size;
Packit Service 672cf4
      char *new_buffer;
Packit Service 672cf4
Packit Service 672cf4
      if (new_size < dh->data.mem.offset + size)
Packit Service 672cf4
	new_size = dh->data.mem.offset + size;
Packit Service 672cf4
Packit Service 672cf4
      new_buffer = malloc (new_size);
Packit Service 672cf4
      if (!new_buffer)
Packit Service 672cf4
	return -1;
Packit Service 672cf4
      memcpy (new_buffer, dh->data.mem.orig_buffer, dh->data.mem.length);
Packit Service 672cf4
Packit Service 672cf4
      dh->data.mem.buffer = new_buffer;
Packit Service 672cf4
      dh->data.mem.size = new_size;
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  unused = dh->data.mem.size - dh->data.mem.offset;
Packit Service 672cf4
  if (unused < size)
Packit Service 672cf4
    {
Packit Service 672cf4
      /* Allocate a large enough buffer with exponential backoff.  */
Packit Service 672cf4
#define INITIAL_ALLOC 512
Packit Service 672cf4
      size_t new_size = dh->data.mem.size
Packit Service 672cf4
	? (2 * dh->data.mem.size) : INITIAL_ALLOC;
Packit Service 672cf4
      char *new_buffer;
Packit Service 672cf4
Packit Service 672cf4
      if (new_size < dh->data.mem.offset + size)
Packit Service 672cf4
	new_size = dh->data.mem.offset + size;
Packit Service 672cf4
Packit Service 672cf4
      new_buffer = realloc (dh->data.mem.buffer, new_size);
Packit Service 672cf4
      if (!new_buffer && new_size > dh->data.mem.offset + size)
Packit Service 672cf4
	{
Packit Service 672cf4
	  /* Maybe we were too greedy, try again.  */
Packit Service 672cf4
	  new_size = dh->data.mem.offset + size;
Packit Service 672cf4
	  new_buffer = realloc (dh->data.mem.buffer, new_size);
Packit Service 672cf4
	}
Packit Service 672cf4
      if (!new_buffer)
Packit Service 672cf4
	return -1;
Packit Service 672cf4
      dh->data.mem.buffer = new_buffer;
Packit Service 672cf4
      dh->data.mem.size = new_size;
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  memcpy (dh->data.mem.buffer + dh->data.mem.offset, buffer, size);
Packit Service 672cf4
  dh->data.mem.offset += size;
Packit Service 672cf4
  if (dh->data.mem.length < dh->data.mem.offset)
Packit Service 672cf4
    dh->data.mem.length = dh->data.mem.offset;
Packit Service 672cf4
  return size;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_off_t
Packit Service 672cf4
mem_seek (gpgme_data_t dh, gpgme_off_t offset, int whence)
Packit Service 672cf4
{
Packit Service 672cf4
  switch (whence)
Packit Service 672cf4
    {
Packit Service 672cf4
    case SEEK_SET:
Packit Service 672cf4
      if (offset < 0 || offset > dh->data.mem.length)
Packit Service 672cf4
	{
Packit Service 672cf4
	  gpg_err_set_errno (EINVAL);
Packit Service 672cf4
	  return -1;
Packit Service 672cf4
	}
Packit Service 672cf4
      dh->data.mem.offset = offset;
Packit Service 672cf4
      break;
Packit Service 672cf4
    case SEEK_CUR:
Packit Service 672cf4
      if ((offset > 0 && dh->data.mem.length - dh->data.mem.offset < offset)
Packit Service 672cf4
	  || (offset < 0 && dh->data.mem.offset < -offset))
Packit Service 672cf4
	{
Packit Service 672cf4
	  gpg_err_set_errno (EINVAL);
Packit Service 672cf4
	  return -1;
Packit Service 672cf4
	}
Packit Service 672cf4
      dh->data.mem.offset += offset;
Packit Service 672cf4
      break;
Packit Service 672cf4
    case SEEK_END:
Packit Service 672cf4
      if (offset > 0 || -offset > dh->data.mem.length)
Packit Service 672cf4
	{
Packit Service 672cf4
	  gpg_err_set_errno (EINVAL);
Packit Service 672cf4
	  return -1;
Packit Service 672cf4
	}
Packit Service 672cf4
      dh->data.mem.offset = dh->data.mem.length + offset;
Packit Service 672cf4
      break;
Packit Service 672cf4
    default:
Packit Service 672cf4
      gpg_err_set_errno (EINVAL);
Packit Service 672cf4
      return -1;
Packit Service 672cf4
    }
Packit Service 672cf4
  return dh->data.mem.offset;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static void
Packit Service 672cf4
mem_release (gpgme_data_t dh)
Packit Service 672cf4
{
Packit Service 672cf4
  if (dh->data.mem.buffer)
Packit Service 672cf4
    free (dh->data.mem.buffer);
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static struct _gpgme_data_cbs mem_cbs =
Packit Service 672cf4
  {
Packit Service 672cf4
    mem_read,
Packit Service 672cf4
    mem_write,
Packit Service 672cf4
    mem_seek,
Packit Service 672cf4
    mem_release,
Packit Service 672cf4
    NULL
Packit Service 672cf4
  };
Packit Service 672cf4
Packit Service 672cf4

Packit Service 672cf4
/* Create a new data buffer and return it in R_DH.  */
Packit Service 672cf4
gpgme_error_t
Packit Service 672cf4
gpgme_data_new (gpgme_data_t *r_dh)
Packit Service 672cf4
{
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 6c01f9
  TRACE_BEG (DEBUG_DATA, "gpgme_data_new", r_dh);
Packit Service 672cf4
Packit Service 672cf4
  err = _gpgme_data_new (r_dh, &mem_cbs);
Packit Service 672cf4
Packit Service 672cf4
  if (err)
Packit Service 672cf4
    return TRACE_ERR (err);
Packit Service 672cf4
Packit Service 6c01f9
  return TRACE_SUC1 ("dh=%p", *r_dh);
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
/* Create a new data buffer filled with SIZE bytes starting from
Packit Service 672cf4
   BUFFER.  If COPY is zero, copying is delayed until necessary, and
Packit Service 672cf4
   the data is taken from the original location when needed.  */
Packit Service 672cf4
gpgme_error_t
Packit Service 672cf4
gpgme_data_new_from_mem (gpgme_data_t *r_dh, const char *buffer,
Packit Service 672cf4
			 size_t size, int copy)
Packit Service 672cf4
{
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 6c01f9
  TRACE_BEG4 (DEBUG_DATA, "gpgme_data_new_from_mem", r_dh,
Packit Service 6c01f9
	      "buffer=%p, size=%u, copy=%i (%s)", buffer, size,
Packit Service 672cf4
	      copy, copy ? "yes" : "no");
Packit Service 672cf4
Packit Service 672cf4
  err = _gpgme_data_new (r_dh, &mem_cbs);
Packit Service 672cf4
  if (err)
Packit Service 672cf4
    return TRACE_ERR (err);
Packit Service 672cf4
Packit Service 672cf4
  if (copy)
Packit Service 672cf4
    {
Packit Service 672cf4
      char *bufcpy = malloc (size);
Packit Service 672cf4
      if (!bufcpy)
Packit Service 672cf4
	{
Packit Service 672cf4
	  int saved_err = gpg_error_from_syserror ();
Packit Service 672cf4
	  _gpgme_data_release (*r_dh);
Packit Service 672cf4
	  return TRACE_ERR (saved_err);
Packit Service 672cf4
	}
Packit Service 672cf4
      memcpy (bufcpy, buffer, size);
Packit Service 672cf4
      (*r_dh)->data.mem.buffer = bufcpy;
Packit Service 672cf4
    }
Packit Service 672cf4
  else
Packit Service 672cf4
    (*r_dh)->data.mem.orig_buffer = buffer;
Packit Service 672cf4
Packit Service 672cf4
  (*r_dh)->data.mem.size = size;
Packit Service 672cf4
  (*r_dh)->data.mem.length = size;
Packit Service 6c01f9
  return TRACE_SUC1 ("dh=%p", *r_dh);
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
/* Destroy the data buffer DH and return a pointer to its content.
Packit Service 672cf4
   The memory has be to released with gpgme_free() by the user.  It's
Packit Service 672cf4
   size is returned in R_LEN.  */
Packit Service 672cf4
char *
Packit Service 672cf4
gpgme_data_release_and_get_mem (gpgme_data_t dh, size_t *r_len)
Packit Service 672cf4
{
Packit Service 672cf4
  char *str = NULL;
Packit Service 672cf4
Packit Service 6c01f9
  TRACE_BEG1 (DEBUG_DATA, "gpgme_data_release_and_get_mem", dh,
Packit Service 672cf4
	      "r_len=%p", r_len);
Packit Service 672cf4
Packit Service 672cf4
  if (!dh || dh->cbs != &mem_cbs)
Packit Service 672cf4
    {
Packit Service 672cf4
      gpgme_data_release (dh);
Packit Service 672cf4
      TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
Packit Service 672cf4
      return NULL;
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  str = dh->data.mem.buffer;
Packit Service 672cf4
  if (!str && dh->data.mem.orig_buffer)
Packit Service 672cf4
    {
Packit Service 6c01f9
      str = malloc (dh->data.mem.length);
Packit Service 672cf4
      if (!str)
Packit Service 672cf4
	{
Packit Service 672cf4
	  int saved_err = gpg_error_from_syserror ();
Packit Service 672cf4
	  gpgme_data_release (dh);
Packit Service 672cf4
	  TRACE_ERR (saved_err);
Packit Service 672cf4
	  return NULL;
Packit Service 672cf4
	}
Packit Service 6c01f9
      memcpy (str, dh->data.mem.orig_buffer, dh->data.mem.length);
Packit Service 672cf4
    }
Packit Service 672cf4
  else
Packit Service 6c01f9
    /* Prevent mem_release from releasing the buffer memory.  We must
Packit Service 6c01f9
       not fail from this point.  */
Packit Service 6c01f9
    dh->data.mem.buffer = NULL;
Packit Service 672cf4
Packit Service 672cf4
  if (r_len)
Packit Service 6c01f9
    *r_len = dh->data.mem.length;
Packit Service 672cf4
Packit Service 672cf4
  gpgme_data_release (dh);
Packit Service 672cf4
Packit Service 672cf4
  if (r_len)
Packit Service 6c01f9
    {
Packit Service 6c01f9
      TRACE_SUC2 ("buffer=%p, len=%u", str, *r_len);
Packit Service 6c01f9
    }
Packit Service 672cf4
  else
Packit Service 6c01f9
    {
Packit Service 6c01f9
      TRACE_SUC1 ("buffer=%p", str);
Packit Service 6c01f9
    }
Packit Service 672cf4
  return str;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
/* Release the memory returned by gpgme_data_release_and_get_mem() and
Packit Service 672cf4
   some other functions.  */
Packit Service 672cf4
void
Packit Service 672cf4
gpgme_free (void *buffer)
Packit Service 672cf4
{
Packit Service 6c01f9
  TRACE (DEBUG_DATA, "gpgme_free", buffer);
Packit Service 672cf4
Packit Service 672cf4
  if (buffer)
Packit Service 672cf4
    free (buffer);
Packit Service 672cf4
}