diff options
author | Marcus Brinkmann <[email protected]> | 2012-01-03 17:13:19 +0000 |
---|---|---|
committer | Marcus Brinkmann <[email protected]> | 2012-01-03 17:13:19 +0000 |
commit | 0868997e186cd847663668f9d7a29806a12da2d2 (patch) | |
tree | 73645f778a2d16213723121a76d2b38ca90edfcc /common/estream.c | |
parent | Add lost ChangeLog entry. (diff) | |
parent | Silence gcc warning. (diff) | |
download | gnupg-0868997e186cd847663668f9d7a29806a12da2d2.tar.gz gnupg-0868997e186cd847663668f9d7a29806a12da2d2.zip |
Merge branch 'master' into npthnpth
Conflicts:
ChangeLog-2011
Makefile.am
agent/ChangeLog-2011
agent/gpg-agent.c
dirmngr/ChangeLog-2011
dirmngr/dirmngr.c
doc/HACKING
g13/g13.c
po/de.po
scd/ChangeLog-2011
scd/apdu.c
scd/command.c
scd/scdaemon.c
scripts/gitlog-to-changelog
tools/ChangeLog-2011
Diffstat (limited to 'common/estream.c')
-rw-r--r-- | common/estream.c | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/common/estream.c b/common/estream.c index 383210dff..32602a0f7 100644 --- a/common/estream.c +++ b/common/estream.c @@ -217,6 +217,17 @@ struct notify_list_s }; typedef struct notify_list_s *notify_list_t; + +/* A private cookie function to implement an internal IOCTL + service. */ +typedef int (*cookie_ioctl_function_t) (void *cookie, int cmd, + void *ptr, size_t *len); +/* IOCTL commands for the private cookie function. */ +#define COOKIE_IOCTL_SNATCH_BUFFER 1 + + + + /* An internal stream object. */ struct estream_internal { @@ -231,6 +242,7 @@ struct estream_internal es_cookie_read_function_t func_read; es_cookie_write_function_t func_write; es_cookie_seek_function_t func_seek; + cookie_ioctl_function_t func_ioctl; es_cookie_close_function_t func_close; int strategy; es_syshd_t syshd; /* A copy of the sytem handle. */ @@ -771,6 +783,33 @@ es_func_mem_seek (void *cookie, off_t *offset, int whence) return 0; } +/* An IOCTL function for memory objects. */ +static int +es_func_mem_ioctl (void *cookie, int cmd, void *ptr, size_t *len) +{ + estream_cookie_mem_t mem_cookie = cookie; + int ret; + + if (cmd == COOKIE_IOCTL_SNATCH_BUFFER) + { + /* Return the internal buffer of the stream to the caller and + invalidate it for the stream. */ + *(void**)ptr = mem_cookie->memory; + *len = mem_cookie->offset; + mem_cookie->memory = NULL; + mem_cookie->memory_size = 0; + mem_cookie->offset = 0; + ret = 0; + } + else + { + _set_errno (EINVAL); + ret = -1; + } + + return ret; +} + /* Destroy function for memory objects. */ static int @@ -1608,6 +1647,7 @@ es_initialize (estream_t stream, stream->intern->func_read = functions.func_read; stream->intern->func_write = functions.func_write; stream->intern->func_seek = functions.func_seek; + stream->intern->func_ioctl = NULL; stream->intern->func_close = functions.func_close; stream->intern->strategy = _IOFBF; stream->intern->syshd = *syshd; @@ -2667,6 +2707,47 @@ es_fopenmem (size_t memlimit, const char *ES__RESTRICT mode) if (es_create (&stream, cookie, &syshd, estream_functions_mem, modeflags, 0)) (*estream_functions_mem.func_close) (cookie); + if (stream) + stream->intern->func_ioctl = es_func_mem_ioctl; + + return stream; +} + + + +/* This is the same as es_fopenmem but intializes the memory with a + copy of (DATA,DATALEN). The stream is initally set to the + beginning. If MEMLIMIT is not 0 but shorter than DATALEN it + DATALEN will be used as the value for MEMLIMIT. */ +estream_t +es_fopenmem_init (size_t memlimit, const char *ES__RESTRICT mode, + const void *data, size_t datalen) +{ + estream_t stream; + + if (memlimit && memlimit < datalen) + memlimit = datalen; + + stream = es_fopenmem (memlimit, mode); + if (stream && data && datalen) + { + if (es_writen (stream, data, datalen, NULL)) + { + int saveerrno = errno; + es_fclose (stream); + stream = NULL; + _set_errno (saveerrno); + } + else + { + es_seek (stream, 0L, SEEK_SET, NULL); + es_set_indicators (stream, 0, 0); + } + } + + if (stream) + stream->intern->func_ioctl = es_func_mem_ioctl; + return stream; } @@ -3082,6 +3163,65 @@ es_fclose (estream_t stream) } +/* This is a special version of es_fclose which can be used with + es_fopenmem to return the memory buffer. This is feature is useful + to write to a memory buffer using estream. Note that the function + does not close the stream if the stream does not support snatching + the buffer. On error NULL is stored at R_BUFFER. Note that if no + write operation has happened, NULL may also be stored at BUFFER on + success. The caller needs to release the returned memory using + es_free. */ +int +es_fclose_snatch (estream_t stream, void **r_buffer, size_t *r_buflen) +{ + int err; + + /* Note: There is no need to lock the stream in a close call. The + object will be destroyed after the close and thus any other + contender for the lock would work on a closed stream. */ + + if (r_buffer) + { + cookie_ioctl_function_t func_ioctl = stream->intern->func_ioctl; + size_t buflen; + + *r_buffer = NULL; + + if (!func_ioctl) + { + _set_errno (EOPNOTSUPP); + err = -1; + goto leave; + } + + if (stream->flags.writing) + { + err = es_flush (stream); + if (err) + goto leave; + stream->flags.writing = 0; + } + + err = func_ioctl (stream->intern->cookie, COOKIE_IOCTL_SNATCH_BUFFER, + r_buffer, &buflen); + if (err) + goto leave; + if (r_buflen) + *r_buflen = buflen; + } + + err = do_close (stream, 0); + + leave: + if (err && r_buffer) + { + mem_free (*r_buffer); + *r_buffer = NULL; + } + return err; +} + + /* Register or unregister a close notification function for STREAM. FNC is the function to call and FNC_VALUE the value passed as second argument. To register the notification the value for MODE |