diff options
| -rw-r--r-- | gpgme/ChangeLog | 4 | ||||
| -rw-r--r-- | gpgme/data-compat.c | 193 | ||||
| -rw-r--r-- | gpgme/data-fd.c | 70 | ||||
| -rw-r--r-- | gpgme/data-mem.c | 266 | ||||
| -rw-r--r-- | gpgme/data-stream.c | 76 | ||||
| -rw-r--r-- | gpgme/data-user.c | 78 | ||||
| -rw-r--r-- | gpgme/data.h | 118 | 
7 files changed, 805 insertions, 0 deletions
| diff --git a/gpgme/ChangeLog b/gpgme/ChangeLog index ce496693..5dba90e0 100644 --- a/gpgme/ChangeLog +++ b/gpgme/ChangeLog @@ -1,5 +1,9 @@  2002-10-09  Marcus Brinkmann  <[email protected]> +	* data.h, data-user.c, data-stream.c, data-mem.c, data-fd.c, +	data-compat.c: New file.  Really check them in this time, completes +	2002-10-08 change. +  	* rungpg.h (GpgStatusHandler): Rename type to GpgmeStatusHandler  	and move to ...  	* types.h (GpgmeStatusHandler): ... here. diff --git a/gpgme/data-compat.c b/gpgme/data-compat.c new file mode 100644 index 00000000..6eec787c --- /dev/null +++ b/gpgme/data-compat.c @@ -0,0 +1,193 @@ +/* data-mem.c - A memory based data object. + *      Copyright (C) 2002 g10 Code GmbH + * + * This file is part of GPGME. + * + * GPGME is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GPGME is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#if HAVE_CONFIG_H +#include <config.h> +#endif + +#include <errno.h> +#include <sys/stat.h> +#include <stdlib.h> + +#include "data.h" +#include "util.h" + + +/* Create a new data buffer filled with LENGTH bytes starting from +   OFFSET within the file FNAME or stream STREAM (exactly one must be +   non-zero).  */ +GpgmeError +gpgme_data_new_from_filepart (GpgmeData *dh, const char *fname, FILE *stream, +			      off_t offset, size_t length) +{ +  GpgmeError err; +  char *buf = NULL; + +  if (stream && fname) +    return mk_error (Invalid_Value); + +  if (fname) +    stream = fopen (fname, "rb"); +  if (!stream) +    return mk_error (File_Error); + +  if (fseek (stream, offset, SEEK_SET)) +    goto ferr; + +  buf = malloc (length); +  if (!buf) +    goto ferr; + +  while (fread (buf, length, 1, stream) < 1 +	 && ferror (stream) && errno == EINTR); +  if (ferror (stream)) +    { +      if (buf) +	free (buf); +      goto ferr; +    } + +  if (fname) +    fclose (stream); + +  err = gpgme_data_new (dh); +  if (err) +    { +      if (buf) +	free (buf); +      return err; +    } + +  (*dh)->data.mem.buffer = buf; +  (*dh)->data.mem.size = length; +  (*dh)->data.mem.length = length; +  return 0; + + ferr: +  { +    int saved_errno = errno; +    if (fname) +      fclose (stream); +    errno = saved_errno; +    return mk_error (File_Error); +  } +} + + +/* Create a new data buffer filled with the content of file FNAME. +   COPY must be non-zero (delayed reads are not supported yet).  */ +GpgmeError +gpgme_data_new_from_file (GpgmeData *dh, const char *fname, int copy) +{ +  struct stat statbuf; + +  if (!fname || !copy) +    return mk_error (Invalid_Value); + +  if (stat (fname, &statbuf) < 0) +    return mk_error (File_Error); + +  return gpgme_data_new_from_filepart (dh, fname, NULL, 0, statbuf.st_size); +} + + +static int +gpgme_error_to_errno (GpgmeError err) +{ +  switch (err) +    { +    case mk_error (EOF): +      return 0; +    case mk_error (Out_Of_Core): +      errno = ENOMEM; +      return -1; +    case mk_error (Invalid_Value): +      errno = EINVAL; +      return -1; +    case mk_error (Busy): +      errno = EBUSY; +      return -1; +    case mk_error (Not_Implemented): +      errno = EOPNOTSUPP; +      return -1; +    default: +      /* XXX Yeah, well.  */ +      errno = EINVAL; +      return -1; +    } +} + +static int +old_user_read (GpgmeData dh, void *buffer, size_t size) +{ +  size_t amt; +  GpgmeError err = (*dh->data.old_user.cb) (dh->data.old_user.handle, +					    buffer, size, &amt); +  if (err) +    return gpgme_error_to_errno (err); +  return amt; +} + + +static off_t +old_user_seek (GpgmeData dh, off_t offset, int whence) +{ +  GpgmeError err; +  if (whence != SEEK_SET || offset) +    return EINVAL; +  err = (*dh->data.old_user.cb) (dh->data.old_user.handle, NULL, 0, NULL); +  if (err) +    return gpgme_error_to_errno (err); +  return 0; +} + + +static struct gpgme_data_cbs old_user_cbs = +  { +    old_user_read, +    NULL, +    old_user_seek, +    NULL +  }; + + +/* Create a new data buffer which retrieves the data from the callback +   function READ_CB.  */ +GpgmeError +gpgme_data_new_with_read_cb (GpgmeData *dh, +                             int (*read_cb) (void *, char *, size_t, size_t *), +                             void *read_cb_value) +{ +  GpgmeError err = _gpgme_data_new (dh, &old_user_cbs); +  if (err) +    return err; + +  (*dh)->data.old_user.cb = read_cb; +  (*dh)->data.old_user.handle = read_cb_value; +  return 0; +} + + +GpgmeError +gpgme_data_rewind (GpgmeData dh) +{ +  return (gpgme_data_seek (dh, 0, SEEK_SET) == -1) +    ? mk_error (File_Error) : 0; +} diff --git a/gpgme/data-fd.c b/gpgme/data-fd.c new file mode 100644 index 00000000..037183d3 --- /dev/null +++ b/gpgme/data-fd.c @@ -0,0 +1,70 @@ +/* data-fd.c - A file descripor based data object. + *      Copyright (C) 2002 g10 Code GmbH + * + * This file is part of GPGME. + * + * GPGME is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GPGME is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#if HAVE_CONFIG_H +#include <config.h> +#endif + +#include <unistd.h> +#include <sys/types.h> + +#include "data.h" + + +static int +fd_read (GpgmeData dh, void *buffer, size_t size) +{ +  return read (dh->data.fd, buffer, size); +} + + +static ssize_t +fd_write (GpgmeData dh, const void *buffer, size_t size) +{ +  return write (dh->data.fd, buffer, size); +} + + +static off_t +fd_seek (GpgmeData dh, off_t offset, int whence) +{ +  return lseek (dh->data.fd, offset, whence); +} + + +static struct gpgme_data_cbs fd_cbs = +  { +    fd_read, +    fd_write, +    fd_seek, +    NULL +  }; + + +GpgmeError +gpgme_data_new_from_fd (GpgmeData *dh, int fd) +{ +  GpgmeError err = _gpgme_data_new (dh, &fd_cbs); +  if (err) +    return err; + +  (*dh)->data.fd = fd; +  return 0; +} diff --git a/gpgme/data-mem.c b/gpgme/data-mem.c new file mode 100644 index 00000000..0afd1168 --- /dev/null +++ b/gpgme/data-mem.c @@ -0,0 +1,266 @@ +/* data-mem.c - A memory based data object. + *      Copyright (C) 2002 g10 Code GmbH + * + * This file is part of GPGME. + * + * GPGME is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GPGME is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#if HAVE_CONFIG_H +#include <config.h> +#endif + +#include <errno.h> +#include <stdlib.h> +#include <unistd.h> +#include <assert.h> + +#include "data.h" +#include "util.h" + + +static int +mem_read (GpgmeData dh, void *buffer, size_t size) +{ +  size_t amt = dh->data.mem.length - dh->data.mem.offset; +  const char *src; + +  if (!amt) +    return 0; + +  if (size < amt) +    amt = size; + +  src = dh->data.mem.buffer ? dh->data.mem.buffer : dh->data.mem.orig_buffer; +  memcpy (buffer, src + dh->data.mem.offset, amt); +  dh->data.mem.offset += amt; +  return amt; +} + + +static ssize_t +mem_write (GpgmeData dh, const void *buffer, size_t size) +{ +  size_t unused; + +  if (!dh->data.mem.buffer && dh->data.mem.orig_buffer) +    { +      size_t new_size = dh->data.mem.size; +      char *new_buffer; + +      if (new_size < dh->data.mem.offset + size) +	new_size = dh->data.mem.offset + size; + +      new_buffer = malloc (new_size); +      if (!new_buffer) +	return -1; +      dh->data.mem.buffer = new_buffer;       +      dh->data.mem.size = new_size; +    } + +  unused = dh->data.mem.size - dh->data.mem.offset; +  if (unused < size) +    { +      /* Allocate a large enough buffer with exponential backoff.  */ +#define INITIAL_ALLOC 512 +      size_t new_size = dh->data.mem.size +	? (2 * dh->data.mem.size) : INITIAL_ALLOC; +      char *new_buffer; + +      if (new_size < dh->data.mem.offset + size) +	new_size = dh->data.mem.offset + size; + +      new_buffer = realloc (dh->data.mem.buffer, new_size); +      if (!new_buffer && new_size > dh->data.mem.offset + size) +	{ +	  /* Maybe we were too greedy, try again.  */ +	  new_size = dh->data.mem.offset + size; +	  new_buffer = realloc (dh->data.mem.buffer, new_size); +	} +      if (!new_buffer) +	return -1; +      dh->data.mem.buffer = new_buffer; +      dh->data.mem.size = new_size; +    } + +  memcpy (dh->data.mem.buffer + dh->data.mem.offset, buffer, size); +  dh->data.mem.offset += size; +  if (dh->data.mem.length < dh->data.mem.offset) +    dh->data.mem.length = dh->data.mem.offset; +  return size; +} + + +static off_t +mem_seek (GpgmeData dh, off_t offset, int whence) +{ +  switch (whence) +    { +    case SEEK_SET: +      if (offset < 0 || offset > dh->data.mem.length) +	{ +	  errno = EINVAL; +	  return -1; +	} +      dh->data.mem.offset = offset; +      break; +    case SEEK_CUR: +      if ((offset > 0 && dh->data.mem.length - dh->data.mem.offset < offset) +	  || (offset < 0 && dh->data.mem.offset < -offset))  +	{ +	  errno = EINVAL; +	  return -1; +	} +      dh->data.mem.offset += offset; +      break; +    case SEEK_END: +      if (offset > 0 || -offset > dh->data.mem.length) +	{ +	  errno = EINVAL; +	  return -1; +	} +      dh->data.mem.offset = dh->data.mem.length - offset; +      break; +    default: +      errno = EINVAL; +      return -1; +    } +  return dh->data.mem.offset; +} + + +static int +mem_release (GpgmeData dh) +{ +  if (dh->data.mem.buffer) +    free (dh->data.mem.buffer); +  return 0; +} + + +static struct gpgme_data_cbs mem_cbs = +  { +    mem_read, +    mem_write, +    mem_seek, +    mem_release +  }; + + +GpgmeError +gpgme_data_new (GpgmeData *dh) +{ +  GpgmeError err = _gpgme_data_new (dh, &mem_cbs); +  if (err) +    return err; + +  return 0; +} + + +/* Create a new data buffer filled with SIZE bytes starting from +   BUFFER.  If COPY is zero, copying is delayed until necessary, and +   the data is taken from the original location when needed.  */ +GpgmeError +gpgme_data_new_from_mem (GpgmeData *dh, const char *buffer, +			 size_t size, int copy) +{ +  GpgmeError err = _gpgme_data_new (dh, &mem_cbs); +  if (err) +    return err; + +  if (copy) +    { +      char *bufcpy = malloc (size); +      if (!bufcpy) +	_gpgme_data_release (*dh); +      memcpy (bufcpy, buffer, size); +      (*dh)->data.mem.buffer = bufcpy; +    } +  else +    (*dh)->data.mem.orig_buffer = buffer; +   +  (*dh)->data.mem.size = size; +  (*dh)->data.mem.length = size; +  return 0; +} + + +/* This function does make sense when we know that it contains no nil +   chars and if the underlying data object is memory based.  */ +char * +_gpgme_data_get_as_string (GpgmeData dh) +{ +  char *dst = NULL; +  const char *src = NULL; + +  assert (dh->cbs == &mem_cbs); + +  src = dh->data.mem.buffer; +  if (!src) +    src = dh->data.mem.orig_buffer; +  dst = malloc (dh->data.mem.length + 1); +  if (dst) +    { +      if (src) +	memcpy (dst, src, dh->data.mem.length); +      dst[dh->data.mem.length] = '\0'; +    } +  return dst; +} + + +char * +gpgme_data_release_and_get_mem (GpgmeData dh, size_t *r_len) +{ +  char *str = NULL; + +  if (!dh || dh->cbs != &mem_cbs) +    return NULL; + +  str = dh->data.mem.buffer; +  if (!str && dh->data.mem.orig_buffer) +    { +      str = malloc (dh->data.mem.length); +      if (!str) +	return NULL; +      memcpy (str, dh->data.mem.orig_buffer, dh->data.mem.length); +    } + +  if (r_len) +    *r_len = dh->data.mem.length; + +  return str; +} + + +/* This function does make sense when we know that it contains no nil +   chars and if the underlying data object is memory based.  */ +char * +_gpgme_data_release_and_return_string (GpgmeData dh) +{ +  char *str = NULL; + +  if (!dh) +    return NULL; + +  assert (dh->cbs == &mem_cbs); +  if (gpgme_data_write (dh, "", 1) == 1) +    str = gpgme_data_release_and_get_mem (dh, NULL); +  else +    gpgme_data_release (dh); + +  return str; +} diff --git a/gpgme/data-stream.c b/gpgme/data-stream.c new file mode 100644 index 00000000..33d44986 --- /dev/null +++ b/gpgme/data-stream.c @@ -0,0 +1,76 @@ +/* data-stream.c - A memory based data object. + *      Copyright (C) 2002 g10 Code GmbH + * + * This file is part of GPGME. + * + * GPGME is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GPGME is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#if HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <sys/types.h> + +#include "data.h" + + +static int +stream_read (GpgmeData dh, void *buffer, size_t size) +{ +  size_t amt = fread (buffer, 1, size, dh->data.stream); +  if (amt > 0) +    return amt; +  return ferror (dh->data.stream) ? -1 : 0; +} + + +static ssize_t +stream_write (GpgmeData dh, const void *buffer, size_t size) +{ +  size_t amt = fwrite (buffer, 1, size, dh->data.stream); +  if (amt > 0) +    return amt; +  return ferror (dh->data.stream) ? -1 : 0; +} + + +static off_t +stream_seek (GpgmeData dh, off_t offset, int whence) +{ +  return fseek (dh->data.stream, offset, whence); +} + + +static struct gpgme_data_cbs stream_cbs = +  { +    stream_read, +    stream_write, +    stream_seek, +    NULL +  }; + + +GpgmeError +gpgme_data_new_from_stream (GpgmeData *dh, FILE *stream) +{ +  GpgmeError err = _gpgme_data_new (dh, &stream_cbs); +  if (err) +    return err; + +  (*dh)->data.stream = stream; +  return 0; +} diff --git a/gpgme/data-user.c b/gpgme/data-user.c new file mode 100644 index 00000000..dd0e5700 --- /dev/null +++ b/gpgme/data-user.c @@ -0,0 +1,78 @@ +/* data-user.c - A user callback based data object. + *      Copyright (C) 2002 g10 Code GmbH + * + * This file is part of GPGME. + * + * GPGME is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GPGME is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#if HAVE_CONFIG_H +#include <config.h> +#endif + +#include <sys/types.h> + +#include "data.h" + + +static int +user_read (GpgmeData dh, void *buffer, size_t size) +{ +  return (*dh->data.user.cbs->read) (dh->data.user.handle, buffer, size); +} + + +static ssize_t +user_write (GpgmeData dh, const void *buffer, size_t size) +{ +  return (*dh->data.user.cbs->write) (dh->data.user.handle, buffer, size); +} + + +static off_t +user_seek (GpgmeData dh, off_t offset, int whence) +{ +  return (*dh->data.user.cbs->seek) (dh->data.user.handle, offset, whence); +} + + +static int +user_release (GpgmeData dh) +{ +  (*dh->data.user.cbs->release) (dh->data.user.handle); +  return 0; +} + + +static struct gpgme_data_cbs user_cbs = +  { +    user_read, +    user_write, +    user_seek, +    user_release +  }; + + +GpgmeError +gpgme_data_new_from_cbs (GpgmeData *dh, struct GpgmeDataCbs *cbs, void *handle) +{ +  GpgmeError err = _gpgme_data_new (dh, &user_cbs); +  if (err) +    return err; + +  (*dh)->data.user.cbs = cbs; +  (*dh)->data.user.handle = handle; +  return 0; +} diff --git a/gpgme/data.h b/gpgme/data.h new file mode 100644 index 00000000..67910153 --- /dev/null +++ b/gpgme/data.h @@ -0,0 +1,118 @@ +/* data.h - Internal data object abstraction interface. + *      Copyright (C) 2002 g10 Code GmbH + * + * This file is part of GPGME. + * + * GPGME is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GPGME is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#ifndef DATA_H +#define DATA_H + +#if HAVE_CONFIG_H +#include <config.h> +#endif + +#include <sys/types.h> +#include <limits.h> + +#include "gpgme.h" + + +/* Read up to SIZE bytes into buffer BUFFER from the data object with +   the handle DH.  Return the number of characters read, 0 on EOF and +   -1 on error.  If an error occurs, errno is set.  */ +typedef int (*gpgme_data_read_cb) (GpgmeData dh, void *buffer, size_t size); + +/* Write up to SIZE bytes from buffer BUFFER to the data object with +   the handle DH.  Return the number of characters written, or -1 on +   error.  If an error occurs, errno is set.  */ +typedef ssize_t (*gpgme_data_write_cb) (GpgmeData dh, const void *buffer, +					size_t size); + +/* Set the current position from where the next read or write starts +   in the data object with the handle DH to OFFSET, relativ to +   WHENCE.  */ +typedef off_t (*gpgme_data_seek_cb) (GpgmeData dh, off_t offset, int whence); + +/* Release the data object with the handle DH.  */ +typedef int (*gpgme_data_release_cb) (GpgmeData dh); + +struct gpgme_data_cbs +{ +  gpgme_data_read_cb read; +  gpgme_data_write_cb write; +  gpgme_data_seek_cb seek; +  gpgme_data_release_cb release; +}; + +struct gpgme_data_s +{ +  struct gpgme_data_cbs *cbs; +  GpgmeDataEncoding encoding; + +#ifdef PIPE_BUF +#define BUFFER_SIZE PIPE_BUF +#else +#ifdef _POSIX_PIPE_BUF +#define BUFFER_SIZE _POSIX_PIPE_BUF +#else +#define BUFFER_SIZE 512 +#endif +#endif +  char pending[BUFFER_SIZE]; +  int pending_len; + +  union +  { +    /* For gpgme_data_new_from_fd.  */ +    int fd; + +    /* For gpgme_data_new_from_stream.  */ +    FILE *stream; + +    /* For gpgme_data_new_from_cbs.  */ +    struct +    { +      struct GpgmeDataCbs *cbs; +      void *handle; +    } user; + +    /* For gpgme_data_new_from_mem.  */ +    struct +    { +      char *buffer; +      const char *orig_buffer; +      /* Allocated size of BUFFER.  */ +      size_t size; +      size_t length; +      size_t offset; +    } mem; + +    /* For gpgme_data_new_from_read_cb.  */ +    struct +    { +      int (*cb) (void *, char *, size_t, size_t *); +      void *handle; +    } old_user; +  } data; +}; + + +GpgmeError _gpgme_data_new (GpgmeData *r_dh, struct gpgme_data_cbs *cbs); + +void _gpgme_data_release (GpgmeData dh); + +#endif	/* DATA_H */ | 
