Index: subversion/libsvn_subr/stream.c =================================================================== --- subversion/libsvn_subr/stream.c (revision 17698) +++ subversion/libsvn_subr/stream.c (working copy) @@ -26,6 +26,7 @@ #include #include #include +#include #ifdef SVN_HAVE_ZLIB #include @@ -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);