diff options
Diffstat (limited to 'agent/gpg-stream.c')
-rw-r--r-- | agent/gpg-stream.c | 1440 |
1 files changed, 0 insertions, 1440 deletions
diff --git a/agent/gpg-stream.c b/agent/gpg-stream.c deleted file mode 100644 index e8baf0e32..000000000 --- a/agent/gpg-stream.c +++ /dev/null @@ -1,1440 +0,0 @@ -/* stream.c - Stream I/O/ layer - Copyright (C) 2004 g10 Code GmbH - - This file is part of libgpg-stream. - - libgpg-stream 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. - - libgpg-stream 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU General Public License - along with libgpg-stream; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - 02111-1307, USA. */ - -#include <sys/types.h> -#include <sys/file.h> -#include <sys/stat.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <stdarg.h> -#include <fcntl.h> -#include <errno.h> -#include <stdio.h> - -#include <gpg-error.h> - -#include "gpg-stream.h" -#include "gpg-stream-config.h" - - - -/* Generally used types. */ - -typedef void *(*func_realloc_t) (void *mem, size_t size); -typedef void (*func_free_t) (void *mem); - - - -/* Buffer management layer. */ - -#define BUFFER_BLOCK_SIZE 1024 - - - -typedef struct buffer *buffer_t; - -/* Callbacks, necessary for filling/flushing/seeking. */ -typedef gpg_error_t (*buffer_func_read_t) (void *handle, - char *buffer, - size_t bytes_to_read, - size_t *bytes_read); -typedef gpg_error_t (*buffer_func_write_t) (void *handle, - const char *buffer, - size_t bytes_to_write, - size_t *bytes_written); -typedef gpg_error_t (*buffer_func_seek_t) (void *handle, - off_t offset, - int whence); - -typedef gpg_error_t (*buffer_func_stat_t) (void *handle, - size_t *size); - -typedef struct buffer_functions -{ - buffer_func_read_t func_read; /* Read callback. */ - buffer_func_write_t func_write; /* Write callback. */ - buffer_func_seek_t func_seek; /* Seek callback. */ - buffer_func_stat_t func_stat; /* Stat callback. */ -} buffer_functions_t; - -typedef struct buffer_conspec -{ - size_t block_size; - func_realloc_t func_realloc; - func_free_t func_free; -} buffer_conspec_t; - -/* Buffer context. */ -struct buffer -{ - void *handle; /* Handle, passed to callbacks. */ - buffer_conspec_t conspec; /* Container spec. */ - buffer_functions_t functions; /* Callback functions. */ - unsigned int flags; /* General flags. */ - struct buffer_in - { - char *container; /* Container holding data. */ - size_t container_size; /* Size of CONTAINER. */ - size_t data_size; /* Size of data in CONTAINER. */ - off_t data_offset; /* Offset inside of CONTAINER. */ - } buffer_in; - struct buffer_out - { - char *container; /* Container holding data. */ - size_t container_size; /* Size of CONTAINER. */ - size_t data_size; /* Size of data in CONTAINER. */ - off_t data_offset; /* Offset inside of CONTAINER. */ - size_t data_flushed; /* Amount of data already flushed. */ - } buffer_out; -}; - - - -/* Buffer contains unflushed data. */ -#define BUFFER_FLAG_DIRTY (1 << 0) - -/* Buffer is secure. */ -#define BUFFER_FLAG_SECURE (1 << 1) - - - -/* Fill buffer. */ -static gpg_error_t -buffer_fill_do (buffer_t buffer) -{ - gpg_error_t err = GPG_ERR_NO_ERROR; - size_t bytes_read = 0; - - if (! buffer->functions.func_read) - err = gpg_error (GPG_ERR_NOT_IMPLEMENTED); - else - { - buffer_func_read_t func_read = buffer->functions.func_read; - - err = (*func_read) (buffer->handle, - buffer->buffer_in.container, - buffer->buffer_in.container_size, - &bytes_read); - } - - buffer->buffer_in.data_offset = 0; - buffer->buffer_in.data_size = bytes_read; - - return err; -} - -/* Empty buffer input. */ -static gpg_error_t -buffer_empty (buffer_t buffer) -{ - gpg_error_t err = GPG_ERR_NO_ERROR; - - buffer->buffer_in.data_size = 0; - buffer->buffer_in.data_offset = 0; - - return err; -} - -/* Flush data contained in buffer. */ -static gpg_error_t -buffer_flush_do (buffer_t buffer) -{ - buffer_func_write_t func_write = buffer->functions.func_write; - gpg_error_t err = GPG_ERR_NO_ERROR; - size_t bytes_written = 0; - - if (! func_write) - err = gpg_error (GPG_ERR_NOT_IMPLEMENTED); - else if (buffer->flags & BUFFER_FLAG_DIRTY) - while ((buffer->buffer_out.data_size - - buffer->buffer_out.data_flushed) && (! err)) - { - - err = (*func_write) (buffer->handle, - buffer->buffer_out.container - + buffer->buffer_out.data_flushed, - buffer->buffer_out.data_size - - buffer->buffer_out.data_flushed, - &bytes_written); - if (! err) - { - buffer->buffer_out.data_size = 0; - buffer->buffer_out.data_offset = 0; - buffer->buffer_out.data_flushed = 0; - buffer->flags &= ~BUFFER_FLAG_DIRTY; - } - else - buffer->buffer_out.data_flushed += bytes_written; - } - - return err; -} - -static gpg_error_t -buffer_stat_do (buffer_t buffer, - size_t *size) -{ - buffer_func_stat_t func_stat = buffer->functions.func_stat; - gpg_error_t err = GPG_ERR_NO_ERROR; - - err = (*func_stat) (buffer->handle, size); - - return err; -} - - - -/* Read from a buffer. */ -gpg_error_t -buffer_read (buffer_t buffer, - char *data, - size_t bytes_to_read, - size_t *bytes_read) -{ - gpg_error_t err = GPG_ERR_NO_ERROR; - size_t data_read = 0; - size_t data_to_copy = 0; - - if (! (buffer->flags & BUFFER_FLAG_DIRTY)) - err = buffer_flush_do (buffer); - - while ((bytes_to_read - data_read) && (! err)) - { - if (buffer->buffer_in.data_offset == buffer->buffer_in.data_size) - { - /* Nothing more to read in current container, try to - fill container with new data. */ - err = buffer_fill_do (buffer); - if (! err) - if (! buffer->buffer_in.data_size) - /* Filling did not result in any data read. */ - break; - } - - if (! err) - { - if ((bytes_to_read - - data_read) > (buffer->buffer_in.data_size - - buffer->buffer_in.data_offset)) - data_to_copy = (buffer->buffer_in.data_size - - buffer->buffer_in.data_offset); - else - data_to_copy = bytes_to_read - data_read; - - memcpy (data + data_read, - buffer->buffer_in.container + buffer->buffer_in.data_offset, - data_to_copy); - buffer->buffer_in.data_offset += data_to_copy; - data_read += data_to_copy; - } - } - - if (bytes_read) - *bytes_read = data_read; - - return err; -} - -/* Write to a buffer. */ -gpg_error_t -buffer_write (buffer_t buffer, - const char *data, - size_t bytes_to_write, - size_t *bytes_written) -{ - gpg_error_t err = GPG_ERR_NO_ERROR; - size_t data_written = 0; - size_t data_to_copy = 0; - - while ((bytes_to_write - data_written) && (! err)) - { - if (buffer->buffer_out.data_offset == buffer->buffer_out.container_size) - /* Container full, flush buffer. */ - err = buffer_flush_do (buffer); - - if (! err) - { - if ((bytes_to_write - - data_written) > (buffer->buffer_out.container_size - - buffer->buffer_out.data_offset)) - data_to_copy = (buffer->buffer_out.container_size - - buffer->buffer_out.data_offset); - else - data_to_copy = bytes_to_write - data_written; - - memcpy (buffer->buffer_out.container - + buffer->buffer_out.data_offset, - data + data_written, - data_to_copy); - if ((buffer->buffer_out.data_offset - + data_to_copy) > buffer->buffer_out.data_size) - buffer->buffer_out.data_size = (buffer->buffer_out.data_offset - + data_to_copy); - buffer->buffer_out.data_offset += data_to_copy; - data_written += data_to_copy; - - if (data_written) - if (! (buffer->flags & BUFFER_FLAG_DIRTY)) - buffer->flags |= BUFFER_FLAG_DIRTY; - } - } - - if (bytes_written) - *bytes_written = data_written; - - return err; -} - -/* Seek in a buffer. */ -gpg_error_t -buffer_seek (buffer_t buffer, - off_t offset, - int whence) -{ - buffer_func_seek_t func_seek = buffer->functions.func_seek; - gpg_error_t err = GPG_ERR_NO_ERROR; - - if (! func_seek) - err = gpg_error (GPG_ERR_NOT_IMPLEMENTED); - else - { - if (buffer->flags & BUFFER_FLAG_DIRTY) - /* Flush data first in order to prevent flushing it to the - wrong offset. */ - err = buffer_flush_do (buffer); - - if (! err) - err = (*func_seek) (buffer->handle, offset, whence); - - if (! err) - err = buffer_empty (buffer); - } - - return err; -} - -/* Return the unread data contained in a buffer. */ -gpg_error_t -buffer_peek (buffer_t buffer, - char **data, - size_t *data_size) -{ - gpg_error_t err = GPG_ERR_NO_ERROR; - - if (buffer->buffer_in.data_offset == buffer->buffer_in.data_size) - /* Refill container. */ - err = buffer_fill_do (buffer); - - if (! err) - { - if (data) - *data = buffer->buffer_in.container + buffer->buffer_in.data_offset; - if (data_size) - *data_size = buffer->buffer_in.data_size - buffer->buffer_in.data_offset; - } - - return err; -} - -/* Skip SIZE bytes of input data contained in buffer. */ -gpg_error_t -buffer_skip (buffer_t buffer, - size_t size) -{ - gpg_error_t err = GPG_ERR_NO_ERROR; - - if (buffer->buffer_in.data_offset + size > buffer->buffer_in.data_size) - err = gpg_error (GPG_ERR_INV_ARG); - else - buffer->buffer_in.data_offset += size; - - return err; -} - - - -/* Create a new buffer. */ -gpg_error_t -buffer_create (buffer_t *buffer, - buffer_conspec_t *conspec, - void *handle, - buffer_functions_t functions) -{ - func_realloc_t func_realloc = realloc; - func_free_t func_free = free; - size_t block_size = BUFFER_BLOCK_SIZE; - gpg_error_t err = GPG_ERR_NO_ERROR; - buffer_t buffer_new = NULL; - char *container_in_new = NULL; - char *container_out_new = NULL; - - if (conspec) - { - if (conspec->func_realloc) - func_realloc = conspec->func_realloc; - if (conspec->func_free) - func_free = conspec->func_free; - if (conspec->block_size) - block_size = conspec->block_size; - } - - buffer_new = malloc (sizeof (*buffer_new)); - if (! buffer_new) - err = gpg_error_from_errno (errno); - - if (! err) - { - container_in_new = (*func_realloc) (NULL, block_size); - if (! container_in_new) - err = gpg_error_from_errno (errno); - } - if (! err) - { - container_out_new = (*func_realloc) (NULL, block_size); - if (! container_out_new) - err = gpg_error_from_errno (errno); - } - - if (! err) - { - buffer_new->handle = handle; - buffer_new->conspec.func_realloc = func_realloc; - buffer_new->conspec.func_free = func_free; - buffer_new->conspec.block_size = block_size; - buffer_new->flags = 0; - buffer_new->functions = functions; - buffer_new->buffer_in.container = container_in_new; - buffer_new->buffer_in.container_size = block_size; - buffer_new->buffer_in.data_size = 0; - buffer_new->buffer_in.data_offset = 0; - buffer_new->buffer_out.container = container_out_new; - buffer_new->buffer_out.container_size = block_size; - buffer_new->buffer_out.data_size = 0; - buffer_new->buffer_out.data_offset = 0; - buffer_new->buffer_out.data_flushed = 0; - *buffer = buffer_new; - } - else - { - if (container_in_new) - free (container_in_new); - if (container_out_new) - free (container_out_new); - if (buffer_new) - free (buffer_new); - } - - return err; -} - -/* Destroy a buffer. */ -gpg_error_t -buffer_destroy (buffer_t buffer) -{ - gpg_error_t err = GPG_ERR_NO_ERROR; - - if (buffer) - { - err = buffer_flush_do (buffer); - (*buffer->conspec.func_free) (buffer->buffer_in.container); - (*buffer->conspec.func_free) (buffer->buffer_out.container); - free (buffer); - } - - return err; -} - -/* Write out unwritten data contained in buffer. */ -gpg_error_t -buffer_flush (buffer_t buffer) -{ - gpg_error_t err = GPG_ERR_NO_ERROR; - - err = buffer_flush_do (buffer); - - return err; -} - -/* Stat buffer. */ -gpg_error_t -buffer_stat (buffer_t buffer, - size_t *size) -{ - gpg_error_t err = GPG_ERR_NO_ERROR; - - err = buffer_stat_do (buffer, size); - - return err; -} - -gpg_error_t -buffer_conspec_get (buffer_t buffer, - buffer_conspec_t *buffer_conspec) -{ - gpg_error_t err = GPG_ERR_NO_ERROR; - - buffer_conspec->block_size = buffer->conspec.block_size; - buffer_conspec->func_realloc = buffer->conspec.func_realloc; - buffer_conspec->func_free = buffer->conspec.func_free; - - return err; -} - - - -/* Stream layer. */ - -/* A Stream Context. */ -struct gpg_stream -{ - void *handle; /* Handle. */ - unsigned int flags; /* Flags. */ - buffer_t buffer; /* Buffer used for I/O. */ - gpg_stream_functions_t functions; /* Callbacks. */ -}; - - - -/* Macros. */ - -/* Standard permissions used for creating new files. */ -#define GPG_STREAM_FILE_PERMISSIONS 0600 - -/* Evaluate EXPRESSION, setting VARIABLE to the return code, if - VARIABLE is zero. */ -#define SET_UNLESS_NONZERO(variable, tmp_variable, expression) \ - do \ - { \ - tmp_variable = expression; \ - if ((! variable) && tmp_variable) \ - variable = tmp_variable; \ - } \ - while (0) - -/* Implementation of Memory I/O. */ - -typedef struct gpg_stream_handle_mem -{ - char *memory; /* Data. */ - size_t memory_size; /* Size of MEMORY. */ - size_t data_size; /* Size of data in MEMORY. */ - size_t block_size; /* Block size. */ - unsigned int grow: 1; /* MEMORY is allowed to grow. */ - size_t offset; /* Current offset in MEMORY. */ - func_realloc_t func_realloc; - func_free_t func_free; -} *gpg_stream_handle_mem_t; - -static gpg_error_t -gpg_stream_func_mem_create (void **handle, - void *spec, - unsigned int flags) -{ - gpg_stream_handle_mem_t mem_handle = NULL; - gpg_stream_spec_mem_t *mem_spec = spec; - gpg_error_t err = GPG_ERR_NO_ERROR; - - mem_handle = malloc (sizeof (*mem_handle)); - if (! mem_handle) - err = gpg_error_from_errno (errno); - else - { - mem_handle->memory = mem_spec ? mem_spec->memory : 0; - mem_handle->memory_size = mem_spec ? mem_spec->memory_size : 0; - mem_handle->data_size = 0; - mem_handle->block_size = ((mem_spec && mem_spec->block_size) - ? mem_spec->block_size : BUFFER_BLOCK_SIZE); - mem_handle->grow = mem_spec ? mem_spec->grow : 1; - mem_handle->offset = 0; - mem_handle->func_realloc = ((mem_spec && mem_spec->func_realloc) - ? mem_spec->func_realloc : realloc); - mem_handle->func_free = ((mem_spec && mem_spec->func_free) - ? mem_spec->func_free : free); - *handle = mem_handle; - } - - return err; -} - -static gpg_error_t -gpg_stream_func_mem_read (void *handle, - char *buffer, - size_t bytes_to_read, - size_t *bytes_read) -{ - gpg_stream_handle_mem_t mem_handle = handle; - gpg_error_t err = GPG_ERR_NO_ERROR; - - if (bytes_to_read > mem_handle->data_size - mem_handle->offset) - bytes_to_read = mem_handle->data_size - mem_handle->offset; - - memcpy (buffer, mem_handle->memory + mem_handle->offset, - bytes_to_read); - mem_handle->offset += bytes_to_read; - *bytes_read = bytes_to_read; - - return err; -} - -static gpg_error_t -gpg_stream_func_mem_write (void *handle, - const char *buffer, - size_t bytes_to_write, - size_t *bytes_written) -{ - gpg_stream_handle_mem_t mem_handle = handle; - gpg_error_t err = GPG_ERR_NO_ERROR; - char *memory_new = NULL; - - if (! mem_handle->grow) - if (bytes_to_write > mem_handle->memory_size - mem_handle->offset) - bytes_to_write = mem_handle->memory_size - mem_handle->offset; - - while (bytes_to_write > mem_handle->memory_size - mem_handle->offset) - { - memory_new = (*mem_handle->func_realloc) - (mem_handle->memory, - mem_handle->memory_size + mem_handle->block_size); - if (! memory_new) - { - err = gpg_error_from_errno (errno); - break; - } - else - { - if (mem_handle->memory != memory_new) - mem_handle->memory = memory_new; - mem_handle->memory_size += mem_handle->block_size; - } - } - - if (! err) - { - memcpy (mem_handle->memory + mem_handle->offset, buffer, - bytes_to_write); - if (mem_handle->offset + bytes_to_write > mem_handle->data_size) - mem_handle->data_size = mem_handle->offset + bytes_to_write; - mem_handle->offset += bytes_to_write; - } - *bytes_written = bytes_to_write; - - return err; -} - -gpg_error_t -gpg_stream_func_mem_seek (void *handle, - off_t offset, - int whence) -{ - gpg_stream_handle_mem_t mem_handle = handle; - gpg_error_t err = GPG_ERR_NO_ERROR; - - switch (whence) - { - case SEEK_SET: - if ((offset < 0) || (offset > mem_handle->data_size)) - err = gpg_error (GPG_ERR_INV_ARG); - else - mem_handle->offset = offset; - break; - - case SEEK_CUR: - if ((mem_handle->offset + offset < 0) - || (mem_handle->offset + offset > mem_handle->data_size)) - err = gpg_error (GPG_ERR_INV_ARG); - else - mem_handle->offset += offset; - break; - - case SEEK_END: - if ((mem_handle->data_size + offset < 0) - || (mem_handle->data_size + offset > mem_handle->data_size)) - err = gpg_error (GPG_ERR_INV_ARG); - else - mem_handle->offset += offset; - } - - return err; -} - -static gpg_error_t -gpg_stream_func_mem_stat (void *handle, - size_t *size) -{ - gpg_stream_handle_mem_t mem_handle = handle; - gpg_error_t err = GPG_ERR_NO_ERROR; - - *size = mem_handle->data_size; - - return err; -} - -static gpg_error_t -gpg_stream_func_mem_destroy (void *handle) -{ - gpg_stream_handle_mem_t mem_handle = handle; - gpg_error_t err = GPG_ERR_NO_ERROR; - - if (mem_handle->memory) - (*mem_handle->func_free) (mem_handle->memory); - free (mem_handle); - - return err; -} - -gpg_stream_functions_t gpg_stream_functions_mem = - { - gpg_stream_func_mem_create, - gpg_stream_func_mem_read, - gpg_stream_func_mem_write, - gpg_stream_func_mem_seek, - gpg_stream_func_mem_stat, - gpg_stream_func_mem_destroy - }; - -/* Implementation of FD I/O. */ - -typedef struct gpg_stream_handle_fd -{ - int fd; -} *gpg_stream_handle_fd_t; - -static gpg_error_t -gpg_stream_func_fd_create (void **handle, - void *spec, - unsigned int flags) -{ - gpg_stream_handle_fd_t fd_handle = NULL; - gpg_stream_spec_fd_t *fd_spec = spec; - gpg_error_t err = GPG_ERR_NO_ERROR; - - fd_handle = malloc (sizeof (*fd_handle)); - if (! fd_handle) - err = gpg_error_from_errno (errno); - else - { - fd_handle->fd = fd_spec->fd; - *handle = fd_handle; - } - - return err; -} - -static gpg_error_t -gpg_stream_func_fd_read (void *handle, - char *buffer, - size_t bytes_to_read, - size_t *bytes_read) - -{ - gpg_stream_handle_fd_t file_handle = handle; - gpg_error_t err = GPG_ERR_NO_ERROR; - ssize_t ret = -1; - - ret = READ (file_handle->fd, buffer, bytes_to_read); - if (ret == -1) - err = gpg_error_from_errno (errno); - else - *bytes_read = ret; - - return err; -} - -static gpg_error_t -gpg_stream_func_fd_write (void *handle, - const char *buffer, - size_t bytes_to_write, - size_t *bytes_written) - -{ - gpg_stream_handle_fd_t file_handle = handle; - gpg_error_t err = GPG_ERR_NO_ERROR; - ssize_t ret = -1; - - ret = WRITE (file_handle->fd, buffer, bytes_to_write); - if (ret == -1) - err = gpg_error_from_errno (errno); - else - *bytes_written = ret; - - return err; -} - -static gpg_error_t -gpg_stream_func_fd_seek (void *handle, - off_t pos, - int whence) -{ - gpg_stream_handle_fd_t file_handle = handle; - gpg_error_t err = GPG_ERR_NO_ERROR; - off_t ret = -1; - - ret = lseek (file_handle->fd, pos, whence); - if (ret == -1) - err = gpg_error_from_errno (errno); - - return err; -} - -static gpg_error_t -gpg_stream_func_fd_stat (void *handle, - size_t *size) -{ - gpg_stream_handle_fd_t file_handle = handle; - gpg_error_t err = GPG_ERR_NO_ERROR; - struct stat statbuf; - int ret = 0; - - ret = fstat (file_handle->fd, &statbuf); - if (ret == -1) - err = gpg_error_from_errno (errno); - else - *size = statbuf.st_size; - - return err; -} - -static gpg_error_t -gpg_stream_func_fd_destroy (void *handle) -{ - gpg_stream_handle_fd_t file_handle = handle; - gpg_error_t err = GPG_ERR_NO_ERROR; - - free (file_handle); - - return err; -} - -gpg_stream_functions_t gpg_stream_functions_fd = - { - gpg_stream_func_fd_create, - gpg_stream_func_fd_read, - gpg_stream_func_fd_write, - gpg_stream_func_fd_seek, - gpg_stream_func_fd_stat, - gpg_stream_func_fd_destroy - }; - - -/* Implementation of File I/O. */ - -static gpg_error_t -gpg_stream_func_file_create (void **handle, - void *spec, - unsigned int flags) -{ - gpg_stream_handle_fd_t file_handle = NULL; - gpg_stream_spec_file_t *file_spec = spec; - gpg_error_t err = GPG_ERR_NO_ERROR; - int open_flags = 0; - int fd = -1; - - file_handle = malloc (sizeof (*file_handle)); - if (! file_handle) - err = gpg_error_from_errno (errno); - - if (! err) - { - struct flag_mapping - { - unsigned int gpg_stream; - unsigned int sys; - } flag_mappings[] = { { GPG_STREAM_FLAG_READ, - O_RDONLY }, - { GPG_STREAM_FLAG_WRITE, - O_WRONLY }, - { GPG_STREAM_FLAG_EXCLUSIVE, - O_EXCL }, - { GPG_STREAM_FLAG_APPEND, - O_APPEND }, - { GPG_STREAM_FLAG_CREATE, - O_CREAT }, - { GPG_STREAM_FLAG_NONBLOCK, - O_NONBLOCK }, - { GPG_STREAM_FLAG_TRUNCATE, - O_TRUNC } }; - unsigned int i = 0; - - for (i = 0; i < (sizeof (flag_mappings) / sizeof (*flag_mappings)); i++) - if (flags & flag_mappings[i].gpg_stream) - open_flags |= flag_mappings[i].sys; - - fd = open (file_spec->filename, open_flags, file_spec->mode); - if (fd == -1) - err = gpg_error_from_errno (errno); - } - - if (! err) - { - file_handle->fd = fd; - *handle = file_handle; - } - else - { - if (file_handle) - free (file_handle); - if (fd != -1) - close (fd); - } - - return err; -} - -static gpg_error_t -gpg_stream_func_file_destroy (void *handle) -{ - gpg_stream_handle_fd_t file_handle = handle; - gpg_error_t err = GPG_ERR_NO_ERROR; - int ret = 0; - - if (file_handle) - { - ret = close (file_handle->fd); - if (ret == -1) - err = gpg_error_from_errno (errno); - free (file_handle); - } - - return err; -} - -gpg_stream_functions_t gpg_stream_functions_file = - { - gpg_stream_func_file_create, - gpg_stream_func_fd_read, - gpg_stream_func_fd_write, - gpg_stream_func_fd_seek, - gpg_stream_func_fd_stat, - gpg_stream_func_file_destroy - }; - - - -static gpg_error_t -gpg_stream_create_do (gpg_stream_t *stream, - gpg_stream_buffer_spec_t *buffer_spec, - void *spec, - unsigned int flags, - gpg_stream_functions_t functions) -{ - buffer_conspec_t conspec = { NULL }; - gpg_error_t err = GPG_ERR_NO_ERROR; - - if (buffer_spec) - { - conspec.func_realloc = buffer_spec->func_realloc; - conspec.func_free = buffer_spec->func_free; - conspec.block_size = buffer_spec->block_size; - } - - if (! (1 - && (0 - || ((flags & GPG_STREAM_FLAG_READ) && functions.func_read) - || ((flags & GPG_STREAM_FLAG_WRITE) && functions.func_write)))) - err = gpg_error (GPG_ERR_INV_ARG); - else - { - buffer_functions_t buffer_fncs = { functions.func_read, - functions.func_write, - functions.func_seek, - functions.func_stat }; - gpg_stream_t stream_new = NULL; - buffer_t buffer = NULL; - void *handle = NULL; - - stream_new = malloc (sizeof (*stream_new)); - if (! stream_new) - err = gpg_error_from_errno (errno); - - if (! err) - if (functions.func_create) - err = (*functions.func_create) (&handle, spec, flags); - - if (! err) - err = buffer_create (&buffer, buffer_spec ? &conspec : NULL, - handle, buffer_fncs); - - if (! err) - { - stream_new->handle = handle; - stream_new->flags = flags; - stream_new->buffer = buffer; - stream_new->functions = functions; - *stream = stream_new; - } - else - { - if (functions.func_destroy) - (*functions.func_destroy) (handle); - if (buffer) - buffer_destroy (buffer); - } - } - - return err; -} - -gpg_error_t -gpg_stream_create (gpg_stream_t *stream, - gpg_stream_buffer_spec_t *buffer_spec, - void *spec, - unsigned int flags, - gpg_stream_functions_t functions) -{ - gpg_error_t err = GPG_ERR_NO_ERROR; - - err = gpg_stream_create_do (stream, buffer_spec, spec, flags, functions); - - return err; -} - -gpg_error_t -gpg_stream_create_file (gpg_stream_t *stream, - const char *filename, - unsigned int flags) -{ - gpg_stream_spec_file_t spec = { filename, GPG_STREAM_FILE_PERMISSIONS }; - gpg_error_t err = GPG_ERR_NO_ERROR; - - err = gpg_stream_create_do (stream, NULL, &spec, flags, gpg_stream_functions_file); - - return err; -} - -gpg_error_t -gpg_stream_create_fd (gpg_stream_t *stream, - int fd, - unsigned int flags) -{ - gpg_stream_spec_fd_t spec = { fd }; - gpg_error_t err = GPG_ERR_NO_ERROR; - - err = gpg_stream_create_do (stream, NULL, &spec, flags, gpg_stream_functions_fd); - - return err; -} - - -gpg_error_t -gpg_stream_destroy (gpg_stream_t stream) -{ - gpg_error_t err = GPG_ERR_NO_ERROR, tmp_err = GPG_ERR_NO_ERROR; - - if (stream) - { - SET_UNLESS_NONZERO (err, tmp_err, buffer_destroy (stream->buffer)); - if (stream->functions.func_destroy) - SET_UNLESS_NONZERO (err, tmp_err, \ - (*stream->functions.func_destroy) (stream->handle)); - free (stream); - } - - return err; -} - -static gpg_error_t -gpg_stream_read_do (gpg_stream_t stream, - char *buffer, - size_t bytes_to_read, - size_t *bytes_read) -{ - gpg_error_t err = GPG_ERR_NO_ERROR; - - if (! (stream->flags & GPG_STREAM_FLAG_READ)) - err = gpg_error (GPG_ERR_NOT_SUPPORTED); - else - err = buffer_read (stream->buffer, - buffer, bytes_to_read, bytes_read); - - return err; -} - -gpg_error_t -gpg_stream_read (gpg_stream_t stream, - char *buffer, - size_t bytes_to_read, - size_t *bytes_read) -{ - gpg_error_t err = GPG_ERR_NO_ERROR; - - err = gpg_stream_read_do (stream, buffer, bytes_to_read, bytes_read); - - return err; -} - -static gpg_error_t -gpg_stream_write_do (gpg_stream_t stream, - const char *buffer, - size_t bytes_to_write, - size_t *bytes_written) -{ - gpg_error_t err = GPG_ERR_NO_ERROR; - - if (! (stream->flags & GPG_STREAM_FLAG_WRITE)) - err = GPG_ERR_NOT_SUPPORTED; - else - err = buffer_write (stream->buffer, - buffer, bytes_to_write, bytes_written); - - return err; -} - -gpg_error_t -gpg_stream_write (gpg_stream_t stream, - const char *buffer, - size_t bytes_to_write, - size_t *bytes_written) -{ - gpg_error_t err = GPG_ERR_NO_ERROR; - - err = gpg_stream_write_do (stream, buffer, bytes_to_write, bytes_written); - - return err; -} - -static gpg_error_t -gpg_stream_read_line_do (gpg_stream_t stream, - char **line, - size_t *line_length) -{ - gpg_error_t err = GPG_ERR_NO_ERROR; - - if (! (stream->flags & GPG_STREAM_FLAG_READ)) - err = gpg_error (GPG_ERR_NOT_SUPPORTED); - else - { - buffer_functions_t buffer_fncs_mem = { gpg_stream_func_mem_read, - gpg_stream_func_mem_write, - gpg_stream_func_mem_seek }; - buffer_conspec_t buffer_conspec = { NULL }; - void *handle = NULL; - char *line_new = NULL; - buffer_t line_buffer = NULL; - char *newline = NULL; - size_t data_size = 0; - char *data = NULL; - size_t line_size = 0; - - buffer_conspec_get (stream->buffer, &buffer_conspec); - - err = gpg_stream_func_mem_create (&handle, NULL, 0); - if (! err) - err = buffer_create (&line_buffer, &buffer_conspec, handle, buffer_fncs_mem); - if (! err) - do - { - err = buffer_peek (stream->buffer, &data, &data_size); - if (! err) - { - size_t bytes_written = 0; - - newline = memchr (data, '\n', data_size); - if (newline) - { - /* Write until newline. */ - line_size += newline - data + 1; - err = buffer_write (line_buffer, data, newline - data + 1, - &bytes_written); - if (! err) - err = buffer_skip (stream->buffer, bytes_written); - break; - } - else - { - /* Write whole block. */ - line_size += data_size; - err = buffer_write (line_buffer, data, data_size, - &bytes_written); - if (! err) - err = buffer_skip (stream->buffer, bytes_written); - } - } - } - while ((! err) && data_size); - - if (! err) - { - /* Complete line has been written to line_buffer. */ - if (line_size) - { - err = buffer_seek (line_buffer, 0, SEEK_SET); - if (! err) - { - line_new = malloc (line_size + 1); - if (! line_new) - err = gpg_error_from_errno (errno); - } - if (! err) - { - size_t bytes_written = 0, written = 0; - - while ((bytes_written < line_size) && (! err)) - { - err = buffer_read (line_buffer, line_new + bytes_written, - line_size - bytes_written, &written); - bytes_written += written; - } - if (! err) - line_new[line_size] = 0; - } - } - } - - if (line_buffer) - buffer_destroy (line_buffer); - if (handle) - gpg_stream_func_mem_destroy (handle); - - if (! err) - { - *line = line_new; - if (line_length) - *line_length = line_size; - } - else - { - if (line_new) - free (line_new); - } - } - - return err; -} - -gpg_error_t -gpg_stream_read_line (gpg_stream_t stream, - char **line, - size_t *line_length) -{ - gpg_error_t err = GPG_ERR_NO_ERROR; - - err = gpg_stream_read_line_do (stream, line, line_length); - - return err; -} - -static gpg_error_t -gpg_stream_print_va_do (gpg_stream_t stream, - const char *format, - va_list ap) -{ - gpg_error_t err = GPG_ERR_NO_ERROR; - FILE *tmp_stream = NULL; - int ret = 0; - - if (! (stream->flags & GPG_STREAM_FLAG_WRITE)) - err = gpg_error (GPG_ERR_NOT_SUPPORTED); - else - { - tmp_stream = tmpfile (); - if (! tmp_stream) - err = gpg_error_from_errno (errno); - - if (! err) - { - ret = vfprintf (tmp_stream, format, ap); - if (ret == -1) - err = gpg_error_from_errno (errno); - } - - if (! err) - { - ret = fseek (tmp_stream, 0, SEEK_SET); - if (ret == -1) - err = gpg_error_from_errno (errno); - } - - if (! err) - { - size_t bytes_read = 0, bytes_written = 0; - char data[BUFFER_BLOCK_SIZE]; - - while (! err) - { - bytes_read = fread (data, 1, sizeof (data), tmp_stream); - if (ferror (tmp_stream)) - err = gpg_error_from_errno (errno); - if (! err) - err = gpg_stream_write_do (stream, data, - bytes_read, &bytes_written); - if (! err) - if (feof (tmp_stream)) - break; - } - } - - if (tmp_stream) - fclose (tmp_stream); - } - - return err; -} - -gpg_error_t -gpg_stream_print_va (gpg_stream_t stream, - const char *format, - va_list ap) -{ - gpg_error_t err = GPG_ERR_NO_ERROR; - - err = gpg_stream_print_va_do (stream, format, ap); - - return err; -} - -gpg_error_t -gpg_stream_print (gpg_stream_t stream, - const char *format, - ...) -{ - gpg_error_t err = GPG_ERR_NO_ERROR; - va_list ap; - - va_start (ap, format); - err = gpg_stream_print_va (stream, format, ap); - va_end (ap); - - return err; -} - -static gpg_error_t -gpg_stream_flush_do (gpg_stream_t stream) -{ - gpg_error_t err = GPG_ERR_NO_ERROR; - - err = buffer_flush (stream->buffer); - - return err; -} - -gpg_error_t -gpg_stream_flush (gpg_stream_t stream) -{ - gpg_error_t err = GPG_ERR_NO_ERROR; - - err = gpg_stream_flush_do (stream); - - return err; -} - -static gpg_error_t -gpg_stream_peek_do (gpg_stream_t stream, - char **buffer, - size_t *size) -{ - gpg_error_t err = GPG_ERR_NO_ERROR; - - err = buffer_peek (stream->buffer, buffer, size); - - return err; -} - -gpg_error_t -gpg_stream_peek (gpg_stream_t stream, - char **buffer, - size_t *size) -{ - gpg_error_t err = GPG_ERR_NO_ERROR; - - err = gpg_stream_peek_do (stream, buffer, size); - - return err; -} - -static gpg_error_t -gpg_stream_seek_do (gpg_stream_t stream, - off_t offset, - int whence) -{ - gpg_error_t err = GPG_ERR_NO_ERROR; - - err = buffer_seek (stream->buffer, offset, whence); - - return err; -} - -gpg_error_t -gpg_stream_seek (gpg_stream_t stream, - off_t offset, - int whence) -{ - gpg_error_t err = GPG_ERR_NO_ERROR; - - err = gpg_stream_seek_do (stream, offset, whence); - - return err; -} - -static gpg_error_t -gpg_stream_stat_do (gpg_stream_t stream, - size_t *size) -{ - gpg_error_t err = GPG_ERR_NO_ERROR; - - err = buffer_stat (stream->buffer, size); - - return err; -} - -gpg_error_t -gpg_stream_stat (gpg_stream_t stream, - size_t *size) -{ - gpg_error_t err = GPG_ERR_NO_ERROR; - - err = gpg_stream_stat_do (stream, size); - - return err; -} - - -static gpg_error_t -gpg_stream_copy_do (gpg_stream_t dst, - gpg_stream_t src) -{ - gpg_error_t err = GPG_ERR_NO_ERROR; - unsigned char buffer[STREAM_BLOCK_SIZE]; - size_t bytes_read = 0; - - while (1) - { - err = gpg_stream_read (src, buffer, sizeof (buffer), &bytes_read); - if (err || (! bytes_read)) - break; - - err = gpg_stream_write (dst, buffer, bytes_read, NULL); - if (err) - break; - } - - return err; -} - -gpg_error_t -gpg_stream_copy (gpg_stream_t dst, - gpg_stream_t src) -{ - gpg_error_t err = GPG_ERR_NO_ERROR; - - err = gpg_stream_copy_do (dst, src); - - return err; -} |