rendered paste bodyIndex: subversion/libsvn_subr/stream.c
===================================================================
--- subversion/libsvn_subr/stream.c (revision 17698)
+++ subversion/libsvn_subr/stream.c (working copy)
@@ -26,6 +26,7 @@
#include <apr_strings.h>
#include <apr_file_io.h>
#include <apr_errno.h>
+#include <apr_md5.h>
#ifdef SVN_HAVE_ZLIB
#include <zlib.h>
@@ -607,6 +608,93 @@
}
+/* MD5 checked stream support */
+
+struct md5_stream_baton
+{
+ apr_md5_ctx_t read_ctx, write_ctx;
+ unsigned char *read_digest;
+ unsigned char *write_digest;
+ svn_stream_t *proxy;
+};
+
+static svn_error_t *
+read_handler_md5 (void *baton, char *buffer, apr_size_t *len)
+{
+ struct md5_stream_baton *btn = baton;
+
+ SVN_ERR (svn_stream_read (btn->proxy, buffer, len));
+
+ if (btn->read_digest)
+ apr_md5_update (&btn->read_ctx, buffer, *len);
+
+ return SVN_NO_ERROR;
+}
+
+
+static svn_error_t *
+write_handler_md5 (void *baton, const char *buffer, apr_size_t *len)
+{
+ struct md5_stream_baton *btn = baton;
+
+ if (btn->write_digest)
+ apr_md5_update (&btn->write_ctx, buffer, *len);
+
+ return svn_stream_write (btn->proxy, buffer, len);
+}
+
+
+static svn_error_t *
+close_handler_md5 (void *baton)
+{
+ struct md5_stream_baton *btn = baton;
+ unsigned char digest[APR_MD5_DIGESTSIZE];
+
+ if (btn->read_digest)
+ {
+ apr_md5_final (digest, &btn->read_ctx);
+ memcpy (btn->read_digest, digest, sizeof (digest));
+ }
+
+ if (btn->write_digest)
+ {
+ apr_md5_final (digest, &btn->write_ctx);
+ memcpy (btn->write_digest, digest, sizeof (digest));
+ }
+
+ return SVN_NO_ERROR;
+}
+
+
+svn_stream_t *
+svn_stream_checksummed (svn_stream_t *stream,
+ unsigned char *read_digest,
+ unsigned char *write_digest,
+ apr_pool_t *pool)
+{
+ svn_stream_t *s;
+ struct md5_stream_baton *baton;
+
+ if (! read_digest && ! write_digest)
+ return stream;
+
+ baton = apr_palloc (pool, sizeof (*baton));
+ apr_md5_init (&baton->read_ctx);
+ apr_md5_init (&baton->write_ctx);
+ baton->read_digest = read_digest;
+ baton->write_digest = write_digest;
+ baton->proxy = stream;
+
+ s = svn_stream_create (baton, pool);
+ svn_stream_set_read (s, read_handler_md5);
+ svn_stream_set_write (s, write_handler_md5);
+ svn_stream_set_close (s, close_handler_md5);
+ return s;
+}
+
+
+
+
/* Miscellaneous stream functions. */
struct string_stream_baton
{
Index: subversion/include/svn_io.h
===================================================================
--- subversion/include/svn_io.h (revision 17698)
+++ subversion/include/svn_io.h (working copy)
@@ -582,6 +582,22 @@
svn_stream_t *svn_stream_compressed (svn_stream_t *stream,
apr_pool_t *pool);
+/** Return a stream that checksums all data read or written. The stream
+ * @a stream is used to read and write all data. The stream is allocated
+ * in @a pool. @a read_digest and @a write_digest should point to an array
+ * of @c APR_MD5_DIGESTSIZE unsigned chars.
+ *
+ * When closed, the digests are written to @a read_digest and
+ * @a write_digest respectively. Both @a read_digest and @a write_digest
+ * can be @c NULL, in which case the respective checksum isn't calculated.
+ *
+ * Read and write operations can be mixed without interfering.
+ */
+svn_stream_t * svn_stream_checksummed (svn_stream_t *stream,
+ unsigned char *read_digest,
+ unsigned char *write_digest,
+ apr_pool_t *pool);
+
/** Read from a generic stream. */
svn_error_t *svn_stream_read (svn_stream_t *stream, char *buffer,
apr_size_t *len);