diff options
Diffstat (limited to 'subversion/libsvn_ra_svn/marshal.c')
-rw-r--r-- | subversion/libsvn_ra_svn/marshal.c | 1553 |
1 files changed, 1365 insertions, 188 deletions
diff --git a/subversion/libsvn_ra_svn/marshal.c b/subversion/libsvn_ra_svn/marshal.c index 588ccb4..7cf483f 100644 --- a/subversion/libsvn_ra_svn/marshal.c +++ b/subversion/libsvn_ra_svn/marshal.c @@ -32,6 +32,7 @@ #include <apr_lib.h> #include <apr_strings.h> +#include "svn_hash.h" #include "svn_types.h" #include "svn_string.h" #include "svn_error.h" @@ -39,11 +40,13 @@ #include "svn_ra_svn.h" #include "svn_private_config.h" #include "svn_ctype.h" +#include "svn_time.h" #include "ra_svn.h" #include "private/svn_string_private.h" #include "private/svn_dep_compat.h" +#include "private/svn_error_private.h" #define svn_iswhitespace(c) ((c) == ' ' || (c) == '\n') @@ -53,15 +56,27 @@ #define SUSPICIOUSLY_HUGE_STRING_SIZE_THRESHOLD (0x100000) +/* Return the APR socket timeout to be used for the connection depending + * on whether there is a blockage handler or zero copy has been activated. */ +static apr_interval_time_t +get_timeout(svn_ra_svn_conn_t *conn) +{ + return conn->block_handler ? 0 : -1; +} + /* --- CONNECTION INITIALIZATION --- */ -svn_ra_svn_conn_t *svn_ra_svn_create_conn2(apr_socket_t *sock, +svn_ra_svn_conn_t *svn_ra_svn_create_conn3(apr_socket_t *sock, apr_file_t *in_file, apr_file_t *out_file, int compression_level, + apr_size_t zero_copy_limit, + apr_size_t error_check_interval, apr_pool_t *pool) { - svn_ra_svn_conn_t *conn = apr_palloc(pool, sizeof(*conn)); + svn_ra_svn_conn_t *conn; + void *mem = apr_palloc(pool, sizeof(*conn) + SVN_RA_SVN__PAGE_SIZE); + conn = (void*)APR_ALIGN((apr_uintptr_t)mem, SVN_RA_SVN__PAGE_SIZE); assert((sock && !in_file && !out_file) || (!sock && in_file && out_file)); #ifdef SVN_HAVE_SASL @@ -72,10 +87,14 @@ svn_ra_svn_conn_t *svn_ra_svn_create_conn2(apr_socket_t *sock, conn->read_ptr = conn->read_buf; conn->read_end = conn->read_buf; conn->write_pos = 0; + conn->written_since_error_check = 0; + conn->error_check_interval = error_check_interval; + conn->may_check_for_error = error_check_interval == 0; conn->block_handler = NULL; conn->block_baton = NULL; conn->capabilities = apr_hash_make(pool); conn->compression_level = compression_level; + conn->zero_copy_limit = zero_copy_limit; conn->pool = pool; if (sock != NULL) @@ -85,6 +104,7 @@ svn_ra_svn_conn_t *svn_ra_svn_create_conn2(apr_socket_t *sock, if (!(apr_socket_addr_get(&sa, APR_REMOTE, sock) == APR_SUCCESS && apr_sockaddr_ip_get(&conn->remote_ip, sa) == APR_SUCCESS)) conn->remote_ip = NULL; + svn_ra_svn__stream_timeout(conn->stream, get_timeout(conn)); } else { @@ -95,14 +115,25 @@ svn_ra_svn_conn_t *svn_ra_svn_create_conn2(apr_socket_t *sock, return conn; } +svn_ra_svn_conn_t *svn_ra_svn_create_conn2(apr_socket_t *sock, + apr_file_t *in_file, + apr_file_t *out_file, + int compression_level, + apr_pool_t *pool) +{ + return svn_ra_svn_create_conn3(sock, in_file, out_file, + compression_level, 0, 0, pool); +} + /* backward-compatible implementation using the default compression level */ svn_ra_svn_conn_t *svn_ra_svn_create_conn(apr_socket_t *sock, apr_file_t *in_file, apr_file_t *out_file, apr_pool_t *pool) { - return svn_ra_svn_create_conn2(sock, in_file, out_file, - SVN_DELTA_COMPRESSION_LEVEL_DEFAULT, pool); + return svn_ra_svn_create_conn3(sock, in_file, out_file, + SVN_DELTA_COMPRESSION_LEVEL_DEFAULT, 0, 0, + pool); } svn_error_t *svn_ra_svn_set_capabilities(svn_ra_svn_conn_t *conn, @@ -119,16 +150,23 @@ svn_error_t *svn_ra_svn_set_capabilities(svn_ra_svn_conn_t *conn, return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL, _("Capability entry is not a word")); word = apr_pstrdup(conn->pool, item->u.word); - apr_hash_set(conn->capabilities, word, APR_HASH_KEY_STRING, word); + svn_hash_sets(conn->capabilities, word, word); } return SVN_NO_ERROR; } +svn_error_t * +svn_ra_svn__set_shim_callbacks(svn_ra_svn_conn_t *conn, + svn_delta_shim_callbacks_t *shim_callbacks) +{ + conn->shim_callbacks = shim_callbacks; + return SVN_NO_ERROR; +} + svn_boolean_t svn_ra_svn_has_capability(svn_ra_svn_conn_t *conn, const char *capability) { - return (apr_hash_get(conn->capabilities, capability, - APR_HASH_KEY_STRING) != NULL); + return (svn_hash_gets(conn->capabilities, capability) != NULL); } int @@ -137,6 +175,12 @@ svn_ra_svn_compression_level(svn_ra_svn_conn_t *conn) return conn->compression_level; } +apr_size_t +svn_ra_svn_zero_copy_limit(svn_ra_svn_conn_t *conn) +{ + return conn->zero_copy_limit; +} + const char *svn_ra_svn_conn_remote_host(svn_ra_svn_conn_t *conn) { return conn->remote_ip; @@ -147,11 +191,9 @@ svn_ra_svn__set_block_handler(svn_ra_svn_conn_t *conn, ra_svn_block_handler_t handler, void *baton) { - apr_interval_time_t interval = (handler) ? 0 : -1; - conn->block_handler = handler; conn->block_baton = baton; - svn_ra_svn__stream_timeout(conn->stream, interval); + svn_ra_svn__stream_timeout(conn->stream, get_timeout(conn)); } svn_boolean_t svn_ra_svn__input_waiting(svn_ra_svn_conn_t *conn, @@ -162,20 +204,6 @@ svn_boolean_t svn_ra_svn__input_waiting(svn_ra_svn_conn_t *conn, /* --- WRITE BUFFER MANAGEMENT --- */ -/* Write bytes into the write buffer until either the write buffer is - * full or we reach END. */ -static const char *writebuf_push(svn_ra_svn_conn_t *conn, const char *data, - const char *end) -{ - apr_ssize_t buflen, copylen; - - buflen = sizeof(conn->write_buf) - conn->write_pos; - copylen = (buflen < end - data) ? buflen : end - data; - memcpy(conn->write_buf + conn->write_pos, data, copylen); - conn->write_pos += copylen; - return data + copylen; -} - /* Write data to socket or output file as appropriate. */ static svn_error_t *writebuf_output(svn_ra_svn_conn_t *conn, apr_pool_t *pool, const char *data, apr_size_t len) @@ -214,6 +242,10 @@ static svn_error_t *writebuf_output(svn_ra_svn_conn_t *conn, apr_pool_t *pool, } } + conn->written_since_error_check += len; + conn->may_check_for_error + = conn->written_since_error_check >= conn->error_check_interval; + if (subpool) svn_pool_destroy(subpool); return SVN_NO_ERROR; @@ -222,7 +254,7 @@ static svn_error_t *writebuf_output(svn_ra_svn_conn_t *conn, apr_pool_t *pool, /* Write data from the write buffer out to the socket. */ static svn_error_t *writebuf_flush(svn_ra_svn_conn_t *conn, apr_pool_t *pool) { - int write_pos = conn->write_pos; + apr_size_t write_pos = conn->write_pos; /* Clear conn->write_pos first in case the block handler does a read. */ conn->write_pos = 0; @@ -233,35 +265,56 @@ static svn_error_t *writebuf_flush(svn_ra_svn_conn_t *conn, apr_pool_t *pool) static svn_error_t *writebuf_write(svn_ra_svn_conn_t *conn, apr_pool_t *pool, const char *data, apr_size_t len) { - const char *end = data + len; - - if (conn->write_pos > 0 && conn->write_pos + len > sizeof(conn->write_buf)) + /* data >= 8k is sent immediately */ + if (len >= sizeof(conn->write_buf) / 2) { - /* Fill and then empty the write buffer. */ - data = writebuf_push(conn, data, end); - SVN_ERR(writebuf_flush(conn, pool)); + if (conn->write_pos > 0) + SVN_ERR(writebuf_flush(conn, pool)); + + return writebuf_output(conn, pool, data, len); } - if (end - data > (apr_ssize_t)sizeof(conn->write_buf)) - SVN_ERR(writebuf_output(conn, pool, data, end - data)); - else - writebuf_push(conn, data, end); + /* ensure room for the data to add */ + if (conn->write_pos + len > sizeof(conn->write_buf)) + SVN_ERR(writebuf_flush(conn, pool)); + + /* buffer the new data block as well */ + memcpy(conn->write_buf + conn->write_pos, data, len); + conn->write_pos += len; + return SVN_NO_ERROR; } -static svn_error_t *writebuf_printf(svn_ra_svn_conn_t *conn, apr_pool_t *pool, - const char *fmt, ...) - __attribute__ ((format(printf, 3, 4))); -static svn_error_t *writebuf_printf(svn_ra_svn_conn_t *conn, apr_pool_t *pool, - const char *fmt, ...) +static svn_error_t * +writebuf_write_short_string(svn_ra_svn_conn_t *conn, apr_pool_t *pool, + const char *data, apr_size_t len) { - va_list ap; - char *str; + apr_size_t left = sizeof(conn->write_buf) - conn->write_pos; + if (len <= left) + { + memcpy(conn->write_buf + conn->write_pos, data, len); + conn->write_pos += len; + return SVN_NO_ERROR; + } + else + return writebuf_write(conn, pool, data, len); +} - va_start(ap, fmt); - str = apr_pvsprintf(pool, fmt, ap); - va_end(ap); - return writebuf_write(conn, pool, str, strlen(str)); +static APR_INLINE svn_error_t * +writebuf_writechar(svn_ra_svn_conn_t *conn, apr_pool_t *pool, char data) +{ + if (conn->write_pos < sizeof(conn->write_buf)) + { + conn->write_buf[conn->write_pos] = data; + conn->write_pos++; + + return SVN_NO_ERROR; + } + else + { + char temp = data; + return writebuf_write(conn, pool, &temp, 1); + } } /* --- READ BUFFER MANAGEMENT --- */ @@ -305,6 +358,31 @@ static svn_error_t *readbuf_input(svn_ra_svn_conn_t *conn, char *data, return SVN_NO_ERROR; } +/* Treat the next LEN input bytes from CONN as "read" */ +static svn_error_t *readbuf_skip(svn_ra_svn_conn_t *conn, apr_uint64_t len) +{ + do + { + apr_size_t buflen = conn->read_end - conn->read_ptr; + apr_size_t copylen = (buflen < len) ? buflen : (apr_size_t)len; + conn->read_ptr += copylen; + len -= copylen; + if (len == 0) + break; + + buflen = sizeof(conn->read_buf); + SVN_ERR(svn_ra_svn__stream_read(conn->stream, conn->read_buf, &buflen)); + if (buflen == 0) + return svn_error_create(SVN_ERR_RA_SVN_CONNECTION_CLOSED, NULL, NULL); + + conn->read_end = conn->read_buf + buflen; + conn->read_ptr = conn->read_buf; + } + while (len > 0); + + return SVN_NO_ERROR; +} + /* Read data from the socket into the read buffer, which must be empty. */ static svn_error_t *readbuf_fill(svn_ra_svn_conn_t *conn, apr_pool_t *pool) { @@ -408,35 +486,85 @@ static svn_error_t *readbuf_skip_leading_garbage(svn_ra_svn_conn_t *conn, /* --- WRITING DATA ITEMS --- */ -svn_error_t *svn_ra_svn_write_number(svn_ra_svn_conn_t *conn, apr_pool_t *pool, - apr_uint64_t number) +static svn_error_t *write_number(svn_ra_svn_conn_t *conn, apr_pool_t *pool, + apr_uint64_t number, char follow) +{ + apr_size_t written; + + /* SVN_INT64_BUFFER_SIZE includes space for a terminating NUL that + * svn__ui64toa will always append. */ + if (conn->write_pos + SVN_INT64_BUFFER_SIZE >= sizeof(conn->write_buf)) + SVN_ERR(writebuf_flush(conn, pool)); + + written = svn__ui64toa(conn->write_buf + conn->write_pos, number); + conn->write_buf[conn->write_pos + written] = follow; + conn->write_pos += written + 1; + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_ra_svn__write_number(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + apr_uint64_t number) { - return writebuf_printf(conn, pool, "%" APR_UINT64_T_FMT " ", number); + return write_number(conn, pool, number, ' '); } -svn_error_t *svn_ra_svn_write_string(svn_ra_svn_conn_t *conn, apr_pool_t *pool, - const svn_string_t *str) +svn_error_t * +svn_ra_svn__write_string(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const svn_string_t *str) { - SVN_ERR(writebuf_printf(conn, pool, "%" APR_SIZE_T_FMT ":", str->len)); + if (str->len < 10) + { + SVN_ERR(writebuf_writechar(conn, pool, (char)(str->len + '0'))); + SVN_ERR(writebuf_writechar(conn, pool, ':')); + } + else + SVN_ERR(write_number(conn, pool, str->len, ':')); + SVN_ERR(writebuf_write(conn, pool, str->data, str->len)); - SVN_ERR(writebuf_write(conn, pool, " ", 1)); + SVN_ERR(writebuf_writechar(conn, pool, ' ')); return SVN_NO_ERROR; } -svn_error_t *svn_ra_svn_write_cstring(svn_ra_svn_conn_t *conn, - apr_pool_t *pool, const char *s) +svn_error_t * +svn_ra_svn__write_cstring(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const char *s) { - return writebuf_printf(conn, pool, "%" APR_SIZE_T_FMT ":%s ", strlen(s), s); + apr_size_t len = strlen(s); + + if (len < 10) + { + SVN_ERR(writebuf_writechar(conn, pool, (char)(len + '0'))); + SVN_ERR(writebuf_writechar(conn, pool, ':')); + } + else + SVN_ERR(write_number(conn, pool, len, ':')); + + SVN_ERR(writebuf_write(conn, pool, s, len)); + SVN_ERR(writebuf_writechar(conn, pool, ' ')); + + return SVN_NO_ERROR; } -svn_error_t *svn_ra_svn_write_word(svn_ra_svn_conn_t *conn, apr_pool_t *pool, - const char *word) +svn_error_t * +svn_ra_svn__write_word(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const char *word) { - return writebuf_printf(conn, pool, "%s ", word); + SVN_ERR(writebuf_write_short_string(conn, pool, word, strlen(word))); + SVN_ERR(writebuf_writechar(conn, pool, ' ')); + + return SVN_NO_ERROR; } -svn_error_t *svn_ra_svn_write_proplist(svn_ra_svn_conn_t *conn, - apr_pool_t *pool, apr_hash_t *props) +svn_error_t * +svn_ra_svn__write_proplist(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + apr_hash_t *props) { apr_pool_t *iterpool; apr_hash_index_t *hi; @@ -454,8 +582,8 @@ svn_error_t *svn_ra_svn_write_proplist(svn_ra_svn_conn_t *conn, apr_hash_this(hi, &key, NULL, &val); propname = key; propval = val; - SVN_ERR(svn_ra_svn_write_tuple(conn, iterpool, "cs", - propname, propval)); + SVN_ERR(svn_ra_svn__write_tuple(conn, iterpool, "cs", + propname, propval)); } svn_pool_destroy(iterpool); } @@ -463,98 +591,332 @@ svn_error_t *svn_ra_svn_write_proplist(svn_ra_svn_conn_t *conn, return SVN_NO_ERROR; } -svn_error_t *svn_ra_svn_start_list(svn_ra_svn_conn_t *conn, apr_pool_t *pool) +svn_error_t * +svn_ra_svn__start_list(svn_ra_svn_conn_t *conn, + apr_pool_t *pool) { + if (conn->write_pos + 2 <= sizeof(conn->write_buf)) + { + conn->write_buf[conn->write_pos] = '('; + conn->write_buf[conn->write_pos+1] = ' '; + conn->write_pos += 2; + return SVN_NO_ERROR; + } + return writebuf_write(conn, pool, "( ", 2); } -svn_error_t *svn_ra_svn_end_list(svn_ra_svn_conn_t *conn, apr_pool_t *pool) +svn_error_t * +svn_ra_svn__end_list(svn_ra_svn_conn_t *conn, + apr_pool_t *pool) { + if (conn->write_pos + 2 <= sizeof(conn->write_buf)) + { + conn->write_buf[conn->write_pos] = ')'; + conn->write_buf[conn->write_pos+1] = ' '; + conn->write_pos += 2; + return SVN_NO_ERROR; + } + return writebuf_write(conn, pool, ") ", 2); } -svn_error_t *svn_ra_svn_flush(svn_ra_svn_conn_t *conn, apr_pool_t *pool) +svn_error_t * +svn_ra_svn__flush(svn_ra_svn_conn_t *conn, + apr_pool_t *pool) { - return writebuf_flush(conn, pool); + SVN_ERR(writebuf_flush(conn, pool)); + conn->may_check_for_error = TRUE; + + return SVN_NO_ERROR; } /* --- WRITING TUPLES --- */ +static svn_error_t * +vwrite_tuple_cstring(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap) +{ + const char *cstr = va_arg(*ap, const char *); + SVN_ERR_ASSERT(cstr); + return svn_ra_svn__write_cstring(conn, pool, cstr); +} + +static svn_error_t * +vwrite_tuple_cstring_opt(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap) +{ + const char *cstr = va_arg(*ap, const char *); + return cstr ? svn_ra_svn__write_cstring(conn, pool, cstr) : SVN_NO_ERROR; +} + +static svn_error_t * +vwrite_tuple_string(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap) +{ + const svn_string_t *str = va_arg(*ap, const svn_string_t *); + SVN_ERR_ASSERT(str); + return svn_ra_svn__write_string(conn, pool, str); +} + +static svn_error_t * +vwrite_tuple_string_opt(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap) +{ + const svn_string_t *str = va_arg(*ap, const svn_string_t *); + return str ? svn_ra_svn__write_string(conn, pool, str) : SVN_NO_ERROR; +} + +static svn_error_t * +vwrite_tuple_word(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap) +{ + const char *cstr = va_arg(*ap, const char *); + SVN_ERR_ASSERT(cstr); + return svn_ra_svn__write_word(conn, pool, cstr); +} + +static svn_error_t * +vwrite_tuple_word_opt(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap) +{ + const char *cstr = va_arg(*ap, const char *); + return cstr ? svn_ra_svn__write_word(conn, pool, cstr) : SVN_NO_ERROR; +} + +static svn_error_t * +vwrite_tuple_revision(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap) +{ + svn_revnum_t rev = va_arg(*ap, svn_revnum_t); + SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(rev)); + return svn_ra_svn__write_number(conn, pool, rev); +} + +static svn_error_t * +vwrite_tuple_revision_opt(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap) +{ + svn_revnum_t rev = va_arg(*ap, svn_revnum_t); + return SVN_IS_VALID_REVNUM(rev) + ? svn_ra_svn__write_number(conn, pool, rev) + : SVN_NO_ERROR; +} + +static svn_error_t * +vwrite_tuple_number(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap) +{ + return svn_ra_svn__write_number(conn, pool, va_arg(*ap, apr_uint64_t)); +} + +static svn_error_t * +vwrite_tuple_boolean(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap) +{ + const char *cstr = va_arg(*ap, svn_boolean_t) ? "true" : "false"; + return svn_ra_svn__write_word(conn, pool, cstr); +} + +static svn_error_t * +write_tuple_cstring(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const char *cstr) +{ + SVN_ERR_ASSERT(cstr); + return svn_ra_svn__write_cstring(conn, pool, cstr); +} + +static svn_error_t * +write_tuple_cstring_opt(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const char *cstr) +{ + return cstr ? svn_ra_svn__write_cstring(conn, pool, cstr) : SVN_NO_ERROR; +} + +static svn_error_t * +write_tuple_string(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const svn_string_t *str) +{ + SVN_ERR_ASSERT(str); + return svn_ra_svn__write_string(conn, pool, str); +} + +static svn_error_t * +write_tuple_string_opt(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const svn_string_t *str) +{ + return str ? svn_ra_svn__write_string(conn, pool, str) : SVN_NO_ERROR; +} + +static svn_error_t * +write_tuple_start_list(svn_ra_svn_conn_t *conn, + apr_pool_t *pool) +{ + return svn_ra_svn__start_list(conn, pool); +} + +static svn_error_t * +write_tuple_end_list(svn_ra_svn_conn_t *conn, + apr_pool_t *pool) +{ + return svn_ra_svn__end_list(conn, pool); +} + +static svn_error_t * +write_tuple_revision(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + svn_revnum_t rev) +{ + SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(rev)); + return svn_ra_svn__write_number(conn, pool, rev); +} + +static svn_error_t * +write_tuple_revision_opt(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + svn_revnum_t rev) +{ + return SVN_IS_VALID_REVNUM(rev) + ? svn_ra_svn__write_number(conn, pool, rev) + : SVN_NO_ERROR; +} + +static svn_error_t * +write_tuple_boolean(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + svn_boolean_t value) +{ + const char *cstr = value ? "true" : "false"; + return svn_ra_svn__write_word(conn, pool, cstr); +} + +static svn_error_t * +write_tuple_depth(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + svn_depth_t depth) +{ + return svn_ra_svn__write_word(conn, pool, svn_depth_to_word(depth)); +} + + +static svn_error_t * +write_cmd_add_node(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const char *path, + const char *parent_token, + const char *token, + const char *copy_path, + svn_revnum_t copy_rev) +{ + SVN_ERR(write_tuple_cstring(conn, pool, path)); + SVN_ERR(write_tuple_cstring(conn, pool, parent_token)); + SVN_ERR(write_tuple_cstring(conn, pool, token)); + SVN_ERR(write_tuple_start_list(conn, pool)); + SVN_ERR(write_tuple_cstring_opt(conn, pool, copy_path)); + SVN_ERR(write_tuple_revision_opt(conn, pool, copy_rev)); + SVN_ERR(write_tuple_end_list(conn, pool)); + + return SVN_NO_ERROR; +} + +static svn_error_t * +write_cmd_open_node(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const char *path, + const char *parent_token, + const char *token, + svn_revnum_t rev) +{ + SVN_ERR(write_tuple_cstring(conn, pool, path)); + SVN_ERR(write_tuple_cstring(conn, pool, parent_token)); + SVN_ERR(write_tuple_cstring(conn, pool, token)); + SVN_ERR(write_tuple_start_list(conn, pool)); + SVN_ERR(write_tuple_revision_opt(conn, pool, rev)); + SVN_ERR(write_tuple_end_list(conn, pool)); + + return SVN_NO_ERROR; +} + +static svn_error_t * +write_cmd_change_node_prop(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const char *token, + const char *name, + const svn_string_t *value) +{ + SVN_ERR(write_tuple_cstring(conn, pool, token)); + SVN_ERR(write_tuple_cstring(conn, pool, name)); + SVN_ERR(write_tuple_start_list(conn, pool)); + SVN_ERR(write_tuple_string_opt(conn, pool, value)); + SVN_ERR(write_tuple_end_list(conn, pool)); + + return SVN_NO_ERROR; +} + +static svn_error_t * +write_cmd_absent_node(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const char *path, + const char *token) +{ + SVN_ERR(write_tuple_cstring(conn, pool, path)); + SVN_ERR(write_tuple_cstring(conn, pool, token)); + + return SVN_NO_ERROR; +} + + + + static svn_error_t *vwrite_tuple(svn_ra_svn_conn_t *conn, apr_pool_t *pool, - const char *fmt, va_list ap) + const char *fmt, va_list *ap) { svn_boolean_t opt = FALSE; - svn_revnum_t rev; - const char *cstr; - const svn_string_t *str; if (*fmt == '!') fmt++; else - SVN_ERR(svn_ra_svn_start_list(conn, pool)); + SVN_ERR(svn_ra_svn__start_list(conn, pool)); for (; *fmt; fmt++) { - if (*fmt == 'n' && !opt) - SVN_ERR(svn_ra_svn_write_number(conn, pool, va_arg(ap, apr_uint64_t))); - else if (*fmt == 'r') - { - rev = va_arg(ap, svn_revnum_t); - SVN_ERR_ASSERT(opt || SVN_IS_VALID_REVNUM(rev)); - if (SVN_IS_VALID_REVNUM(rev)) - SVN_ERR(svn_ra_svn_write_number(conn, pool, rev)); - } + if (*fmt == 'c') + SVN_ERR(opt ? vwrite_tuple_cstring_opt(conn, pool, ap) + : vwrite_tuple_cstring(conn, pool, ap)); else if (*fmt == 's') - { - str = va_arg(ap, const svn_string_t *); - SVN_ERR_ASSERT(opt || str); - if (str) - SVN_ERR(svn_ra_svn_write_string(conn, pool, str)); - } - else if (*fmt == 'c') - { - cstr = va_arg(ap, const char *); - SVN_ERR_ASSERT(opt || cstr); - if (cstr) - SVN_ERR(svn_ra_svn_write_cstring(conn, pool, cstr)); - } - else if (*fmt == 'w') - { - cstr = va_arg(ap, const char *); - SVN_ERR_ASSERT(opt || cstr); - if (cstr) - SVN_ERR(svn_ra_svn_write_word(conn, pool, cstr)); - } - else if (*fmt == 'b' && !opt) - { - cstr = va_arg(ap, svn_boolean_t) ? "true" : "false"; - SVN_ERR(svn_ra_svn_write_word(conn, pool, cstr)); - } - else if (*fmt == '?') - opt = TRUE; + SVN_ERR(opt ? vwrite_tuple_string_opt(conn, pool, ap) + : vwrite_tuple_string(conn, pool, ap)); else if (*fmt == '(' && !opt) - SVN_ERR(svn_ra_svn_start_list(conn, pool)); + SVN_ERR(write_tuple_start_list(conn, pool)); else if (*fmt == ')') { - SVN_ERR(svn_ra_svn_end_list(conn, pool)); + SVN_ERR(write_tuple_end_list(conn, pool)); opt = FALSE; } + else if (*fmt == '?') + opt = TRUE; + else if (*fmt == 'w') + SVN_ERR(opt ? vwrite_tuple_word_opt(conn, pool, ap) + : vwrite_tuple_word(conn, pool, ap)); + else if (*fmt == 'r') + SVN_ERR(opt ? vwrite_tuple_revision_opt(conn, pool, ap) + : vwrite_tuple_revision(conn, pool, ap)); + else if (*fmt == 'n' && !opt) + SVN_ERR(vwrite_tuple_number(conn, pool, ap)); + else if (*fmt == 'b' && !opt) + SVN_ERR(vwrite_tuple_boolean(conn, pool, ap)); else if (*fmt == '!' && !*(fmt + 1)) return SVN_NO_ERROR; else SVN_ERR_MALFUNCTION(); } - SVN_ERR(svn_ra_svn_end_list(conn, pool)); + SVN_ERR(svn_ra_svn__end_list(conn, pool)); return SVN_NO_ERROR; } -svn_error_t *svn_ra_svn_write_tuple(svn_ra_svn_conn_t *conn, apr_pool_t *pool, - const char *fmt, ...) +svn_error_t * +svn_ra_svn__write_tuple(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const char *fmt, ...) { svn_error_t *err; va_list ap; va_start(ap, fmt); - err = vwrite_tuple(conn, pool, fmt, ap); + err = vwrite_tuple(conn, pool, fmt, &ap); va_end(ap); return err; } @@ -613,7 +975,7 @@ static svn_error_t *read_string(svn_ra_svn_conn_t *conn, apr_pool_t *pool, ? len : SUSPICIOUSLY_HUGE_STRING_SIZE_THRESHOLD; - svn_stringbuf_ensure(stringbuf, stringbuf->len + readbuf_len + 1); + svn_stringbuf_ensure(stringbuf, stringbuf->len + readbuf_len); dest = stringbuf->data + stringbuf->len; } @@ -659,7 +1021,8 @@ static svn_error_t *read_item(svn_ra_svn_conn_t *conn, apr_pool_t *pool, if (!svn_ctype_isdigit(c)) break; val = val * 10 + (c - '0'); - if ((val / 10) != prev_val) /* val wrapped past maximum value */ + /* val wrapped past maximum value? */ + if (prev_val >= (APR_UINT64_MAX / 10) && (val / 10) != prev_val) return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL, _("Number is larger than maximum")); } @@ -713,8 +1076,99 @@ static svn_error_t *read_item(svn_ra_svn_conn_t *conn, apr_pool_t *pool, return SVN_NO_ERROR; } -svn_error_t *svn_ra_svn_read_item(svn_ra_svn_conn_t *conn, apr_pool_t *pool, - svn_ra_svn_item_t **item) +/* Given the first non-whitespace character FIRST_CHAR, read the first + * command (word) encountered in CONN into *ITEM. If ITEM is NULL, skip + * to the end of the current list. Use POOL for allocations. */ +static svn_error_t * +read_command_only(svn_ra_svn_conn_t *conn, apr_pool_t *pool, + const char **item, char first_char) +{ + char c = first_char; + + /* Determine the item type and read it in. Make sure that c is the + * first character at the end of the item so we can test to make + * sure it's whitespace. */ + if (svn_ctype_isdigit(c)) + { + /* It's a number or a string. Read the number part, either way. */ + apr_uint64_t val, prev_val=0; + val = c - '0'; + while (1) + { + prev_val = val; + SVN_ERR(readbuf_getchar(conn, pool, &c)); + if (!svn_ctype_isdigit(c)) + break; + val = val * 10 + (c - '0'); + if (prev_val >= (APR_UINT64_MAX / 10)) /* > maximum value? */ + return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL, + _("Number is larger than maximum")); + } + if (c == ':') + { + /* It's a string. */ + SVN_ERR(readbuf_skip(conn, val)); + SVN_ERR(readbuf_getchar(conn, pool, &c)); + } + } + else if (svn_ctype_isalpha(c)) + { + /* It's a word. */ + if (item) + { + /* This is the word we want to read */ + + char *buf = apr_palloc(pool, 32); + apr_size_t len = 1; + buf[0] = c; + + while (1) + { + SVN_ERR(readbuf_getchar(conn, pool, &c)); + if (!svn_ctype_isalnum(c) && c != '-') + break; + buf[len] = c; + if (++len == 32) + return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL, + _("Word too long")); + } + buf[len] = 0; + *item = buf; + } + else + { + /* we don't need the actual word, just skip it */ + do + { + SVN_ERR(readbuf_getchar(conn, pool, &c)); + } + while (svn_ctype_isalnum(c) || c == '-'); + } + } + else if (c == '(') + { + /* Read in the list items. */ + while (1) + { + SVN_ERR(readbuf_getchar_skip_whitespace(conn, pool, &c)); + if (c == ')') + break; + + if (item && *item == NULL) + SVN_ERR(read_command_only(conn, pool, item, c)); + else + SVN_ERR(read_command_only(conn, pool, NULL, c)); + } + SVN_ERR(readbuf_getchar(conn, pool, &c)); + } + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_ra_svn__read_item(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + svn_ra_svn_item_t **item) { char c; @@ -725,8 +1179,9 @@ svn_error_t *svn_ra_svn_read_item(svn_ra_svn_conn_t *conn, apr_pool_t *pool, return read_item(conn, pool, *item, c, 0); } -svn_error_t *svn_ra_svn_skip_leading_garbage(svn_ra_svn_conn_t *conn, - apr_pool_t *pool) +svn_error_t * +svn_ra_svn__skip_leading_garbage(svn_ra_svn_conn_t *conn, + apr_pool_t *pool) { return readbuf_skip_leading_garbage(conn, pool); } @@ -831,9 +1286,10 @@ static svn_error_t *vparse_tuple(const apr_array_header_t *items, apr_pool_t *po return SVN_NO_ERROR; } -svn_error_t *svn_ra_svn_parse_tuple(const apr_array_header_t *list, - apr_pool_t *pool, - const char *fmt, ...) +svn_error_t * +svn_ra_svn__parse_tuple(const apr_array_header_t *list, + apr_pool_t *pool, + const char *fmt, ...) { svn_error_t *err; va_list ap; @@ -844,14 +1300,16 @@ svn_error_t *svn_ra_svn_parse_tuple(const apr_array_header_t *list, return err; } -svn_error_t *svn_ra_svn_read_tuple(svn_ra_svn_conn_t *conn, apr_pool_t *pool, - const char *fmt, ...) +svn_error_t * +svn_ra_svn__read_tuple(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const char *fmt, ...) { va_list ap; svn_ra_svn_item_t *item; svn_error_t *err; - SVN_ERR(svn_ra_svn_read_item(conn, pool, &item)); + SVN_ERR(svn_ra_svn__read_item(conn, pool, &item)); if (item->kind != SVN_RA_SVN_LIST) return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL, _("Malformed network data")); @@ -861,9 +1319,23 @@ svn_error_t *svn_ra_svn_read_tuple(svn_ra_svn_conn_t *conn, apr_pool_t *pool, return err; } -svn_error_t *svn_ra_svn_parse_proplist(const apr_array_header_t *list, - apr_pool_t *pool, - apr_hash_t **props) +svn_error_t * +svn_ra_svn__read_command_only(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const char **command) +{ + char c; + SVN_ERR(readbuf_getchar_skip_whitespace(conn, pool, &c)); + + *command = NULL; + return read_command_only(conn, pool, command, c); +} + + +svn_error_t * +svn_ra_svn__parse_proplist(const apr_array_header_t *list, + apr_pool_t *pool, + apr_hash_t **props) { char *name; svn_string_t *value; @@ -877,8 +1349,9 @@ svn_error_t *svn_ra_svn_parse_proplist(const apr_array_header_t *list, if (elt->kind != SVN_RA_SVN_LIST) return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL, _("Proplist element not a list")); - SVN_ERR(svn_ra_svn_parse_tuple(elt->u.list, pool, "cs", &name, &value)); - apr_hash_set(*props, name, APR_HASH_KEY_STRING, value); + SVN_ERR(svn_ra_svn__parse_tuple(elt->u.list, pool, "cs", + &name, &value)); + svn_hash_sets(*props, name, value); } return SVN_NO_ERROR; @@ -924,8 +1397,8 @@ svn_error_t *svn_ra_svn__handle_failure_status(const apr_array_header_t *params, if (elt->kind != SVN_RA_SVN_LIST) return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL, _("Malformed error list")); - SVN_ERR(svn_ra_svn_parse_tuple(elt->u.list, subpool, "nccn", &apr_err, - &message, &file, &line)); + SVN_ERR(svn_ra_svn__parse_tuple(elt->u.list, subpool, "nccn", + &apr_err, &message, &file, &line)); /* The message field should have been optional, but we can't easily change that, so "" means a nonexistent message. */ if (!*message) @@ -954,16 +1427,17 @@ svn_error_t *svn_ra_svn__handle_failure_status(const apr_array_header_t *params, return err; } -svn_error_t *svn_ra_svn_read_cmd_response(svn_ra_svn_conn_t *conn, - apr_pool_t *pool, - const char *fmt, ...) +svn_error_t * +svn_ra_svn__read_cmd_response(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const char *fmt, ...) { va_list ap; const char *status; apr_array_header_t *params; svn_error_t *err; - SVN_ERR(svn_ra_svn_read_tuple(conn, pool, "wl", &status, ¶ms)); + SVN_ERR(svn_ra_svn__read_tuple(conn, pool, "wl", &status, ¶ms)); if (strcmp(status, "success") == 0) { va_start(ap, fmt); @@ -981,11 +1455,12 @@ svn_error_t *svn_ra_svn_read_cmd_response(svn_ra_svn_conn_t *conn, status); } -svn_error_t *svn_ra_svn_handle_commands2(svn_ra_svn_conn_t *conn, - apr_pool_t *pool, - const svn_ra_svn_cmd_entry_t *commands, - void *baton, - svn_boolean_t error_on_disconnect) +svn_error_t * +svn_ra_svn__handle_commands2(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const svn_ra_svn_cmd_entry_t *commands, + void *baton, + svn_boolean_t error_on_disconnect) { apr_pool_t *subpool = svn_pool_create(pool); apr_pool_t *iterpool = svn_pool_create(subpool); @@ -996,12 +1471,12 @@ svn_error_t *svn_ra_svn_handle_commands2(svn_ra_svn_conn_t *conn, apr_hash_t *cmd_hash = apr_hash_make(subpool); for (command = commands; command->cmdname; command++) - apr_hash_set(cmd_hash, command->cmdname, APR_HASH_KEY_STRING, command); + svn_hash_sets(cmd_hash, command->cmdname, command); while (1) { svn_pool_clear(iterpool); - err = svn_ra_svn_read_tuple(conn, iterpool, "wl", &cmdname, ¶ms); + err = svn_ra_svn__read_tuple(conn, iterpool, "wl", &cmdname, ¶ms); if (err) { if (!error_on_disconnect @@ -1013,20 +1488,20 @@ svn_error_t *svn_ra_svn_handle_commands2(svn_ra_svn_conn_t *conn, } return err; } - command = apr_hash_get(cmd_hash, cmdname, APR_HASH_KEY_STRING); + command = svn_hash_gets(cmd_hash, cmdname); if (command) err = (*command->handler)(conn, iterpool, params, baton); else { err = svn_error_createf(SVN_ERR_RA_SVN_UNKNOWN_CMD, NULL, - _("Unknown command '%s'"), cmdname); + _("Unknown editor command '%s'"), cmdname); err = svn_error_create(SVN_ERR_RA_SVN_CMD_ERR, err, NULL); } if (err && err->apr_err == SVN_ERR_RA_SVN_CMD_ERR) { - write_err = svn_ra_svn_write_cmd_failure( + write_err = svn_ra_svn__write_cmd_failure( conn, iterpool, svn_ra_svn__locate_real_error_child(err)); svn_error_clear(err); @@ -1044,69 +1519,771 @@ svn_error_t *svn_ra_svn_handle_commands2(svn_ra_svn_conn_t *conn, return SVN_NO_ERROR; } -svn_error_t *svn_ra_svn_handle_commands(svn_ra_svn_conn_t *conn, - apr_pool_t *pool, - const svn_ra_svn_cmd_entry_t *commands, - void *baton) +svn_error_t * +svn_ra_svn__write_cmd_target_rev(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + svn_revnum_t rev) { - return svn_ra_svn_handle_commands2(conn, pool, commands, baton, TRUE); + SVN_ERR(writebuf_write_short_string(conn, pool, "( target-rev ( ", 15)); + SVN_ERR(write_tuple_revision(conn, pool, rev)); + SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); + + return SVN_NO_ERROR; } -svn_error_t *svn_ra_svn_write_cmd(svn_ra_svn_conn_t *conn, apr_pool_t *pool, - const char *cmdname, const char *fmt, ...) +svn_error_t * +svn_ra_svn__write_cmd_open_root(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + svn_revnum_t rev, + const char *token) { - va_list ap; - svn_error_t *err; + SVN_ERR(writebuf_write_short_string(conn, pool, "( open-root ( ", 14)); + SVN_ERR(write_tuple_start_list(conn, pool)); + SVN_ERR(write_tuple_revision_opt(conn, pool, rev)); + SVN_ERR(write_tuple_end_list(conn, pool)); + SVN_ERR(write_tuple_cstring(conn, pool, token)); + SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_ra_svn__write_cmd_delete_entry(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const char *path, + svn_revnum_t rev, + const char *token) +{ + SVN_ERR(writebuf_write_short_string(conn, pool, "( delete-entry ( ", 17)); + SVN_ERR(write_tuple_cstring(conn, pool, path)); + SVN_ERR(write_tuple_start_list(conn, pool)); + SVN_ERR(write_tuple_revision_opt(conn, pool, rev)); + SVN_ERR(write_tuple_end_list(conn, pool)); + SVN_ERR(write_tuple_cstring(conn, pool, token)); + SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_ra_svn__write_cmd_add_dir(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const char *path, + const char *parent_token, + const char *token, + const char *copy_path, + svn_revnum_t copy_rev) +{ + SVN_ERR(writebuf_write_short_string(conn, pool, "( add-dir ( ", 12)); + SVN_ERR(write_cmd_add_node(conn, pool, path, parent_token, token, + copy_path, copy_rev)); + SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_ra_svn__write_cmd_open_dir(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const char *path, + const char *parent_token, + const char *token, + svn_revnum_t rev) +{ + SVN_ERR(writebuf_write_short_string(conn, pool, "( open-dir ( ", 13)); + SVN_ERR(write_cmd_open_node(conn, pool, path, parent_token, token, rev)); + SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_ra_svn__write_cmd_change_dir_prop(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const char *token, + const char *name, + const svn_string_t *value) +{ + SVN_ERR(writebuf_write_short_string(conn, pool, "( change-dir-prop ( ", 20)); + SVN_ERR(write_cmd_change_node_prop(conn, pool, token, name, value)); + SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_ra_svn__write_cmd_close_dir(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const char *token) +{ + SVN_ERR(writebuf_write_short_string(conn, pool, "( close-dir ( ", 14)); + SVN_ERR(write_tuple_cstring(conn, pool, token)); + SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_ra_svn__write_cmd_absent_dir(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const char *path, + const char *parent_token) +{ + SVN_ERR(writebuf_write_short_string(conn, pool, "( absent-dir ( ", 15)); + SVN_ERR(write_cmd_absent_node(conn, pool, path, parent_token)); + SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_ra_svn__write_cmd_add_file(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const char *path, + const char *parent_token, + const char *token, + const char *copy_path, + svn_revnum_t copy_rev) +{ + SVN_ERR(writebuf_write_short_string(conn, pool, "( add-file ( ", 13)); + SVN_ERR(write_cmd_add_node(conn, pool, path, parent_token, token, + copy_path, copy_rev)); + SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_ra_svn__write_cmd_open_file(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const char *path, + const char *parent_token, + const char *token, + svn_revnum_t rev) +{ + SVN_ERR(writebuf_write_short_string(conn, pool, "( open-file ( ", 14)); + SVN_ERR(write_cmd_open_node(conn, pool, path, parent_token, token, rev)); + SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_ra_svn__write_cmd_change_file_prop(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const char *token, + const char *name, + const svn_string_t *value) +{ + SVN_ERR(writebuf_write_short_string(conn, pool, "( change-file-prop ( ", 21)); + SVN_ERR(write_cmd_change_node_prop(conn, pool, token, name, value)); + SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_ra_svn__write_cmd_close_file(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const char *token, + const char *text_checksum) +{ + SVN_ERR(writebuf_write_short_string(conn, pool, "( close-file ( ", 15)); + SVN_ERR(write_tuple_cstring(conn, pool, token)); + SVN_ERR(write_tuple_start_list(conn, pool)); + SVN_ERR(write_tuple_cstring_opt(conn, pool, text_checksum)); + SVN_ERR(write_tuple_end_list(conn, pool)); + SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_ra_svn__write_cmd_absent_file(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const char *path, + const char *parent_token) +{ + SVN_ERR(writebuf_write_short_string(conn, pool, "( absent-file ( ", 16)); + SVN_ERR(write_cmd_absent_node(conn, pool, path, parent_token)); + SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_ra_svn__write_cmd_textdelta_chunk(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const char *token, + const svn_string_t *chunk) +{ + SVN_ERR(writebuf_write_short_string(conn, pool, "( textdelta-chunk ( ", 20)); + SVN_ERR(write_tuple_cstring(conn, pool, token)); + SVN_ERR(write_tuple_string(conn, pool, chunk)); + SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_ra_svn__write_cmd_textdelta_end(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const char *token) +{ + SVN_ERR(writebuf_write_short_string(conn, pool, "( textdelta-end ( ", 18)); + SVN_ERR(write_tuple_cstring(conn, pool, token)); + SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_ra_svn__write_cmd_apply_textdelta(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const char *token, + const char *base_checksum) +{ + SVN_ERR(writebuf_write_short_string(conn, pool, "( apply-textdelta ( ", 20)); + SVN_ERR(write_tuple_cstring(conn, pool, token)); + SVN_ERR(write_tuple_start_list(conn, pool)); + SVN_ERR(write_tuple_cstring_opt(conn, pool, base_checksum)); + SVN_ERR(write_tuple_end_list(conn, pool)); + SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_ra_svn__write_cmd_close_edit(svn_ra_svn_conn_t *conn, + apr_pool_t *pool) +{ + return writebuf_write_short_string(conn, pool, "( close-edit ( ) ) ", 19); +} + +svn_error_t * +svn_ra_svn__write_cmd_abort_edit(svn_ra_svn_conn_t *conn, + apr_pool_t *pool) +{ + return writebuf_write_short_string(conn, pool, "( abort-edit ( ) ) ", 19); +} + +svn_error_t * +svn_ra_svn__write_cmd_set_path(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const char *path, + svn_revnum_t rev, + svn_boolean_t start_empty, + const char *lock_token, + svn_depth_t depth) +{ + SVN_ERR(writebuf_write_short_string(conn, pool, "( set-path ( ", 13)); + SVN_ERR(write_tuple_cstring(conn, pool, path)); + SVN_ERR(write_tuple_revision(conn, pool, rev)); + SVN_ERR(write_tuple_boolean(conn, pool, start_empty)); + SVN_ERR(write_tuple_start_list(conn, pool)); + SVN_ERR(write_tuple_cstring_opt(conn, pool, lock_token)); + SVN_ERR(write_tuple_end_list(conn, pool)); + SVN_ERR(write_tuple_depth(conn, pool, depth)); + SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_ra_svn__write_cmd_delete_path(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const char *path) +{ + SVN_ERR(writebuf_write_short_string(conn, pool, "( delete-path ( ", 16)); + SVN_ERR(write_tuple_cstring(conn, pool, path)); + SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_ra_svn__write_cmd_link_path(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const char *path, + const char *url, + svn_revnum_t rev, + svn_boolean_t start_empty, + const char *lock_token, + svn_depth_t depth) +{ + SVN_ERR(writebuf_write_short_string(conn, pool, "( link-path ( ", 14)); + SVN_ERR(write_tuple_cstring(conn, pool, path)); + SVN_ERR(write_tuple_cstring(conn, pool, url)); + SVN_ERR(write_tuple_revision(conn, pool, rev)); + SVN_ERR(write_tuple_boolean(conn, pool, start_empty)); + SVN_ERR(write_tuple_start_list(conn, pool)); + SVN_ERR(write_tuple_cstring_opt(conn, pool,lock_token)); + SVN_ERR(write_tuple_end_list(conn, pool)); + SVN_ERR(write_tuple_depth(conn, pool, depth)); + SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_ra_svn__write_cmd_finish_report(svn_ra_svn_conn_t *conn, + apr_pool_t *pool) +{ + return writebuf_write_short_string(conn, pool, "( finish-report ( ) ) ", 22); +} + +svn_error_t * +svn_ra_svn__write_cmd_abort_report(svn_ra_svn_conn_t *conn, + apr_pool_t *pool) +{ + return writebuf_write_short_string(conn, pool, "( abort-report ( ) ) ", 21); +} + +svn_error_t * +svn_ra_svn__write_cmd_reparent(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const char *url) +{ + SVN_ERR(writebuf_write_short_string(conn, pool, "( reparent ( ", 13)); + SVN_ERR(write_tuple_cstring(conn, pool, url)); + SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_ra_svn__write_cmd_get_latest_rev(svn_ra_svn_conn_t *conn, + apr_pool_t *pool) +{ + return writebuf_write_short_string(conn, pool, "( get-latest-rev ( ) ) ", 23); +} + +svn_error_t * +svn_ra_svn__write_cmd_get_dated_rev(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + apr_time_t tm) +{ + SVN_ERR(writebuf_write_short_string(conn, pool, "( get-dated-rev ( ", 18)); + SVN_ERR(write_tuple_cstring(conn, pool, svn_time_to_cstring(tm, pool))); + SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_ra_svn__write_cmd_change_rev_prop2(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + svn_revnum_t rev, + const char *name, + const svn_string_t *value, + svn_boolean_t dont_care, + const svn_string_t *old_value) +{ + SVN_ERR(writebuf_write_short_string(conn, pool, "( change-rev-prop2 ( ", 21)); + SVN_ERR(write_tuple_revision(conn, pool, rev)); + SVN_ERR(write_tuple_cstring(conn, pool, name)); + SVN_ERR(write_tuple_start_list(conn, pool)); + SVN_ERR(write_tuple_string_opt(conn, pool, value)); + SVN_ERR(write_tuple_end_list(conn, pool)); + SVN_ERR(write_tuple_start_list(conn, pool)); + SVN_ERR(write_tuple_boolean(conn, pool, dont_care)); + SVN_ERR(write_tuple_string_opt(conn, pool, old_value)); + SVN_ERR(write_tuple_end_list(conn, pool)); + SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_ra_svn__write_cmd_change_rev_prop(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + svn_revnum_t rev, + const char *name, + const svn_string_t *value) +{ + SVN_ERR(writebuf_write_short_string(conn, pool, "( change-rev-prop ( ", 20)); + SVN_ERR(write_tuple_revision(conn, pool, rev)); + SVN_ERR(write_tuple_cstring(conn, pool, name)); + SVN_ERR(write_tuple_string_opt(conn, pool, value)); + SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_ra_svn__write_cmd_rev_proplist(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + svn_revnum_t rev) +{ + SVN_ERR(writebuf_write_short_string(conn, pool, "( rev-proplist ( ", 17)); + SVN_ERR(write_tuple_revision(conn, pool, rev)); + SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_ra_svn__write_cmd_rev_prop(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + svn_revnum_t rev, + const char *name) +{ + SVN_ERR(writebuf_write_short_string(conn, pool, "( rev-prop ( ", 13)); + SVN_ERR(write_tuple_revision(conn, pool, rev)); + SVN_ERR(write_tuple_cstring(conn, pool, name)); + SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_ra_svn__write_cmd_get_file(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const char *path, + svn_revnum_t rev, + svn_boolean_t props, + svn_boolean_t stream) +{ + SVN_ERR(writebuf_write_short_string(conn, pool, "( get-file ( ", 13)); + SVN_ERR(write_tuple_cstring(conn, pool, path)); + SVN_ERR(write_tuple_start_list(conn, pool)); + SVN_ERR(write_tuple_revision_opt(conn, pool, rev)); + SVN_ERR(write_tuple_end_list(conn, pool)); + SVN_ERR(write_tuple_boolean(conn, pool, props)); + SVN_ERR(write_tuple_boolean(conn, pool, stream)); + SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_ra_svn__write_cmd_update(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + svn_revnum_t rev, + const char *target, + svn_boolean_t recurse, + svn_depth_t depth, + svn_boolean_t send_copyfrom_args, + svn_boolean_t ignore_ancestry) +{ + SVN_ERR(writebuf_write_short_string(conn, pool, "( update ( ", 11)); + SVN_ERR(write_tuple_start_list(conn, pool)); + SVN_ERR(write_tuple_revision_opt(conn, pool, rev)); + SVN_ERR(write_tuple_end_list(conn, pool)); + SVN_ERR(write_tuple_cstring(conn, pool, target)); + SVN_ERR(write_tuple_boolean(conn, pool, recurse)); + SVN_ERR(write_tuple_depth(conn, pool, depth)); + SVN_ERR(write_tuple_boolean(conn, pool, send_copyfrom_args)); + SVN_ERR(write_tuple_boolean(conn, pool, ignore_ancestry)); + SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_ra_svn__write_cmd_switch(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + svn_revnum_t rev, + const char *target, + svn_boolean_t recurse, + const char *switch_url, + svn_depth_t depth, + svn_boolean_t send_copyfrom_args, + svn_boolean_t ignore_ancestry) +{ + SVN_ERR(writebuf_write_short_string(conn, pool, "( switch ( ", 11)); + SVN_ERR(write_tuple_start_list(conn, pool)); + SVN_ERR(write_tuple_revision_opt(conn, pool, rev)); + SVN_ERR(write_tuple_end_list(conn, pool)); + SVN_ERR(write_tuple_cstring(conn, pool, target)); + SVN_ERR(write_tuple_boolean(conn, pool, recurse)); + SVN_ERR(write_tuple_cstring(conn, pool, switch_url)); + SVN_ERR(write_tuple_depth(conn, pool, depth)); + SVN_ERR(write_tuple_boolean(conn, pool, send_copyfrom_args)); + SVN_ERR(write_tuple_boolean(conn, pool, ignore_ancestry)); + SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_ra_svn__write_cmd_status(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const char *target, + svn_boolean_t recurse, + svn_revnum_t rev, + svn_depth_t depth) +{ + SVN_ERR(writebuf_write_short_string(conn, pool, "( status ( ", 11)); + SVN_ERR(write_tuple_cstring(conn, pool, target)); + SVN_ERR(write_tuple_boolean(conn, pool, recurse)); + SVN_ERR(write_tuple_start_list(conn, pool)); + SVN_ERR(write_tuple_revision_opt(conn, pool, rev)); + SVN_ERR(write_tuple_end_list(conn, pool)); + SVN_ERR(write_tuple_depth(conn, pool, depth)); + SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_ra_svn__write_cmd_diff(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + svn_revnum_t rev, + const char *target, + svn_boolean_t recurse, + svn_boolean_t ignore_ancestry, + const char *versus_url, + svn_boolean_t text_deltas, + svn_depth_t depth) +{ + SVN_ERR(writebuf_write_short_string(conn, pool, "( diff ( ", 9)); + SVN_ERR(write_tuple_start_list(conn, pool)); + SVN_ERR(write_tuple_revision_opt(conn, pool, rev)); + SVN_ERR(write_tuple_end_list(conn, pool)); + SVN_ERR(write_tuple_cstring(conn, pool, target)); + SVN_ERR(write_tuple_boolean(conn, pool, recurse)); + SVN_ERR(write_tuple_boolean(conn, pool, ignore_ancestry)); + SVN_ERR(write_tuple_cstring(conn, pool, versus_url)); + SVN_ERR(write_tuple_boolean(conn, pool, text_deltas)); + SVN_ERR(write_tuple_depth(conn, pool, depth)); + SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_ra_svn__write_cmd_check_path(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const char *path, + svn_revnum_t rev) +{ + SVN_ERR(writebuf_write_short_string(conn, pool, "( check-path ( ", 15)); + SVN_ERR(write_tuple_cstring(conn, pool, path)); + SVN_ERR(write_tuple_start_list(conn, pool)); + SVN_ERR(write_tuple_revision_opt(conn, pool, rev)); + SVN_ERR(write_tuple_end_list(conn, pool)); + SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); - SVN_ERR(svn_ra_svn_start_list(conn, pool)); - SVN_ERR(svn_ra_svn_write_word(conn, pool, cmdname)); - va_start(ap, fmt); - err = vwrite_tuple(conn, pool, fmt, ap); - va_end(ap); - if (err) - return err; - SVN_ERR(svn_ra_svn_end_list(conn, pool)); return SVN_NO_ERROR; } -svn_error_t *svn_ra_svn_write_cmd_response(svn_ra_svn_conn_t *conn, - apr_pool_t *pool, - const char *fmt, ...) +svn_error_t * +svn_ra_svn__write_cmd_stat(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const char *path, + svn_revnum_t rev) +{ + SVN_ERR(writebuf_write_short_string(conn, pool, "( stat ( ", 9)); + SVN_ERR(write_tuple_cstring(conn, pool, path)); + SVN_ERR(write_tuple_start_list(conn, pool)); + SVN_ERR(write_tuple_revision_opt(conn, pool, rev)); + SVN_ERR(write_tuple_end_list(conn, pool)); + SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_ra_svn__write_cmd_get_file_revs(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const char *path, + svn_revnum_t start, + svn_revnum_t end, + svn_boolean_t include_merged_revisions) +{ + SVN_ERR(writebuf_write_short_string(conn, pool, "( get-file-revs ( ", 18)); + SVN_ERR(write_tuple_cstring(conn, pool, path)); + SVN_ERR(write_tuple_start_list(conn, pool)); + SVN_ERR(write_tuple_revision_opt(conn, pool, start)); + SVN_ERR(write_tuple_end_list(conn, pool)); + SVN_ERR(write_tuple_start_list(conn, pool)); + SVN_ERR(write_tuple_revision_opt(conn, pool, end)); + SVN_ERR(write_tuple_end_list(conn, pool)); + SVN_ERR(write_tuple_boolean(conn, pool, include_merged_revisions)); + SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_ra_svn__write_cmd_lock(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const char *path, + const char *comment, + svn_boolean_t steal_lock, + svn_revnum_t revnum) +{ + SVN_ERR(writebuf_write_short_string(conn, pool, "( lock ( ", 9)); + SVN_ERR(write_tuple_cstring(conn, pool, path)); + SVN_ERR(write_tuple_start_list(conn, pool)); + SVN_ERR(write_tuple_cstring_opt(conn, pool, comment)); + SVN_ERR(write_tuple_end_list(conn, pool)); + SVN_ERR(write_tuple_boolean(conn, pool, steal_lock)); + SVN_ERR(write_tuple_start_list(conn, pool)); + SVN_ERR(write_tuple_revision_opt(conn, pool, revnum)); + SVN_ERR(write_tuple_end_list(conn, pool)); + SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_ra_svn__write_cmd_unlock(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const char *path, + const char *token, + svn_boolean_t break_lock) +{ + SVN_ERR(writebuf_write_short_string(conn, pool, "( unlock ( ", 11)); + SVN_ERR(write_tuple_cstring(conn, pool, path)); + SVN_ERR(write_tuple_start_list(conn, pool)); + SVN_ERR(write_tuple_cstring_opt(conn, pool, token)); + SVN_ERR(write_tuple_end_list(conn, pool)); + SVN_ERR(write_tuple_boolean(conn, pool, break_lock)); + SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_ra_svn__write_cmd_get_lock(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const char *path) +{ + SVN_ERR(writebuf_write_short_string(conn, pool, "( get-lock ( ", 13)); + SVN_ERR(write_tuple_cstring(conn, pool, path)); + SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_ra_svn__write_cmd_get_locks(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const char *path, + svn_depth_t depth) +{ + SVN_ERR(writebuf_write_short_string(conn, pool, "( get-locks ( ", 14)); + SVN_ERR(write_tuple_cstring(conn, pool, path)); + SVN_ERR(write_tuple_start_list(conn, pool)); + SVN_ERR(write_tuple_depth(conn, pool, depth)); + SVN_ERR(write_tuple_end_list(conn, pool)); + SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_ra_svn__write_cmd_replay(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + svn_revnum_t rev, + svn_revnum_t low_water_mark, + svn_boolean_t send_deltas) +{ + SVN_ERR(writebuf_write_short_string(conn, pool, "( replay ( ", 11)); + SVN_ERR(write_tuple_revision(conn, pool, rev)); + SVN_ERR(write_tuple_revision(conn, pool, low_water_mark)); + SVN_ERR(write_tuple_boolean(conn, pool, send_deltas)); + SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_ra_svn__write_cmd_replay_range(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + svn_revnum_t start_revision, + svn_revnum_t end_revision, + svn_revnum_t low_water_mark, + svn_boolean_t send_deltas) +{ + SVN_ERR(writebuf_write_short_string(conn, pool, "( replay-range ( ", 17)); + SVN_ERR(write_tuple_revision(conn, pool, start_revision)); + SVN_ERR(write_tuple_revision(conn, pool, end_revision)); + SVN_ERR(write_tuple_revision(conn, pool, low_water_mark)); + SVN_ERR(write_tuple_boolean(conn, pool, send_deltas)); + SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_ra_svn__write_cmd_get_deleted_rev(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const char *path, + svn_revnum_t peg_revision, + svn_revnum_t end_revision) +{ + SVN_ERR(writebuf_write_short_string(conn, pool, "( get-deleted-rev ( ", 20)); + SVN_ERR(write_tuple_cstring(conn, pool, path)); + SVN_ERR(write_tuple_revision(conn, pool, peg_revision)); + SVN_ERR(write_tuple_revision(conn, pool, end_revision)); + SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_ra_svn__write_cmd_get_iprops(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const char *path, + svn_revnum_t revision) +{ + SVN_ERR(writebuf_write_short_string(conn, pool, "( get-iprops ( ", 15)); + SVN_ERR(write_tuple_cstring(conn, pool, path)); + SVN_ERR(write_tuple_start_list(conn, pool)); + SVN_ERR(write_tuple_revision_opt(conn, pool, revision)); + SVN_ERR(write_tuple_end_list(conn, pool)); + SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_ra_svn__write_cmd_finish_replay(svn_ra_svn_conn_t *conn, + apr_pool_t *pool) +{ + return writebuf_write_short_string(conn, pool, "( finish-replay ( ) ) ", 22); +} + +svn_error_t *svn_ra_svn__write_cmd_response(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const char *fmt, ...) { va_list ap; svn_error_t *err; - SVN_ERR(svn_ra_svn_start_list(conn, pool)); - SVN_ERR(svn_ra_svn_write_word(conn, pool, "success")); + SVN_ERR(writebuf_write_short_string(conn, pool, "( success ", 10)); va_start(ap, fmt); - err = vwrite_tuple(conn, pool, fmt, ap); + err = vwrite_tuple(conn, pool, fmt, &ap); va_end(ap); - if (err) - return err; - SVN_ERR(svn_ra_svn_end_list(conn, pool)); - return SVN_NO_ERROR; + return err ? svn_error_trace(err) : svn_ra_svn__end_list(conn, pool); } -svn_error_t *svn_ra_svn_write_cmd_failure(svn_ra_svn_conn_t *conn, - apr_pool_t *pool, svn_error_t *err) +svn_error_t *svn_ra_svn__write_cmd_failure(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, svn_error_t *err) { char buffer[128]; - SVN_ERR(svn_ra_svn_start_list(conn, pool)); - SVN_ERR(svn_ra_svn_write_word(conn, pool, "failure")); - SVN_ERR(svn_ra_svn_start_list(conn, pool)); + SVN_ERR(writebuf_write_short_string(conn, pool, "( failure ( ", 12)); for (; err; err = err->child) { - const char *msg = svn_err_best_message(err, buffer, sizeof(buffer)); + const char *msg; + +#ifdef SVN_ERR__TRACING + if (svn_error__is_tracing_link(err)) + msg = err->message; + else +#endif + msg = svn_err_best_message(err, buffer, sizeof(buffer)); /* The message string should have been optional, but we can't easily change that, so marshal nonexistent messages as "". */ - SVN_ERR(svn_ra_svn_write_tuple(conn, pool, "nccn", - (apr_uint64_t) err->apr_err, - msg ? msg : "", - err->file ? err->file : "", - (apr_uint64_t) err->line)); + SVN_ERR(svn_ra_svn__write_tuple(conn, pool, "nccn", + (apr_uint64_t) err->apr_err, + msg ? msg : "", + err->file ? err->file : "", + (apr_uint64_t) err->line)); } - SVN_ERR(svn_ra_svn_end_list(conn, pool)); - SVN_ERR(svn_ra_svn_end_list(conn, pool)); - return SVN_NO_ERROR; + return writebuf_write_short_string(conn, pool, ") ) ", 4); } |