Here is my first crack at fixing this issue. Yes, yes, i know
i'm supposed to be finishing up the add-horkage patch, but when i
found ra_svn was broken yesterday, i found out about ra_svn not
having checksumming and got interested in this first. So sue me!
To test the apply_textdelta changes, change line 243 of editor.c
from:
SVN_ERR(svn_ra_svn_write_cmd(b->conn, pool, "apply-textdelta", "ccc",
b->token,
(base_checksum ? base_checksum : ""),
(result_checksum ? result_checksum : "")));
to:
SVN_ERR(svn_ra_svn_write_cmd(b->conn, pool, "apply-textdelta", "ccc",
b->token,
(base_checksum ? "broke" : ""),
(result_checksum ? "ekorb" : "")));
then run basic_tests.py.
To test get_file changes, change line 375 of serve.c
from:
hex_digest = svn_md5_digest_to_cstring(digest, pool);
to:
hex_digest = "broke";
then run that svnserve and svn cat a file from it. Those two
tests are how i verified that the new code does what it's
supposed to. This patch passes make svnchec,.
Patch and log message:
Hook ra_svn up with checksumming action.
Big thanks to Greg Hudson for answering innumerable questions
about ra_svn, and suggesting most of how this works. The rest is
inspired by ra_dav's checksumming support.
* subversion/libsvn_ra_svn/client.c: Include <apr_md5.h> and "svn_md5.h".
(ra_svn_get_file): Read a checksum from the get-file response.
Calculate a checksum as the file is read, and compare it to the
provided checksum.
* subversion/libsvn_ra_svn/editor.c: Include <apr_md5.h> and "svn_md5.h".
(ra_svn_svndiff_close): Read a command response in order to catch
errors decoding the svndiff (this is where any checksum errors
found by the receiver will be reported).
(ra_svn_apply_textdelta): Send base_checksum and result_checksum
along with the token in the apply-textdelta command (turning NULL
pointers into "").
(ra_svn_handle_apply_textdelta): Read base_checksum and
result_checksum from the sender (turning "" into NULL pointers),
and pass them along to apply_textdelta. Wrap the svn_stream_close
call with SVN_CMD_ERR so checksum errors will be reported to the
sender, otherwise send an empty command response so the sender
knows it succeeded.
* subversion/svnserve/serve.c: Include <apr_md5.h> and "svn_md5.h".
(get_file): Get the checksum for the file and send it in the
get-file response.
Index: subversion/libsvn_ra_svn/client.c
===================================================================
--- subversion/libsvn_ra_svn/client.c (revision 4701)
+++ subversion/libsvn_ra_svn/client.c (working copy)
@@ -24,6 +24,7 @@
#include <apr_lib.h>
#include <apr_strings.h>
#include <apr_network_io.h>
+#include <apr_md5.h>
#include "svn_types.h"
#include "svn_string.h"
@@ -34,6 +35,7 @@
#include "svn_config.h"
#include "svn_ra.h"
#include "svn_ra_svn.h"
+#include "svn_md5.h"
#include "ra_svn.h"
@@ -505,10 +507,15 @@ static svn_error_t *ra_svn_get_file(void
apr_pool_t *pool = conn->pool;
svn_ra_svn_item_t *item;
apr_array_header_t *proplist;
+ unsigned char digest[MD5_DIGESTSIZE];
+ const char *expected_checksum, *hex_digest;
+ apr_md5_ctx_t md5_context;
SVN_ERR(svn_ra_svn_write_cmd(conn, pool, "get-file", "c[r]bb", path,
rev, (props != NULL), (stream != NULL)));
- SVN_ERR(svn_ra_svn_read_cmd_response(conn, pool, "rl", &rev, &proplist));
+ SVN_ERR(svn_ra_svn_read_cmd_response(conn, pool, "crl",
+ &expected_checksum,
+ &rev, &proplist));
if (fetched_rev)
*fetched_rev = rev;
@@ -519,6 +526,8 @@ static svn_error_t *ra_svn_get_file(void
if (!stream)
return SVN_NO_ERROR;
+ apr_md5_init(&md5_context);
+
/* Read the file's contents. */
while (1)
{
@@ -528,10 +537,23 @@ static svn_error_t *ra_svn_get_file(void
"Non-string as part of file contents");
if (item->u.string->len == 0)
break;
- if (stream)
- SVN_ERR(svn_stream_write(stream, item->u.string->data,
- &item->u.string->len));
+
+ apr_md5_update(&md5_context, item->u.string->data, item->u.string->len);
+
+ SVN_ERR(svn_stream_write(stream, item->u.string->data,
+ &item->u.string->len));
}
+
+ apr_md5_final(digest, &md5_context);
+ hex_digest = svn_md5_digest_to_cstring(digest, pool);
+ if (strcmp (hex_digest, expected_checksum) != 0)
+ return svn_error_createf
+ (SVN_ERR_CHECKSUM_MISMATCH, NULL,
+ "ra_svn_get_file: checksum mismatch for '%s':\n"
+ " expected checksum: %s\n"
+ " actual checksum: %s\n",
+ path, expected_checksum, hex_digest);
+
SVN_ERR(svn_stream_close(stream));
return SVN_NO_ERROR;
}
Index: subversion/libsvn_ra_svn/editor.c
===================================================================
--- subversion/libsvn_ra_svn/editor.c (revision 4701)
+++ subversion/libsvn_ra_svn/editor.c (working copy)
@@ -23,6 +23,7 @@
#include <apr_general.h>
#include <apr_lib.h>
#include <apr_strings.h>
+#include <apr_md5.h>
#include <assert.h>
@@ -32,6 +33,7 @@
#include "svn_delta.h"
#include "svn_ra_svn.h"
#include "svn_pools.h"
+#include "svn_md5.h"
#include "ra_svn.h"
@@ -222,7 +224,10 @@ static svn_error_t *ra_svn_svndiff_close
{
ra_svn_baton_t *b = baton;
- return svn_ra_svn_write_cstring(b->conn, b->pool, "");
+ SVN_ERR(svn_ra_svn_write_cstring(b->conn, b->pool, ""));
+
+ /* Check for errors decoding the svndiff. */
+ return svn_ra_svn_read_cmd_response(b->conn, b->pool, "");
}
static svn_error_t *ra_svn_apply_textdelta(void *file_baton,
@@ -237,8 +242,10 @@ static svn_error_t *ra_svn_apply_textdel
svn_boolean_t wanted;
/* Tell the other side we're starting a text delta. */
- SVN_ERR(svn_ra_svn_write_cmd(b->conn, pool, "apply-textdelta", "c",
- b->token));
+ SVN_ERR(svn_ra_svn_write_cmd(b->conn, pool, "apply-textdelta", "ccc",
+ b->token,
+ (base_checksum ? base_checksum : ""),
+ (result_checksum ? result_checksum : "")));
SVN_ERR(svn_ra_svn_read_cmd_response(b->conn, pool, "b", &wanted));
if (wanted)
@@ -559,12 +566,21 @@ static svn_error_t *ra_svn_handle_apply_
svn_stream_t *stream;
apr_pool_t *subpool;
svn_ra_svn_item_t *item;
+ char *base_checksum, *result_checksum;
/* Parse arguments, make the editor call, and respond. */
- SVN_ERR(svn_ra_svn_parse_tuple(params, pool, "c", &token));
+ SVN_ERR(svn_ra_svn_parse_tuple(params, pool, "ccc", &token,
+ &base_checksum, &result_checksum));
+
+ if (base_checksum[0] == '\0')
+ base_checksum = NULL;
+ if (result_checksum[0] == '\0')
+ result_checksum = NULL;
+
SVN_CMD_ERR(lookup_token(ds, token, &entry, pool));
/* ### todo#510: convert to new apply_text interface. */
- SVN_CMD_ERR(ds->editor->apply_textdelta(entry->baton, NULL, NULL,
+ SVN_CMD_ERR(ds->editor->apply_textdelta(entry->baton,
+ base_checksum, result_checksum,
pool, &wh, &wh_baton));
SVN_ERR(svn_ra_svn_write_cmd_response(conn, pool, "b", (wh != NULL)));
@@ -592,7 +608,8 @@ static svn_error_t *ra_svn_handle_apply_
apr_pool_clear(subpool);
}
apr_pool_destroy(subpool);
- SVN_ERR(svn_stream_close(stream));
+ SVN_CMD_ERR(svn_stream_close(stream));
+ SVN_ERR(svn_ra_svn_write_cmd_response(conn, pool, ""));
return SVN_NO_ERROR;
}
Index: subversion/svnserve/serve.c
===================================================================
--- subversion/svnserve/serve.c (revision 4701)
+++ subversion/svnserve/serve.c (working copy)
@@ -26,6 +26,7 @@
#include <apr_network_io.h>
#include <apr_user.h>
#include <apr_file_info.h>
+#include <apr_md5.h>
#include <svn_types.h>
#include <svn_string.h>
@@ -37,6 +38,7 @@
#include <svn_path.h>
#include <svn_time.h>
#include <svn_utf.h>
+#include <svn_md5.h>
#include "server.h"
@@ -349,7 +351,7 @@ static svn_error_t *get_file(svn_ra_svn_
apr_array_header_t *params, void *baton)
{
server_baton_t *b = baton;
- const char *path, *full_path;
+ const char *path, *full_path, *hex_digest;
svn_revnum_t rev;
svn_fs_root_t *root;
svn_stream_t *contents;
@@ -358,6 +360,7 @@ static svn_error_t *get_file(svn_ra_svn_
char buf[4096];
apr_size_t len;
svn_boolean_t want_props, want_contents;
+ unsigned char digest[MD5_DIGESTSIZE];
/* Parse arguments. */
SVN_ERR(svn_ra_svn_parse_tuple(params, pool, "c[r]bb", &path, &rev,
@@ -368,6 +371,8 @@ static svn_error_t *get_file(svn_ra_svn_
/* Fetch the properties and a stream for the contents. */
SVN_CMD_ERR(svn_fs_revision_root(&root, b->fs, rev, pool));
+ SVN_CMD_ERR(svn_fs_file_md5_checksum(digest, root, full_path, pool));
+ hex_digest = svn_md5_digest_to_cstring(digest, pool);
if (want_props)
SVN_CMD_ERR(get_props(&props, root, full_path, pool));
if (want_contents)
@@ -377,6 +382,7 @@ static svn_error_t *get_file(svn_ra_svn_
SVN_ERR(svn_ra_svn_start_list(conn, pool));
SVN_ERR(svn_ra_svn_write_word(conn, pool, "success"));
SVN_ERR(svn_ra_svn_start_list(conn, pool));
+ SVN_ERR(svn_ra_svn_write_cstring(conn, pool, hex_digest));
SVN_ERR(svn_ra_svn_write_number(conn, pool, rev));
SVN_ERR(write_proplist(conn, pool, props));
SVN_ERR(svn_ra_svn_end_list(conn, pool));
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org
Received on Mon Feb 3 00:45:32 2003