summaryrefslogtreecommitdiff
path: root/subversion/libsvn_ra_svn/marshal.c
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/libsvn_ra_svn/marshal.c')
-rw-r--r--subversion/libsvn_ra_svn/marshal.c902
1 files changed, 614 insertions, 288 deletions
diff --git a/subversion/libsvn_ra_svn/marshal.c b/subversion/libsvn_ra_svn/marshal.c
index 7cf483f..0778269 100644
--- a/subversion/libsvn_ra_svn/marshal.c
+++ b/subversion/libsvn_ra_svn/marshal.c
@@ -40,6 +40,7 @@
#include "svn_ra_svn.h"
#include "svn_private_config.h"
#include "svn_ctype.h"
+#include "svn_sorts.h"
#include "svn_time.h"
#include "ra_svn.h"
@@ -47,6 +48,7 @@
#include "private/svn_string_private.h"
#include "private/svn_dep_compat.h"
#include "private/svn_error_private.h"
+#include "private/svn_subr_private.h"
#define svn_iswhitespace(c) ((c) == ' ' || (c) == '\n')
@@ -56,6 +58,19 @@
#define SUSPICIOUSLY_HUGE_STRING_SIZE_THRESHOLD (0x100000)
+/* We don't use "words" longer than this in our protocol. The longest word
+ * we are currently using is only about 16 chars long but we leave room for
+ * longer future capability and command names.
+ */
+#define MAX_WORD_LENGTH 31
+
+/* The generic parsers will use the following value to limit the recursion
+ * depth to some reasonable value. The current protocol implementation
+ * actually uses only maximum item nesting level of around 5. So, there is
+ * plenty of headroom here.
+ */
+#define ITEM_NESTING_LIMIT 64
+
/* 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
@@ -66,19 +81,20 @@ get_timeout(svn_ra_svn_conn_t *conn)
/* --- CONNECTION INITIALIZATION --- */
-svn_ra_svn_conn_t *svn_ra_svn_create_conn3(apr_socket_t *sock,
- apr_file_t *in_file,
- apr_file_t *out_file,
+svn_ra_svn_conn_t *svn_ra_svn_create_conn4(apr_socket_t *sock,
+ svn_stream_t *in_stream,
+ svn_stream_t *out_stream,
int compression_level,
apr_size_t zero_copy_limit,
apr_size_t error_check_interval,
- apr_pool_t *pool)
+ apr_pool_t *result_pool)
{
svn_ra_svn_conn_t *conn;
- void *mem = apr_palloc(pool, sizeof(*conn) + SVN_RA_SVN__PAGE_SIZE);
+ void *mem = apr_palloc(result_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));
+ assert((sock && !in_stream && !out_stream)
+ || (!sock && in_stream && out_stream));
#ifdef SVN_HAVE_SASL
conn->sock = sock;
conn->encrypted = FALSE;
@@ -92,15 +108,15 @@ svn_ra_svn_conn_t *svn_ra_svn_create_conn3(apr_socket_t *sock,
conn->may_check_for_error = error_check_interval == 0;
conn->block_handler = NULL;
conn->block_baton = NULL;
- conn->capabilities = apr_hash_make(pool);
+ conn->capabilities = apr_hash_make(result_pool);
conn->compression_level = compression_level;
conn->zero_copy_limit = zero_copy_limit;
- conn->pool = pool;
+ conn->pool = result_pool;
if (sock != NULL)
{
apr_sockaddr_t *sa;
- conn->stream = svn_ra_svn__stream_from_sock(sock, pool);
+ conn->stream = svn_ra_svn__stream_from_sock(sock, result_pool);
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;
@@ -108,34 +124,14 @@ svn_ra_svn_conn_t *svn_ra_svn_create_conn3(apr_socket_t *sock,
}
else
{
- conn->stream = svn_ra_svn__stream_from_files(in_file, out_file, pool);
+ conn->stream = svn_ra_svn__stream_from_streams(in_stream, out_stream,
+ result_pool);
conn->remote_ip = NULL;
}
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_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,
const apr_array_header_t *list)
{
@@ -155,6 +151,12 @@ svn_error_t *svn_ra_svn_set_capabilities(svn_ra_svn_conn_t *conn,
return SVN_NO_ERROR;
}
+apr_pool_t *
+svn_ra_svn__get_pool(svn_ra_svn_conn_t *conn)
+{
+ return conn->pool;
+}
+
svn_error_t *
svn_ra_svn__set_shim_callbacks(svn_ra_svn_conn_t *conn,
svn_delta_shim_callbacks_t *shim_callbacks)
@@ -196,10 +198,10 @@ svn_ra_svn__set_block_handler(svn_ra_svn_conn_t *conn,
svn_ra_svn__stream_timeout(conn->stream, get_timeout(conn));
}
-svn_boolean_t svn_ra_svn__input_waiting(svn_ra_svn_conn_t *conn,
- apr_pool_t *pool)
+svn_error_t *svn_ra_svn__data_available(svn_ra_svn_conn_t *conn,
+ svn_boolean_t *data_available)
{
- return svn_ra_svn__stream_pending(conn->stream);
+ return svn_ra_svn__stream_data_available(conn->stream, data_available);
}
/* --- WRITE BUFFER MANAGEMENT --- */
@@ -285,20 +287,13 @@ static svn_error_t *writebuf_write(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
return SVN_NO_ERROR;
}
-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)
-{
- 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);
-}
+/* Write STRING_LITERAL, which is a string literal argument.
+
+ Note: The purpose of the empty string "" in the macro definition is to
+ assert that STRING_LITERAL is in fact a string literal. Otherwise, the
+ string concatenation attempt should produce a compile-time error. */
+#define writebuf_write_literal(conn, pool, string_literal) \
+ writebuf_write(conn, pool, string_literal, sizeof(string_literal "") - 1)
static APR_INLINE svn_error_t *
writebuf_writechar(svn_ra_svn_conn_t *conn, apr_pool_t *pool, char data)
@@ -389,7 +384,9 @@ static svn_error_t *readbuf_fill(svn_ra_svn_conn_t *conn, apr_pool_t *pool)
apr_size_t len;
SVN_ERR_ASSERT(conn->read_ptr == conn->read_end);
- SVN_ERR(writebuf_flush(conn, pool));
+ if (conn->write_pos)
+ SVN_ERR(writebuf_flush(conn, pool));
+
len = sizeof(conn->read_buf);
SVN_ERR(readbuf_input(conn, conn->read_buf, &len, pool));
conn->read_ptr = conn->read_buf;
@@ -397,7 +394,11 @@ static svn_error_t *readbuf_fill(svn_ra_svn_conn_t *conn, apr_pool_t *pool)
return SVN_NO_ERROR;
}
-static APR_INLINE svn_error_t *
+/* This is a hot function calling a cold function. GCC and others tend to
+ * inline the cold sub-function instead of this hot one. Therefore, be
+ * very insistent on lining this one. It is not a correctness issue, though.
+ */
+static SVN__FORCE_INLINE svn_error_t *
readbuf_getchar(svn_ra_svn_conn_t *conn, apr_pool_t *pool, char *result)
{
if (conn->read_ptr == conn->read_end)
@@ -511,21 +512,32 @@ svn_ra_svn__write_number(svn_ra_svn_conn_t *conn,
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)
+static svn_error_t *
+svn_ra_svn__write_ncstring(svn_ra_svn_conn_t *conn,
+ apr_pool_t *pool,
+ const char *s,
+ apr_size_t len)
{
- if (str->len < 10)
+ if (len < 10)
{
- SVN_ERR(writebuf_writechar(conn, pool, (char)(str->len + '0')));
+ SVN_ERR(writebuf_writechar(conn, pool, (char)(len + '0')));
SVN_ERR(writebuf_writechar(conn, pool, ':'));
}
else
- SVN_ERR(write_number(conn, pool, str->len, ':'));
+ SVN_ERR(write_number(conn, pool, len, ':'));
- SVN_ERR(writebuf_write(conn, pool, str->data, str->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_string(svn_ra_svn_conn_t *conn,
+ apr_pool_t *pool,
+ const svn_string_t *str)
+{
+ SVN_ERR(svn_ra_svn__write_ncstring(conn, pool, str->data, str->len));
return SVN_NO_ERROR;
}
@@ -534,19 +546,7 @@ svn_ra_svn__write_cstring(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
const char *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, ' '));
-
+ SVN_ERR(svn_ra_svn__write_ncstring(conn, pool, s, strlen(s)));
return SVN_NO_ERROR;
}
@@ -555,38 +555,52 @@ svn_ra_svn__write_word(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
const char *word)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, word, strlen(word)));
+ SVN_ERR(writebuf_write(conn, pool, word, strlen(word)));
SVN_ERR(writebuf_writechar(conn, pool, ' '));
return SVN_NO_ERROR;
}
svn_error_t *
+svn_ra_svn__write_boolean(svn_ra_svn_conn_t *conn,
+ apr_pool_t *pool,
+ svn_boolean_t value)
+{
+ if (value)
+ SVN_ERR(writebuf_write_literal(conn, pool, "true "));
+ else
+ SVN_ERR(writebuf_write_literal(conn, pool, "false "));
+
+ 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)
{
- apr_pool_t *iterpool;
apr_hash_index_t *hi;
- const void *key;
- void *val;
const char *propname;
svn_string_t *propval;
+ apr_size_t len;
+ /* One might use an iterpool here but that would only be used when the
+ send buffer gets flushed and only by the CONN's progress callback.
+ That should happen at most once for typical prop lists and even then
+ use only a few bytes at best.
+ */
if (props)
- {
- iterpool = svn_pool_create(pool);
- for (hi = apr_hash_first(pool, props); hi; hi = apr_hash_next(hi))
- {
- svn_pool_clear(iterpool);
- apr_hash_this(hi, &key, NULL, &val);
- propname = key;
- propval = val;
- SVN_ERR(svn_ra_svn__write_tuple(conn, iterpool, "cs",
- propname, propval));
- }
- svn_pool_destroy(iterpool);
- }
+ for (hi = apr_hash_first(pool, props); hi; hi = apr_hash_next(hi))
+ {
+ apr_hash_this(hi, (const void **)&propname,
+ (apr_ssize_t *)&len,
+ (void **)&propval);
+
+ SVN_ERR(svn_ra_svn__start_list(conn, pool));
+ SVN_ERR(svn_ra_svn__write_ncstring(conn, pool, propname, len));
+ SVN_ERR(svn_ra_svn__write_string(conn, pool, propval));
+ SVN_ERR(svn_ra_svn__end_list(conn, pool));
+ }
return SVN_NO_ERROR;
}
@@ -704,8 +718,7 @@ vwrite_tuple_number(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
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);
+ return svn_ra_svn__write_boolean(conn, pool, va_arg(*ap, svn_boolean_t));
}
static svn_error_t *
@@ -780,8 +793,7 @@ 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);
+ return svn_ra_svn__write_boolean(conn, pool, value);
}
static svn_error_t *
@@ -929,10 +941,10 @@ svn_ra_svn__write_tuple(svn_ra_svn_conn_t *conn,
static svn_error_t *read_string(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
svn_ra_svn_item_t *item, apr_uint64_t len64)
{
- svn_stringbuf_t *stringbuf;
apr_size_t len = (apr_size_t)len64;
apr_size_t readbuf_len;
char *dest;
+ apr_size_t buflen;
/* We can't store strings longer than the maximum size of apr_size_t,
* so check for wrapping */
@@ -940,58 +952,61 @@ static svn_error_t *read_string(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
_("String length larger than maximum"));
- /* Read the string in chunks. The chunk size is large enough to avoid
- * re-allocation in typical cases, and small enough to ensure we do not
- * pre-allocate an unreasonable amount of memory if (perhaps due to
- * network data corruption or a DOS attack), we receive a bogus claim that
- * a very long string is going to follow. In that case, we start small
- * and wait for all that data to actually show up. This does not fully
- * prevent DOS attacks but makes them harder (you have to actually send
- * gigabytes of data). */
- readbuf_len = len < SUSPICIOUSLY_HUGE_STRING_SIZE_THRESHOLD
- ? len
- : SUSPICIOUSLY_HUGE_STRING_SIZE_THRESHOLD;
- stringbuf = svn_stringbuf_create_ensure(readbuf_len, pool);
- dest = stringbuf->data;
-
- /* Read remaining string data directly into the string structure.
- * Do it iteratively, if necessary. */
- while (readbuf_len)
+ buflen = conn->read_end - conn->read_ptr;
+ /* Shorter strings can be copied directly from the read buffer. */
+ if (len <= buflen)
{
- SVN_ERR(readbuf_read(conn, pool, dest, readbuf_len));
-
- stringbuf->len += readbuf_len;
- len -= readbuf_len;
+ item->kind = SVN_RA_SVN_STRING;
+ item->u.string = svn_string_ncreate(conn->read_ptr, len, pool);
+ conn->read_ptr += len;
+ }
+ else
+ {
+ /* Read the string in chunks. The chunk size is large enough to avoid
+ * re-allocation in typical cases, and small enough to ensure we do
+ * not pre-allocate an unreasonable amount of memory if (perhaps due
+ * to network data corruption or a DOS attack), we receive a bogus
+ * claim that a very long string is going to follow. In that case, we
+ * start small and wait for all that data to actually show up. This
+ * does not fully prevent DOS attacks but makes them harder (you have
+ * to actually send gigabytes of data). */
+ svn_stringbuf_t *stringbuf = svn_stringbuf_create_empty(pool);
+
+ /* Read string data directly into the string structure.
+ * Do it iteratively. */
+ do
+ {
+ /* Determine length of chunk to read and re-alloc the buffer. */
+ readbuf_len
+ = len < SUSPICIOUSLY_HUGE_STRING_SIZE_THRESHOLD
+ ? len
+ : SUSPICIOUSLY_HUGE_STRING_SIZE_THRESHOLD;
- /* Early exit. In most cases, strings can be read in the first
- * iteration. */
- if (len == 0)
- break;
+ svn_stringbuf_ensure(stringbuf, stringbuf->len + readbuf_len);
+ dest = stringbuf->data + stringbuf->len;
- /* Prepare next iteration: determine length of chunk to read
- * and re-alloc the string buffer. */
- readbuf_len
- = len < SUSPICIOUSLY_HUGE_STRING_SIZE_THRESHOLD
- ? len
- : SUSPICIOUSLY_HUGE_STRING_SIZE_THRESHOLD;
+ /* read data & update length info */
+ SVN_ERR(readbuf_read(conn, pool, dest, readbuf_len));
- svn_stringbuf_ensure(stringbuf, stringbuf->len + readbuf_len);
- dest = stringbuf->data + stringbuf->len;
- }
+ stringbuf->len += readbuf_len;
+ len -= readbuf_len;
+ }
+ while (len);
- /* zero-terminate the string */
- stringbuf->data[stringbuf->len] = '\0';
+ /* zero-terminate the string */
+ stringbuf->data[stringbuf->len] = '\0';
- /* Return the string properly wrapped into an RA_SVN item. */
- item->kind = SVN_RA_SVN_STRING;
- item->u.string = svn_stringbuf__morph_into_string(stringbuf);
+ /* Return the string properly wrapped into an RA_SVN item. */
+ item->kind = SVN_RA_SVN_STRING;
+ item->u.string = svn_stringbuf__morph_into_string(stringbuf);
+ }
return SVN_NO_ERROR;
}
/* Given the first non-whitespace character FIRST_CHAR, read an item
* into the already allocated structure ITEM. LEVEL should be set
- * to 0 for the first call and is used to enforce a recurssion limit
+ * to 0 for the first call and is used to enforce a recursion limit
* on the parser. */
static svn_error_t *read_item(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
svn_ra_svn_item_t *item, char first_char,
@@ -999,12 +1014,11 @@ static svn_error_t *read_item(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
{
char c = first_char;
apr_uint64_t val;
- svn_stringbuf_t *str;
svn_ra_svn_item_t *listitem;
- if (++level >= 64)
+ if (++level >= ITEM_NESTING_LIMIT)
return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
- _("Too many nested items"));
+ _("Items are nested too deeply"));
/* Determine the item type and read it in. Make sure that c is the
@@ -1022,7 +1036,8 @@ static svn_error_t *read_item(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
break;
val = val * 10 + (c - '0');
/* val wrapped past maximum value? */
- if (prev_val >= (APR_UINT64_MAX / 10) && (val / 10) != prev_val)
+ if ((prev_val >= (APR_UINT64_MAX / 10))
+ && (val < APR_UINT64_MAX - 10))
return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
_("Number is larger than maximum"));
}
@@ -1041,18 +1056,28 @@ static svn_error_t *read_item(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
}
else if (svn_ctype_isalpha(c))
{
- /* It's a word. */
- str = svn_stringbuf_create_ensure(16, pool);
- svn_stringbuf_appendbyte(str, c);
+ /* It's a word. Read it into a buffer of limited size. */
+ char *buffer = apr_palloc(pool, MAX_WORD_LENGTH + 1);
+ char *end = buffer + MAX_WORD_LENGTH;
+ char *p = buffer + 1;
+
+ buffer[0] = c;
while (1)
{
- SVN_ERR(readbuf_getchar(conn, pool, &c));
- if (!svn_ctype_isalnum(c) && c != '-')
+ SVN_ERR(readbuf_getchar(conn, pool, p));
+ if (!svn_ctype_isalnum(*p) && *p != '-')
break;
- svn_stringbuf_appendbyte(str, c);
+
+ if (++p == end)
+ return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
+ _("Word is too long"));
}
+
+ c = *p;
+ *p = '\0';
+
item->kind = SVN_RA_SVN_WORD;
- item->u.word = str->data;
+ item->u.word = buffer;
}
else if (c == '(')
{
@@ -1179,6 +1204,36 @@ svn_ra_svn__read_item(svn_ra_svn_conn_t *conn,
return read_item(conn, pool, *item, c, 0);
}
+/* Drain existing whitespace from the receive buffer of CONN until either
+ there is no data in the underlying receive socket anymore or we found
+ a non-whitespace char. Set *HAS_ITEM to TRUE in the latter case.
+ */
+static svn_error_t *
+svn_ra_svn__has_item(svn_boolean_t *has_item,
+ svn_ra_svn_conn_t *conn,
+ apr_pool_t *pool)
+{
+ do
+ {
+ if (conn->read_ptr == conn->read_end)
+ {
+ svn_boolean_t available;
+ if (conn->write_pos)
+ SVN_ERR(writebuf_flush(conn, pool));
+
+ SVN_ERR(svn_ra_svn__data_available(conn, &available));
+ if (!available)
+ break;
+
+ SVN_ERR(readbuf_fill(conn, pool));
+ }
+ }
+ while (svn_iswhitespace(*conn->read_ptr) && ++conn->read_ptr);
+
+ *has_item = conn->read_ptr != conn->read_end;
+ return SVN_NO_ERROR;
+}
+
svn_error_t *
svn_ra_svn__skip_leading_garbage(svn_ra_svn_conn_t *conn,
apr_pool_t *pool)
@@ -1202,14 +1257,15 @@ static svn_error_t *vparse_tuple(const apr_array_header_t *items, apr_pool_t *po
if (**fmt == '?')
(*fmt)++;
elt = &APR_ARRAY_IDX(items, count, svn_ra_svn_item_t);
- if (**fmt == 'n' && elt->kind == SVN_RA_SVN_NUMBER)
- *va_arg(*ap, apr_uint64_t *) = elt->u.number;
- else if (**fmt == 'r' && elt->kind == SVN_RA_SVN_NUMBER)
- *va_arg(*ap, svn_revnum_t *) = (svn_revnum_t) elt->u.number;
- else if (**fmt == 's' && elt->kind == SVN_RA_SVN_STRING)
- *va_arg(*ap, svn_string_t **) = elt->u.string;
+ if (**fmt == '(' && elt->kind == SVN_RA_SVN_LIST)
+ {
+ (*fmt)++;
+ SVN_ERR(vparse_tuple(elt->u.list, pool, fmt, ap));
+ }
else if (**fmt == 'c' && elt->kind == SVN_RA_SVN_STRING)
*va_arg(*ap, const char **) = elt->u.string->data;
+ else if (**fmt == 's' && elt->kind == SVN_RA_SVN_STRING)
+ *va_arg(*ap, svn_string_t **) = elt->u.string;
else if (**fmt == 'w' && elt->kind == SVN_RA_SVN_WORD)
*va_arg(*ap, const char **) = elt->u.word;
else if (**fmt == 'b' && elt->kind == SVN_RA_SVN_WORD)
@@ -1221,6 +1277,10 @@ static svn_error_t *vparse_tuple(const apr_array_header_t *items, apr_pool_t *po
else
break;
}
+ else if (**fmt == 'n' && elt->kind == SVN_RA_SVN_NUMBER)
+ *va_arg(*ap, apr_uint64_t *) = elt->u.number;
+ else if (**fmt == 'r' && elt->kind == SVN_RA_SVN_NUMBER)
+ *va_arg(*ap, svn_revnum_t *) = (svn_revnum_t) elt->u.number;
else if (**fmt == 'B' && elt->kind == SVN_RA_SVN_WORD)
{
if (strcmp(elt->u.word, "true") == 0)
@@ -1230,13 +1290,17 @@ static svn_error_t *vparse_tuple(const apr_array_header_t *items, apr_pool_t *po
else
break;
}
- else if (**fmt == 'l' && elt->kind == SVN_RA_SVN_LIST)
- *va_arg(*ap, apr_array_header_t **) = elt->u.list;
- else if (**fmt == '(' && elt->kind == SVN_RA_SVN_LIST)
+ else if (**fmt == '3' && elt->kind == SVN_RA_SVN_WORD)
{
- (*fmt)++;
- SVN_ERR(vparse_tuple(elt->u.list, pool, fmt, ap));
+ if (strcmp(elt->u.word, "true") == 0)
+ *va_arg(*ap, svn_tristate_t *) = svn_tristate_true;
+ else if (strcmp(elt->u.word, "false") == 0)
+ *va_arg(*ap, svn_tristate_t *) = svn_tristate_false;
+ else
+ break;
}
+ else if (**fmt == 'l' && elt->kind == SVN_RA_SVN_LIST)
+ *va_arg(*ap, apr_array_header_t **) = elt->u.list;
else if (**fmt == ')')
return SVN_NO_ERROR;
else
@@ -1268,6 +1332,9 @@ static svn_error_t *vparse_tuple(const apr_array_header_t *items, apr_pool_t *po
case 'n':
*va_arg(*ap, apr_uint64_t *) = SVN_RA_SVN_UNSPECIFIED_NUMBER;
break;
+ case '3':
+ *va_arg(*ap, svn_tristate_t *) = svn_tristate_unknown;
+ break;
case '(':
nesting_level++;
break;
@@ -1337,21 +1404,21 @@ svn_ra_svn__parse_proplist(const apr_array_header_t *list,
apr_pool_t *pool,
apr_hash_t **props)
{
- char *name;
+ svn_string_t *name;
svn_string_t *value;
svn_ra_svn_item_t *elt;
int i;
- *props = apr_hash_make(pool);
+ *props = svn_hash__make(pool);
for (i = 0; i < list->nelts; i++)
{
elt = &APR_ARRAY_IDX(list, i, svn_ra_svn_item_t);
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",
+ SVN_ERR(svn_ra_svn__parse_tuple(elt->u.list, pool, "ss",
&name, &value));
- svn_hash_sets(*props, name, value);
+ apr_hash_set(*props, name->data, name->len, value);
}
return SVN_NO_ERROR;
@@ -1447,7 +1514,7 @@ svn_ra_svn__read_cmd_response(svn_ra_svn_conn_t *conn,
}
else if (strcmp(status, "failure") == 0)
{
- return svn_ra_svn__handle_failure_status(params, pool);
+ return svn_error_trace(svn_ra_svn__handle_failure_status(params, pool));
}
return svn_error_createf(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
@@ -1456,6 +1523,76 @@ svn_ra_svn__read_cmd_response(svn_ra_svn_conn_t *conn,
}
svn_error_t *
+svn_ra_svn__has_command(svn_boolean_t *has_command,
+ svn_boolean_t *terminated,
+ svn_ra_svn_conn_t *conn,
+ apr_pool_t *pool)
+{
+ svn_error_t *err = svn_ra_svn__has_item(has_command, conn, pool);
+ if (err && err->apr_err == SVN_ERR_RA_SVN_CONNECTION_CLOSED)
+ {
+ *terminated = TRUE;
+ svn_error_clear(err);
+ return SVN_NO_ERROR;
+ }
+
+ *terminated = FALSE;
+ return svn_error_trace(err);
+}
+
+svn_error_t *
+svn_ra_svn__handle_command(svn_boolean_t *terminate,
+ apr_hash_t *cmd_hash,
+ void *baton,
+ svn_ra_svn_conn_t *conn,
+ svn_boolean_t error_on_disconnect,
+ apr_pool_t *pool)
+{
+ const char *cmdname;
+ svn_error_t *err, *write_err;
+ apr_array_header_t *params;
+ const svn_ra_svn_cmd_entry_t *command;
+
+ *terminate = FALSE;
+ err = svn_ra_svn__read_tuple(conn, pool, "wl", &cmdname, &params);
+ if (err)
+ {
+ if (!error_on_disconnect
+ && err->apr_err == SVN_ERR_RA_SVN_CONNECTION_CLOSED)
+ {
+ svn_error_clear(err);
+ *terminate = TRUE;
+ return SVN_NO_ERROR;
+ }
+ return err;
+ }
+
+ command = svn_hash_gets(cmd_hash, cmdname);
+ if (command)
+ {
+ err = (*command->handler)(conn, pool, params, baton);
+ *terminate = command->terminate;
+ }
+ else
+ {
+ err = svn_error_createf(SVN_ERR_RA_SVN_UNKNOWN_CMD, NULL,
+ _("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(
+ conn, pool,
+ svn_ra_svn__locate_real_error_child(err));
+ svn_error_clear(err);
+ return write_err ? write_err : SVN_NO_ERROR;
+ }
+
+ return err;
+}
+
+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,
@@ -1464,10 +1601,7 @@ svn_ra_svn__handle_commands2(svn_ra_svn_conn_t *conn,
{
apr_pool_t *subpool = svn_pool_create(pool);
apr_pool_t *iterpool = svn_pool_create(subpool);
- const char *cmdname;
const svn_ra_svn_cmd_entry_t *command;
- svn_error_t *err, *write_err;
- apr_array_header_t *params;
apr_hash_t *cmd_hash = apr_hash_make(subpool);
for (command = commands; command->cmdname; command++)
@@ -1475,43 +1609,18 @@ svn_ra_svn__handle_commands2(svn_ra_svn_conn_t *conn,
while (1)
{
+ svn_boolean_t terminate;
+ svn_error_t *err;
svn_pool_clear(iterpool);
- err = svn_ra_svn__read_tuple(conn, iterpool, "wl", &cmdname, &params);
- if (err)
- {
- if (!error_on_disconnect
- && err->apr_err == SVN_ERR_RA_SVN_CONNECTION_CLOSED)
- {
- svn_error_clear(err);
- svn_pool_destroy(subpool);
- return SVN_NO_ERROR;
- }
- return err;
- }
- 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 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)
+ err = svn_ra_svn__handle_command(&terminate, cmd_hash, baton, conn,
+ error_on_disconnect, iterpool);
+ if (err)
{
- write_err = svn_ra_svn__write_cmd_failure(
- conn, iterpool,
- svn_ra_svn__locate_real_error_child(err));
- svn_error_clear(err);
- if (write_err)
- return write_err;
+ svn_pool_destroy(subpool);
+ return svn_error_trace(err);
}
- else if (err)
- return err;
-
- if (command && command->terminate)
+ if (terminate)
break;
}
svn_pool_destroy(iterpool);
@@ -1524,9 +1633,9 @@ svn_ra_svn__write_cmd_target_rev(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
svn_revnum_t rev)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( target-rev ( ", 15));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( target-rev ( "));
SVN_ERR(write_tuple_revision(conn, pool, rev));
- SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -1537,12 +1646,12 @@ svn_ra_svn__write_cmd_open_root(svn_ra_svn_conn_t *conn,
svn_revnum_t rev,
const char *token)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( open-root ( ", 14));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( open-root ( "));
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));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -1554,13 +1663,13 @@ svn_ra_svn__write_cmd_delete_entry(svn_ra_svn_conn_t *conn,
svn_revnum_t rev,
const char *token)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( delete-entry ( ", 17));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( delete-entry ( "));
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));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -1574,10 +1683,10 @@ svn_ra_svn__write_cmd_add_dir(svn_ra_svn_conn_t *conn,
const char *copy_path,
svn_revnum_t copy_rev)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( add-dir ( ", 12));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( add-dir ( "));
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));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -1590,9 +1699,9 @@ svn_ra_svn__write_cmd_open_dir(svn_ra_svn_conn_t *conn,
const char *token,
svn_revnum_t rev)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( open-dir ( ", 13));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( open-dir ( "));
SVN_ERR(write_cmd_open_node(conn, pool, path, parent_token, token, rev));
- SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -1604,9 +1713,9 @@ svn_ra_svn__write_cmd_change_dir_prop(svn_ra_svn_conn_t *conn,
const char *name,
const svn_string_t *value)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( change-dir-prop ( ", 20));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( change-dir-prop ( "));
SVN_ERR(write_cmd_change_node_prop(conn, pool, token, name, value));
- SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -1616,9 +1725,9 @@ 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(writebuf_write_literal(conn, pool, "( close-dir ( "));
SVN_ERR(write_tuple_cstring(conn, pool, token));
- SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -1629,9 +1738,9 @@ svn_ra_svn__write_cmd_absent_dir(svn_ra_svn_conn_t *conn,
const char *path,
const char *parent_token)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( absent-dir ( ", 15));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( absent-dir ( "));
SVN_ERR(write_cmd_absent_node(conn, pool, path, parent_token));
- SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -1645,10 +1754,10 @@ svn_ra_svn__write_cmd_add_file(svn_ra_svn_conn_t *conn,
const char *copy_path,
svn_revnum_t copy_rev)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( add-file ( ", 13));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( add-file ( "));
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));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -1661,9 +1770,9 @@ svn_ra_svn__write_cmd_open_file(svn_ra_svn_conn_t *conn,
const char *token,
svn_revnum_t rev)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( open-file ( ", 14));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( open-file ( "));
SVN_ERR(write_cmd_open_node(conn, pool, path, parent_token, token, rev));
- SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -1675,9 +1784,9 @@ svn_ra_svn__write_cmd_change_file_prop(svn_ra_svn_conn_t *conn,
const char *name,
const svn_string_t *value)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( change-file-prop ( ", 21));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( change-file-prop ( "));
SVN_ERR(write_cmd_change_node_prop(conn, pool, token, name, value));
- SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -1688,12 +1797,12 @@ svn_ra_svn__write_cmd_close_file(svn_ra_svn_conn_t *conn,
const char *token,
const char *text_checksum)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( close-file ( ", 15));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( close-file ( "));
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));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -1704,9 +1813,9 @@ svn_ra_svn__write_cmd_absent_file(svn_ra_svn_conn_t *conn,
const char *path,
const char *parent_token)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( absent-file ( ", 16));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( absent-file ( "));
SVN_ERR(write_cmd_absent_node(conn, pool, path, parent_token));
- SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -1717,10 +1826,10 @@ svn_ra_svn__write_cmd_textdelta_chunk(svn_ra_svn_conn_t *conn,
const char *token,
const svn_string_t *chunk)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( textdelta-chunk ( ", 20));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( textdelta-chunk ( "));
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));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -1730,9 +1839,9 @@ 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(writebuf_write_literal(conn, pool, "( textdelta-end ( "));
SVN_ERR(write_tuple_cstring(conn, pool, token));
- SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -1743,12 +1852,12 @@ svn_ra_svn__write_cmd_apply_textdelta(svn_ra_svn_conn_t *conn,
const char *token,
const char *base_checksum)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( apply-textdelta ( ", 20));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( apply-textdelta ( "));
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));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -1757,14 +1866,14 @@ 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);
+ return writebuf_write_literal(conn, pool, "( close-edit ( ) ) ");
}
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);
+ return writebuf_write_literal(conn, pool, "( abort-edit ( ) ) ");
}
svn_error_t *
@@ -1776,7 +1885,7 @@ svn_ra_svn__write_cmd_set_path(svn_ra_svn_conn_t *conn,
const char *lock_token,
svn_depth_t depth)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( set-path ( ", 13));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( set-path ( "));
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));
@@ -1784,7 +1893,7 @@ svn_ra_svn__write_cmd_set_path(svn_ra_svn_conn_t *conn,
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));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -1794,9 +1903,9 @@ 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(writebuf_write_literal(conn, pool, "( delete-path ( "));
SVN_ERR(write_tuple_cstring(conn, pool, path));
- SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -1811,7 +1920,7 @@ svn_ra_svn__write_cmd_link_path(svn_ra_svn_conn_t *conn,
const char *lock_token,
svn_depth_t depth)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( link-path ( ", 14));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( link-path ( "));
SVN_ERR(write_tuple_cstring(conn, pool, path));
SVN_ERR(write_tuple_cstring(conn, pool, url));
SVN_ERR(write_tuple_revision(conn, pool, rev));
@@ -1820,7 +1929,7 @@ svn_ra_svn__write_cmd_link_path(svn_ra_svn_conn_t *conn,
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));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -1829,14 +1938,14 @@ 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);
+ return writebuf_write_literal(conn, pool, "( finish-report ( ) ) ");
}
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);
+ return writebuf_write_literal(conn, pool, "( abort-report ( ) ) ");
}
svn_error_t *
@@ -1844,9 +1953,9 @@ 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(writebuf_write_literal(conn, pool, "( reparent ( "));
SVN_ERR(write_tuple_cstring(conn, pool, url));
- SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -1855,7 +1964,7 @@ 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);
+ return writebuf_write_literal(conn, pool, "( get-latest-rev ( ) ) ");
}
svn_error_t *
@@ -1863,9 +1972,9 @@ 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(writebuf_write_literal(conn, pool, "( get-dated-rev ( "));
SVN_ERR(write_tuple_cstring(conn, pool, svn_time_to_cstring(tm, pool)));
- SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -1879,7 +1988,7 @@ svn_ra_svn__write_cmd_change_rev_prop2(svn_ra_svn_conn_t *conn,
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(writebuf_write_literal(conn, pool, "( change-rev-prop2 ( "));
SVN_ERR(write_tuple_revision(conn, pool, rev));
SVN_ERR(write_tuple_cstring(conn, pool, name));
SVN_ERR(write_tuple_start_list(conn, pool));
@@ -1889,7 +1998,7 @@ svn_ra_svn__write_cmd_change_rev_prop2(svn_ra_svn_conn_t *conn,
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));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -1901,11 +2010,11 @@ svn_ra_svn__write_cmd_change_rev_prop(svn_ra_svn_conn_t *conn,
const char *name,
const svn_string_t *value)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( change-rev-prop ( ", 20));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( change-rev-prop ( "));
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));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -1915,9 +2024,9 @@ 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(writebuf_write_literal(conn, pool, "( rev-proplist ( "));
SVN_ERR(write_tuple_revision(conn, pool, rev));
- SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -1928,10 +2037,10 @@ svn_ra_svn__write_cmd_rev_prop(svn_ra_svn_conn_t *conn,
svn_revnum_t rev,
const char *name)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( rev-prop ( ", 13));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( rev-prop ( "));
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));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -1944,14 +2053,18 @@ svn_ra_svn__write_cmd_get_file(svn_ra_svn_conn_t *conn,
svn_boolean_t props,
svn_boolean_t stream)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( get-file ( ", 13));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( get-file ( "));
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));
+
+ /* Always send the, nominally optional, want-iprops as "false" to
+ workaround a bug in svnserve 1.8.0-1.8.8 that causes the server
+ to see "true" if it is omitted. */
+ SVN_ERR(writebuf_write_literal(conn, pool, " false ) ) "));
return SVN_NO_ERROR;
}
@@ -1966,7 +2079,7 @@ svn_ra_svn__write_cmd_update(svn_ra_svn_conn_t *conn,
svn_boolean_t send_copyfrom_args,
svn_boolean_t ignore_ancestry)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( update ( ", 11));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( update ( "));
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));
@@ -1975,7 +2088,7 @@ svn_ra_svn__write_cmd_update(svn_ra_svn_conn_t *conn,
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));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -1991,7 +2104,7 @@ svn_ra_svn__write_cmd_switch(svn_ra_svn_conn_t *conn,
svn_boolean_t send_copyfrom_args,
svn_boolean_t ignore_ancestry)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( switch ( ", 11));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( switch ( "));
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));
@@ -2001,7 +2114,7 @@ svn_ra_svn__write_cmd_switch(svn_ra_svn_conn_t *conn,
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));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -2014,14 +2127,14 @@ svn_ra_svn__write_cmd_status(svn_ra_svn_conn_t *conn,
svn_revnum_t rev,
svn_depth_t depth)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( status ( ", 11));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( status ( "));
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));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -2037,7 +2150,7 @@ svn_ra_svn__write_cmd_diff(svn_ra_svn_conn_t *conn,
svn_boolean_t text_deltas,
svn_depth_t depth)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( diff ( ", 9));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( diff ( "));
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));
@@ -2047,7 +2160,7 @@ svn_ra_svn__write_cmd_diff(svn_ra_svn_conn_t *conn,
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));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -2058,12 +2171,12 @@ svn_ra_svn__write_cmd_check_path(svn_ra_svn_conn_t *conn,
const char *path,
svn_revnum_t rev)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( check-path ( ", 15));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( check-path ( "));
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(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -2074,12 +2187,12 @@ svn_ra_svn__write_cmd_stat(svn_ra_svn_conn_t *conn,
const char *path,
svn_revnum_t rev)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( stat ( ", 9));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( stat ( "));
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(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -2092,7 +2205,7 @@ svn_ra_svn__write_cmd_get_file_revs(svn_ra_svn_conn_t *conn,
svn_revnum_t end,
svn_boolean_t include_merged_revisions)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( get-file-revs ( ", 18));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( get-file-revs ( "));
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));
@@ -2101,7 +2214,7 @@ svn_ra_svn__write_cmd_get_file_revs(svn_ra_svn_conn_t *conn,
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));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -2114,7 +2227,7 @@ svn_ra_svn__write_cmd_lock(svn_ra_svn_conn_t *conn,
svn_boolean_t steal_lock,
svn_revnum_t revnum)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( lock ( ", 9));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( lock ( "));
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));
@@ -2123,7 +2236,7 @@ svn_ra_svn__write_cmd_lock(svn_ra_svn_conn_t *conn,
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));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -2135,13 +2248,13 @@ svn_ra_svn__write_cmd_unlock(svn_ra_svn_conn_t *conn,
const char *token,
svn_boolean_t break_lock)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( unlock ( ", 11));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( unlock ( "));
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));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -2151,9 +2264,9 @@ 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(writebuf_write_literal(conn, pool, "( get-lock ( "));
SVN_ERR(write_tuple_cstring(conn, pool, path));
- SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -2164,12 +2277,12 @@ svn_ra_svn__write_cmd_get_locks(svn_ra_svn_conn_t *conn,
const char *path,
svn_depth_t depth)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( get-locks ( ", 14));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( get-locks ( "));
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));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -2181,11 +2294,11 @@ svn_ra_svn__write_cmd_replay(svn_ra_svn_conn_t *conn,
svn_revnum_t low_water_mark,
svn_boolean_t send_deltas)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( replay ( ", 11));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( replay ( "));
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));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -2198,12 +2311,12 @@ svn_ra_svn__write_cmd_replay_range(svn_ra_svn_conn_t *conn,
svn_revnum_t low_water_mark,
svn_boolean_t send_deltas)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( replay-range ( ", 17));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( replay-range ( "));
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));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -2215,11 +2328,11 @@ svn_ra_svn__write_cmd_get_deleted_rev(svn_ra_svn_conn_t *conn,
svn_revnum_t peg_revision,
svn_revnum_t end_revision)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( get-deleted-rev ( ", 20));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( get-deleted-rev ( "));
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));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -2230,12 +2343,12 @@ svn_ra_svn__write_cmd_get_iprops(svn_ra_svn_conn_t *conn,
const char *path,
svn_revnum_t revision)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( get-iprops ( ", 15));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( get-iprops ( "));
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));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -2244,7 +2357,7 @@ 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);
+ return writebuf_write_literal(conn, pool, "( finish-replay ( ) ) ");
}
svn_error_t *svn_ra_svn__write_cmd_response(svn_ra_svn_conn_t *conn,
@@ -2254,7 +2367,7 @@ svn_error_t *svn_ra_svn__write_cmd_response(svn_ra_svn_conn_t *conn,
va_list ap;
svn_error_t *err;
- SVN_ERR(writebuf_write_short_string(conn, pool, "( success ", 10));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( success "));
va_start(ap, fmt);
err = vwrite_tuple(conn, pool, fmt, &ap);
va_end(ap);
@@ -2262,10 +2375,11 @@ svn_error_t *svn_ra_svn__write_cmd_response(svn_ra_svn_conn_t *conn,
}
svn_error_t *svn_ra_svn__write_cmd_failure(svn_ra_svn_conn_t *conn,
- apr_pool_t *pool, svn_error_t *err)
+ apr_pool_t *pool,
+ const svn_error_t *err)
{
char buffer[128];
- SVN_ERR(writebuf_write_short_string(conn, pool, "( failure ( ", 12));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( failure ( "));
for (; err; err = err->child)
{
const char *msg;
@@ -2285,5 +2399,217 @@ svn_error_t *svn_ra_svn__write_cmd_failure(svn_ra_svn_conn_t *conn,
err->file ? err->file : "",
(apr_uint64_t) err->line));
}
- return writebuf_write_short_string(conn, pool, ") ) ", 4);
+ return writebuf_write_literal(conn, pool, ") ) ");
+}
+
+svn_error_t *
+svn_ra_svn__write_data_log_changed_path(svn_ra_svn_conn_t *conn,
+ apr_pool_t *pool,
+ const char *path,
+ char action,
+ const char *copyfrom_path,
+ svn_revnum_t copyfrom_rev,
+ svn_node_kind_t node_kind,
+ svn_boolean_t text_modified,
+ svn_boolean_t props_modified)
+{
+ SVN_ERR(write_tuple_start_list(conn, pool));
+
+ SVN_ERR(write_tuple_cstring(conn, pool, path));
+ SVN_ERR(writebuf_writechar(conn, pool, action));
+ SVN_ERR(writebuf_writechar(conn, pool, ' '));
+ SVN_ERR(write_tuple_start_list(conn, pool));
+ SVN_ERR(write_tuple_cstring_opt(conn, pool, copyfrom_path));
+ SVN_ERR(write_tuple_revision_opt(conn, pool, copyfrom_rev));
+ SVN_ERR(write_tuple_end_list(conn, pool));
+ SVN_ERR(write_tuple_start_list(conn, pool));
+ SVN_ERR(write_tuple_cstring(conn, pool, svn_node_kind_to_word(node_kind)));
+ SVN_ERR(write_tuple_boolean(conn, pool, text_modified));
+ SVN_ERR(write_tuple_boolean(conn, pool, props_modified));
+
+ return writebuf_write_literal(conn, pool, ") ) ");
+}
+
+svn_error_t *
+svn_ra_svn__write_data_log_entry(svn_ra_svn_conn_t *conn,
+ apr_pool_t *pool,
+ svn_revnum_t revision,
+ const svn_string_t *author,
+ const svn_string_t *date,
+ const svn_string_t *message,
+ svn_boolean_t has_children,
+ svn_boolean_t invalid_revnum,
+ unsigned revprop_count)
+{
+ SVN_ERR(write_tuple_revision(conn, pool, revision));
+ SVN_ERR(write_tuple_start_list(conn, pool));
+ SVN_ERR(write_tuple_string_opt(conn, pool, author));
+ SVN_ERR(write_tuple_end_list(conn, pool));
+ SVN_ERR(write_tuple_start_list(conn, pool));
+ SVN_ERR(write_tuple_string_opt(conn, pool, date));
+ SVN_ERR(write_tuple_end_list(conn, pool));
+ SVN_ERR(write_tuple_start_list(conn, pool));
+ SVN_ERR(write_tuple_string_opt(conn, pool, message));
+ SVN_ERR(write_tuple_end_list(conn, pool));
+ SVN_ERR(write_tuple_boolean(conn, pool, has_children));
+ SVN_ERR(write_tuple_boolean(conn, pool, invalid_revnum));
+ SVN_ERR(svn_ra_svn__write_number(conn, pool, revprop_count));
+
+ return SVN_NO_ERROR;
+}
+
+/* If condition COND is not met, return a "malformed network data" error.
+ */
+#define CHECK_PROTOCOL_COND(cond)\
+ if (!(cond)) \
+ return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL, \
+ _("Malformed network data"));
+
+/* In *RESULT, return the SVN-style string at index IDX in tuple ITEMS.
+ */
+static svn_error_t *
+svn_ra_svn__read_string(const apr_array_header_t *items,
+ int idx,
+ svn_string_t **result)
+{
+ svn_ra_svn_item_t *elt = &APR_ARRAY_IDX(items, idx, svn_ra_svn_item_t);
+ CHECK_PROTOCOL_COND(elt->kind == SVN_RA_SVN_STRING);
+ *result = elt->u.string;
+
+ return SVN_NO_ERROR;
+}
+
+/* In *RESULT, return the C-style string at index IDX in tuple ITEMS.
+ */
+static svn_error_t *
+svn_ra_svn__read_cstring(const apr_array_header_t *items,
+ int idx,
+ const char **result)
+{
+ svn_ra_svn_item_t *elt = &APR_ARRAY_IDX(items, idx, svn_ra_svn_item_t);
+ CHECK_PROTOCOL_COND(elt->kind == SVN_RA_SVN_STRING);
+ *result = elt->u.string->data;
+
+ return SVN_NO_ERROR;
+}
+
+/* In *RESULT, return the word at index IDX in tuple ITEMS.
+ */
+static svn_error_t *
+svn_ra_svn__read_word(const apr_array_header_t *items,
+ int idx,
+ const char **result)
+{
+ svn_ra_svn_item_t *elt = &APR_ARRAY_IDX(items, idx, svn_ra_svn_item_t);
+ CHECK_PROTOCOL_COND(elt->kind == SVN_RA_SVN_WORD);
+ *result = elt->u.word;
+
+ return SVN_NO_ERROR;
+}
+
+/* In *RESULT, return the revision at index IDX in tuple ITEMS.
+ */
+static svn_error_t *
+svn_ra_svn__read_revision(const apr_array_header_t *items,
+ int idx,
+ svn_revnum_t *result)
+{
+ svn_ra_svn_item_t *elt = &APR_ARRAY_IDX(items, idx, svn_ra_svn_item_t);
+ CHECK_PROTOCOL_COND(elt->kind == SVN_RA_SVN_NUMBER);
+ *result = (svn_revnum_t)elt->u.number;
+
+ return SVN_NO_ERROR;
+}
+
+/* In *RESULT, return the boolean at index IDX in tuple ITEMS.
+ */
+static svn_error_t *
+svn_ra_svn__read_boolean(const apr_array_header_t *items,
+ int idx,
+ apr_uint64_t *result)
+{
+ svn_ra_svn_item_t *elt = &APR_ARRAY_IDX(items, idx, svn_ra_svn_item_t);
+ CHECK_PROTOCOL_COND(elt->kind == SVN_RA_SVN_WORD);
+ if (elt->u.word[0] == 't' && strcmp(elt->u.word, "true") == 0)
+ *result = TRUE;
+ else if (strcmp(elt->u.word, "false") == 0)
+ *result = FALSE;
+ else
+ CHECK_PROTOCOL_COND(FALSE);
+
+ return SVN_NO_ERROR;
+}
+
+/* In *RESULT, return the tuple at index IDX in tuple ITEMS.
+ */
+static svn_error_t *
+svn_ra_svn__read_list(const apr_array_header_t *items,
+ int idx,
+ const apr_array_header_t **result)
+{
+ svn_ra_svn_item_t *elt = &APR_ARRAY_IDX(items, idx, svn_ra_svn_item_t);
+ CHECK_PROTOCOL_COND(elt->kind == SVN_RA_SVN_LIST);
+
+ *result = elt->u.list;
+ return SVN_NO_ERROR;
+}
+
+/* Verify the tuple ITEMS contains at least MIN and at most MAX elements.
+ */
+static svn_error_t *
+svn_ra_svn__read_check_array_size(const apr_array_header_t *items,
+ int min,
+ int max)
+{
+ CHECK_PROTOCOL_COND(items->nelts >= min && items->nelts <= max);
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_ra_svn__read_data_log_changed_entry(const apr_array_header_t *items,
+ svn_string_t **cpath,
+ const char **action,
+ const char **copy_path,
+ svn_revnum_t *copy_rev,
+ const char **kind_str,
+ apr_uint64_t *text_mods,
+ apr_uint64_t *prop_mods)
+{
+ const apr_array_header_t *sub_items;
+
+ /* initialize optional values */
+ *copy_path = NULL;
+ *copy_rev = SVN_INVALID_REVNUM;
+ *kind_str = NULL;
+ *text_mods = SVN_RA_SVN_UNSPECIFIED_NUMBER;
+ *prop_mods = SVN_RA_SVN_UNSPECIFIED_NUMBER;
+
+ /* top-level elements (mandatory) */
+ SVN_ERR(svn_ra_svn__read_check_array_size(items, 3, INT_MAX));
+ SVN_ERR(svn_ra_svn__read_string(items, 0, cpath));
+ SVN_ERR(svn_ra_svn__read_word(items, 1, action));
+
+ /* first sub-structure (mandatory) */
+ SVN_ERR(svn_ra_svn__read_list(items, 2, &sub_items));
+ if (sub_items->nelts)
+ {
+ SVN_ERR(svn_ra_svn__read_check_array_size(sub_items, 2, 2));
+ SVN_ERR(svn_ra_svn__read_cstring(sub_items, 0, copy_path));
+ SVN_ERR(svn_ra_svn__read_revision(sub_items, 1, copy_rev));
+ }
+
+ /* second sub-structure (optional) */
+ if (items->nelts >= 4)
+ {
+ SVN_ERR(svn_ra_svn__read_list(items, 3, &sub_items));
+ switch (MIN(3, sub_items->nelts))
+ {
+ case 3 : SVN_ERR(svn_ra_svn__read_boolean(sub_items, 2, prop_mods));
+ case 2 : SVN_ERR(svn_ra_svn__read_boolean(sub_items, 1, text_mods));
+ case 1 : SVN_ERR(svn_ra_svn__read_cstring(sub_items, 0, kind_str));
+ default: break;
+ }
+ }
+
+ return SVN_NO_ERROR;
}