estream: New function es_fclose_snatch.

* common/estream.c (cookie_ioctl_function_t): New type.
(es_fclose_snatch): New function.
(COOKIE_IOCTL_SNATCH_BUFFER): New constant.
(struct estream_internal): Add field FUNC_IOCTL.
(es_initialize): Clear FUNC_IOCTL.
(es_func_mem_ioctl): New function.
(es_fopenmem, es_fopenmem_init): Init FUNC_IOCTL.
This commit is contained in:
Werner Koch 2011-12-15 14:45:08 +01:00
parent 792e137ec7
commit 7737a2c269
2 changed files with 109 additions and 1 deletions

View File

@ -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,9 @@ 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;
}
@ -2701,6 +2744,10 @@ es_fopenmem_init (size_t memlimit, const char *ES__RESTRICT mode,
es_set_indicators (stream, 0, 0);
}
}
if (stream)
stream->intern->func_ioctl = es_func_mem_ioctl;
return stream;
}
@ -3082,6 +3129,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

View File

@ -1,5 +1,5 @@
/* estream.h - Extended stream I/O Library
* Copyright (C) 2004, 2005, 2006, 2007, 2010 g10 Code GmbH
* Copyright (C) 2004, 2005, 2006, 2007, 2010, 2011 g10 Code GmbH
*
* This file is part of Libestream.
*
@ -88,6 +88,7 @@
#define es_freopen _ESTREAM_PREFIX(es_freopen)
#define es_fopencookie _ESTREAM_PREFIX(es_fopencookie)
#define es_fclose _ESTREAM_PREFIX(es_fclose)
#define es_fclose_snatch _ESTREAM_PREFIX(es_fclose_snatch)
#define es_onclose _ESTREAM_PREFIX(es_onclose)
#define es_fileno _ESTREAM_PREFIX(es_fileno)
#define es_fileno_unlocked _ESTREAM_PREFIX(es_fileno_unlocked)
@ -285,6 +286,7 @@ estream_t es_fopencookie (void *ES__RESTRICT cookie,
const char *ES__RESTRICT mode,
es_cookie_io_functions_t functions);
int es_fclose (estream_t stream);
int es_fclose_snatch (estream_t stream, void **r_buffer, size_t *r_buflen);
int es_onclose (estream_t stream, int mode,
void (*fnc) (estream_t, void*), void *fnc_value);
int es_fileno (estream_t stream);