summaryrefslogtreecommitdiff
path: root/subversion/libsvn_subr/stream.c
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/libsvn_subr/stream.c')
-rw-r--r--subversion/libsvn_subr/stream.c337
1 files changed, 239 insertions, 98 deletions
diff --git a/subversion/libsvn_subr/stream.c b/subversion/libsvn_subr/stream.c
index 65ecc6a..93a4c42 100644
--- a/subversion/libsvn_subr/stream.c
+++ b/subversion/libsvn_subr/stream.c
@@ -21,8 +21,6 @@
* ====================================================================
*/
-#include "svn_private_config.h"
-
#include <assert.h>
#include <stdio.h>
@@ -42,8 +40,11 @@
#include "svn_utf.h"
#include "svn_checksum.h"
#include "svn_path.h"
+#include "svn_private_config.h"
+#include "private/svn_error_private.h"
#include "private/svn_eol_private.h"
#include "private/svn_io_private.h"
+#include "private/svn_subr_private.h"
struct svn_stream_t {
@@ -55,6 +56,7 @@ struct svn_stream_t {
svn_stream_mark_fn_t mark_fn;
svn_stream_seek_fn_t seek_fn;
svn_stream__is_buffered_fn_t is_buffered_fn;
+ apr_file_t *file; /* Maybe NULL */
};
@@ -80,6 +82,7 @@ svn_stream_create(void *baton, apr_pool_t *pool)
stream->mark_fn = NULL;
stream->seek_fn = NULL;
stream->is_buffered_fn = NULL;
+ stream->file = NULL;
return stream;
}
@@ -138,7 +141,7 @@ svn_error_t *
svn_stream_read(svn_stream_t *stream, char *buffer, apr_size_t *len)
{
SVN_ERR_ASSERT(stream->read_fn != NULL);
- return stream->read_fn(stream->baton, buffer, len);
+ return svn_error_trace(stream->read_fn(stream->baton, buffer, len));
}
@@ -146,9 +149,10 @@ svn_error_t *
svn_stream_skip(svn_stream_t *stream, apr_size_t len)
{
if (stream->skip_fn == NULL)
- return skip_default_handler(stream->baton, len, stream->read_fn);
+ return svn_error_trace(
+ skip_default_handler(stream->baton, len, stream->read_fn));
- return stream->skip_fn(stream->baton, len);
+ return svn_error_trace(stream->skip_fn(stream->baton, len));
}
@@ -156,7 +160,7 @@ svn_error_t *
svn_stream_write(svn_stream_t *stream, const char *data, apr_size_t *len)
{
SVN_ERR_ASSERT(stream->write_fn != NULL);
- return stream->write_fn(stream->baton, data, len);
+ return svn_error_trace(stream->write_fn(stream->baton, data, len));
}
@@ -170,7 +174,7 @@ svn_stream_reset(svn_stream_t *stream)
svn_boolean_t
svn_stream_supports_mark(svn_stream_t *stream)
{
- return stream->mark_fn == NULL ? FALSE : TRUE;
+ return stream->mark_fn != NULL;
}
svn_error_t *
@@ -180,7 +184,7 @@ svn_stream_mark(svn_stream_t *stream, svn_stream_mark_t **mark,
if (stream->mark_fn == NULL)
return svn_error_create(SVN_ERR_STREAM_SEEK_NOT_SUPPORTED, NULL, NULL);
- return stream->mark_fn(stream->baton, mark, pool);
+ return svn_error_trace(stream->mark_fn(stream->baton, mark, pool));
}
svn_error_t *
@@ -189,7 +193,7 @@ svn_stream_seek(svn_stream_t *stream, const svn_stream_mark_t *mark)
if (stream->seek_fn == NULL)
return svn_error_create(SVN_ERR_STREAM_SEEK_NOT_SUPPORTED, NULL, NULL);
- return stream->seek_fn(stream->baton, mark);
+ return svn_error_trace(stream->seek_fn(stream->baton, mark));
}
svn_boolean_t
@@ -206,9 +210,17 @@ svn_stream_close(svn_stream_t *stream)
{
if (stream->close_fn == NULL)
return SVN_NO_ERROR;
- return stream->close_fn(stream->baton);
+ return svn_error_trace(stream->close_fn(stream->baton));
}
+svn_error_t *
+svn_stream_puts(svn_stream_t *stream,
+ const char *str)
+{
+ apr_size_t len;
+ len = strlen(str);
+ return svn_error_trace(svn_stream_write(stream, str, &len));
+}
svn_error_t *
svn_stream_printf(svn_stream_t *stream,
@@ -218,14 +230,12 @@ svn_stream_printf(svn_stream_t *stream,
{
const char *message;
va_list ap;
- apr_size_t len;
va_start(ap, fmt);
message = apr_pvsprintf(pool, fmt, ap);
va_end(ap);
- len = strlen(message);
- return svn_stream_write(stream, message, &len);
+ return svn_error_trace(svn_stream_puts(stream, message));
}
@@ -238,7 +248,6 @@ svn_stream_printf_from_utf8(svn_stream_t *stream,
{
const char *message, *translated;
va_list ap;
- apr_size_t len;
va_start(ap, fmt);
message = apr_pvsprintf(pool, fmt, ap);
@@ -247,9 +256,7 @@ svn_stream_printf_from_utf8(svn_stream_t *stream,
SVN_ERR(svn_utf_cstring_from_utf8_ex2(&translated, message, encoding,
pool));
- len = strlen(translated);
-
- return svn_stream_write(stream, translated, &len);
+ return svn_error_trace(svn_stream_puts(stream, translated));
}
/* Size that 90% of the lines we encounter will be not longer than.
@@ -409,7 +416,7 @@ stream_readline_chunky(svn_stringbuf_t **stringbuf,
/* Move the stream read pointer to the first position behind the EOL.
*/
SVN_ERR(svn_stream_seek(stream, mark));
- return svn_stream_skip(stream, total_parsed);
+ return svn_error_trace(svn_stream_skip(stream, total_parsed));
}
/* Guts of svn_stream_readline().
@@ -678,31 +685,31 @@ svn_stream_tee(svn_stream_t *out1,
static svn_error_t *
read_handler_disown(void *baton, char *buffer, apr_size_t *len)
{
- return svn_stream_read(baton, buffer, len);
+ return svn_error_trace(svn_stream_read(baton, buffer, len));
}
static svn_error_t *
skip_handler_disown(void *baton, apr_size_t len)
{
- return svn_stream_skip(baton, len);
+ return svn_error_trace(svn_stream_skip(baton, len));
}
static svn_error_t *
write_handler_disown(void *baton, const char *buffer, apr_size_t *len)
{
- return svn_stream_write(baton, buffer, len);
+ return svn_error_trace(svn_stream_write(baton, buffer, len));
}
static svn_error_t *
mark_handler_disown(void *baton, svn_stream_mark_t **mark, apr_pool_t *pool)
{
- return svn_stream_mark(baton, mark, pool);
+ return svn_error_trace(svn_stream_mark(baton, mark, pool));
}
static svn_error_t *
seek_handler_disown(void *baton, const svn_stream_mark_t *mark)
{
- return svn_stream_seek(baton, mark);
+ return svn_error_trace(svn_stream_seek(baton, mark));
}
static svn_boolean_t
@@ -763,7 +770,7 @@ read_handler_apr(void *baton, char *buffer, apr_size_t *len)
err = svn_io_file_read_full2(btn->file, buffer, *len, len,
&eof, btn->pool);
- return err;
+ return svn_error_trace(err);
}
static svn_error_t *
@@ -772,7 +779,8 @@ skip_handler_apr(void *baton, apr_size_t len)
struct baton_apr *btn = baton;
apr_off_t offset = len;
- return svn_io_file_seek(btn->file, APR_CUR, &offset, btn->pool);
+ return svn_error_trace(
+ svn_io_file_seek(btn->file, APR_CUR, &offset, btn->pool));
}
static svn_error_t *
@@ -790,7 +798,7 @@ write_handler_apr(void *baton, const char *data, apr_size_t *len)
else
err = svn_io_file_write_full(btn->file, data, *len, len, btn->pool);
- return err;
+ return svn_error_trace(err);
}
static svn_error_t *
@@ -798,7 +806,7 @@ close_handler_apr(void *baton)
{
struct baton_apr *btn = baton;
- return svn_io_file_close(btn->file, btn->pool);
+ return svn_error_trace(svn_io_file_close(btn->file, btn->pool));
}
static svn_error_t *
@@ -840,7 +848,7 @@ svn_stream_open_readonly(svn_stream_t **stream,
{
apr_file_t *file;
- SVN_ERR(svn_io_file_open(&file, path, APR_READ | APR_BUFFERED | APR_BINARY,
+ SVN_ERR(svn_io_file_open(&file, path, APR_READ | APR_BUFFERED,
APR_OS_DEFAULT, result_pool));
*stream = svn_stream_from_aprfile2(file, FALSE, result_pool);
@@ -859,7 +867,6 @@ svn_stream_open_writable(svn_stream_t **stream,
SVN_ERR(svn_io_file_open(&file, path,
APR_WRITE
| APR_BUFFERED
- | APR_BINARY
| APR_CREATE
| APR_EXCL,
APR_OS_DEFAULT, result_pool));
@@ -908,6 +915,7 @@ svn_stream_from_aprfile2(apr_file_t *file,
svn_stream_set_mark(stream, mark_handler_apr);
svn_stream_set_seek(stream, seek_handler_apr);
svn_stream__set_is_buffered(stream, is_buffered_handler_apr);
+ stream->file = file;
if (! disown)
svn_stream_set_close(stream, close_handler_apr);
@@ -915,6 +923,12 @@ svn_stream_from_aprfile2(apr_file_t *file,
return stream;
}
+apr_file_t *
+svn_stream__aprfile(svn_stream_t *stream)
+{
+ return stream->file;
+}
+
/* Compressed stream support */
@@ -955,59 +969,6 @@ zfree(voidpf opaque, voidpf address)
/* Empty, since we allocate on the pool */
}
-/* Converts a zlib error to an svn_error_t. zerr is the error code,
- function is the function name, and stream is the z_stream we are
- using. */
-static svn_error_t *
-zerr_to_svn_error(int zerr, const char *function, z_stream *stream)
-{
- apr_status_t status;
- const char *message;
-
- if (zerr == Z_OK)
- return SVN_NO_ERROR;
-
- switch (zerr)
- {
- case Z_STREAM_ERROR:
- status = SVN_ERR_STREAM_MALFORMED_DATA;
- message = "stream error";
- break;
-
- case Z_MEM_ERROR:
- status = APR_ENOMEM;
- message = "out of memory";
- break;
-
- case Z_BUF_ERROR:
- status = APR_ENOMEM;
- message = "buffer error";
- break;
-
- case Z_VERSION_ERROR:
- status = SVN_ERR_STREAM_UNRECOGNIZED_DATA;
- message = "version error";
- break;
-
- case Z_DATA_ERROR:
- status = SVN_ERR_STREAM_MALFORMED_DATA;
- message = "corrupted data";
- break;
-
- default:
- status = SVN_ERR_STREAM_UNRECOGNIZED_DATA;
- message = "error";
- break;
- }
-
- if (stream->msg != NULL)
- return svn_error_createf(status, NULL, "zlib (%s): %s: %s", function,
- message, stream->msg);
- else
- return svn_error_createf(status, NULL, "zlib (%s): %s", function,
- message);
-}
-
/* Helper function to figure out the sync mode */
static svn_error_t *
read_helper_gz(svn_read_fn_t read_fn,
@@ -1055,11 +1016,11 @@ read_handler_gz(void *baton, char *buffer, apr_size_t *len)
&btn->in->avail_in, &btn->read_flush));
zerr = inflateInit(btn->in);
- SVN_ERR(zerr_to_svn_error(zerr, "inflateInit", btn->in));
+ SVN_ERR(svn_error__wrap_zlib(zerr, "inflateInit", btn->in->msg));
}
btn->in->next_out = (Bytef *) buffer;
- btn->in->avail_out = *len;
+ btn->in->avail_out = (uInt) *len;
while (btn->in->avail_out > 0)
{
@@ -1082,7 +1043,8 @@ read_handler_gz(void *baton, char *buffer, apr_size_t *len)
if (zerr == Z_STREAM_END)
break;
else if (zerr != Z_OK)
- return zerr_to_svn_error(zerr, "inflate", btn->in);
+ return svn_error_trace(svn_error__wrap_zlib(zerr, "inflate",
+ btn->in->msg));
}
*len -= btn->in->avail_out;
@@ -1107,7 +1069,7 @@ write_handler_gz(void *baton, const char *buffer, apr_size_t *len)
btn->out->opaque = btn->pool;
zerr = deflateInit(btn->out, Z_DEFAULT_COMPRESSION);
- SVN_ERR(zerr_to_svn_error(zerr, "deflateInit", btn->out));
+ SVN_ERR(svn_error__wrap_zlib(zerr, "deflateInit", btn->out->msg));
}
/* The largest buffer we should need is 0.1% larger than the
@@ -1117,15 +1079,15 @@ write_handler_gz(void *baton, const char *buffer, apr_size_t *len)
write_buf = apr_palloc(subpool, buf_size);
btn->out->next_in = (Bytef *) buffer; /* Casting away const! */
- btn->out->avail_in = *len;
+ btn->out->avail_in = (uInt) *len;
while (btn->out->avail_in > 0)
{
btn->out->next_out = write_buf;
- btn->out->avail_out = buf_size;
+ btn->out->avail_out = (uInt) buf_size;
zerr = deflate(btn->out, Z_NO_FLUSH);
- SVN_ERR(zerr_to_svn_error(zerr, "deflate", btn->out));
+ SVN_ERR(svn_error__wrap_zlib(zerr, "deflate", btn->out->msg));
write_len = buf_size - btn->out->avail_out;
if (write_len > 0)
SVN_ERR(btn->write(btn->subbaton, write_buf, &write_len));
@@ -1146,7 +1108,7 @@ close_handler_gz(void *baton)
if (btn->in != NULL)
{
zerr = inflateEnd(btn->in);
- SVN_ERR(zerr_to_svn_error(zerr, "inflateEnd", btn->in));
+ SVN_ERR(svn_error__wrap_zlib(zerr, "inflateEnd", btn->in->msg));
}
if (btn->out != NULL)
@@ -1163,7 +1125,8 @@ close_handler_gz(void *baton)
zerr = deflate(btn->out, Z_FINISH);
if (zerr != Z_STREAM_END && zerr != Z_OK)
- return zerr_to_svn_error(zerr, "deflate", btn->out);
+ return svn_error_trace(svn_error__wrap_zlib(zerr, "deflate",
+ btn->out->msg));
write_len = ZBUFFER_SIZE - btn->out->avail_out;
if (write_len > 0)
SVN_ERR(btn->write(btn->subbaton, buf, &write_len));
@@ -1172,11 +1135,11 @@ close_handler_gz(void *baton)
}
zerr = deflateEnd(btn->out);
- SVN_ERR(zerr_to_svn_error(zerr, "deflateEnd", btn->out));
+ SVN_ERR(svn_error__wrap_zlib(zerr, "deflateEnd", btn->out->msg));
}
if (btn->close != NULL)
- return btn->close(btn->subbaton);
+ return svn_error_trace(btn->close(btn->subbaton));
else
return SVN_NO_ERROR;
}
@@ -1251,7 +1214,7 @@ write_handler_checksum(void *baton, const char *buffer, apr_size_t *len)
if (btn->write_checksum && *len > 0)
SVN_ERR(svn_checksum_update(btn->write_ctx, buffer, *len));
- return svn_stream_write(btn->proxy, buffer, len);
+ return svn_error_trace(svn_stream_write(btn->proxy, buffer, len));
}
@@ -1280,7 +1243,7 @@ close_handler_checksum(void *baton)
if (btn->write_ctx)
SVN_ERR(svn_checksum_final(btn->write_checksum, btn->write_ctx, btn->pool));
- return svn_stream_close(btn->proxy);
+ return svn_error_trace(svn_stream_close(btn->proxy));
}
@@ -1336,21 +1299,21 @@ static svn_error_t *
read_handler_md5(void *baton, char *buffer, apr_size_t *len)
{
struct md5_stream_baton *btn = baton;
- return svn_stream_read(btn->proxy, buffer, len);
+ return svn_error_trace(svn_stream_read(btn->proxy, buffer, len));
}
static svn_error_t *
skip_handler_md5(void *baton, apr_size_t len)
{
struct md5_stream_baton *btn = baton;
- return svn_stream_skip(btn->proxy, len);
+ return svn_error_trace(svn_stream_skip(btn->proxy, len));
}
static svn_error_t *
write_handler_md5(void *baton, const char *buffer, apr_size_t *len)
{
struct md5_stream_baton *btn = baton;
- return svn_stream_write(btn->proxy, buffer, len);
+ return svn_error_trace(svn_stream_write(btn->proxy, buffer, len));
}
static svn_error_t *
@@ -1692,3 +1655,181 @@ svn_string_from_stream(svn_string_t **result,
return SVN_NO_ERROR;
}
+
+
+/* These are somewhat arbirary, if we ever get good empirical data as to
+ actually valid values, feel free to update them. */
+#define BUFFER_BLOCK_SIZE 1024
+#define BUFFER_MAX_SIZE 100000
+
+svn_stream_t *
+svn_stream_buffered(apr_pool_t *result_pool)
+{
+ return svn_stream__from_spillbuf(BUFFER_BLOCK_SIZE, BUFFER_MAX_SIZE,
+ result_pool);
+}
+
+
+
+/*** Lazyopen Streams ***/
+
+/* Custom baton for lazyopen-style wrapper streams. */
+typedef struct lazyopen_baton_t {
+
+ /* Callback function and baton for opening the wrapped stream. */
+ svn_stream_lazyopen_func_t open_func;
+ void *open_baton;
+
+ /* The wrapped stream, or NULL if the stream hasn't yet been
+ opened. */
+ svn_stream_t *real_stream;
+ apr_pool_t *pool;
+
+ /* Whether to open the wrapped stream on a close call. */
+ svn_boolean_t open_on_close;
+
+} lazyopen_baton_t;
+
+
+/* Use B->open_func/baton to create and set B->real_stream iff it
+ isn't already set. */
+static svn_error_t *
+lazyopen_if_unopened(lazyopen_baton_t *b)
+{
+ if (b->real_stream == NULL)
+ {
+ svn_stream_t *stream;
+ apr_pool_t *scratch_pool = svn_pool_create(b->pool);
+
+ SVN_ERR(b->open_func(&stream, b->open_baton,
+ b->pool, scratch_pool));
+
+ svn_pool_destroy(scratch_pool);
+
+ b->real_stream = stream;
+ }
+
+ return SVN_NO_ERROR;
+}
+
+/* Implements svn_read_fn_t */
+static svn_error_t *
+read_handler_lazyopen(void *baton,
+ char *buffer,
+ apr_size_t *len)
+{
+ lazyopen_baton_t *b = baton;
+
+ SVN_ERR(lazyopen_if_unopened(b));
+ SVN_ERR(svn_stream_read(b->real_stream, buffer, len));
+
+ return SVN_NO_ERROR;
+}
+
+/* Implements svn_stream_skip_fn_t */
+static svn_error_t *
+skip_handler_lazyopen(void *baton,
+ apr_size_t len)
+{
+ lazyopen_baton_t *b = baton;
+
+ SVN_ERR(lazyopen_if_unopened(b));
+ SVN_ERR(svn_stream_skip(b->real_stream, len));
+
+ return SVN_NO_ERROR;
+}
+
+/* Implements svn_write_fn_t */
+static svn_error_t *
+write_handler_lazyopen(void *baton,
+ const char *data,
+ apr_size_t *len)
+{
+ lazyopen_baton_t *b = baton;
+
+ SVN_ERR(lazyopen_if_unopened(b));
+ SVN_ERR(svn_stream_write(b->real_stream, data, len));
+
+ return SVN_NO_ERROR;
+}
+
+/* Implements svn_close_fn_t */
+static svn_error_t *
+close_handler_lazyopen(void *baton)
+{
+ lazyopen_baton_t *b = baton;
+
+ if (b->open_on_close)
+ SVN_ERR(lazyopen_if_unopened(b));
+ if (b->real_stream)
+ SVN_ERR(svn_stream_close(b->real_stream));
+
+ return SVN_NO_ERROR;
+}
+
+/* Implements svn_stream_mark_fn_t */
+static svn_error_t *
+mark_handler_lazyopen(void *baton,
+ svn_stream_mark_t **mark,
+ apr_pool_t *pool)
+{
+ lazyopen_baton_t *b = baton;
+
+ SVN_ERR(lazyopen_if_unopened(b));
+ SVN_ERR(svn_stream_mark(b->real_stream, mark, pool));
+
+ return SVN_NO_ERROR;
+}
+
+/* Implements svn_stream_seek_fn_t */
+static svn_error_t *
+seek_handler_lazyopen(void *baton,
+ const svn_stream_mark_t *mark)
+{
+ lazyopen_baton_t *b = baton;
+
+ SVN_ERR(lazyopen_if_unopened(b));
+ SVN_ERR(svn_stream_seek(b->real_stream, mark));
+
+ return SVN_NO_ERROR;
+}
+
+/* Implements svn_stream__is_buffered_fn_t */
+static svn_boolean_t
+is_buffered_lazyopen(void *baton)
+{
+ lazyopen_baton_t *b = baton;
+
+ /* No lazy open as we cannot handle an open error. */
+ if (!b->real_stream)
+ return FALSE;
+
+ return svn_stream__is_buffered(b->real_stream);
+}
+
+svn_stream_t *
+svn_stream_lazyopen_create(svn_stream_lazyopen_func_t open_func,
+ void *open_baton,
+ svn_boolean_t open_on_close,
+ apr_pool_t *result_pool)
+{
+ lazyopen_baton_t *lob = apr_pcalloc(result_pool, sizeof(*lob));
+ svn_stream_t *stream;
+
+ lob->open_func = open_func;
+ lob->open_baton = open_baton;
+ lob->real_stream = NULL;
+ lob->pool = result_pool;
+ lob->open_on_close = open_on_close;
+
+ stream = svn_stream_create(lob, result_pool);
+ svn_stream_set_read(stream, read_handler_lazyopen);
+ svn_stream_set_skip(stream, skip_handler_lazyopen);
+ svn_stream_set_write(stream, write_handler_lazyopen);
+ svn_stream_set_close(stream, close_handler_lazyopen);
+ svn_stream_set_mark(stream, mark_handler_lazyopen);
+ svn_stream_set_seek(stream, seek_handler_lazyopen);
+ svn_stream__set_is_buffered(stream, is_buffered_lazyopen);
+
+ return stream;
+}