2 * marshal.c : Marshalling routines for Subversion protocol
4 * ====================================================================
5 * Licensed to the Apache Software Foundation (ASF) under one
6 * or more contributor license agreements. See the NOTICE file
7 * distributed with this work for additional information
8 * regarding copyright ownership. The ASF licenses this file
9 * to you under the Apache License, Version 2.0 (the
10 * "License"); you may not use this file except in compliance
11 * with the License. You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing,
16 * software distributed under the License is distributed on an
17 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18 * KIND, either express or implied. See the License for the
19 * specific language governing permissions and limitations
21 * ====================================================================
29 #define APR_WANT_STRFUNC
31 #include <apr_general.h>
33 #include <apr_strings.h>
36 #include "svn_types.h"
37 #include "svn_string.h"
38 #include "svn_error.h"
39 #include "svn_pools.h"
40 #include "svn_ra_svn.h"
41 #include "svn_private_config.h"
42 #include "svn_ctype.h"
43 #include "svn_sorts.h"
48 #include "private/svn_string_private.h"
49 #include "private/svn_dep_compat.h"
50 #include "private/svn_error_private.h"
51 #include "private/svn_subr_private.h"
53 #define svn_iswhitespace(c) ((c) == ' ' || (c) == '\n')
55 /* If we receive data that *claims* to be followed by a very long string,
56 * we should not trust that claim right away. But everything up to 1 MB
57 * should be too small to be instrumental for a DOS attack. */
59 #define SUSPICIOUSLY_HUGE_STRING_SIZE_THRESHOLD (0x100000)
61 /* We don't use "words" longer than this in our protocol. The longest word
62 * we are currently using is only about 16 chars long but we leave room for
63 * longer future capability and command names.
65 #define MAX_WORD_LENGTH 31
67 /* The generic parsers will use the following value to limit the recursion
68 * depth to some reasonable value. The current protocol implementation
69 * actually uses only maximum item nesting level of around 5. So, there is
70 * plenty of headroom here.
72 #define ITEM_NESTING_LIMIT 64
74 /* Return the APR socket timeout to be used for the connection depending
75 * on whether there is a blockage handler or zero copy has been activated. */
76 static apr_interval_time_t
77 get_timeout(svn_ra_svn_conn_t *conn)
79 return conn->block_handler ? 0 : -1;
82 /* --- CONNECTION INITIALIZATION --- */
84 svn_ra_svn_conn_t *svn_ra_svn_create_conn4(apr_socket_t *sock,
85 svn_stream_t *in_stream,
86 svn_stream_t *out_stream,
87 int compression_level,
88 apr_size_t zero_copy_limit,
89 apr_size_t error_check_interval,
90 apr_pool_t *result_pool)
92 svn_ra_svn_conn_t *conn;
93 void *mem = apr_palloc(result_pool, sizeof(*conn) + SVN_RA_SVN__PAGE_SIZE);
94 conn = (void*)APR_ALIGN((apr_uintptr_t)mem, SVN_RA_SVN__PAGE_SIZE);
96 assert((sock && !in_stream && !out_stream)
97 || (!sock && in_stream && out_stream));
100 conn->encrypted = FALSE;
102 conn->session = NULL;
103 conn->read_ptr = conn->read_buf;
104 conn->read_end = conn->read_buf;
106 conn->written_since_error_check = 0;
107 conn->error_check_interval = error_check_interval;
108 conn->may_check_for_error = error_check_interval == 0;
109 conn->block_handler = NULL;
110 conn->block_baton = NULL;
111 conn->capabilities = apr_hash_make(result_pool);
112 conn->compression_level = compression_level;
113 conn->zero_copy_limit = zero_copy_limit;
114 conn->pool = result_pool;
119 conn->stream = svn_ra_svn__stream_from_sock(sock, result_pool);
120 if (!(apr_socket_addr_get(&sa, APR_REMOTE, sock) == APR_SUCCESS
121 && apr_sockaddr_ip_get(&conn->remote_ip, sa) == APR_SUCCESS))
122 conn->remote_ip = NULL;
123 svn_ra_svn__stream_timeout(conn->stream, get_timeout(conn));
127 conn->stream = svn_ra_svn__stream_from_streams(in_stream, out_stream,
129 conn->remote_ip = NULL;
135 svn_error_t *svn_ra_svn_set_capabilities(svn_ra_svn_conn_t *conn,
136 const apr_array_header_t *list)
139 svn_ra_svn_item_t *item;
142 for (i = 0; i < list->nelts; i++)
144 item = &APR_ARRAY_IDX(list, i, svn_ra_svn_item_t);
145 if (item->kind != SVN_RA_SVN_WORD)
146 return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
147 _("Capability entry is not a word"));
148 word = apr_pstrdup(conn->pool, item->u.word);
149 svn_hash_sets(conn->capabilities, word, word);
155 svn_ra_svn__get_pool(svn_ra_svn_conn_t *conn)
161 svn_ra_svn__set_shim_callbacks(svn_ra_svn_conn_t *conn,
162 svn_delta_shim_callbacks_t *shim_callbacks)
164 conn->shim_callbacks = shim_callbacks;
168 svn_boolean_t svn_ra_svn_has_capability(svn_ra_svn_conn_t *conn,
169 const char *capability)
171 return (svn_hash_gets(conn->capabilities, capability) != NULL);
175 svn_ra_svn_compression_level(svn_ra_svn_conn_t *conn)
177 return conn->compression_level;
181 svn_ra_svn_zero_copy_limit(svn_ra_svn_conn_t *conn)
183 return conn->zero_copy_limit;
186 const char *svn_ra_svn_conn_remote_host(svn_ra_svn_conn_t *conn)
188 return conn->remote_ip;
192 svn_ra_svn__set_block_handler(svn_ra_svn_conn_t *conn,
193 ra_svn_block_handler_t handler,
196 conn->block_handler = handler;
197 conn->block_baton = baton;
198 svn_ra_svn__stream_timeout(conn->stream, get_timeout(conn));
201 svn_error_t *svn_ra_svn__data_available(svn_ra_svn_conn_t *conn,
202 svn_boolean_t *data_available)
204 return svn_ra_svn__stream_data_available(conn->stream, data_available);
207 /* --- WRITE BUFFER MANAGEMENT --- */
209 /* Write data to socket or output file as appropriate. */
210 static svn_error_t *writebuf_output(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
211 const char *data, apr_size_t len)
213 const char *end = data + len;
215 apr_pool_t *subpool = NULL;
216 svn_ra_svn__session_baton_t *session = conn->session;
222 if (session && session->callbacks && session->callbacks->cancel_func)
223 SVN_ERR((session->callbacks->cancel_func)(session->callbacks_baton));
225 SVN_ERR(svn_ra_svn__stream_write(conn->stream, data, &count));
229 subpool = svn_pool_create(pool);
231 svn_pool_clear(subpool);
232 SVN_ERR(conn->block_handler(conn, subpool, conn->block_baton));
238 const svn_ra_callbacks2_t *cb = session->callbacks;
239 session->bytes_written += count;
241 if (cb && cb->progress_func)
242 (cb->progress_func)(session->bytes_written + session->bytes_read,
243 -1, cb->progress_baton, subpool);
247 conn->written_since_error_check += len;
248 conn->may_check_for_error
249 = conn->written_since_error_check >= conn->error_check_interval;
252 svn_pool_destroy(subpool);
256 /* Write data from the write buffer out to the socket. */
257 static svn_error_t *writebuf_flush(svn_ra_svn_conn_t *conn, apr_pool_t *pool)
259 apr_size_t write_pos = conn->write_pos;
261 /* Clear conn->write_pos first in case the block handler does a read. */
263 SVN_ERR(writebuf_output(conn, pool, conn->write_buf, write_pos));
267 static svn_error_t *writebuf_write(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
268 const char *data, apr_size_t len)
270 /* data >= 8k is sent immediately */
271 if (len >= sizeof(conn->write_buf) / 2)
273 if (conn->write_pos > 0)
274 SVN_ERR(writebuf_flush(conn, pool));
276 return writebuf_output(conn, pool, data, len);
279 /* ensure room for the data to add */
280 if (conn->write_pos + len > sizeof(conn->write_buf))
281 SVN_ERR(writebuf_flush(conn, pool));
283 /* buffer the new data block as well */
284 memcpy(conn->write_buf + conn->write_pos, data, len);
285 conn->write_pos += len;
290 /* Write STRING_LITERAL, which is a string literal argument.
292 Note: The purpose of the empty string "" in the macro definition is to
293 assert that STRING_LITERAL is in fact a string literal. Otherwise, the
294 string concatenation attempt should produce a compile-time error. */
295 #define writebuf_write_literal(conn, pool, string_literal) \
296 writebuf_write(conn, pool, string_literal, sizeof(string_literal "") - 1)
298 static APR_INLINE svn_error_t *
299 writebuf_writechar(svn_ra_svn_conn_t *conn, apr_pool_t *pool, char data)
301 if (conn->write_pos < sizeof(conn->write_buf))
303 conn->write_buf[conn->write_pos] = data;
311 return writebuf_write(conn, pool, &temp, 1);
315 /* --- READ BUFFER MANAGEMENT --- */
317 /* Read bytes into DATA until either the read buffer is empty or
319 static char *readbuf_drain(svn_ra_svn_conn_t *conn, char *data, char *end)
321 apr_ssize_t buflen, copylen;
323 buflen = conn->read_end - conn->read_ptr;
324 copylen = (buflen < end - data) ? buflen : end - data;
325 memcpy(data, conn->read_ptr, copylen);
326 conn->read_ptr += copylen;
327 return data + copylen;
330 /* Read data from socket or input file as appropriate. */
331 static svn_error_t *readbuf_input(svn_ra_svn_conn_t *conn, char *data,
332 apr_size_t *len, apr_pool_t *pool)
334 svn_ra_svn__session_baton_t *session = conn->session;
336 if (session && session->callbacks && session->callbacks->cancel_func)
337 SVN_ERR((session->callbacks->cancel_func)(session->callbacks_baton));
339 SVN_ERR(svn_ra_svn__stream_read(conn->stream, data, len));
341 return svn_error_create(SVN_ERR_RA_SVN_CONNECTION_CLOSED, NULL, NULL);
345 const svn_ra_callbacks2_t *cb = session->callbacks;
346 session->bytes_read += *len;
348 if (cb && cb->progress_func)
349 (cb->progress_func)(session->bytes_read + session->bytes_written,
350 -1, cb->progress_baton, pool);
356 /* Treat the next LEN input bytes from CONN as "read" */
357 static svn_error_t *readbuf_skip(svn_ra_svn_conn_t *conn, apr_uint64_t len)
361 apr_size_t buflen = conn->read_end - conn->read_ptr;
362 apr_size_t copylen = (buflen < len) ? buflen : (apr_size_t)len;
363 conn->read_ptr += copylen;
368 buflen = sizeof(conn->read_buf);
369 SVN_ERR(svn_ra_svn__stream_read(conn->stream, conn->read_buf, &buflen));
371 return svn_error_create(SVN_ERR_RA_SVN_CONNECTION_CLOSED, NULL, NULL);
373 conn->read_end = conn->read_buf + buflen;
374 conn->read_ptr = conn->read_buf;
381 /* Read data from the socket into the read buffer, which must be empty. */
382 static svn_error_t *readbuf_fill(svn_ra_svn_conn_t *conn, apr_pool_t *pool)
386 SVN_ERR_ASSERT(conn->read_ptr == conn->read_end);
388 SVN_ERR(writebuf_flush(conn, pool));
390 len = sizeof(conn->read_buf);
391 SVN_ERR(readbuf_input(conn, conn->read_buf, &len, pool));
392 conn->read_ptr = conn->read_buf;
393 conn->read_end = conn->read_buf + len;
397 /* This is a hot function calling a cold function. GCC and others tend to
398 * inline the cold sub-function instead of this hot one. Therefore, be
399 * very insistent on lining this one. It is not a correctness issue, though.
401 static SVN__FORCE_INLINE svn_error_t *
402 readbuf_getchar(svn_ra_svn_conn_t *conn, apr_pool_t *pool, char *result)
404 if (conn->read_ptr == conn->read_end)
405 SVN_ERR(readbuf_fill(conn, pool));
406 *result = *conn->read_ptr++;
410 static svn_error_t *readbuf_getchar_skip_whitespace(svn_ra_svn_conn_t *conn,
415 SVN_ERR(readbuf_getchar(conn, pool, result));
416 while (svn_iswhitespace(*result));
420 /* Read the next LEN bytes from CONN and copy them to *DATA. */
421 static svn_error_t *readbuf_read(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
422 char *data, apr_size_t len)
424 char *end = data + len;
427 /* Copy in an appropriate amount of data from the buffer. */
428 data = readbuf_drain(conn, data, end);
430 /* Read large chunks directly into buffer. */
431 while (end - data > (apr_ssize_t)sizeof(conn->read_buf))
433 SVN_ERR(writebuf_flush(conn, pool));
435 SVN_ERR(readbuf_input(conn, data, &count, pool));
441 /* The remaining amount to read is small; fill the buffer and
443 SVN_ERR(readbuf_fill(conn, pool));
444 data = readbuf_drain(conn, data, end);
450 static svn_error_t *readbuf_skip_leading_garbage(svn_ra_svn_conn_t *conn,
453 char buf[256]; /* Must be smaller than sizeof(conn->read_buf) - 1. */
456 svn_boolean_t lparen = FALSE;
458 SVN_ERR_ASSERT(conn->read_ptr == conn->read_end);
461 /* Read some data directly from the connection input source. */
463 SVN_ERR(readbuf_input(conn, buf, &len, pool));
466 /* Scan the data for '(' WS with a very simple state machine. */
467 for (p = buf; p < end; p++)
469 if (lparen && svn_iswhitespace(*p))
472 lparen = (*p == '(');
478 /* p now points to the whitespace just after the left paren. Fake
479 * up the left paren and then copy what we have into the read
481 conn->read_buf[0] = '(';
482 memcpy(conn->read_buf + 1, p, end - p);
483 conn->read_ptr = conn->read_buf;
484 conn->read_end = conn->read_buf + 1 + (end - p);
488 /* --- WRITING DATA ITEMS --- */
490 static svn_error_t *write_number(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
491 apr_uint64_t number, char follow)
495 /* SVN_INT64_BUFFER_SIZE includes space for a terminating NUL that
496 * svn__ui64toa will always append. */
497 if (conn->write_pos + SVN_INT64_BUFFER_SIZE >= sizeof(conn->write_buf))
498 SVN_ERR(writebuf_flush(conn, pool));
500 written = svn__ui64toa(conn->write_buf + conn->write_pos, number);
501 conn->write_buf[conn->write_pos + written] = follow;
502 conn->write_pos += written + 1;
508 svn_ra_svn__write_number(svn_ra_svn_conn_t *conn,
512 return write_number(conn, pool, number, ' ');
516 svn_ra_svn__write_ncstring(svn_ra_svn_conn_t *conn,
523 SVN_ERR(writebuf_writechar(conn, pool, (char)(len + '0')));
524 SVN_ERR(writebuf_writechar(conn, pool, ':'));
527 SVN_ERR(write_number(conn, pool, len, ':'));
529 SVN_ERR(writebuf_write(conn, pool, s, len));
530 SVN_ERR(writebuf_writechar(conn, pool, ' '));
536 svn_ra_svn__write_string(svn_ra_svn_conn_t *conn,
538 const svn_string_t *str)
540 SVN_ERR(svn_ra_svn__write_ncstring(conn, pool, str->data, str->len));
545 svn_ra_svn__write_cstring(svn_ra_svn_conn_t *conn,
549 SVN_ERR(svn_ra_svn__write_ncstring(conn, pool, s, strlen(s)));
554 svn_ra_svn__write_word(svn_ra_svn_conn_t *conn,
558 SVN_ERR(writebuf_write(conn, pool, word, strlen(word)));
559 SVN_ERR(writebuf_writechar(conn, pool, ' '));
565 svn_ra_svn__write_boolean(svn_ra_svn_conn_t *conn,
570 SVN_ERR(writebuf_write_literal(conn, pool, "true "));
572 SVN_ERR(writebuf_write_literal(conn, pool, "false "));
578 svn_ra_svn__write_proplist(svn_ra_svn_conn_t *conn,
582 apr_hash_index_t *hi;
583 const char *propname;
584 svn_string_t *propval;
587 /* One might use an iterpool here but that would only be used when the
588 send buffer gets flushed and only by the CONN's progress callback.
589 That should happen at most once for typical prop lists and even then
590 use only a few bytes at best.
593 for (hi = apr_hash_first(pool, props); hi; hi = apr_hash_next(hi))
595 apr_hash_this(hi, (const void **)&propname,
599 SVN_ERR(svn_ra_svn__start_list(conn, pool));
600 SVN_ERR(svn_ra_svn__write_ncstring(conn, pool, propname, len));
601 SVN_ERR(svn_ra_svn__write_string(conn, pool, propval));
602 SVN_ERR(svn_ra_svn__end_list(conn, pool));
609 svn_ra_svn__start_list(svn_ra_svn_conn_t *conn,
612 if (conn->write_pos + 2 <= sizeof(conn->write_buf))
614 conn->write_buf[conn->write_pos] = '(';
615 conn->write_buf[conn->write_pos+1] = ' ';
616 conn->write_pos += 2;
620 return writebuf_write(conn, pool, "( ", 2);
624 svn_ra_svn__end_list(svn_ra_svn_conn_t *conn,
627 if (conn->write_pos + 2 <= sizeof(conn->write_buf))
629 conn->write_buf[conn->write_pos] = ')';
630 conn->write_buf[conn->write_pos+1] = ' ';
631 conn->write_pos += 2;
635 return writebuf_write(conn, pool, ") ", 2);
639 svn_ra_svn__flush(svn_ra_svn_conn_t *conn,
642 SVN_ERR(writebuf_flush(conn, pool));
643 conn->may_check_for_error = TRUE;
648 /* --- WRITING TUPLES --- */
651 vwrite_tuple_cstring(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
653 const char *cstr = va_arg(*ap, const char *);
654 SVN_ERR_ASSERT(cstr);
655 return svn_ra_svn__write_cstring(conn, pool, cstr);
659 vwrite_tuple_cstring_opt(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
661 const char *cstr = va_arg(*ap, const char *);
662 return cstr ? svn_ra_svn__write_cstring(conn, pool, cstr) : SVN_NO_ERROR;
666 vwrite_tuple_string(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
668 const svn_string_t *str = va_arg(*ap, const svn_string_t *);
670 return svn_ra_svn__write_string(conn, pool, str);
674 vwrite_tuple_string_opt(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
676 const svn_string_t *str = va_arg(*ap, const svn_string_t *);
677 return str ? svn_ra_svn__write_string(conn, pool, str) : SVN_NO_ERROR;
681 vwrite_tuple_word(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
683 const char *cstr = va_arg(*ap, const char *);
684 SVN_ERR_ASSERT(cstr);
685 return svn_ra_svn__write_word(conn, pool, cstr);
689 vwrite_tuple_word_opt(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
691 const char *cstr = va_arg(*ap, const char *);
692 return cstr ? svn_ra_svn__write_word(conn, pool, cstr) : SVN_NO_ERROR;
696 vwrite_tuple_revision(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
698 svn_revnum_t rev = va_arg(*ap, svn_revnum_t);
699 SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(rev));
700 return svn_ra_svn__write_number(conn, pool, rev);
704 vwrite_tuple_revision_opt(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
706 svn_revnum_t rev = va_arg(*ap, svn_revnum_t);
707 return SVN_IS_VALID_REVNUM(rev)
708 ? svn_ra_svn__write_number(conn, pool, rev)
713 vwrite_tuple_number(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
715 return svn_ra_svn__write_number(conn, pool, va_arg(*ap, apr_uint64_t));
719 vwrite_tuple_boolean(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
721 return svn_ra_svn__write_boolean(conn, pool, va_arg(*ap, svn_boolean_t));
725 write_tuple_cstring(svn_ra_svn_conn_t *conn,
729 SVN_ERR_ASSERT(cstr);
730 return svn_ra_svn__write_cstring(conn, pool, cstr);
734 write_tuple_cstring_opt(svn_ra_svn_conn_t *conn,
738 return cstr ? svn_ra_svn__write_cstring(conn, pool, cstr) : SVN_NO_ERROR;
742 write_tuple_string(svn_ra_svn_conn_t *conn,
744 const svn_string_t *str)
747 return svn_ra_svn__write_string(conn, pool, str);
751 write_tuple_string_opt(svn_ra_svn_conn_t *conn,
753 const svn_string_t *str)
755 return str ? svn_ra_svn__write_string(conn, pool, str) : SVN_NO_ERROR;
759 write_tuple_start_list(svn_ra_svn_conn_t *conn,
762 return svn_ra_svn__start_list(conn, pool);
766 write_tuple_end_list(svn_ra_svn_conn_t *conn,
769 return svn_ra_svn__end_list(conn, pool);
773 write_tuple_revision(svn_ra_svn_conn_t *conn,
777 SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(rev));
778 return svn_ra_svn__write_number(conn, pool, rev);
782 write_tuple_revision_opt(svn_ra_svn_conn_t *conn,
786 return SVN_IS_VALID_REVNUM(rev)
787 ? svn_ra_svn__write_number(conn, pool, rev)
792 write_tuple_boolean(svn_ra_svn_conn_t *conn,
796 return svn_ra_svn__write_boolean(conn, pool, value);
800 write_tuple_depth(svn_ra_svn_conn_t *conn,
804 return svn_ra_svn__write_word(conn, pool, svn_depth_to_word(depth));
809 write_cmd_add_node(svn_ra_svn_conn_t *conn,
812 const char *parent_token,
814 const char *copy_path,
815 svn_revnum_t copy_rev)
817 SVN_ERR(write_tuple_cstring(conn, pool, path));
818 SVN_ERR(write_tuple_cstring(conn, pool, parent_token));
819 SVN_ERR(write_tuple_cstring(conn, pool, token));
820 SVN_ERR(write_tuple_start_list(conn, pool));
821 SVN_ERR(write_tuple_cstring_opt(conn, pool, copy_path));
822 SVN_ERR(write_tuple_revision_opt(conn, pool, copy_rev));
823 SVN_ERR(write_tuple_end_list(conn, pool));
829 write_cmd_open_node(svn_ra_svn_conn_t *conn,
832 const char *parent_token,
836 SVN_ERR(write_tuple_cstring(conn, pool, path));
837 SVN_ERR(write_tuple_cstring(conn, pool, parent_token));
838 SVN_ERR(write_tuple_cstring(conn, pool, token));
839 SVN_ERR(write_tuple_start_list(conn, pool));
840 SVN_ERR(write_tuple_revision_opt(conn, pool, rev));
841 SVN_ERR(write_tuple_end_list(conn, pool));
847 write_cmd_change_node_prop(svn_ra_svn_conn_t *conn,
851 const svn_string_t *value)
853 SVN_ERR(write_tuple_cstring(conn, pool, token));
854 SVN_ERR(write_tuple_cstring(conn, pool, name));
855 SVN_ERR(write_tuple_start_list(conn, pool));
856 SVN_ERR(write_tuple_string_opt(conn, pool, value));
857 SVN_ERR(write_tuple_end_list(conn, pool));
863 write_cmd_absent_node(svn_ra_svn_conn_t *conn,
868 SVN_ERR(write_tuple_cstring(conn, pool, path));
869 SVN_ERR(write_tuple_cstring(conn, pool, token));
877 static svn_error_t *vwrite_tuple(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
878 const char *fmt, va_list *ap)
880 svn_boolean_t opt = FALSE;
885 SVN_ERR(svn_ra_svn__start_list(conn, pool));
889 SVN_ERR(opt ? vwrite_tuple_cstring_opt(conn, pool, ap)
890 : vwrite_tuple_cstring(conn, pool, ap));
891 else if (*fmt == 's')
892 SVN_ERR(opt ? vwrite_tuple_string_opt(conn, pool, ap)
893 : vwrite_tuple_string(conn, pool, ap));
894 else if (*fmt == '(' && !opt)
895 SVN_ERR(write_tuple_start_list(conn, pool));
896 else if (*fmt == ')')
898 SVN_ERR(write_tuple_end_list(conn, pool));
901 else if (*fmt == '?')
903 else if (*fmt == 'w')
904 SVN_ERR(opt ? vwrite_tuple_word_opt(conn, pool, ap)
905 : vwrite_tuple_word(conn, pool, ap));
906 else if (*fmt == 'r')
907 SVN_ERR(opt ? vwrite_tuple_revision_opt(conn, pool, ap)
908 : vwrite_tuple_revision(conn, pool, ap));
909 else if (*fmt == 'n' && !opt)
910 SVN_ERR(vwrite_tuple_number(conn, pool, ap));
911 else if (*fmt == 'b' && !opt)
912 SVN_ERR(vwrite_tuple_boolean(conn, pool, ap));
913 else if (*fmt == '!' && !*(fmt + 1))
916 SVN_ERR_MALFUNCTION();
918 SVN_ERR(svn_ra_svn__end_list(conn, pool));
923 svn_ra_svn__write_tuple(svn_ra_svn_conn_t *conn,
925 const char *fmt, ...)
931 err = vwrite_tuple(conn, pool, fmt, &ap);
936 /* --- READING DATA ITEMS --- */
938 /* Read LEN bytes from CONN into already-allocated structure ITEM.
939 * Afterwards, *ITEM is of type 'SVN_RA_SVN_STRING', and its string
940 * data is allocated in POOL. */
941 static svn_error_t *read_string(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
942 svn_ra_svn_item_t *item, apr_uint64_t len64)
944 apr_size_t len = (apr_size_t)len64;
945 apr_size_t readbuf_len;
949 /* We can't store strings longer than the maximum size of apr_size_t,
950 * so check for wrapping */
951 if (len64 > APR_SIZE_MAX)
952 return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
953 _("String length larger than maximum"));
955 buflen = conn->read_end - conn->read_ptr;
956 /* Shorter strings can be copied directly from the read buffer. */
959 item->kind = SVN_RA_SVN_STRING;
960 item->u.string = svn_string_ncreate(conn->read_ptr, len, pool);
961 conn->read_ptr += len;
965 /* Read the string in chunks. The chunk size is large enough to avoid
966 * re-allocation in typical cases, and small enough to ensure we do
967 * not pre-allocate an unreasonable amount of memory if (perhaps due
968 * to network data corruption or a DOS attack), we receive a bogus
969 * claim that a very long string is going to follow. In that case, we
970 * start small and wait for all that data to actually show up. This
971 * does not fully prevent DOS attacks but makes them harder (you have
972 * to actually send gigabytes of data). */
973 svn_stringbuf_t *stringbuf = svn_stringbuf_create_empty(pool);
975 /* Read string data directly into the string structure.
976 * Do it iteratively. */
979 /* Determine length of chunk to read and re-alloc the buffer. */
981 = len < SUSPICIOUSLY_HUGE_STRING_SIZE_THRESHOLD
983 : SUSPICIOUSLY_HUGE_STRING_SIZE_THRESHOLD;
985 svn_stringbuf_ensure(stringbuf, stringbuf->len + readbuf_len);
986 dest = stringbuf->data + stringbuf->len;
988 /* read data & update length info */
989 SVN_ERR(readbuf_read(conn, pool, dest, readbuf_len));
991 stringbuf->len += readbuf_len;
996 /* zero-terminate the string */
997 stringbuf->data[stringbuf->len] = '\0';
999 /* Return the string properly wrapped into an RA_SVN item. */
1000 item->kind = SVN_RA_SVN_STRING;
1001 item->u.string = svn_stringbuf__morph_into_string(stringbuf);
1004 return SVN_NO_ERROR;
1007 /* Given the first non-whitespace character FIRST_CHAR, read an item
1008 * into the already allocated structure ITEM. LEVEL should be set
1009 * to 0 for the first call and is used to enforce a recursion limit
1011 static svn_error_t *read_item(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
1012 svn_ra_svn_item_t *item, char first_char,
1015 char c = first_char;
1017 svn_ra_svn_item_t *listitem;
1019 if (++level >= ITEM_NESTING_LIMIT)
1020 return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
1021 _("Items are nested too deeply"));
1024 /* Determine the item type and read it in. Make sure that c is the
1025 * first character at the end of the item so we can test to make
1026 * sure it's whitespace. */
1027 if (svn_ctype_isdigit(c))
1029 /* It's a number or a string. Read the number part, either way. */
1033 apr_uint64_t prev_val = val;
1034 SVN_ERR(readbuf_getchar(conn, pool, &c));
1035 if (!svn_ctype_isdigit(c))
1037 val = val * 10 + (c - '0');
1038 /* val wrapped past maximum value? */
1039 if ((prev_val >= (APR_UINT64_MAX / 10))
1040 && (val < APR_UINT64_MAX - 10))
1041 return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
1042 _("Number is larger than maximum"));
1046 /* It's a string. */
1047 SVN_ERR(read_string(conn, pool, item, val));
1048 SVN_ERR(readbuf_getchar(conn, pool, &c));
1052 /* It's a number. */
1053 item->kind = SVN_RA_SVN_NUMBER;
1054 item->u.number = val;
1057 else if (svn_ctype_isalpha(c))
1059 /* It's a word. Read it into a buffer of limited size. */
1060 char *buffer = apr_palloc(pool, MAX_WORD_LENGTH + 1);
1061 char *end = buffer + MAX_WORD_LENGTH;
1062 char *p = buffer + 1;
1067 SVN_ERR(readbuf_getchar(conn, pool, p));
1068 if (!svn_ctype_isalnum(*p) && *p != '-')
1072 return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
1073 _("Word is too long"));
1079 item->kind = SVN_RA_SVN_WORD;
1080 item->u.word = buffer;
1084 /* Read in the list items. */
1085 item->kind = SVN_RA_SVN_LIST;
1086 item->u.list = apr_array_make(pool, 4, sizeof(svn_ra_svn_item_t));
1089 SVN_ERR(readbuf_getchar_skip_whitespace(conn, pool, &c));
1092 listitem = apr_array_push(item->u.list);
1093 SVN_ERR(read_item(conn, pool, listitem, c, level));
1095 SVN_ERR(readbuf_getchar(conn, pool, &c));
1098 if (!svn_iswhitespace(c))
1099 return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
1100 _("Malformed network data"));
1101 return SVN_NO_ERROR;
1104 /* Given the first non-whitespace character FIRST_CHAR, read the first
1105 * command (word) encountered in CONN into *ITEM. If ITEM is NULL, skip
1106 * to the end of the current list. Use POOL for allocations. */
1107 static svn_error_t *
1108 read_command_only(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
1109 const char **item, char first_char)
1111 char c = first_char;
1113 /* Determine the item type and read it in. Make sure that c is the
1114 * first character at the end of the item so we can test to make
1115 * sure it's whitespace. */
1116 if (svn_ctype_isdigit(c))
1118 /* It's a number or a string. Read the number part, either way. */
1119 apr_uint64_t val, prev_val=0;
1124 SVN_ERR(readbuf_getchar(conn, pool, &c));
1125 if (!svn_ctype_isdigit(c))
1127 val = val * 10 + (c - '0');
1128 if (prev_val >= (APR_UINT64_MAX / 10)) /* > maximum value? */
1129 return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
1130 _("Number is larger than maximum"));
1134 /* It's a string. */
1135 SVN_ERR(readbuf_skip(conn, val));
1136 SVN_ERR(readbuf_getchar(conn, pool, &c));
1139 else if (svn_ctype_isalpha(c))
1144 /* This is the word we want to read */
1146 char *buf = apr_palloc(pool, 32);
1152 SVN_ERR(readbuf_getchar(conn, pool, &c));
1153 if (!svn_ctype_isalnum(c) && c != '-')
1157 return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
1158 _("Word too long"));
1165 /* we don't need the actual word, just skip it */
1168 SVN_ERR(readbuf_getchar(conn, pool, &c));
1170 while (svn_ctype_isalnum(c) || c == '-');
1175 /* Read in the list items. */
1178 SVN_ERR(readbuf_getchar_skip_whitespace(conn, pool, &c));
1182 if (item && *item == NULL)
1183 SVN_ERR(read_command_only(conn, pool, item, c));
1185 SVN_ERR(read_command_only(conn, pool, NULL, c));
1187 SVN_ERR(readbuf_getchar(conn, pool, &c));
1190 return SVN_NO_ERROR;
1194 svn_ra_svn__read_item(svn_ra_svn_conn_t *conn,
1196 svn_ra_svn_item_t **item)
1200 /* Allocate space, read the first character, and then do the rest of
1201 * the work. This makes sense because of the way lists are read. */
1202 *item = apr_palloc(pool, sizeof(**item));
1203 SVN_ERR(readbuf_getchar_skip_whitespace(conn, pool, &c));
1204 return read_item(conn, pool, *item, c, 0);
1207 /* Drain existing whitespace from the receive buffer of CONN until either
1208 there is no data in the underlying receive socket anymore or we found
1209 a non-whitespace char. Set *HAS_ITEM to TRUE in the latter case.
1211 static svn_error_t *
1212 svn_ra_svn__has_item(svn_boolean_t *has_item,
1213 svn_ra_svn_conn_t *conn,
1218 if (conn->read_ptr == conn->read_end)
1220 svn_boolean_t available;
1221 if (conn->write_pos)
1222 SVN_ERR(writebuf_flush(conn, pool));
1224 SVN_ERR(svn_ra_svn__data_available(conn, &available));
1228 SVN_ERR(readbuf_fill(conn, pool));
1231 while (svn_iswhitespace(*conn->read_ptr) && ++conn->read_ptr);
1233 *has_item = conn->read_ptr != conn->read_end;
1234 return SVN_NO_ERROR;
1238 svn_ra_svn__skip_leading_garbage(svn_ra_svn_conn_t *conn,
1241 return readbuf_skip_leading_garbage(conn, pool);
1244 /* --- READING AND PARSING TUPLES --- */
1246 /* Parse a tuple of svn_ra_svn_item_t *'s. Advance *FMT to the end of the
1247 * tuple specification and advance AP by the corresponding arguments. */
1248 static svn_error_t *vparse_tuple(const apr_array_header_t *items, apr_pool_t *pool,
1249 const char **fmt, va_list *ap)
1251 int count, nesting_level;
1252 svn_ra_svn_item_t *elt;
1254 for (count = 0; **fmt && count < items->nelts; (*fmt)++, count++)
1256 /* '?' just means the tuple may stop; skip past it. */
1259 elt = &APR_ARRAY_IDX(items, count, svn_ra_svn_item_t);
1260 if (**fmt == '(' && elt->kind == SVN_RA_SVN_LIST)
1263 SVN_ERR(vparse_tuple(elt->u.list, pool, fmt, ap));
1265 else if (**fmt == 'c' && elt->kind == SVN_RA_SVN_STRING)
1266 *va_arg(*ap, const char **) = elt->u.string->data;
1267 else if (**fmt == 's' && elt->kind == SVN_RA_SVN_STRING)
1268 *va_arg(*ap, svn_string_t **) = elt->u.string;
1269 else if (**fmt == 'w' && elt->kind == SVN_RA_SVN_WORD)
1270 *va_arg(*ap, const char **) = elt->u.word;
1271 else if (**fmt == 'b' && elt->kind == SVN_RA_SVN_WORD)
1273 if (strcmp(elt->u.word, "true") == 0)
1274 *va_arg(*ap, svn_boolean_t *) = TRUE;
1275 else if (strcmp(elt->u.word, "false") == 0)
1276 *va_arg(*ap, svn_boolean_t *) = FALSE;
1280 else if (**fmt == 'n' && elt->kind == SVN_RA_SVN_NUMBER)
1281 *va_arg(*ap, apr_uint64_t *) = elt->u.number;
1282 else if (**fmt == 'r' && elt->kind == SVN_RA_SVN_NUMBER)
1283 *va_arg(*ap, svn_revnum_t *) = (svn_revnum_t) elt->u.number;
1284 else if (**fmt == 'B' && elt->kind == SVN_RA_SVN_WORD)
1286 if (strcmp(elt->u.word, "true") == 0)
1287 *va_arg(*ap, apr_uint64_t *) = TRUE;
1288 else if (strcmp(elt->u.word, "false") == 0)
1289 *va_arg(*ap, apr_uint64_t *) = FALSE;
1293 else if (**fmt == '3' && elt->kind == SVN_RA_SVN_WORD)
1295 if (strcmp(elt->u.word, "true") == 0)
1296 *va_arg(*ap, svn_tristate_t *) = svn_tristate_true;
1297 else if (strcmp(elt->u.word, "false") == 0)
1298 *va_arg(*ap, svn_tristate_t *) = svn_tristate_false;
1302 else if (**fmt == 'l' && elt->kind == SVN_RA_SVN_LIST)
1303 *va_arg(*ap, apr_array_header_t **) = elt->u.list;
1304 else if (**fmt == ')')
1305 return SVN_NO_ERROR;
1312 for (; **fmt; (*fmt)++)
1319 *va_arg(*ap, svn_revnum_t *) = SVN_INVALID_REVNUM;
1322 *va_arg(*ap, svn_string_t **) = NULL;
1326 *va_arg(*ap, const char **) = NULL;
1329 *va_arg(*ap, apr_array_header_t **) = NULL;
1333 *va_arg(*ap, apr_uint64_t *) = SVN_RA_SVN_UNSPECIFIED_NUMBER;
1336 *va_arg(*ap, svn_tristate_t *) = svn_tristate_unknown;
1342 if (--nesting_level < 0)
1343 return SVN_NO_ERROR;
1346 SVN_ERR_MALFUNCTION();
1350 if (**fmt && **fmt != ')')
1351 return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
1352 _("Malformed network data"));
1353 return SVN_NO_ERROR;
1357 svn_ra_svn__parse_tuple(const apr_array_header_t *list,
1359 const char *fmt, ...)
1365 err = vparse_tuple(list, pool, &fmt, &ap);
1371 svn_ra_svn__read_tuple(svn_ra_svn_conn_t *conn,
1373 const char *fmt, ...)
1376 svn_ra_svn_item_t *item;
1379 SVN_ERR(svn_ra_svn__read_item(conn, pool, &item));
1380 if (item->kind != SVN_RA_SVN_LIST)
1381 return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
1382 _("Malformed network data"));
1384 err = vparse_tuple(item->u.list, pool, &fmt, &ap);
1390 svn_ra_svn__read_command_only(svn_ra_svn_conn_t *conn,
1392 const char **command)
1395 SVN_ERR(readbuf_getchar_skip_whitespace(conn, pool, &c));
1398 return read_command_only(conn, pool, command, c);
1403 svn_ra_svn__parse_proplist(const apr_array_header_t *list,
1408 svn_string_t *value;
1409 svn_ra_svn_item_t *elt;
1412 *props = svn_hash__make(pool);
1413 for (i = 0; i < list->nelts; i++)
1415 elt = &APR_ARRAY_IDX(list, i, svn_ra_svn_item_t);
1416 if (elt->kind != SVN_RA_SVN_LIST)
1417 return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
1418 _("Proplist element not a list"));
1419 SVN_ERR(svn_ra_svn__parse_tuple(elt->u.list, pool, "ss",
1421 apr_hash_set(*props, name->data, name->len, value);
1424 return SVN_NO_ERROR;
1428 /* --- READING AND WRITING COMMANDS AND RESPONSES --- */
1430 svn_error_t *svn_ra_svn__locate_real_error_child(svn_error_t *err)
1432 svn_error_t *this_link;
1434 SVN_ERR_ASSERT(err);
1436 for (this_link = err;
1437 this_link && (this_link->apr_err == SVN_ERR_RA_SVN_CMD_ERR);
1438 this_link = this_link->child)
1441 SVN_ERR_ASSERT(this_link);
1445 svn_error_t *svn_ra_svn__handle_failure_status(const apr_array_header_t *params,
1448 const char *message, *file;
1449 svn_error_t *err = NULL;
1450 svn_ra_svn_item_t *elt;
1452 apr_uint64_t apr_err, line;
1453 apr_pool_t *subpool = svn_pool_create(pool);
1455 if (params->nelts == 0)
1456 return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
1457 _("Empty error list"));
1459 /* Rebuild the error list from the end, to avoid reversing the order. */
1460 for (i = params->nelts - 1; i >= 0; i--)
1462 svn_pool_clear(subpool);
1463 elt = &APR_ARRAY_IDX(params, i, svn_ra_svn_item_t);
1464 if (elt->kind != SVN_RA_SVN_LIST)
1465 return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
1466 _("Malformed error list"));
1467 SVN_ERR(svn_ra_svn__parse_tuple(elt->u.list, subpool, "nccn",
1468 &apr_err, &message, &file, &line));
1469 /* The message field should have been optional, but we can't
1470 easily change that, so "" means a nonexistent message. */
1474 /* Skip over links in the error chain that were intended only to
1475 exist on the server (to wrap real errors intended for the
1476 client) but accidentally got included in the server's actual
1478 if ((apr_status_t)apr_err != SVN_ERR_RA_SVN_CMD_ERR)
1480 err = svn_error_create((apr_status_t)apr_err, err, message);
1481 err->file = apr_pstrdup(err->pool, file);
1482 err->line = (long)line;
1486 svn_pool_destroy(subpool);
1488 /* If we get here, then we failed to find a real error in the error
1489 chain that the server proported to be sending us. That's bad. */
1491 err = svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
1492 _("Malformed error list"));
1498 svn_ra_svn__read_cmd_response(svn_ra_svn_conn_t *conn,
1500 const char *fmt, ...)
1504 apr_array_header_t *params;
1507 SVN_ERR(svn_ra_svn__read_tuple(conn, pool, "wl", &status, ¶ms));
1508 if (strcmp(status, "success") == 0)
1511 err = vparse_tuple(params, pool, &fmt, &ap);
1515 else if (strcmp(status, "failure") == 0)
1517 return svn_error_trace(svn_ra_svn__handle_failure_status(params, pool));
1520 return svn_error_createf(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
1521 _("Unknown status '%s' in command response"),
1526 svn_ra_svn__has_command(svn_boolean_t *has_command,
1527 svn_boolean_t *terminated,
1528 svn_ra_svn_conn_t *conn,
1531 svn_error_t *err = svn_ra_svn__has_item(has_command, conn, pool);
1532 if (err && err->apr_err == SVN_ERR_RA_SVN_CONNECTION_CLOSED)
1535 svn_error_clear(err);
1536 return SVN_NO_ERROR;
1539 *terminated = FALSE;
1540 return svn_error_trace(err);
1544 svn_ra_svn__handle_command(svn_boolean_t *terminate,
1545 apr_hash_t *cmd_hash,
1547 svn_ra_svn_conn_t *conn,
1548 svn_boolean_t error_on_disconnect,
1551 const char *cmdname;
1552 svn_error_t *err, *write_err;
1553 apr_array_header_t *params;
1554 const svn_ra_svn_cmd_entry_t *command;
1557 err = svn_ra_svn__read_tuple(conn, pool, "wl", &cmdname, ¶ms);
1560 if (!error_on_disconnect
1561 && err->apr_err == SVN_ERR_RA_SVN_CONNECTION_CLOSED)
1563 svn_error_clear(err);
1565 return SVN_NO_ERROR;
1570 command = svn_hash_gets(cmd_hash, cmdname);
1573 err = (*command->handler)(conn, pool, params, baton);
1574 *terminate = command->terminate;
1578 err = svn_error_createf(SVN_ERR_RA_SVN_UNKNOWN_CMD, NULL,
1579 _("Unknown editor command '%s'"), cmdname);
1580 err = svn_error_create(SVN_ERR_RA_SVN_CMD_ERR, err, NULL);
1583 if (err && err->apr_err == SVN_ERR_RA_SVN_CMD_ERR)
1585 write_err = svn_ra_svn__write_cmd_failure(
1587 svn_ra_svn__locate_real_error_child(err));
1588 svn_error_clear(err);
1589 return write_err ? write_err : SVN_NO_ERROR;
1596 svn_ra_svn__handle_commands2(svn_ra_svn_conn_t *conn,
1598 const svn_ra_svn_cmd_entry_t *commands,
1600 svn_boolean_t error_on_disconnect)
1602 apr_pool_t *subpool = svn_pool_create(pool);
1603 apr_pool_t *iterpool = svn_pool_create(subpool);
1604 const svn_ra_svn_cmd_entry_t *command;
1605 apr_hash_t *cmd_hash = apr_hash_make(subpool);
1607 for (command = commands; command->cmdname; command++)
1608 svn_hash_sets(cmd_hash, command->cmdname, command);
1612 svn_boolean_t terminate;
1614 svn_pool_clear(iterpool);
1616 err = svn_ra_svn__handle_command(&terminate, cmd_hash, baton, conn,
1617 error_on_disconnect, iterpool);
1620 svn_pool_destroy(subpool);
1621 return svn_error_trace(err);
1626 svn_pool_destroy(iterpool);
1627 svn_pool_destroy(subpool);
1628 return SVN_NO_ERROR;
1632 svn_ra_svn__write_cmd_target_rev(svn_ra_svn_conn_t *conn,
1636 SVN_ERR(writebuf_write_literal(conn, pool, "( target-rev ( "));
1637 SVN_ERR(write_tuple_revision(conn, pool, rev));
1638 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
1640 return SVN_NO_ERROR;
1644 svn_ra_svn__write_cmd_open_root(svn_ra_svn_conn_t *conn,
1649 SVN_ERR(writebuf_write_literal(conn, pool, "( open-root ( "));
1650 SVN_ERR(write_tuple_start_list(conn, pool));
1651 SVN_ERR(write_tuple_revision_opt(conn, pool, rev));
1652 SVN_ERR(write_tuple_end_list(conn, pool));
1653 SVN_ERR(write_tuple_cstring(conn, pool, token));
1654 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
1656 return SVN_NO_ERROR;
1660 svn_ra_svn__write_cmd_delete_entry(svn_ra_svn_conn_t *conn,
1666 SVN_ERR(writebuf_write_literal(conn, pool, "( delete-entry ( "));
1667 SVN_ERR(write_tuple_cstring(conn, pool, path));
1668 SVN_ERR(write_tuple_start_list(conn, pool));
1669 SVN_ERR(write_tuple_revision_opt(conn, pool, rev));
1670 SVN_ERR(write_tuple_end_list(conn, pool));
1671 SVN_ERR(write_tuple_cstring(conn, pool, token));
1672 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
1674 return SVN_NO_ERROR;
1678 svn_ra_svn__write_cmd_add_dir(svn_ra_svn_conn_t *conn,
1681 const char *parent_token,
1683 const char *copy_path,
1684 svn_revnum_t copy_rev)
1686 SVN_ERR(writebuf_write_literal(conn, pool, "( add-dir ( "));
1687 SVN_ERR(write_cmd_add_node(conn, pool, path, parent_token, token,
1688 copy_path, copy_rev));
1689 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
1691 return SVN_NO_ERROR;
1695 svn_ra_svn__write_cmd_open_dir(svn_ra_svn_conn_t *conn,
1698 const char *parent_token,
1702 SVN_ERR(writebuf_write_literal(conn, pool, "( open-dir ( "));
1703 SVN_ERR(write_cmd_open_node(conn, pool, path, parent_token, token, rev));
1704 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
1706 return SVN_NO_ERROR;
1710 svn_ra_svn__write_cmd_change_dir_prop(svn_ra_svn_conn_t *conn,
1714 const svn_string_t *value)
1716 SVN_ERR(writebuf_write_literal(conn, pool, "( change-dir-prop ( "));
1717 SVN_ERR(write_cmd_change_node_prop(conn, pool, token, name, value));
1718 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
1720 return SVN_NO_ERROR;
1724 svn_ra_svn__write_cmd_close_dir(svn_ra_svn_conn_t *conn,
1728 SVN_ERR(writebuf_write_literal(conn, pool, "( close-dir ( "));
1729 SVN_ERR(write_tuple_cstring(conn, pool, token));
1730 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
1732 return SVN_NO_ERROR;
1736 svn_ra_svn__write_cmd_absent_dir(svn_ra_svn_conn_t *conn,
1739 const char *parent_token)
1741 SVN_ERR(writebuf_write_literal(conn, pool, "( absent-dir ( "));
1742 SVN_ERR(write_cmd_absent_node(conn, pool, path, parent_token));
1743 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
1745 return SVN_NO_ERROR;
1749 svn_ra_svn__write_cmd_add_file(svn_ra_svn_conn_t *conn,
1752 const char *parent_token,
1754 const char *copy_path,
1755 svn_revnum_t copy_rev)
1757 SVN_ERR(writebuf_write_literal(conn, pool, "( add-file ( "));
1758 SVN_ERR(write_cmd_add_node(conn, pool, path, parent_token, token,
1759 copy_path, copy_rev));
1760 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
1762 return SVN_NO_ERROR;
1766 svn_ra_svn__write_cmd_open_file(svn_ra_svn_conn_t *conn,
1769 const char *parent_token,
1773 SVN_ERR(writebuf_write_literal(conn, pool, "( open-file ( "));
1774 SVN_ERR(write_cmd_open_node(conn, pool, path, parent_token, token, rev));
1775 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
1777 return SVN_NO_ERROR;
1781 svn_ra_svn__write_cmd_change_file_prop(svn_ra_svn_conn_t *conn,
1785 const svn_string_t *value)
1787 SVN_ERR(writebuf_write_literal(conn, pool, "( change-file-prop ( "));
1788 SVN_ERR(write_cmd_change_node_prop(conn, pool, token, name, value));
1789 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
1791 return SVN_NO_ERROR;
1795 svn_ra_svn__write_cmd_close_file(svn_ra_svn_conn_t *conn,
1798 const char *text_checksum)
1800 SVN_ERR(writebuf_write_literal(conn, pool, "( close-file ( "));
1801 SVN_ERR(write_tuple_cstring(conn, pool, token));
1802 SVN_ERR(write_tuple_start_list(conn, pool));
1803 SVN_ERR(write_tuple_cstring_opt(conn, pool, text_checksum));
1804 SVN_ERR(write_tuple_end_list(conn, pool));
1805 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
1807 return SVN_NO_ERROR;
1811 svn_ra_svn__write_cmd_absent_file(svn_ra_svn_conn_t *conn,
1814 const char *parent_token)
1816 SVN_ERR(writebuf_write_literal(conn, pool, "( absent-file ( "));
1817 SVN_ERR(write_cmd_absent_node(conn, pool, path, parent_token));
1818 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
1820 return SVN_NO_ERROR;
1824 svn_ra_svn__write_cmd_textdelta_chunk(svn_ra_svn_conn_t *conn,
1827 const svn_string_t *chunk)
1829 SVN_ERR(writebuf_write_literal(conn, pool, "( textdelta-chunk ( "));
1830 SVN_ERR(write_tuple_cstring(conn, pool, token));
1831 SVN_ERR(write_tuple_string(conn, pool, chunk));
1832 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
1834 return SVN_NO_ERROR;
1838 svn_ra_svn__write_cmd_textdelta_end(svn_ra_svn_conn_t *conn,
1842 SVN_ERR(writebuf_write_literal(conn, pool, "( textdelta-end ( "));
1843 SVN_ERR(write_tuple_cstring(conn, pool, token));
1844 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
1846 return SVN_NO_ERROR;
1850 svn_ra_svn__write_cmd_apply_textdelta(svn_ra_svn_conn_t *conn,
1853 const char *base_checksum)
1855 SVN_ERR(writebuf_write_literal(conn, pool, "( apply-textdelta ( "));
1856 SVN_ERR(write_tuple_cstring(conn, pool, token));
1857 SVN_ERR(write_tuple_start_list(conn, pool));
1858 SVN_ERR(write_tuple_cstring_opt(conn, pool, base_checksum));
1859 SVN_ERR(write_tuple_end_list(conn, pool));
1860 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
1862 return SVN_NO_ERROR;
1866 svn_ra_svn__write_cmd_close_edit(svn_ra_svn_conn_t *conn,
1869 return writebuf_write_literal(conn, pool, "( close-edit ( ) ) ");
1873 svn_ra_svn__write_cmd_abort_edit(svn_ra_svn_conn_t *conn,
1876 return writebuf_write_literal(conn, pool, "( abort-edit ( ) ) ");
1880 svn_ra_svn__write_cmd_set_path(svn_ra_svn_conn_t *conn,
1884 svn_boolean_t start_empty,
1885 const char *lock_token,
1888 SVN_ERR(writebuf_write_literal(conn, pool, "( set-path ( "));
1889 SVN_ERR(write_tuple_cstring(conn, pool, path));
1890 SVN_ERR(write_tuple_revision(conn, pool, rev));
1891 SVN_ERR(write_tuple_boolean(conn, pool, start_empty));
1892 SVN_ERR(write_tuple_start_list(conn, pool));
1893 SVN_ERR(write_tuple_cstring_opt(conn, pool, lock_token));
1894 SVN_ERR(write_tuple_end_list(conn, pool));
1895 SVN_ERR(write_tuple_depth(conn, pool, depth));
1896 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
1898 return SVN_NO_ERROR;
1902 svn_ra_svn__write_cmd_delete_path(svn_ra_svn_conn_t *conn,
1906 SVN_ERR(writebuf_write_literal(conn, pool, "( delete-path ( "));
1907 SVN_ERR(write_tuple_cstring(conn, pool, path));
1908 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
1910 return SVN_NO_ERROR;
1914 svn_ra_svn__write_cmd_link_path(svn_ra_svn_conn_t *conn,
1919 svn_boolean_t start_empty,
1920 const char *lock_token,
1923 SVN_ERR(writebuf_write_literal(conn, pool, "( link-path ( "));
1924 SVN_ERR(write_tuple_cstring(conn, pool, path));
1925 SVN_ERR(write_tuple_cstring(conn, pool, url));
1926 SVN_ERR(write_tuple_revision(conn, pool, rev));
1927 SVN_ERR(write_tuple_boolean(conn, pool, start_empty));
1928 SVN_ERR(write_tuple_start_list(conn, pool));
1929 SVN_ERR(write_tuple_cstring_opt(conn, pool,lock_token));
1930 SVN_ERR(write_tuple_end_list(conn, pool));
1931 SVN_ERR(write_tuple_depth(conn, pool, depth));
1932 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
1934 return SVN_NO_ERROR;
1938 svn_ra_svn__write_cmd_finish_report(svn_ra_svn_conn_t *conn,
1941 return writebuf_write_literal(conn, pool, "( finish-report ( ) ) ");
1945 svn_ra_svn__write_cmd_abort_report(svn_ra_svn_conn_t *conn,
1948 return writebuf_write_literal(conn, pool, "( abort-report ( ) ) ");
1952 svn_ra_svn__write_cmd_reparent(svn_ra_svn_conn_t *conn,
1956 SVN_ERR(writebuf_write_literal(conn, pool, "( reparent ( "));
1957 SVN_ERR(write_tuple_cstring(conn, pool, url));
1958 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
1960 return SVN_NO_ERROR;
1964 svn_ra_svn__write_cmd_get_latest_rev(svn_ra_svn_conn_t *conn,
1967 return writebuf_write_literal(conn, pool, "( get-latest-rev ( ) ) ");
1971 svn_ra_svn__write_cmd_get_dated_rev(svn_ra_svn_conn_t *conn,
1975 SVN_ERR(writebuf_write_literal(conn, pool, "( get-dated-rev ( "));
1976 SVN_ERR(write_tuple_cstring(conn, pool, svn_time_to_cstring(tm, pool)));
1977 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
1979 return SVN_NO_ERROR;
1983 svn_ra_svn__write_cmd_change_rev_prop2(svn_ra_svn_conn_t *conn,
1987 const svn_string_t *value,
1988 svn_boolean_t dont_care,
1989 const svn_string_t *old_value)
1991 SVN_ERR(writebuf_write_literal(conn, pool, "( change-rev-prop2 ( "));
1992 SVN_ERR(write_tuple_revision(conn, pool, rev));
1993 SVN_ERR(write_tuple_cstring(conn, pool, name));
1994 SVN_ERR(write_tuple_start_list(conn, pool));
1995 SVN_ERR(write_tuple_string_opt(conn, pool, value));
1996 SVN_ERR(write_tuple_end_list(conn, pool));
1997 SVN_ERR(write_tuple_start_list(conn, pool));
1998 SVN_ERR(write_tuple_boolean(conn, pool, dont_care));
1999 SVN_ERR(write_tuple_string_opt(conn, pool, old_value));
2000 SVN_ERR(write_tuple_end_list(conn, pool));
2001 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
2003 return SVN_NO_ERROR;
2007 svn_ra_svn__write_cmd_change_rev_prop(svn_ra_svn_conn_t *conn,
2011 const svn_string_t *value)
2013 SVN_ERR(writebuf_write_literal(conn, pool, "( change-rev-prop ( "));
2014 SVN_ERR(write_tuple_revision(conn, pool, rev));
2015 SVN_ERR(write_tuple_cstring(conn, pool, name));
2016 SVN_ERR(write_tuple_string_opt(conn, pool, value));
2017 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
2019 return SVN_NO_ERROR;
2023 svn_ra_svn__write_cmd_rev_proplist(svn_ra_svn_conn_t *conn,
2027 SVN_ERR(writebuf_write_literal(conn, pool, "( rev-proplist ( "));
2028 SVN_ERR(write_tuple_revision(conn, pool, rev));
2029 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
2031 return SVN_NO_ERROR;
2035 svn_ra_svn__write_cmd_rev_prop(svn_ra_svn_conn_t *conn,
2040 SVN_ERR(writebuf_write_literal(conn, pool, "( rev-prop ( "));
2041 SVN_ERR(write_tuple_revision(conn, pool, rev));
2042 SVN_ERR(write_tuple_cstring(conn, pool, name));
2043 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
2045 return SVN_NO_ERROR;
2049 svn_ra_svn__write_cmd_get_file(svn_ra_svn_conn_t *conn,
2053 svn_boolean_t props,
2054 svn_boolean_t stream)
2056 SVN_ERR(writebuf_write_literal(conn, pool, "( get-file ( "));
2057 SVN_ERR(write_tuple_cstring(conn, pool, path));
2058 SVN_ERR(write_tuple_start_list(conn, pool));
2059 SVN_ERR(write_tuple_revision_opt(conn, pool, rev));
2060 SVN_ERR(write_tuple_end_list(conn, pool));
2061 SVN_ERR(write_tuple_boolean(conn, pool, props));
2062 SVN_ERR(write_tuple_boolean(conn, pool, stream));
2064 /* Always send the, nominally optional, want-iprops as "false" to
2065 workaround a bug in svnserve 1.8.0-1.8.8 that causes the server
2066 to see "true" if it is omitted. */
2067 SVN_ERR(writebuf_write_literal(conn, pool, " false ) ) "));
2069 return SVN_NO_ERROR;
2073 svn_ra_svn__write_cmd_update(svn_ra_svn_conn_t *conn,
2077 svn_boolean_t recurse,
2079 svn_boolean_t send_copyfrom_args,
2080 svn_boolean_t ignore_ancestry)
2082 SVN_ERR(writebuf_write_literal(conn, pool, "( update ( "));
2083 SVN_ERR(write_tuple_start_list(conn, pool));
2084 SVN_ERR(write_tuple_revision_opt(conn, pool, rev));
2085 SVN_ERR(write_tuple_end_list(conn, pool));
2086 SVN_ERR(write_tuple_cstring(conn, pool, target));
2087 SVN_ERR(write_tuple_boolean(conn, pool, recurse));
2088 SVN_ERR(write_tuple_depth(conn, pool, depth));
2089 SVN_ERR(write_tuple_boolean(conn, pool, send_copyfrom_args));
2090 SVN_ERR(write_tuple_boolean(conn, pool, ignore_ancestry));
2091 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
2093 return SVN_NO_ERROR;
2097 svn_ra_svn__write_cmd_switch(svn_ra_svn_conn_t *conn,
2101 svn_boolean_t recurse,
2102 const char *switch_url,
2104 svn_boolean_t send_copyfrom_args,
2105 svn_boolean_t ignore_ancestry)
2107 SVN_ERR(writebuf_write_literal(conn, pool, "( switch ( "));
2108 SVN_ERR(write_tuple_start_list(conn, pool));
2109 SVN_ERR(write_tuple_revision_opt(conn, pool, rev));
2110 SVN_ERR(write_tuple_end_list(conn, pool));
2111 SVN_ERR(write_tuple_cstring(conn, pool, target));
2112 SVN_ERR(write_tuple_boolean(conn, pool, recurse));
2113 SVN_ERR(write_tuple_cstring(conn, pool, switch_url));
2114 SVN_ERR(write_tuple_depth(conn, pool, depth));
2115 SVN_ERR(write_tuple_boolean(conn, pool, send_copyfrom_args));
2116 SVN_ERR(write_tuple_boolean(conn, pool, ignore_ancestry));
2117 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
2119 return SVN_NO_ERROR;
2123 svn_ra_svn__write_cmd_status(svn_ra_svn_conn_t *conn,
2126 svn_boolean_t recurse,
2130 SVN_ERR(writebuf_write_literal(conn, pool, "( status ( "));
2131 SVN_ERR(write_tuple_cstring(conn, pool, target));
2132 SVN_ERR(write_tuple_boolean(conn, pool, recurse));
2133 SVN_ERR(write_tuple_start_list(conn, pool));
2134 SVN_ERR(write_tuple_revision_opt(conn, pool, rev));
2135 SVN_ERR(write_tuple_end_list(conn, pool));
2136 SVN_ERR(write_tuple_depth(conn, pool, depth));
2137 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
2139 return SVN_NO_ERROR;
2143 svn_ra_svn__write_cmd_diff(svn_ra_svn_conn_t *conn,
2147 svn_boolean_t recurse,
2148 svn_boolean_t ignore_ancestry,
2149 const char *versus_url,
2150 svn_boolean_t text_deltas,
2153 SVN_ERR(writebuf_write_literal(conn, pool, "( diff ( "));
2154 SVN_ERR(write_tuple_start_list(conn, pool));
2155 SVN_ERR(write_tuple_revision_opt(conn, pool, rev));
2156 SVN_ERR(write_tuple_end_list(conn, pool));
2157 SVN_ERR(write_tuple_cstring(conn, pool, target));
2158 SVN_ERR(write_tuple_boolean(conn, pool, recurse));
2159 SVN_ERR(write_tuple_boolean(conn, pool, ignore_ancestry));
2160 SVN_ERR(write_tuple_cstring(conn, pool, versus_url));
2161 SVN_ERR(write_tuple_boolean(conn, pool, text_deltas));
2162 SVN_ERR(write_tuple_depth(conn, pool, depth));
2163 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
2165 return SVN_NO_ERROR;
2169 svn_ra_svn__write_cmd_check_path(svn_ra_svn_conn_t *conn,
2174 SVN_ERR(writebuf_write_literal(conn, pool, "( check-path ( "));
2175 SVN_ERR(write_tuple_cstring(conn, pool, path));
2176 SVN_ERR(write_tuple_start_list(conn, pool));
2177 SVN_ERR(write_tuple_revision_opt(conn, pool, rev));
2178 SVN_ERR(write_tuple_end_list(conn, pool));
2179 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
2181 return SVN_NO_ERROR;
2185 svn_ra_svn__write_cmd_stat(svn_ra_svn_conn_t *conn,
2190 SVN_ERR(writebuf_write_literal(conn, pool, "( stat ( "));
2191 SVN_ERR(write_tuple_cstring(conn, pool, path));
2192 SVN_ERR(write_tuple_start_list(conn, pool));
2193 SVN_ERR(write_tuple_revision_opt(conn, pool, rev));
2194 SVN_ERR(write_tuple_end_list(conn, pool));
2195 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
2197 return SVN_NO_ERROR;
2201 svn_ra_svn__write_cmd_get_file_revs(svn_ra_svn_conn_t *conn,
2206 svn_boolean_t include_merged_revisions)
2208 SVN_ERR(writebuf_write_literal(conn, pool, "( get-file-revs ( "));
2209 SVN_ERR(write_tuple_cstring(conn, pool, path));
2210 SVN_ERR(write_tuple_start_list(conn, pool));
2211 SVN_ERR(write_tuple_revision_opt(conn, pool, start));
2212 SVN_ERR(write_tuple_end_list(conn, pool));
2213 SVN_ERR(write_tuple_start_list(conn, pool));
2214 SVN_ERR(write_tuple_revision_opt(conn, pool, end));
2215 SVN_ERR(write_tuple_end_list(conn, pool));
2216 SVN_ERR(write_tuple_boolean(conn, pool, include_merged_revisions));
2217 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
2219 return SVN_NO_ERROR;
2223 svn_ra_svn__write_cmd_lock(svn_ra_svn_conn_t *conn,
2226 const char *comment,
2227 svn_boolean_t steal_lock,
2228 svn_revnum_t revnum)
2230 SVN_ERR(writebuf_write_literal(conn, pool, "( lock ( "));
2231 SVN_ERR(write_tuple_cstring(conn, pool, path));
2232 SVN_ERR(write_tuple_start_list(conn, pool));
2233 SVN_ERR(write_tuple_cstring_opt(conn, pool, comment));
2234 SVN_ERR(write_tuple_end_list(conn, pool));
2235 SVN_ERR(write_tuple_boolean(conn, pool, steal_lock));
2236 SVN_ERR(write_tuple_start_list(conn, pool));
2237 SVN_ERR(write_tuple_revision_opt(conn, pool, revnum));
2238 SVN_ERR(write_tuple_end_list(conn, pool));
2239 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
2241 return SVN_NO_ERROR;
2245 svn_ra_svn__write_cmd_unlock(svn_ra_svn_conn_t *conn,
2249 svn_boolean_t break_lock)
2251 SVN_ERR(writebuf_write_literal(conn, pool, "( unlock ( "));
2252 SVN_ERR(write_tuple_cstring(conn, pool, path));
2253 SVN_ERR(write_tuple_start_list(conn, pool));
2254 SVN_ERR(write_tuple_cstring_opt(conn, pool, token));
2255 SVN_ERR(write_tuple_end_list(conn, pool));
2256 SVN_ERR(write_tuple_boolean(conn, pool, break_lock));
2257 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
2259 return SVN_NO_ERROR;
2263 svn_ra_svn__write_cmd_get_lock(svn_ra_svn_conn_t *conn,
2267 SVN_ERR(writebuf_write_literal(conn, pool, "( get-lock ( "));
2268 SVN_ERR(write_tuple_cstring(conn, pool, path));
2269 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
2271 return SVN_NO_ERROR;
2275 svn_ra_svn__write_cmd_get_locks(svn_ra_svn_conn_t *conn,
2280 SVN_ERR(writebuf_write_literal(conn, pool, "( get-locks ( "));
2281 SVN_ERR(write_tuple_cstring(conn, pool, path));
2282 SVN_ERR(write_tuple_start_list(conn, pool));
2283 SVN_ERR(write_tuple_depth(conn, pool, depth));
2284 SVN_ERR(write_tuple_end_list(conn, pool));
2285 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
2287 return SVN_NO_ERROR;
2291 svn_ra_svn__write_cmd_replay(svn_ra_svn_conn_t *conn,
2294 svn_revnum_t low_water_mark,
2295 svn_boolean_t send_deltas)
2297 SVN_ERR(writebuf_write_literal(conn, pool, "( replay ( "));
2298 SVN_ERR(write_tuple_revision(conn, pool, rev));
2299 SVN_ERR(write_tuple_revision(conn, pool, low_water_mark));
2300 SVN_ERR(write_tuple_boolean(conn, pool, send_deltas));
2301 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
2303 return SVN_NO_ERROR;
2307 svn_ra_svn__write_cmd_replay_range(svn_ra_svn_conn_t *conn,
2309 svn_revnum_t start_revision,
2310 svn_revnum_t end_revision,
2311 svn_revnum_t low_water_mark,
2312 svn_boolean_t send_deltas)
2314 SVN_ERR(writebuf_write_literal(conn, pool, "( replay-range ( "));
2315 SVN_ERR(write_tuple_revision(conn, pool, start_revision));
2316 SVN_ERR(write_tuple_revision(conn, pool, end_revision));
2317 SVN_ERR(write_tuple_revision(conn, pool, low_water_mark));
2318 SVN_ERR(write_tuple_boolean(conn, pool, send_deltas));
2319 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
2321 return SVN_NO_ERROR;
2325 svn_ra_svn__write_cmd_get_deleted_rev(svn_ra_svn_conn_t *conn,
2328 svn_revnum_t peg_revision,
2329 svn_revnum_t end_revision)
2331 SVN_ERR(writebuf_write_literal(conn, pool, "( get-deleted-rev ( "));
2332 SVN_ERR(write_tuple_cstring(conn, pool, path));
2333 SVN_ERR(write_tuple_revision(conn, pool, peg_revision));
2334 SVN_ERR(write_tuple_revision(conn, pool, end_revision));
2335 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
2337 return SVN_NO_ERROR;
2341 svn_ra_svn__write_cmd_get_iprops(svn_ra_svn_conn_t *conn,
2344 svn_revnum_t revision)
2346 SVN_ERR(writebuf_write_literal(conn, pool, "( get-iprops ( "));
2347 SVN_ERR(write_tuple_cstring(conn, pool, path));
2348 SVN_ERR(write_tuple_start_list(conn, pool));
2349 SVN_ERR(write_tuple_revision_opt(conn, pool, revision));
2350 SVN_ERR(write_tuple_end_list(conn, pool));
2351 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
2353 return SVN_NO_ERROR;
2357 svn_ra_svn__write_cmd_finish_replay(svn_ra_svn_conn_t *conn,
2360 return writebuf_write_literal(conn, pool, "( finish-replay ( ) ) ");
2363 svn_error_t *svn_ra_svn__write_cmd_response(svn_ra_svn_conn_t *conn,
2365 const char *fmt, ...)
2370 SVN_ERR(writebuf_write_literal(conn, pool, "( success "));
2372 err = vwrite_tuple(conn, pool, fmt, &ap);
2374 return err ? svn_error_trace(err) : svn_ra_svn__end_list(conn, pool);
2377 svn_error_t *svn_ra_svn__write_cmd_failure(svn_ra_svn_conn_t *conn,
2379 const svn_error_t *err)
2382 SVN_ERR(writebuf_write_literal(conn, pool, "( failure ( "));
2383 for (; err; err = err->child)
2387 #ifdef SVN_ERR__TRACING
2388 if (svn_error__is_tracing_link(err))
2392 msg = svn_err_best_message(err, buffer, sizeof(buffer));
2394 /* The message string should have been optional, but we can't
2395 easily change that, so marshal nonexistent messages as "". */
2396 SVN_ERR(svn_ra_svn__write_tuple(conn, pool, "nccn",
2397 (apr_uint64_t) err->apr_err,
2399 err->file ? err->file : "",
2400 (apr_uint64_t) err->line));
2402 return writebuf_write_literal(conn, pool, ") ) ");
2406 svn_ra_svn__write_data_log_changed_path(svn_ra_svn_conn_t *conn,
2410 const char *copyfrom_path,
2411 svn_revnum_t copyfrom_rev,
2412 svn_node_kind_t node_kind,
2413 svn_boolean_t text_modified,
2414 svn_boolean_t props_modified)
2416 SVN_ERR(write_tuple_start_list(conn, pool));
2418 SVN_ERR(write_tuple_cstring(conn, pool, path));
2419 SVN_ERR(writebuf_writechar(conn, pool, action));
2420 SVN_ERR(writebuf_writechar(conn, pool, ' '));
2421 SVN_ERR(write_tuple_start_list(conn, pool));
2422 SVN_ERR(write_tuple_cstring_opt(conn, pool, copyfrom_path));
2423 SVN_ERR(write_tuple_revision_opt(conn, pool, copyfrom_rev));
2424 SVN_ERR(write_tuple_end_list(conn, pool));
2425 SVN_ERR(write_tuple_start_list(conn, pool));
2426 SVN_ERR(write_tuple_cstring(conn, pool, svn_node_kind_to_word(node_kind)));
2427 SVN_ERR(write_tuple_boolean(conn, pool, text_modified));
2428 SVN_ERR(write_tuple_boolean(conn, pool, props_modified));
2430 return writebuf_write_literal(conn, pool, ") ) ");
2434 svn_ra_svn__write_data_log_entry(svn_ra_svn_conn_t *conn,
2436 svn_revnum_t revision,
2437 const svn_string_t *author,
2438 const svn_string_t *date,
2439 const svn_string_t *message,
2440 svn_boolean_t has_children,
2441 svn_boolean_t invalid_revnum,
2442 unsigned revprop_count)
2444 SVN_ERR(write_tuple_revision(conn, pool, revision));
2445 SVN_ERR(write_tuple_start_list(conn, pool));
2446 SVN_ERR(write_tuple_string_opt(conn, pool, author));
2447 SVN_ERR(write_tuple_end_list(conn, pool));
2448 SVN_ERR(write_tuple_start_list(conn, pool));
2449 SVN_ERR(write_tuple_string_opt(conn, pool, date));
2450 SVN_ERR(write_tuple_end_list(conn, pool));
2451 SVN_ERR(write_tuple_start_list(conn, pool));
2452 SVN_ERR(write_tuple_string_opt(conn, pool, message));
2453 SVN_ERR(write_tuple_end_list(conn, pool));
2454 SVN_ERR(write_tuple_boolean(conn, pool, has_children));
2455 SVN_ERR(write_tuple_boolean(conn, pool, invalid_revnum));
2456 SVN_ERR(svn_ra_svn__write_number(conn, pool, revprop_count));
2458 return SVN_NO_ERROR;
2461 /* If condition COND is not met, return a "malformed network data" error.
2463 #define CHECK_PROTOCOL_COND(cond)\
2465 return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL, \
2466 _("Malformed network data"));
2468 /* In *RESULT, return the SVN-style string at index IDX in tuple ITEMS.
2470 static svn_error_t *
2471 svn_ra_svn__read_string(const apr_array_header_t *items,
2473 svn_string_t **result)
2475 svn_ra_svn_item_t *elt = &APR_ARRAY_IDX(items, idx, svn_ra_svn_item_t);
2476 CHECK_PROTOCOL_COND(elt->kind == SVN_RA_SVN_STRING);
2477 *result = elt->u.string;
2479 return SVN_NO_ERROR;
2482 /* In *RESULT, return the C-style string at index IDX in tuple ITEMS.
2484 static svn_error_t *
2485 svn_ra_svn__read_cstring(const apr_array_header_t *items,
2487 const char **result)
2489 svn_ra_svn_item_t *elt = &APR_ARRAY_IDX(items, idx, svn_ra_svn_item_t);
2490 CHECK_PROTOCOL_COND(elt->kind == SVN_RA_SVN_STRING);
2491 *result = elt->u.string->data;
2493 return SVN_NO_ERROR;
2496 /* In *RESULT, return the word at index IDX in tuple ITEMS.
2498 static svn_error_t *
2499 svn_ra_svn__read_word(const apr_array_header_t *items,
2501 const char **result)
2503 svn_ra_svn_item_t *elt = &APR_ARRAY_IDX(items, idx, svn_ra_svn_item_t);
2504 CHECK_PROTOCOL_COND(elt->kind == SVN_RA_SVN_WORD);
2505 *result = elt->u.word;
2507 return SVN_NO_ERROR;
2510 /* In *RESULT, return the revision at index IDX in tuple ITEMS.
2512 static svn_error_t *
2513 svn_ra_svn__read_revision(const apr_array_header_t *items,
2515 svn_revnum_t *result)
2517 svn_ra_svn_item_t *elt = &APR_ARRAY_IDX(items, idx, svn_ra_svn_item_t);
2518 CHECK_PROTOCOL_COND(elt->kind == SVN_RA_SVN_NUMBER);
2519 *result = (svn_revnum_t)elt->u.number;
2521 return SVN_NO_ERROR;
2524 /* In *RESULT, return the boolean at index IDX in tuple ITEMS.
2526 static svn_error_t *
2527 svn_ra_svn__read_boolean(const apr_array_header_t *items,
2529 apr_uint64_t *result)
2531 svn_ra_svn_item_t *elt = &APR_ARRAY_IDX(items, idx, svn_ra_svn_item_t);
2532 CHECK_PROTOCOL_COND(elt->kind == SVN_RA_SVN_WORD);
2533 if (elt->u.word[0] == 't' && strcmp(elt->u.word, "true") == 0)
2535 else if (strcmp(elt->u.word, "false") == 0)
2538 CHECK_PROTOCOL_COND(FALSE);
2540 return SVN_NO_ERROR;
2543 /* In *RESULT, return the tuple at index IDX in tuple ITEMS.
2545 static svn_error_t *
2546 svn_ra_svn__read_list(const apr_array_header_t *items,
2548 const apr_array_header_t **result)
2550 svn_ra_svn_item_t *elt = &APR_ARRAY_IDX(items, idx, svn_ra_svn_item_t);
2551 CHECK_PROTOCOL_COND(elt->kind == SVN_RA_SVN_LIST);
2553 *result = elt->u.list;
2554 return SVN_NO_ERROR;
2557 /* Verify the tuple ITEMS contains at least MIN and at most MAX elements.
2559 static svn_error_t *
2560 svn_ra_svn__read_check_array_size(const apr_array_header_t *items,
2564 CHECK_PROTOCOL_COND(items->nelts >= min && items->nelts <= max);
2565 return SVN_NO_ERROR;
2569 svn_ra_svn__read_data_log_changed_entry(const apr_array_header_t *items,
2570 svn_string_t **cpath,
2571 const char **action,
2572 const char **copy_path,
2573 svn_revnum_t *copy_rev,
2574 const char **kind_str,
2575 apr_uint64_t *text_mods,
2576 apr_uint64_t *prop_mods)
2578 const apr_array_header_t *sub_items;
2580 /* initialize optional values */
2582 *copy_rev = SVN_INVALID_REVNUM;
2584 *text_mods = SVN_RA_SVN_UNSPECIFIED_NUMBER;
2585 *prop_mods = SVN_RA_SVN_UNSPECIFIED_NUMBER;
2587 /* top-level elements (mandatory) */
2588 SVN_ERR(svn_ra_svn__read_check_array_size(items, 3, INT_MAX));
2589 SVN_ERR(svn_ra_svn__read_string(items, 0, cpath));
2590 SVN_ERR(svn_ra_svn__read_word(items, 1, action));
2592 /* first sub-structure (mandatory) */
2593 SVN_ERR(svn_ra_svn__read_list(items, 2, &sub_items));
2594 if (sub_items->nelts)
2596 SVN_ERR(svn_ra_svn__read_check_array_size(sub_items, 2, 2));
2597 SVN_ERR(svn_ra_svn__read_cstring(sub_items, 0, copy_path));
2598 SVN_ERR(svn_ra_svn__read_revision(sub_items, 1, copy_rev));
2601 /* second sub-structure (optional) */
2602 if (items->nelts >= 4)
2604 SVN_ERR(svn_ra_svn__read_list(items, 3, &sub_items));
2605 switch (MIN(3, sub_items->nelts))
2607 case 3 : SVN_ERR(svn_ra_svn__read_boolean(sub_items, 2, prop_mods));
2608 case 2 : SVN_ERR(svn_ra_svn__read_boolean(sub_items, 1, text_mods));
2609 case 1 : SVN_ERR(svn_ra_svn__read_cstring(sub_items, 0, kind_str));
2614 return SVN_NO_ERROR;