diff options
Diffstat (limited to 'lib/opencdk/stream.c')
-rw-r--r-- | lib/opencdk/stream.c | 1471 |
1 files changed, 0 insertions, 1471 deletions
diff --git a/lib/opencdk/stream.c b/lib/opencdk/stream.c deleted file mode 100644 index 496115aa3e..0000000000 --- a/lib/opencdk/stream.c +++ /dev/null @@ -1,1471 +0,0 @@ -/* stream.c - The stream implementation - * Copyright (C) 2002-2012 Free Software Foundation, Inc. - * - * Author: Timo Schulz - * - * This file is part of OpenCDK. - * - * The OpenCDK library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library 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 Lesser General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif -#include <assert.h> -#include <stdio.h> -#include <sys/stat.h> -#include <string.h> -#include <stdlib.h> -#include <errno.h> -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif - -#include "opencdk.h" -#include "main.h" -#include "filters.h" -#include "stream.h" -#include "types.h" - -/* This is the maximal amount of bytes we map. */ -#define MAX_MAP_SIZE 16777216 - -static cdk_error_t stream_flush(cdk_stream_t s); -static cdk_error_t stream_filter_write(cdk_stream_t s); -static int stream_cache_flush(cdk_stream_t s, FILE * fp); -struct stream_filter_s *filter_add(cdk_stream_t s, filter_fnct_t fnc, - int type); - - -/* FIXME: The read/write/putc/getc function cannot directly - return an error code. It is stored in an error variable - inside the string. Right now there is no code to - return the error code or to reset it. */ - -/** - * cdk_stream_open: - * @file: The file to open - * @ret_s: The new STREAM object - * - * Creates a new stream based on an existing file. The stream is - * opened in read-only mode. - **/ -cdk_error_t cdk_stream_open(const char *file, cdk_stream_t * ret_s) -{ - return _cdk_stream_open_mode(file, "rb", ret_s); -} - - -/* Helper function to allow to open a stream in different modes. */ -cdk_error_t -_cdk_stream_open_mode(const char *file, const char *mode, - cdk_stream_t * ret_s) -{ - cdk_stream_t s; - - if (!file || !ret_s) { - gnutls_assert(); - return CDK_Inv_Value; - } -#ifdef DEBUG_STREAM - _gnutls_read_log("open stream `%s'\n", file); -#endif - *ret_s = NULL; - s = cdk_calloc(1, sizeof *s); - if (!s) { - gnutls_assert(); - return CDK_Out_Of_Core; - } - s->fname = cdk_strdup(file); - if (!s->fname) { - cdk_free(s); - gnutls_assert(); - return CDK_Out_Of_Core; - } - s->fp = fopen(file, mode); - if (!s->fp) { - cdk_free(s->fname); - cdk_free(s); - gnutls_assert(); - return CDK_File_Error; - } -#ifdef DEBUG_STREAM - _gnutls_read_log("open stream fd=%d\n", fileno(s->fp)); -#endif - s->flags.write = 0; - *ret_s = s; - return 0; -} - - -/** - * cdk_stream_new_from_cbs: - * @cbs: the callback context with all user callback functions - * @opa: uint8_t handle which is passed to all callbacks. - * @ret_s: the allocated stream - * - * This function creates a stream which uses user callback - * for the core operations (open, close, read, write, seek). - */ -cdk_error_t -cdk_stream_new_from_cbs(cdk_stream_cbs_t cbs, void *opa, - cdk_stream_t * ret_s) -{ - cdk_stream_t s; - - if (!cbs || !opa || !ret_s) { - gnutls_assert(); - return CDK_Inv_Value; - } - - *ret_s = NULL; - s = cdk_calloc(1, sizeof *s); - if (!s) { - gnutls_assert(); - return CDK_Out_Of_Core; - } - - s->cbs.read = cbs->read; - s->cbs.write = cbs->write; - s->cbs.seek = cbs->seek; - s->cbs.release = cbs->release; - s->cbs.open = cbs->open; - s->cbs_hd = opa; - *ret_s = s; - - /* If there is a user callback for open, we need to call it - here because read/write expects an open stream. */ - if (s->cbs.open) - return s->cbs.open(s->cbs_hd); - return 0; -} - - -/** - * cdk_stream_new: - * @file: The name of the new file - * @ret_s: The new STREAM object - * - * Create a new stream into the given file. - **/ -cdk_error_t cdk_stream_new(const char *file, cdk_stream_t * ret_s) -{ - cdk_stream_t s; - - if (!ret_s) { - gnutls_assert(); - return CDK_Inv_Value; - } -#ifdef DEBUG_STREAM - _gnutls_read_log("new stream `%s'\n", file ? file : "[temp]"); -#endif - *ret_s = NULL; - s = cdk_calloc(1, sizeof *s); - if (!s) { - gnutls_assert(); - return CDK_Out_Of_Core; - } - s->flags.write = 1; - if (!file) - s->flags.temp = 1; - else { - s->fname = cdk_strdup(file); - if (!s->fname) { - cdk_free(s); - gnutls_assert(); - return CDK_Out_Of_Core; - } - } - s->fp = _cdk_tmpfile(); - if (!s->fp) { - cdk_free(s->fname); - cdk_free(s); - gnutls_assert(); - return CDK_File_Error; - } -#ifdef DEBUG_STREAM - _gnutls_read_log("new stream fd=%d\n", fileno(s->fp)); -#endif - *ret_s = s; - return 0; -} - -/** - * cdk_stream_create: - * @file: the filename - * @ret_s: the object - * - * Creates a new stream. - * The difference to cdk_stream_new is, that no filtering can be used with - * this kind of stream and everything is written directly to the stream. - **/ -cdk_error_t cdk_stream_create(const char *file, cdk_stream_t * ret_s) -{ - cdk_stream_t s; - - if (!file || !ret_s) { - gnutls_assert(); - return CDK_Inv_Value; - } -#ifdef DEBUG_STREAM - _gnutls_read_log("create stream `%s'\n", file); -#endif - *ret_s = NULL; - s = cdk_calloc(1, sizeof *s); - if (!s) { - gnutls_assert(); - return CDK_Out_Of_Core; - } - s->flags.write = 1; - s->flags.filtrated = 1; - s->fname = cdk_strdup(file); - if (!s->fname) { - cdk_free(s); - gnutls_assert(); - return CDK_Out_Of_Core; - } - s->fp = fopen(file, "w+b"); - if (!s->fp) { - cdk_free(s->fname); - cdk_free(s); - gnutls_assert(); - return CDK_File_Error; - } -#ifdef DEBUG_STREAM - _gnutls_read_log("stream create fd=%d\n", fileno(s->fp)); -#endif - *ret_s = s; - return 0; -} - - -/** - * cdk_stream_tmp_new: - * @r_out: the new temp stream. - * - * Allocates a new tempory stream which is not associated with a file. - */ -cdk_error_t cdk_stream_tmp_new(cdk_stream_t * r_out) -{ - return cdk_stream_new(NULL, r_out); -} - - - -/** - * cdk_stream_tmp_from_mem: - * @buf: the buffer which shall be written to the temp stream. - * @buflen: how large the buffer is - * @r_out: the new stream with the given contents. - * - * Creates a new tempory stream with the given contests. - */ -cdk_error_t -cdk_stream_tmp_from_mem(const void *buf, size_t buflen, - cdk_stream_t * r_out) -{ - cdk_stream_t s; - cdk_error_t rc; - int nwritten; - - *r_out = NULL; - rc = cdk_stream_tmp_new(&s); - if (rc) { - gnutls_assert(); - return rc; - } - - nwritten = cdk_stream_write(s, buf, buflen); - if (nwritten == EOF) { - cdk_stream_close(s); - gnutls_assert(); - return s->error; - } - cdk_stream_seek(s, 0); - *r_out = s; - return 0; -} - - -cdk_error_t -_cdk_stream_fpopen(FILE * fp, unsigned write_mode, cdk_stream_t * ret_out) -{ - cdk_stream_t s; - - *ret_out = NULL; - s = cdk_calloc(1, sizeof *s); - if (!s) { - gnutls_assert(); - return CDK_Out_Of_Core; - } -#ifdef DEBUG_STREAM - _gnutls_read_log("stream ref fd=%d\n", fileno(fp)); -#endif - s->fp = fp; - s->fp_ref = 1; - s->flags.filtrated = 1; - s->flags.write = write_mode; - - *ret_out = s; - return 0; -} - - -cdk_error_t _cdk_stream_append(const char *file, cdk_stream_t * ret_s) -{ - cdk_stream_t s; - cdk_error_t rc; - - if (!ret_s) { - gnutls_assert(); - return CDK_Inv_Value; - } - *ret_s = NULL; - - rc = _cdk_stream_open_mode(file, "a+b", &s); - if (rc) { - gnutls_assert(); - return rc; - } - - /* In the append mode, we need to write to the flag. */ - s->flags.write = 1; - *ret_s = s; - return 0; -} - -/** - * cdk_stream_is_compressed: - * @s: the stream - * - * Check whether stream is compressed. - * - * Returns: 0 if the stream is uncompressed, otherwise the compression - * algorithm. - */ -int cdk_stream_is_compressed(cdk_stream_t s) -{ - if (!s) - return 0; - return s->flags.compressed; -} - -void _cdk_stream_set_compress_algo(cdk_stream_t s, int algo) -{ - if (!s) - return; - s->flags.compressed = algo; -} - - -cdk_error_t cdk_stream_flush(cdk_stream_t s) -{ - cdk_error_t rc; - - if (!s) { - gnutls_assert(); - return CDK_Inv_Value; - } - - /* The user callback does not support flush */ - if (s->cbs_hd) - return 0; - - /* For read-only streams, no flush is needed. */ - if (!s->flags.write) - return 0; - - if (!s->flags.filtrated) { - if (!cdk_stream_get_length(s)) - return 0; - rc = cdk_stream_seek(s, 0); - if (!rc) - rc = stream_flush(s); - if (!rc) - rc = stream_filter_write(s); - s->flags.filtrated = 1; - if (rc) { - s->error = rc; - gnutls_assert(); - return rc; - } - } - return 0; -} - - -void cdk_stream_tmp_set_mode(cdk_stream_t s, int val) -{ - if (s && s->flags.temp) - s->fmode = val; -} - - -/** - * cdk_stream_close: - * @s: The STREAM object. - * - * Close a stream and flush all buffers. This function work different - * for read or write streams. When the stream is for reading, the - * filtering is already done and we can simply close the file and all - * buffers. But for the case it's a write stream, we need to apply - * all registered filters now. The file is closed in the filter - * function and not here. - **/ -cdk_error_t cdk_stream_close(cdk_stream_t s) -{ - struct stream_filter_s *f, *f2; - cdk_error_t rc; - - if (!s) { - gnutls_assert(); - return CDK_Inv_Value; - } -#ifdef DEBUG_STREAM - _gnutls_read_log("close stream ref=%d `%s'\n", - s->fp_ref, s->fname ? s->fname : "[temp]"); -#endif - - /* In the user callback mode, we call the release cb if possible - and just free the stream. */ - if (s->cbs_hd) { - if (s->cbs.release) - rc = s->cbs.release(s->cbs_hd); - else - rc = 0; - cdk_free(s); - gnutls_assert(); - return rc; - } - - - rc = 0; - if (!s->flags.filtrated && !s->error) - rc = cdk_stream_flush(s); - if (!s->fp_ref && (s->fname || s->flags.temp)) { - int err; - -#ifdef DEBUG_STREAM - _gnutls_read_log("close stream fd=%d\n", fileno(s->fp)); -#endif - err = fclose(s->fp); - s->fp = NULL; - if (err) - rc = CDK_File_Error; - } - - /* Iterate over the filter list and use the cleanup flag to - free the allocated internal structures. */ - f = s->filters; - while (f) { - f2 = f->next; - if (f->fnct) - f->fnct(f->uint8_t, STREAMCTL_FREE, NULL, NULL); - cdk_free(f); - f = f2; - } - - if (s->fname) { - cdk_free(s->fname); - s->fname = NULL; - } - - cdk_free(s->cache.buf); - s->cache.alloced = 0; - - cdk_free(s); - - if (rc) - gnutls_assert(); - - return rc; -} - - -/** - * cdk_stream_eof: - * @s: The STREAM object. - * - * Return if the associated file handle was set to EOF. This - * function will only work with read streams. - **/ -int cdk_stream_eof(cdk_stream_t s) -{ - return s ? s->flags.eof : -1; -} - - -const char *_cdk_stream_get_fname(cdk_stream_t s) -{ - if (!s) - return NULL; - if (s->flags.temp) - return NULL; - return s->fname ? s->fname : NULL; -} - - -/* Return the underlying FP of the stream. - WARNING: This handle should not be closed. */ -FILE *_cdk_stream_get_fp(cdk_stream_t s) -{ - return s ? s->fp : NULL; -} - - -int _cdk_stream_get_errno(cdk_stream_t s) -{ - return s ? s->error : CDK_Inv_Value; -} - - -/** - * cdk_stream_get_length: - * @s: The STREAM object. - * - * Return the length of the associated file handle. This function - * should work for both read and write streams. For write streams an - * additional flush is used to write possible pending data. - **/ -off_t cdk_stream_get_length(cdk_stream_t s) -{ - struct stat statbuf; - cdk_error_t rc; - - if (!s) { - gnutls_assert(); - return (off_t) 0; - } - - /* The user callback does not support stat. */ - if (s->cbs_hd) - return 0; - - rc = stream_flush(s); - if (rc) { - s->error = rc; - gnutls_assert(); - return (off_t) 0; - } - - if (fstat(fileno(s->fp), &statbuf)) { - s->error = CDK_File_Error; - gnutls_assert(); - return (off_t) 0; - } - - return statbuf.st_size; -} - - -static struct stream_filter_s *filter_add2(cdk_stream_t s) -{ - struct stream_filter_s *f; - - assert(s); - - f = cdk_calloc(1, sizeof *f); - if (!f) - return NULL; - f->next = s->filters; - s->filters = f; - return f; -} - - -static struct stream_filter_s *filter_search(cdk_stream_t s, - filter_fnct_t fnc) -{ - struct stream_filter_s *f; - - assert(s); - - for (f = s->filters; f; f = f->next) { - if (f->fnct == fnc) - return f; - } - - return NULL; -} - -static inline void set_uint8_t(struct stream_filter_s *f) -{ - switch (f->type) { - case fARMOR: - f->uint8_t = &f->u.afx; - break; - case fCIPHER: - f->uint8_t = &f->u.cfx; - break; - case fLITERAL: - f->uint8_t = &f->u.pfx; - break; - case fCOMPRESS: - f->uint8_t = &f->u.zfx; - break; - case fHASH: - f->uint8_t = &f->u.mfx; - break; - case fTEXT: - f->uint8_t = &f->u.tfx; - break; - default: - f->uint8_t = NULL; - } - -} - -struct stream_filter_s *filter_add(cdk_stream_t s, filter_fnct_t fnc, - int type) -{ - struct stream_filter_s *f; - - assert(s); - - s->flags.filtrated = 0; - f = filter_search(s, fnc); - if (f) - return f; - f = filter_add2(s); - if (!f) - return NULL; - f->fnct = fnc; - f->flags.enabled = 1; - f->tmp = NULL; - f->type = type; - - set_uint8_t(f); - - return f; -} - -static int stream_get_mode(cdk_stream_t s) -{ - assert(s); - - if (s->flags.temp) - return s->fmode; - return s->flags.write; -} - - -static filter_fnct_t stream_id_to_filter(int type) -{ - switch (type) { - case fARMOR: - return _cdk_filter_armor; - case fLITERAL: - return _cdk_filter_literal; - case fTEXT: - return _cdk_filter_text; -/* case fCIPHER : return _cdk_filter_cipher; */ -/* case fCOMPRESS: return _cdk_filter_compress; */ - default: - return NULL; - } -} - - -/** - * cdk_stream_filter_disable: - * @s: The STREAM object - * @type: The numberic filter ID. - * - * Disables the filter with the type 'type'. - **/ -cdk_error_t cdk_stream_filter_disable(cdk_stream_t s, int type) -{ - struct stream_filter_s *f; - filter_fnct_t fnc; - - if (!s) { - gnutls_assert(); - return CDK_Inv_Value; - } - - fnc = stream_id_to_filter(type); - if (!fnc) { - gnutls_assert(); - return CDK_Inv_Value; - } - f = filter_search(s, fnc); - if (f) - f->flags.enabled = 0; - return 0; -} - - -/* WARNING: tmp should not be closed by the caller. */ -static cdk_error_t stream_fp_replace(cdk_stream_t s, FILE ** tmp) -{ - int rc; - - assert(s); - -#ifdef DEBUG_STREAM - _gnutls_read_log("replace stream fd=%d with fd=%d\n", - fileno(s->fp), fileno(*tmp)); -#endif - rc = fclose(s->fp); - if (rc) { - s->fp = NULL; - gnutls_assert(); - return CDK_File_Error; - } - s->fp = *tmp; - *tmp = NULL; - return 0; -} - - -/* This function is exactly like filter_read, except the fact that we can't - use tmpfile () all the time. That's why we open the real file when there - is no last filter. */ -static cdk_error_t stream_filter_write(cdk_stream_t s) -{ - struct stream_filter_s *f; - cdk_error_t rc = 0; - - assert(s); - - if (s->flags.filtrated) { - gnutls_assert(); - return CDK_Inv_Value; - } - - for (f = s->filters; f; f = f->next) { - if (!f->flags.enabled) - continue; - /* if there is no next filter, create the final output file */ -#ifdef DEBUG_STREAM - _gnutls_read_log - ("filter [write]: last filter=%d fname=%s\n", - f->next ? 1 : 0, s->fname); -#endif - if (!f->next && s->fname) - f->tmp = fopen(s->fname, "w+b"); - else - f->tmp = _cdk_tmpfile(); - if (!f->tmp) { - rc = CDK_File_Error; - break; - } - /* If there is no next filter, flush the cache. We also do this - when the next filter is the armor filter because this filter - is special and before it starts, all data should be written. */ - if ((!f->next || f->next->type == fARMOR) && s->cache.size) { - rc = stream_cache_flush(s, f->tmp); - if (rc) - break; - } - rc = f->fnct(f->uint8_t, f->ctl, s->fp, f->tmp); -#ifdef DEBUG_STREAM - _gnutls_read_log("filter [write]: type=%d rc=%d\n", - f->type, rc); -#endif - if (!rc) - rc = stream_fp_replace(s, &f->tmp); - if (!rc) - rc = cdk_stream_seek(s, 0); - if (rc) { -#ifdef DEBUG_STREAM - _gnutls_read_log("filter [close]: fd=%d\n", - fileno(f->tmp)); -#endif - fclose(f->tmp); - f->tmp = NULL; - break; - } - } - return rc; -} - - -/* Here all data from the file handle is passed through all filters. - The scheme works like this: - Create a tempfile and use it for the output of the filter. Then the - original file handle will be closed and replace with the temp handle. - The file pointer will be set to the begin and the game starts again. */ -static cdk_error_t stream_filter_read(cdk_stream_t s) -{ - struct stream_filter_s *f; - cdk_error_t rc = 0; - - assert(s); - - if (s->flags.filtrated) - return 0; - - for (f = s->filters; f; f = f->next) { - if (!f->flags.enabled) - continue; - if (f->flags.error) { -#ifdef DEBUG_STREAM - _gnutls_read_log - ("filter %s [read]: has the error flag; skipped\n", - s->fname ? s->fname : "[temp]"); -#endif - continue; - } - - f->tmp = _cdk_tmpfile(); - if (!f->tmp) { - rc = CDK_File_Error; - break; - } - rc = f->fnct(f->uint8_t, f->ctl, s->fp, f->tmp); -#ifdef DEBUG_STREAM - _gnutls_read_log("filter %s [read]: type=%d rc=%d\n", - s->fname ? s->fname : "[temp]", f->type, - rc); -#endif - if (rc) { - f->flags.error = 1; - break; - } - - f->flags.error = 0; - /* If the filter is read-only, do not replace the FP because - the contents were not altered in any way. */ - if (!f->flags.rdonly) { - rc = stream_fp_replace(s, &f->tmp); - if (rc) - break; - } else { - fclose(f->tmp); - f->tmp = NULL; - } - rc = cdk_stream_seek(s, 0); - if (rc) - break; - /* Disable the filter after it was successfully used. The idea - is the following: let's say the armor filter was pushed and - later more filters were added. The second time the filter code - will be executed, only the new filter should be started but - not the old because we already used it. */ - f->flags.enabled = 0; - } - - return rc; -} - - -void *_cdk_stream_get_uint8_t(cdk_stream_t s, int fid) -{ - struct stream_filter_s *f; - - if (!s) - return NULL; - - for (f = s->filters; f; f = f->next) { - if ((int) f->type == fid) - return f->uint8_t; - } - return NULL; -} - - -/** - * cdk_stream_read: - * @s: The STREAM object. - * @buf: The buffer to insert the readed bytes. - * @count: Request so much bytes. - * - * Tries to read count bytes from the STREAM object. - * When this function is called the first time, it can take a while - * because all filters need to be processed. Please remember that you - * need to add the filters in reserved order. - **/ -int cdk_stream_read(cdk_stream_t s, void *buf, size_t buflen) -{ - int nread; - int rc; - - if (!s) { - gnutls_assert(); - return EOF; - } - - if (s->cbs_hd) { - if (s->cbs.read) - return s->cbs.read(s->cbs_hd, buf, buflen); - return 0; - } - - if (s->flags.write && !s->flags.temp) { - s->error = CDK_Inv_Mode; - gnutls_assert(); - return EOF; /* This is a write stream */ - } - - if (!s->flags.no_filter && !s->cache.on && !s->flags.filtrated) { - rc = stream_filter_read(s); - if (rc) { - s->error = rc; - if (s->fp && feof(s->fp)) - s->flags.eof = 1; - gnutls_assert(); - return EOF; - } - s->flags.filtrated = 1; - } - - if (!buf || !buflen) - return 0; - - nread = fread(buf, 1, buflen, s->fp); - if (!nread) - nread = EOF; - - if (feof(s->fp)) { - s->error = 0; - s->flags.eof = 1; - } - return nread; -} - - -int cdk_stream_getc(cdk_stream_t s) -{ - unsigned char buf[2] = {0}; - int nread; - - if (!s) { - gnutls_assert(); - return EOF; - } - nread = cdk_stream_read(s, buf, 1); - if (nread == EOF) { - s->error = CDK_File_Error; - gnutls_assert(); - return EOF; - } - return buf[0]; -} - - -/** - * cdk_stream_write: - * @s: The STREAM object - * @buf: The buffer with the values to write. - * @count: The size of the buffer. - * - * Tries to write count bytes into the stream. - * In this function we simply write the bytes to the stream. We can't - * use the filters here because it would mean they have to support - * partial flushing. - **/ -int cdk_stream_write(cdk_stream_t s, const void *buf, size_t count) -{ - int nwritten; - - if (!s) { - gnutls_assert(); - return EOF; - } - - if (s->cbs_hd) { - if (s->cbs.write) - return s->cbs.write(s->cbs_hd, buf, count); - return 0; - } - - if (!s->flags.write) { - s->error = CDK_Inv_Mode; /* this is a read stream */ - gnutls_assert(); - return EOF; - } - - if (!buf || !count) - return stream_flush(s); - - if (s->cache.on) { -#ifdef DEBUG_STREAM - _gnutls_read_log("stream[ref=%u]: written %d bytes\n", - s->fp_ref, (int) count); -#endif - - /* We need to resize the buffer if the additional data wouldn't - fit into it. We allocate more memory to avoid to resize it the - next time the function is used. */ - if (s->cache.size + count > s->cache.alloced) { - byte *old = s->cache.buf; - - s->cache.buf = - cdk_calloc(1, - s->cache.alloced + count + - STREAM_BUFSIZE); - s->cache.alloced += (count + STREAM_BUFSIZE); - memcpy(s->cache.buf, old, s->cache.size); - cdk_free(old); -#ifdef DEBUG_STREAM - _gnutls_read_log - ("stream: enlarge cache to %d octets\n", - (int) s->cache.alloced); -#endif - } - - memcpy(s->cache.buf + s->cache.size, buf, count); - s->cache.size += count; - return count; - } -#ifdef DEBUG_STREAM - _gnutls_read_log("stream[fd=%u]: written %d bytes\n", - fileno(s->fp), (int) count); -#endif - - nwritten = fwrite(buf, 1, count, s->fp); - if (!nwritten) - nwritten = EOF; - return nwritten; -} - - -int cdk_stream_putc(cdk_stream_t s, int c) -{ - byte buf[2]; - int nwritten; - - if (!s) { - gnutls_assert(); - return EOF; - } - buf[0] = c; - nwritten = cdk_stream_write(s, buf, 1); - if (nwritten == EOF) - return EOF; - return 0; -} - - -off_t cdk_stream_tell(cdk_stream_t s) -{ - return s ? ftell(s->fp) : (off_t) 0; -} - - -cdk_error_t cdk_stream_seek(cdk_stream_t s, off_t offset) -{ - off_t len; - - if (!s) { - gnutls_assert(); - return CDK_Inv_Value; - } - - if (s->cbs_hd) { - if (s->cbs.seek) - return s->cbs.seek(s->cbs_hd, offset); - return 0; - } - - /* Set or reset the EOF flag. */ - len = cdk_stream_get_length(s); - if (len == offset) - s->flags.eof = 1; - else - s->flags.eof = 0; - - if (fseek(s->fp, offset, SEEK_SET)) { - gnutls_assert(); - return CDK_File_Error; - } - return 0; -} - - -static cdk_error_t stream_flush(cdk_stream_t s) -{ - assert(s); - - /* For some constellations it cannot be assured that the - return value is defined, thus we ignore it for now. */ - (void) fflush(s->fp); - return 0; -} - - -/** - * cdk_stream_set_armor_flag: - * @s: the stream object - * @type: the type of armor to use - * - * If the file is in read-mode, no armor type needs to be - * defined (armor_type=0) because the armor filter will be - * used for decoding existing armor data. - * For the write mode, @armor_type can be set to any valid - * armor type (message, key, sig). - **/ -cdk_error_t cdk_stream_set_armor_flag(cdk_stream_t s, int armor_type) -{ - struct stream_filter_s *f; - - if (!s) { - gnutls_assert(); - return CDK_Inv_Value; - } - f = filter_add(s, _cdk_filter_armor, fARMOR); - if (!f) { - gnutls_assert(); - return CDK_Out_Of_Core; - } - f->u.afx.idx = f->u.afx.idx2 = armor_type; - f->ctl = stream_get_mode(s); - return 0; -} - - -/** - * cdk_stream_set_literal_flag: - * @s: the stream object - * @mode: the mode to use (binary, text, unicode) - * @fname: the file name to store in the packet. - * - * In read mode it kicks off the literal decoding routine to - * unwrap the data from the packet. The @mode parameter is ignored. - * In write mode the function can be used to wrap the stream data - * into a literal packet with the given mode and file name. - **/ -cdk_error_t -cdk_stream_set_literal_flag(cdk_stream_t s, cdk_lit_format_t mode, - const char *fname) -{ - struct stream_filter_s *f; - const char *orig_fname; - -#ifdef DEBUG_STREAM - _gnutls_read_log("stream: enable literal mode.\n"); -#endif - - if (!s) { - gnutls_assert(); - return CDK_Inv_Value; - } - - orig_fname = _cdk_stream_get_fname(s); - f = filter_add(s, _cdk_filter_literal, fLITERAL); - if (!f) { - gnutls_assert(); - return CDK_Out_Of_Core; - } - f->u.pfx.mode = mode; - f->u.pfx.filename = fname ? cdk_strdup(fname) : NULL; - f->u.pfx.orig_filename = - orig_fname ? cdk_strdup(orig_fname) : NULL; - f->ctl = stream_get_mode(s); - if (s->blkmode > 0) { - f->u.pfx.blkmode.on = 1; - f->u.pfx.blkmode.size = s->blkmode; - } - return 0; -} - - -/** - * cdk_stream_set_compress_flag: - * @s: the stream object - * @algo: the compression algo - * @level: level of compression (0..9) - * - * In read mode it kicks off the decompression filter to retrieve - * the uncompressed data. - * In write mode the stream data will be compressed with the - * given algorithm at the given level. - **/ -cdk_error_t -cdk_stream_set_compress_flag(cdk_stream_t s, int algo, int level) -{ - - gnutls_assert(); - return CDK_Not_Implemented; -} - - -/** - * cdk_stream_set_text_flag: - * @s: the stream object - * @lf: line ending - * - * Pushes the text filter to store the stream data in cannoncial format. - **/ -cdk_error_t cdk_stream_set_text_flag(cdk_stream_t s, const char *lf) -{ - struct stream_filter_s *f; - - if (!s) { - gnutls_assert(); - return CDK_Inv_Value; - } - f = filter_add(s, _cdk_filter_text, fTEXT); - if (!f) { - gnutls_assert(); - return CDK_Out_Of_Core; - } - f->ctl = stream_get_mode(s); - f->u.tfx.lf = lf; - return 0; -} - -/** - * cdk_stream_enable_cache: - * @s: the stream object - * @val: 1=on, 0=off - * - * Enables or disable the cache section of a stream object. - **/ -cdk_error_t cdk_stream_enable_cache(cdk_stream_t s, int val) -{ - if (!s) { - gnutls_assert(); - return CDK_Inv_Value; - } - if (!s->flags.write) { - gnutls_assert(); - return CDK_Inv_Mode; - } - s->cache.on = val; - if (!s->cache.buf) { - s->cache.buf = cdk_calloc(1, STREAM_BUFSIZE); - s->cache.alloced = STREAM_BUFSIZE; -#ifdef DEBUG_STREAM - _gnutls_read_log("stream: allocate cache of %d octets\n", - STREAM_BUFSIZE); -#endif - } - return 0; -} - - -static int stream_cache_flush(cdk_stream_t s, FILE * fp) -{ - int nwritten; - - assert(s); - - /* FIXME: We should find a way to use cdk_stream_write here. */ - if (s->cache.size > 0) { - nwritten = fwrite(s->cache.buf, 1, s->cache.size, fp); - if (!nwritten) { - gnutls_assert(); - return CDK_File_Error; - } - s->cache.size = 0; - s->cache.on = 0; - memset(s->cache.buf, 0, s->cache.alloced); - } - return 0; -} - - -/** - * cdk_stream_kick_off: - * @inp: the input stream - * @out: the output stream. - * - * Passes the entire data from @inp into the output stream @out - * with all the activated filters. - */ -cdk_error_t cdk_stream_kick_off(cdk_stream_t inp, cdk_stream_t out) -{ - byte buf[BUFSIZE]; - int nread, nwritten; - cdk_error_t rc; - - if (!inp || !out) { - gnutls_assert(); - return CDK_Inv_Value; - } - rc = CDK_Success; - while (!cdk_stream_eof(inp)) { - nread = cdk_stream_read(inp, buf, DIM(buf)); - if (!nread || nread == EOF) - break; - nwritten = cdk_stream_write(out, buf, nread); - if (!nwritten || nwritten == EOF) { /* In case of errors, we leave the loop. */ - rc = inp->error; - break; - } - } - - memset(buf, 0, sizeof(buf)); - return rc; -} - - -/** - * cdk_stream_mmap_part: - * @s: the stream - * @off: the offset where to start - * @len: how much bytes shall be mapped - * @ret_buf: the buffer to store the content - * @ret_buflen: length of the buffer - * - * Maps the data of the given stream into a memory section. @ret_count - * contains the length of the buffer. - **/ -cdk_error_t -cdk_stream_mmap_part(cdk_stream_t s, off_t off, size_t len, - byte ** ret_buf, size_t * ret_buflen) -{ - cdk_error_t rc; - off_t oldpos; - unsigned int n; - - if (!ret_buf || !ret_buflen) { - gnutls_assert(); - return CDK_Inv_Value; - } - *ret_buf = NULL; - *ret_buflen = 0; - - if (!s) { - gnutls_assert(); - return CDK_Inv_Value; - } - - /* Memory mapping is not supported on custom I/O objects. */ - if (s->cbs_hd) { -#ifdef DEBUG_STREAM - _gnutls_read_log - ("cdk_stream_mmap_part: not supported on callbacks\n"); -#endif - gnutls_assert(); - return CDK_Inv_Mode; - } - - oldpos = cdk_stream_tell(s); - rc = cdk_stream_flush(s); - if (rc) { - gnutls_assert(); - return rc; - } - rc = cdk_stream_seek(s, off); - if (rc) { - gnutls_assert(); - return rc; - } - if (!len) - len = cdk_stream_get_length(s); - if (!len) { - _gnutls_read_log - ("cdk_stream_mmap_part: invalid file size %lu\n", - (unsigned long) len); - gnutls_assert(); - return s->error; - } - if (len > MAX_MAP_SIZE) { - gnutls_assert(); - return CDK_Too_Short; - } - - *ret_buf = cdk_calloc(1, len + 1); - *ret_buflen = len; - n = cdk_stream_read(s, *ret_buf, len); - if (n != len) - *ret_buflen = n; - rc = cdk_stream_seek(s, oldpos); - if (rc) - gnutls_assert(); - return rc; -} - - -cdk_error_t cdk_stream_mmap(cdk_stream_t inp, byte ** buf, size_t * buflen) -{ - off_t len; - - /* We need to make sure all data is flushed before we retrieve the size. */ - cdk_stream_flush(inp); - len = cdk_stream_get_length(inp); - return cdk_stream_mmap_part(inp, 0, len, buf, buflen); -} - - -/** - * cdk_stream_peek: - * @inp: the input stream handle - * @s: buffer - * @count: number of bytes to peek - * - * The function acts like cdk_stream_read with the difference that - * the file pointer is moved to the old position after the bytes were read. - **/ -int cdk_stream_peek(cdk_stream_t inp, byte * buf, size_t buflen) -{ - off_t off; - int nbytes; - - if (!inp || !buf) - return 0; - if (inp->cbs_hd) - return 0; - - off = cdk_stream_tell(inp); - nbytes = cdk_stream_read(inp, buf, buflen); - if (nbytes == -1) - return 0; - if (cdk_stream_seek(inp, off)) - return 0; - return nbytes; -} - - -/* Try to read a line from the given stream. */ -int _cdk_stream_gets(cdk_stream_t s, char *buf, size_t count) -{ - int c, i; - - assert(s); - - i = 0; - while (!cdk_stream_eof(s) && count > 0) { - c = cdk_stream_getc(s); - if (c == EOF || c == '\r' || c == '\n') { - buf[i++] = '\0'; - break; - } - buf[i++] = c; - count--; - } - return i; -} - - -/* Try to write string into the stream @s. */ -int _cdk_stream_puts(cdk_stream_t s, const char *buf) -{ - return cdk_stream_write(s, buf, strlen(buf)); -} - - -/* Activate the block mode for the given stream. */ -cdk_error_t _cdk_stream_set_blockmode(cdk_stream_t s, size_t nbytes) -{ - assert(s); - -#ifdef DEBUG_STREAM - _gnutls_read_log("stream: activate block mode with blocksize %d\n", - (int) nbytes); -#endif - s->blkmode = nbytes; - return 0; -} - - -/* Return the block mode state of the given stream. */ -int _cdk_stream_get_blockmode(cdk_stream_t s) -{ - return s ? s->blkmode : 0; -} |