Blame src/data-mem.c

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