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;
948 /* We can't store strings longer than the maximum size of apr_size_t,
949 * so check for wrapping */
950 if (len64 > APR_SIZE_MAX)
951 return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
952 _("String length larger than maximum"));
954 /* Shorter strings can be copied directly from the read buffer. */
955 if (conn->read_ptr + len <= conn->read_end)
957 item->kind = SVN_RA_SVN_STRING;
958 item->u.string = svn_string_ncreate(conn->read_ptr, len, pool);
959 conn->read_ptr += len;
963 /* Read the string in chunks. The chunk size is large enough to avoid
964 * re-allocation in typical cases, and small enough to ensure we do
965 * not pre-allocate an unreasonable amount of memory if (perhaps due
966 * to network data corruption or a DOS attack), we receive a bogus
967 * claim that a very long string is going to follow. In that case, we
968 * start small and wait for all that data to actually show up. This
969 * does not fully prevent DOS attacks but makes them harder (you have
970 * to actually send gigabytes of data). */
971 svn_stringbuf_t *stringbuf = svn_stringbuf_create_empty(pool);
973 /* Read string data directly into the string structure.
974 * Do it iteratively. */
977 /* Determine length of chunk to read and re-alloc the buffer. */
979 = len < SUSPICIOUSLY_HUGE_STRING_SIZE_THRESHOLD
981 : SUSPICIOUSLY_HUGE_STRING_SIZE_THRESHOLD;
983 svn_stringbuf_ensure(stringbuf, stringbuf->len + readbuf_len);
984 dest = stringbuf->data + stringbuf->len;
986 /* read data & update length info */
987 SVN_ERR(readbuf_read(conn, pool, dest, readbuf_len));
989 stringbuf->len += readbuf_len;
994 /* zero-terminate the string */
995 stringbuf->data[stringbuf->len] = '\0';
997 /* Return the string properly wrapped into an RA_SVN item. */
998 item->kind = SVN_RA_SVN_STRING;
999 item->u.string = svn_stringbuf__morph_into_string(stringbuf);
1002 return SVN_NO_ERROR;
1005 /* Given the first non-whitespace character FIRST_CHAR, read an item
1006 * into the already allocated structure ITEM. LEVEL should be set
1007 * to 0 for the first call and is used to enforce a recursion limit
1009 static svn_error_t *read_item(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
1010 svn_ra_svn_item_t *item, char first_char,
1013 char c = first_char;
1015 svn_ra_svn_item_t *listitem;
1017 if (++level >= ITEM_NESTING_LIMIT)
1018 return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
1019 _("Items are nested too deeply"));
1022 /* Determine the item type and read it in. Make sure that c is the
1023 * first character at the end of the item so we can test to make
1024 * sure it's whitespace. */
1025 if (svn_ctype_isdigit(c))
1027 /* It's a number or a string. Read the number part, either way. */
1031 apr_uint64_t prev_val = val;
1032 SVN_ERR(readbuf_getchar(conn, pool, &c));
1033 if (!svn_ctype_isdigit(c))
1035 val = val * 10 + (c - '0');
1036 /* val wrapped past maximum value? */
1037 if ((prev_val >= (APR_UINT64_MAX / 10))
1038 && (val < APR_UINT64_MAX - 10))
1039 return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
1040 _("Number is larger than maximum"));
1044 /* It's a string. */
1045 SVN_ERR(read_string(conn, pool, item, val));
1046 SVN_ERR(readbuf_getchar(conn, pool, &c));
1050 /* It's a number. */
1051 item->kind = SVN_RA_SVN_NUMBER;
1052 item->u.number = val;
1055 else if (svn_ctype_isalpha(c))
1057 /* It's a word. Read it into a buffer of limited size. */
1058 char *buffer = apr_palloc(pool, MAX_WORD_LENGTH + 1);
1059 char *end = buffer + MAX_WORD_LENGTH;
1060 char *p = buffer + 1;
1065 SVN_ERR(readbuf_getchar(conn, pool, p));
1066 if (!svn_ctype_isalnum(*p) && *p != '-')
1070 return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
1071 _("Word is too long"));
1077 item->kind = SVN_RA_SVN_WORD;
1078 item->u.word = buffer;
1082 /* Read in the list items. */
1083 item->kind = SVN_RA_SVN_LIST;
1084 item->u.list = apr_array_make(pool, 4, sizeof(svn_ra_svn_item_t));
1087 SVN_ERR(readbuf_getchar_skip_whitespace(conn, pool, &c));
1090 listitem = apr_array_push(item->u.list);
1091 SVN_ERR(read_item(conn, pool, listitem, c, level));
1093 SVN_ERR(readbuf_getchar(conn, pool, &c));
1096 if (!svn_iswhitespace(c))
1097 return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
1098 _("Malformed network data"));
1099 return SVN_NO_ERROR;
1102 /* Given the first non-whitespace character FIRST_CHAR, read the first
1103 * command (word) encountered in CONN into *ITEM. If ITEM is NULL, skip
1104 * to the end of the current list. Use POOL for allocations. */
1105 static svn_error_t *
1106 read_command_only(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
1107 const char **item, char first_char)
1109 char c = first_char;
1111 /* Determine the item type and read it in. Make sure that c is the
1112 * first character at the end of the item so we can test to make
1113 * sure it's whitespace. */
1114 if (svn_ctype_isdigit(c))
1116 /* It's a number or a string. Read the number part, either way. */
1117 apr_uint64_t val, prev_val=0;
1122 SVN_ERR(readbuf_getchar(conn, pool, &c));
1123 if (!svn_ctype_isdigit(c))
1125 val = val * 10 + (c - '0');
1126 if (prev_val >= (APR_UINT64_MAX / 10)) /* > maximum value? */
1127 return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
1128 _("Number is larger than maximum"));
1132 /* It's a string. */
1133 SVN_ERR(readbuf_skip(conn, val));
1134 SVN_ERR(readbuf_getchar(conn, pool, &c));
1137 else if (svn_ctype_isalpha(c))
1142 /* This is the word we want to read */
1144 char *buf = apr_palloc(pool, 32);
1150 SVN_ERR(readbuf_getchar(conn, pool, &c));
1151 if (!svn_ctype_isalnum(c) && c != '-')
1155 return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
1156 _("Word too long"));
1163 /* we don't need the actual word, just skip it */
1166 SVN_ERR(readbuf_getchar(conn, pool, &c));
1168 while (svn_ctype_isalnum(c) || c == '-');
1173 /* Read in the list items. */
1176 SVN_ERR(readbuf_getchar_skip_whitespace(conn, pool, &c));
1180 if (item && *item == NULL)
1181 SVN_ERR(read_command_only(conn, pool, item, c));
1183 SVN_ERR(read_command_only(conn, pool, NULL, c));
1185 SVN_ERR(readbuf_getchar(conn, pool, &c));
1188 return SVN_NO_ERROR;
1192 svn_ra_svn__read_item(svn_ra_svn_conn_t *conn,
1194 svn_ra_svn_item_t **item)
1198 /* Allocate space, read the first character, and then do the rest of
1199 * the work. This makes sense because of the way lists are read. */
1200 *item = apr_palloc(pool, sizeof(**item));
1201 SVN_ERR(readbuf_getchar_skip_whitespace(conn, pool, &c));
1202 return read_item(conn, pool, *item, c, 0);
1205 /* Drain existing whitespace from the receive buffer of CONN until either
1206 there is no data in the underlying receive socket anymore or we found
1207 a non-whitespace char. Set *HAS_ITEM to TRUE in the latter case.
1209 static svn_error_t *
1210 svn_ra_svn__has_item(svn_boolean_t *has_item,
1211 svn_ra_svn_conn_t *conn,
1216 if (conn->read_ptr == conn->read_end)
1218 svn_boolean_t available;
1219 if (conn->write_pos)
1220 SVN_ERR(writebuf_flush(conn, pool));
1222 SVN_ERR(svn_ra_svn__data_available(conn, &available));
1226 SVN_ERR(readbuf_fill(conn, pool));
1229 while (svn_iswhitespace(*conn->read_ptr) && ++conn->read_ptr);
1231 *has_item = conn->read_ptr != conn->read_end;
1232 return SVN_NO_ERROR;
1236 svn_ra_svn__skip_leading_garbage(svn_ra_svn_conn_t *conn,
1239 return readbuf_skip_leading_garbage(conn, pool);
1242 /* --- READING AND PARSING TUPLES --- */
1244 /* Parse a tuple of svn_ra_svn_item_t *'s. Advance *FMT to the end of the
1245 * tuple specification and advance AP by the corresponding arguments. */
1246 static svn_error_t *vparse_tuple(const apr_array_header_t *items, apr_pool_t *pool,
1247 const char **fmt, va_list *ap)
1249 int count, nesting_level;
1250 svn_ra_svn_item_t *elt;
1252 for (count = 0; **fmt && count < items->nelts; (*fmt)++, count++)
1254 /* '?' just means the tuple may stop; skip past it. */
1257 elt = &APR_ARRAY_IDX(items, count, svn_ra_svn_item_t);
1258 if (**fmt == '(' && elt->kind == SVN_RA_SVN_LIST)
1261 SVN_ERR(vparse_tuple(elt->u.list, pool, fmt, ap));
1263 else if (**fmt == 'c' && elt->kind == SVN_RA_SVN_STRING)
1264 *va_arg(*ap, const char **) = elt->u.string->data;
1265 else if (**fmt == 's' && elt->kind == SVN_RA_SVN_STRING)
1266 *va_arg(*ap, svn_string_t **) = elt->u.string;
1267 else if (**fmt == 'w' && elt->kind == SVN_RA_SVN_WORD)
1268 *va_arg(*ap, const char **) = elt->u.word;
1269 else if (**fmt == 'b' && elt->kind == SVN_RA_SVN_WORD)
1271 if (strcmp(elt->u.word, "true") == 0)
1272 *va_arg(*ap, svn_boolean_t *) = TRUE;
1273 else if (strcmp(elt->u.word, "false") == 0)
1274 *va_arg(*ap, svn_boolean_t *) = FALSE;
1278 else if (**fmt == 'n' && elt->kind == SVN_RA_SVN_NUMBER)
1279 *va_arg(*ap, apr_uint64_t *) = elt->u.number;
1280 else if (**fmt == 'r' && elt->kind == SVN_RA_SVN_NUMBER)
1281 *va_arg(*ap, svn_revnum_t *) = (svn_revnum_t) elt->u.number;
1282 else if (**fmt == 'B' && elt->kind == SVN_RA_SVN_WORD)
1284 if (strcmp(elt->u.word, "true") == 0)
1285 *va_arg(*ap, apr_uint64_t *) = TRUE;
1286 else if (strcmp(elt->u.word, "false") == 0)
1287 *va_arg(*ap, apr_uint64_t *) = FALSE;
1291 else if (**fmt == '3' && elt->kind == SVN_RA_SVN_WORD)
1293 if (strcmp(elt->u.word, "true") == 0)
1294 *va_arg(*ap, svn_tristate_t *) = svn_tristate_true;
1295 else if (strcmp(elt->u.word, "false") == 0)
1296 *va_arg(*ap, svn_tristate_t *) = svn_tristate_false;
1300 else if (**fmt == 'l' && elt->kind == SVN_RA_SVN_LIST)
1301 *va_arg(*ap, apr_array_header_t **) = elt->u.list;
1302 else if (**fmt == ')')
1303 return SVN_NO_ERROR;
1310 for (; **fmt; (*fmt)++)
1317 *va_arg(*ap, svn_revnum_t *) = SVN_INVALID_REVNUM;
1320 *va_arg(*ap, svn_string_t **) = NULL;
1324 *va_arg(*ap, const char **) = NULL;
1327 *va_arg(*ap, apr_array_header_t **) = NULL;
1331 *va_arg(*ap, apr_uint64_t *) = SVN_RA_SVN_UNSPECIFIED_NUMBER;
1334 *va_arg(*ap, svn_tristate_t *) = svn_tristate_unknown;
1340 if (--nesting_level < 0)
1341 return SVN_NO_ERROR;
1344 SVN_ERR_MALFUNCTION();
1348 if (**fmt && **fmt != ')')
1349 return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
1350 _("Malformed network data"));
1351 return SVN_NO_ERROR;
1355 svn_ra_svn__parse_tuple(const apr_array_header_t *list,
1357 const char *fmt, ...)
1363 err = vparse_tuple(list, pool, &fmt, &ap);
1369 svn_ra_svn__read_tuple(svn_ra_svn_conn_t *conn,
1371 const char *fmt, ...)
1374 svn_ra_svn_item_t *item;
1377 SVN_ERR(svn_ra_svn__read_item(conn, pool, &item));
1378 if (item->kind != SVN_RA_SVN_LIST)
1379 return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
1380 _("Malformed network data"));
1382 err = vparse_tuple(item->u.list, pool, &fmt, &ap);
1388 svn_ra_svn__read_command_only(svn_ra_svn_conn_t *conn,
1390 const char **command)
1393 SVN_ERR(readbuf_getchar_skip_whitespace(conn, pool, &c));
1396 return read_command_only(conn, pool, command, c);
1401 svn_ra_svn__parse_proplist(const apr_array_header_t *list,
1406 svn_string_t *value;
1407 svn_ra_svn_item_t *elt;
1410 *props = svn_hash__make(pool);
1411 for (i = 0; i < list->nelts; i++)
1413 elt = &APR_ARRAY_IDX(list, i, svn_ra_svn_item_t);
1414 if (elt->kind != SVN_RA_SVN_LIST)
1415 return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
1416 _("Proplist element not a list"));
1417 SVN_ERR(svn_ra_svn__parse_tuple(elt->u.list, pool, "ss",
1419 apr_hash_set(*props, name->data, name->len, value);
1422 return SVN_NO_ERROR;
1426 /* --- READING AND WRITING COMMANDS AND RESPONSES --- */
1428 svn_error_t *svn_ra_svn__locate_real_error_child(svn_error_t *err)
1430 svn_error_t *this_link;
1432 SVN_ERR_ASSERT(err);
1434 for (this_link = err;
1435 this_link && (this_link->apr_err == SVN_ERR_RA_SVN_CMD_ERR);
1436 this_link = this_link->child)
1439 SVN_ERR_ASSERT(this_link);
1443 svn_error_t *svn_ra_svn__handle_failure_status(const apr_array_header_t *params,
1446 const char *message, *file;
1447 svn_error_t *err = NULL;
1448 svn_ra_svn_item_t *elt;
1450 apr_uint64_t apr_err, line;
1451 apr_pool_t *subpool = svn_pool_create(pool);
1453 if (params->nelts == 0)
1454 return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
1455 _("Empty error list"));
1457 /* Rebuild the error list from the end, to avoid reversing the order. */
1458 for (i = params->nelts - 1; i >= 0; i--)
1460 svn_pool_clear(subpool);
1461 elt = &APR_ARRAY_IDX(params, i, svn_ra_svn_item_t);
1462 if (elt->kind != SVN_RA_SVN_LIST)
1463 return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
1464 _("Malformed error list"));
1465 SVN_ERR(svn_ra_svn__parse_tuple(elt->u.list, subpool, "nccn",
1466 &apr_err, &message, &file, &line));
1467 /* The message field should have been optional, but we can't
1468 easily change that, so "" means a nonexistent message. */
1472 /* Skip over links in the error chain that were intended only to
1473 exist on the server (to wrap real errors intended for the
1474 client) but accidentally got included in the server's actual
1476 if ((apr_status_t)apr_err != SVN_ERR_RA_SVN_CMD_ERR)
1478 err = svn_error_create((apr_status_t)apr_err, err, message);
1479 err->file = apr_pstrdup(err->pool, file);
1480 err->line = (long)line;
1484 svn_pool_destroy(subpool);
1486 /* If we get here, then we failed to find a real error in the error
1487 chain that the server proported to be sending us. That's bad. */
1489 err = svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
1490 _("Malformed error list"));
1496 svn_ra_svn__read_cmd_response(svn_ra_svn_conn_t *conn,
1498 const char *fmt, ...)
1502 apr_array_header_t *params;
1505 SVN_ERR(svn_ra_svn__read_tuple(conn, pool, "wl", &status, ¶ms));
1506 if (strcmp(status, "success") == 0)
1509 err = vparse_tuple(params, pool, &fmt, &ap);
1513 else if (strcmp(status, "failure") == 0)
1515 return svn_error_trace(svn_ra_svn__handle_failure_status(params, pool));
1518 return svn_error_createf(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
1519 _("Unknown status '%s' in command response"),
1524 svn_ra_svn__has_command(svn_boolean_t *has_command,
1525 svn_boolean_t *terminated,
1526 svn_ra_svn_conn_t *conn,
1529 svn_error_t *err = svn_ra_svn__has_item(has_command, conn, pool);
1530 if (err && err->apr_err == SVN_ERR_RA_SVN_CONNECTION_CLOSED)
1533 svn_error_clear(err);
1534 return SVN_NO_ERROR;
1537 *terminated = FALSE;
1538 return svn_error_trace(err);
1542 svn_ra_svn__handle_command(svn_boolean_t *terminate,
1543 apr_hash_t *cmd_hash,
1545 svn_ra_svn_conn_t *conn,
1546 svn_boolean_t error_on_disconnect,
1549 const char *cmdname;
1550 svn_error_t *err, *write_err;
1551 apr_array_header_t *params;
1552 const svn_ra_svn_cmd_entry_t *command;
1555 err = svn_ra_svn__read_tuple(conn, pool, "wl", &cmdname, ¶ms);
1558 if (!error_on_disconnect
1559 && err->apr_err == SVN_ERR_RA_SVN_CONNECTION_CLOSED)
1561 svn_error_clear(err);
1563 return SVN_NO_ERROR;
1568 command = svn_hash_gets(cmd_hash, cmdname);
1571 err = (*command->handler)(conn, pool, params, baton);
1572 *terminate = command->terminate;
1576 err = svn_error_createf(SVN_ERR_RA_SVN_UNKNOWN_CMD, NULL,
1577 _("Unknown editor command '%s'"), cmdname);
1578 err = svn_error_create(SVN_ERR_RA_SVN_CMD_ERR, err, NULL);
1581 if (err && err->apr_err == SVN_ERR_RA_SVN_CMD_ERR)
1583 write_err = svn_ra_svn__write_cmd_failure(
1585 svn_ra_svn__locate_real_error_child(err));
1586 svn_error_clear(err);
1587 return write_err ? write_err : SVN_NO_ERROR;
1594 svn_ra_svn__handle_commands2(svn_ra_svn_conn_t *conn,
1596 const svn_ra_svn_cmd_entry_t *commands,
1598 svn_boolean_t error_on_disconnect)
1600 apr_pool_t *subpool = svn_pool_create(pool);
1601 apr_pool_t *iterpool = svn_pool_create(subpool);
1602 const svn_ra_svn_cmd_entry_t *command;
1603 apr_hash_t *cmd_hash = apr_hash_make(subpool);
1605 for (command = commands; command->cmdname; command++)
1606 svn_hash_sets(cmd_hash, command->cmdname, command);
1610 svn_boolean_t terminate;
1612 svn_pool_clear(iterpool);
1614 err = svn_ra_svn__handle_command(&terminate, cmd_hash, baton, conn,
1615 error_on_disconnect, iterpool);
1618 svn_pool_destroy(subpool);
1619 return svn_error_trace(err);
1624 svn_pool_destroy(iterpool);
1625 svn_pool_destroy(subpool);
1626 return SVN_NO_ERROR;
1630 svn_ra_svn__write_cmd_target_rev(svn_ra_svn_conn_t *conn,
1634 SVN_ERR(writebuf_write_literal(conn, pool, "( target-rev ( "));
1635 SVN_ERR(write_tuple_revision(conn, pool, rev));
1636 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
1638 return SVN_NO_ERROR;
1642 svn_ra_svn__write_cmd_open_root(svn_ra_svn_conn_t *conn,
1647 SVN_ERR(writebuf_write_literal(conn, pool, "( open-root ( "));
1648 SVN_ERR(write_tuple_start_list(conn, pool));
1649 SVN_ERR(write_tuple_revision_opt(conn, pool, rev));
1650 SVN_ERR(write_tuple_end_list(conn, pool));
1651 SVN_ERR(write_tuple_cstring(conn, pool, token));
1652 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
1654 return SVN_NO_ERROR;
1658 svn_ra_svn__write_cmd_delete_entry(svn_ra_svn_conn_t *conn,
1664 SVN_ERR(writebuf_write_literal(conn, pool, "( delete-entry ( "));
1665 SVN_ERR(write_tuple_cstring(conn, pool, path));
1666 SVN_ERR(write_tuple_start_list(conn, pool));
1667 SVN_ERR(write_tuple_revision_opt(conn, pool, rev));
1668 SVN_ERR(write_tuple_end_list(conn, pool));
1669 SVN_ERR(write_tuple_cstring(conn, pool, token));
1670 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
1672 return SVN_NO_ERROR;
1676 svn_ra_svn__write_cmd_add_dir(svn_ra_svn_conn_t *conn,
1679 const char *parent_token,
1681 const char *copy_path,
1682 svn_revnum_t copy_rev)
1684 SVN_ERR(writebuf_write_literal(conn, pool, "( add-dir ( "));
1685 SVN_ERR(write_cmd_add_node(conn, pool, path, parent_token, token,
1686 copy_path, copy_rev));
1687 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
1689 return SVN_NO_ERROR;
1693 svn_ra_svn__write_cmd_open_dir(svn_ra_svn_conn_t *conn,
1696 const char *parent_token,
1700 SVN_ERR(writebuf_write_literal(conn, pool, "( open-dir ( "));
1701 SVN_ERR(write_cmd_open_node(conn, pool, path, parent_token, token, rev));
1702 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
1704 return SVN_NO_ERROR;
1708 svn_ra_svn__write_cmd_change_dir_prop(svn_ra_svn_conn_t *conn,
1712 const svn_string_t *value)
1714 SVN_ERR(writebuf_write_literal(conn, pool, "( change-dir-prop ( "));
1715 SVN_ERR(write_cmd_change_node_prop(conn, pool, token, name, value));
1716 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
1718 return SVN_NO_ERROR;
1722 svn_ra_svn__write_cmd_close_dir(svn_ra_svn_conn_t *conn,
1726 SVN_ERR(writebuf_write_literal(conn, pool, "( close-dir ( "));
1727 SVN_ERR(write_tuple_cstring(conn, pool, token));
1728 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
1730 return SVN_NO_ERROR;
1734 svn_ra_svn__write_cmd_absent_dir(svn_ra_svn_conn_t *conn,
1737 const char *parent_token)
1739 SVN_ERR(writebuf_write_literal(conn, pool, "( absent-dir ( "));
1740 SVN_ERR(write_cmd_absent_node(conn, pool, path, parent_token));
1741 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
1743 return SVN_NO_ERROR;
1747 svn_ra_svn__write_cmd_add_file(svn_ra_svn_conn_t *conn,
1750 const char *parent_token,
1752 const char *copy_path,
1753 svn_revnum_t copy_rev)
1755 SVN_ERR(writebuf_write_literal(conn, pool, "( add-file ( "));
1756 SVN_ERR(write_cmd_add_node(conn, pool, path, parent_token, token,
1757 copy_path, copy_rev));
1758 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
1760 return SVN_NO_ERROR;
1764 svn_ra_svn__write_cmd_open_file(svn_ra_svn_conn_t *conn,
1767 const char *parent_token,
1771 SVN_ERR(writebuf_write_literal(conn, pool, "( open-file ( "));
1772 SVN_ERR(write_cmd_open_node(conn, pool, path, parent_token, token, rev));
1773 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
1775 return SVN_NO_ERROR;
1779 svn_ra_svn__write_cmd_change_file_prop(svn_ra_svn_conn_t *conn,
1783 const svn_string_t *value)
1785 SVN_ERR(writebuf_write_literal(conn, pool, "( change-file-prop ( "));
1786 SVN_ERR(write_cmd_change_node_prop(conn, pool, token, name, value));
1787 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
1789 return SVN_NO_ERROR;
1793 svn_ra_svn__write_cmd_close_file(svn_ra_svn_conn_t *conn,
1796 const char *text_checksum)
1798 SVN_ERR(writebuf_write_literal(conn, pool, "( close-file ( "));
1799 SVN_ERR(write_tuple_cstring(conn, pool, token));
1800 SVN_ERR(write_tuple_start_list(conn, pool));
1801 SVN_ERR(write_tuple_cstring_opt(conn, pool, text_checksum));
1802 SVN_ERR(write_tuple_end_list(conn, pool));
1803 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
1805 return SVN_NO_ERROR;
1809 svn_ra_svn__write_cmd_absent_file(svn_ra_svn_conn_t *conn,
1812 const char *parent_token)
1814 SVN_ERR(writebuf_write_literal(conn, pool, "( absent-file ( "));
1815 SVN_ERR(write_cmd_absent_node(conn, pool, path, parent_token));
1816 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
1818 return SVN_NO_ERROR;
1822 svn_ra_svn__write_cmd_textdelta_chunk(svn_ra_svn_conn_t *conn,
1825 const svn_string_t *chunk)
1827 SVN_ERR(writebuf_write_literal(conn, pool, "( textdelta-chunk ( "));
1828 SVN_ERR(write_tuple_cstring(conn, pool, token));
1829 SVN_ERR(write_tuple_string(conn, pool, chunk));
1830 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
1832 return SVN_NO_ERROR;
1836 svn_ra_svn__write_cmd_textdelta_end(svn_ra_svn_conn_t *conn,
1840 SVN_ERR(writebuf_write_literal(conn, pool, "( textdelta-end ( "));
1841 SVN_ERR(write_tuple_cstring(conn, pool, token));
1842 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
1844 return SVN_NO_ERROR;
1848 svn_ra_svn__write_cmd_apply_textdelta(svn_ra_svn_conn_t *conn,
1851 const char *base_checksum)
1853 SVN_ERR(writebuf_write_literal(conn, pool, "( apply-textdelta ( "));
1854 SVN_ERR(write_tuple_cstring(conn, pool, token));
1855 SVN_ERR(write_tuple_start_list(conn, pool));
1856 SVN_ERR(write_tuple_cstring_opt(conn, pool, base_checksum));
1857 SVN_ERR(write_tuple_end_list(conn, pool));
1858 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
1860 return SVN_NO_ERROR;
1864 svn_ra_svn__write_cmd_close_edit(svn_ra_svn_conn_t *conn,
1867 return writebuf_write_literal(conn, pool, "( close-edit ( ) ) ");
1871 svn_ra_svn__write_cmd_abort_edit(svn_ra_svn_conn_t *conn,
1874 return writebuf_write_literal(conn, pool, "( abort-edit ( ) ) ");
1878 svn_ra_svn__write_cmd_set_path(svn_ra_svn_conn_t *conn,
1882 svn_boolean_t start_empty,
1883 const char *lock_token,
1886 SVN_ERR(writebuf_write_literal(conn, pool, "( set-path ( "));
1887 SVN_ERR(write_tuple_cstring(conn, pool, path));
1888 SVN_ERR(write_tuple_revision(conn, pool, rev));
1889 SVN_ERR(write_tuple_boolean(conn, pool, start_empty));
1890 SVN_ERR(write_tuple_start_list(conn, pool));
1891 SVN_ERR(write_tuple_cstring_opt(conn, pool, lock_token));
1892 SVN_ERR(write_tuple_end_list(conn, pool));
1893 SVN_ERR(write_tuple_depth(conn, pool, depth));
1894 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
1896 return SVN_NO_ERROR;
1900 svn_ra_svn__write_cmd_delete_path(svn_ra_svn_conn_t *conn,
1904 SVN_ERR(writebuf_write_literal(conn, pool, "( delete-path ( "));
1905 SVN_ERR(write_tuple_cstring(conn, pool, path));
1906 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
1908 return SVN_NO_ERROR;
1912 svn_ra_svn__write_cmd_link_path(svn_ra_svn_conn_t *conn,
1917 svn_boolean_t start_empty,
1918 const char *lock_token,
1921 SVN_ERR(writebuf_write_literal(conn, pool, "( link-path ( "));
1922 SVN_ERR(write_tuple_cstring(conn, pool, path));
1923 SVN_ERR(write_tuple_cstring(conn, pool, url));
1924 SVN_ERR(write_tuple_revision(conn, pool, rev));
1925 SVN_ERR(write_tuple_boolean(conn, pool, start_empty));
1926 SVN_ERR(write_tuple_start_list(conn, pool));
1927 SVN_ERR(write_tuple_cstring_opt(conn, pool,lock_token));
1928 SVN_ERR(write_tuple_end_list(conn, pool));
1929 SVN_ERR(write_tuple_depth(conn, pool, depth));
1930 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
1932 return SVN_NO_ERROR;
1936 svn_ra_svn__write_cmd_finish_report(svn_ra_svn_conn_t *conn,
1939 return writebuf_write_literal(conn, pool, "( finish-report ( ) ) ");
1943 svn_ra_svn__write_cmd_abort_report(svn_ra_svn_conn_t *conn,
1946 return writebuf_write_literal(conn, pool, "( abort-report ( ) ) ");
1950 svn_ra_svn__write_cmd_reparent(svn_ra_svn_conn_t *conn,
1954 SVN_ERR(writebuf_write_literal(conn, pool, "( reparent ( "));
1955 SVN_ERR(write_tuple_cstring(conn, pool, url));
1956 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
1958 return SVN_NO_ERROR;
1962 svn_ra_svn__write_cmd_get_latest_rev(svn_ra_svn_conn_t *conn,
1965 return writebuf_write_literal(conn, pool, "( get-latest-rev ( ) ) ");
1969 svn_ra_svn__write_cmd_get_dated_rev(svn_ra_svn_conn_t *conn,
1973 SVN_ERR(writebuf_write_literal(conn, pool, "( get-dated-rev ( "));
1974 SVN_ERR(write_tuple_cstring(conn, pool, svn_time_to_cstring(tm, pool)));
1975 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
1977 return SVN_NO_ERROR;
1981 svn_ra_svn__write_cmd_change_rev_prop2(svn_ra_svn_conn_t *conn,
1985 const svn_string_t *value,
1986 svn_boolean_t dont_care,
1987 const svn_string_t *old_value)
1989 SVN_ERR(writebuf_write_literal(conn, pool, "( change-rev-prop2 ( "));
1990 SVN_ERR(write_tuple_revision(conn, pool, rev));
1991 SVN_ERR(write_tuple_cstring(conn, pool, name));
1992 SVN_ERR(write_tuple_start_list(conn, pool));
1993 SVN_ERR(write_tuple_string_opt(conn, pool, value));
1994 SVN_ERR(write_tuple_end_list(conn, pool));
1995 SVN_ERR(write_tuple_start_list(conn, pool));
1996 SVN_ERR(write_tuple_boolean(conn, pool, dont_care));
1997 SVN_ERR(write_tuple_string_opt(conn, pool, old_value));
1998 SVN_ERR(write_tuple_end_list(conn, pool));
1999 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
2001 return SVN_NO_ERROR;
2005 svn_ra_svn__write_cmd_change_rev_prop(svn_ra_svn_conn_t *conn,
2009 const svn_string_t *value)
2011 SVN_ERR(writebuf_write_literal(conn, pool, "( change-rev-prop ( "));
2012 SVN_ERR(write_tuple_revision(conn, pool, rev));
2013 SVN_ERR(write_tuple_cstring(conn, pool, name));
2014 SVN_ERR(write_tuple_string_opt(conn, pool, value));
2015 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
2017 return SVN_NO_ERROR;
2021 svn_ra_svn__write_cmd_rev_proplist(svn_ra_svn_conn_t *conn,
2025 SVN_ERR(writebuf_write_literal(conn, pool, "( rev-proplist ( "));
2026 SVN_ERR(write_tuple_revision(conn, pool, rev));
2027 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
2029 return SVN_NO_ERROR;
2033 svn_ra_svn__write_cmd_rev_prop(svn_ra_svn_conn_t *conn,
2038 SVN_ERR(writebuf_write_literal(conn, pool, "( rev-prop ( "));
2039 SVN_ERR(write_tuple_revision(conn, pool, rev));
2040 SVN_ERR(write_tuple_cstring(conn, pool, name));
2041 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
2043 return SVN_NO_ERROR;
2047 svn_ra_svn__write_cmd_get_file(svn_ra_svn_conn_t *conn,
2051 svn_boolean_t props,
2052 svn_boolean_t stream)
2054 SVN_ERR(writebuf_write_literal(conn, pool, "( get-file ( "));
2055 SVN_ERR(write_tuple_cstring(conn, pool, path));
2056 SVN_ERR(write_tuple_start_list(conn, pool));
2057 SVN_ERR(write_tuple_revision_opt(conn, pool, rev));
2058 SVN_ERR(write_tuple_end_list(conn, pool));
2059 SVN_ERR(write_tuple_boolean(conn, pool, props));
2060 SVN_ERR(write_tuple_boolean(conn, pool, stream));
2062 /* Always send the, nominally optional, want-iprops as "false" to
2063 workaround a bug in svnserve 1.8.0-1.8.8 that causes the server
2064 to see "true" if it is omitted. */
2065 SVN_ERR(writebuf_write_literal(conn, pool, " false ) ) "));
2067 return SVN_NO_ERROR;
2071 svn_ra_svn__write_cmd_update(svn_ra_svn_conn_t *conn,
2075 svn_boolean_t recurse,
2077 svn_boolean_t send_copyfrom_args,
2078 svn_boolean_t ignore_ancestry)
2080 SVN_ERR(writebuf_write_literal(conn, pool, "( update ( "));
2081 SVN_ERR(write_tuple_start_list(conn, pool));
2082 SVN_ERR(write_tuple_revision_opt(conn, pool, rev));
2083 SVN_ERR(write_tuple_end_list(conn, pool));
2084 SVN_ERR(write_tuple_cstring(conn, pool, target));
2085 SVN_ERR(write_tuple_boolean(conn, pool, recurse));
2086 SVN_ERR(write_tuple_depth(conn, pool, depth));
2087 SVN_ERR(write_tuple_boolean(conn, pool, send_copyfrom_args));
2088 SVN_ERR(write_tuple_boolean(conn, pool, ignore_ancestry));
2089 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
2091 return SVN_NO_ERROR;
2095 svn_ra_svn__write_cmd_switch(svn_ra_svn_conn_t *conn,
2099 svn_boolean_t recurse,
2100 const char *switch_url,
2102 svn_boolean_t send_copyfrom_args,
2103 svn_boolean_t ignore_ancestry)
2105 SVN_ERR(writebuf_write_literal(conn, pool, "( switch ( "));
2106 SVN_ERR(write_tuple_start_list(conn, pool));
2107 SVN_ERR(write_tuple_revision_opt(conn, pool, rev));
2108 SVN_ERR(write_tuple_end_list(conn, pool));
2109 SVN_ERR(write_tuple_cstring(conn, pool, target));
2110 SVN_ERR(write_tuple_boolean(conn, pool, recurse));
2111 SVN_ERR(write_tuple_cstring(conn, pool, switch_url));
2112 SVN_ERR(write_tuple_depth(conn, pool, depth));
2113 SVN_ERR(write_tuple_boolean(conn, pool, send_copyfrom_args));
2114 SVN_ERR(write_tuple_boolean(conn, pool, ignore_ancestry));
2115 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
2117 return SVN_NO_ERROR;
2121 svn_ra_svn__write_cmd_status(svn_ra_svn_conn_t *conn,
2124 svn_boolean_t recurse,
2128 SVN_ERR(writebuf_write_literal(conn, pool, "( status ( "));
2129 SVN_ERR(write_tuple_cstring(conn, pool, target));
2130 SVN_ERR(write_tuple_boolean(conn, pool, recurse));
2131 SVN_ERR(write_tuple_start_list(conn, pool));
2132 SVN_ERR(write_tuple_revision_opt(conn, pool, rev));
2133 SVN_ERR(write_tuple_end_list(conn, pool));
2134 SVN_ERR(write_tuple_depth(conn, pool, depth));
2135 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
2137 return SVN_NO_ERROR;
2141 svn_ra_svn__write_cmd_diff(svn_ra_svn_conn_t *conn,
2145 svn_boolean_t recurse,
2146 svn_boolean_t ignore_ancestry,
2147 const char *versus_url,
2148 svn_boolean_t text_deltas,
2151 SVN_ERR(writebuf_write_literal(conn, pool, "( diff ( "));
2152 SVN_ERR(write_tuple_start_list(conn, pool));
2153 SVN_ERR(write_tuple_revision_opt(conn, pool, rev));
2154 SVN_ERR(write_tuple_end_list(conn, pool));
2155 SVN_ERR(write_tuple_cstring(conn, pool, target));
2156 SVN_ERR(write_tuple_boolean(conn, pool, recurse));
2157 SVN_ERR(write_tuple_boolean(conn, pool, ignore_ancestry));
2158 SVN_ERR(write_tuple_cstring(conn, pool, versus_url));
2159 SVN_ERR(write_tuple_boolean(conn, pool, text_deltas));
2160 SVN_ERR(write_tuple_depth(conn, pool, depth));
2161 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
2163 return SVN_NO_ERROR;
2167 svn_ra_svn__write_cmd_check_path(svn_ra_svn_conn_t *conn,
2172 SVN_ERR(writebuf_write_literal(conn, pool, "( check-path ( "));
2173 SVN_ERR(write_tuple_cstring(conn, pool, path));
2174 SVN_ERR(write_tuple_start_list(conn, pool));
2175 SVN_ERR(write_tuple_revision_opt(conn, pool, rev));
2176 SVN_ERR(write_tuple_end_list(conn, pool));
2177 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
2179 return SVN_NO_ERROR;
2183 svn_ra_svn__write_cmd_stat(svn_ra_svn_conn_t *conn,
2188 SVN_ERR(writebuf_write_literal(conn, pool, "( stat ( "));
2189 SVN_ERR(write_tuple_cstring(conn, pool, path));
2190 SVN_ERR(write_tuple_start_list(conn, pool));
2191 SVN_ERR(write_tuple_revision_opt(conn, pool, rev));
2192 SVN_ERR(write_tuple_end_list(conn, pool));
2193 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
2195 return SVN_NO_ERROR;
2199 svn_ra_svn__write_cmd_get_file_revs(svn_ra_svn_conn_t *conn,
2204 svn_boolean_t include_merged_revisions)
2206 SVN_ERR(writebuf_write_literal(conn, pool, "( get-file-revs ( "));
2207 SVN_ERR(write_tuple_cstring(conn, pool, path));
2208 SVN_ERR(write_tuple_start_list(conn, pool));
2209 SVN_ERR(write_tuple_revision_opt(conn, pool, start));
2210 SVN_ERR(write_tuple_end_list(conn, pool));
2211 SVN_ERR(write_tuple_start_list(conn, pool));
2212 SVN_ERR(write_tuple_revision_opt(conn, pool, end));
2213 SVN_ERR(write_tuple_end_list(conn, pool));
2214 SVN_ERR(write_tuple_boolean(conn, pool, include_merged_revisions));
2215 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
2217 return SVN_NO_ERROR;
2221 svn_ra_svn__write_cmd_lock(svn_ra_svn_conn_t *conn,
2224 const char *comment,
2225 svn_boolean_t steal_lock,
2226 svn_revnum_t revnum)
2228 SVN_ERR(writebuf_write_literal(conn, pool, "( lock ( "));
2229 SVN_ERR(write_tuple_cstring(conn, pool, path));
2230 SVN_ERR(write_tuple_start_list(conn, pool));
2231 SVN_ERR(write_tuple_cstring_opt(conn, pool, comment));
2232 SVN_ERR(write_tuple_end_list(conn, pool));
2233 SVN_ERR(write_tuple_boolean(conn, pool, steal_lock));
2234 SVN_ERR(write_tuple_start_list(conn, pool));
2235 SVN_ERR(write_tuple_revision_opt(conn, pool, revnum));
2236 SVN_ERR(write_tuple_end_list(conn, pool));
2237 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
2239 return SVN_NO_ERROR;
2243 svn_ra_svn__write_cmd_unlock(svn_ra_svn_conn_t *conn,
2247 svn_boolean_t break_lock)
2249 SVN_ERR(writebuf_write_literal(conn, pool, "( unlock ( "));
2250 SVN_ERR(write_tuple_cstring(conn, pool, path));
2251 SVN_ERR(write_tuple_start_list(conn, pool));
2252 SVN_ERR(write_tuple_cstring_opt(conn, pool, token));
2253 SVN_ERR(write_tuple_end_list(conn, pool));
2254 SVN_ERR(write_tuple_boolean(conn, pool, break_lock));
2255 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
2257 return SVN_NO_ERROR;
2261 svn_ra_svn__write_cmd_get_lock(svn_ra_svn_conn_t *conn,
2265 SVN_ERR(writebuf_write_literal(conn, pool, "( get-lock ( "));
2266 SVN_ERR(write_tuple_cstring(conn, pool, path));
2267 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
2269 return SVN_NO_ERROR;
2273 svn_ra_svn__write_cmd_get_locks(svn_ra_svn_conn_t *conn,
2278 SVN_ERR(writebuf_write_literal(conn, pool, "( get-locks ( "));
2279 SVN_ERR(write_tuple_cstring(conn, pool, path));
2280 SVN_ERR(write_tuple_start_list(conn, pool));
2281 SVN_ERR(write_tuple_depth(conn, pool, depth));
2282 SVN_ERR(write_tuple_end_list(conn, pool));
2283 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
2285 return SVN_NO_ERROR;
2289 svn_ra_svn__write_cmd_replay(svn_ra_svn_conn_t *conn,
2292 svn_revnum_t low_water_mark,
2293 svn_boolean_t send_deltas)
2295 SVN_ERR(writebuf_write_literal(conn, pool, "( replay ( "));
2296 SVN_ERR(write_tuple_revision(conn, pool, rev));
2297 SVN_ERR(write_tuple_revision(conn, pool, low_water_mark));
2298 SVN_ERR(write_tuple_boolean(conn, pool, send_deltas));
2299 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
2301 return SVN_NO_ERROR;
2305 svn_ra_svn__write_cmd_replay_range(svn_ra_svn_conn_t *conn,
2307 svn_revnum_t start_revision,
2308 svn_revnum_t end_revision,
2309 svn_revnum_t low_water_mark,
2310 svn_boolean_t send_deltas)
2312 SVN_ERR(writebuf_write_literal(conn, pool, "( replay-range ( "));
2313 SVN_ERR(write_tuple_revision(conn, pool, start_revision));
2314 SVN_ERR(write_tuple_revision(conn, pool, end_revision));
2315 SVN_ERR(write_tuple_revision(conn, pool, low_water_mark));
2316 SVN_ERR(write_tuple_boolean(conn, pool, send_deltas));
2317 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
2319 return SVN_NO_ERROR;
2323 svn_ra_svn__write_cmd_get_deleted_rev(svn_ra_svn_conn_t *conn,
2326 svn_revnum_t peg_revision,
2327 svn_revnum_t end_revision)
2329 SVN_ERR(writebuf_write_literal(conn, pool, "( get-deleted-rev ( "));
2330 SVN_ERR(write_tuple_cstring(conn, pool, path));
2331 SVN_ERR(write_tuple_revision(conn, pool, peg_revision));
2332 SVN_ERR(write_tuple_revision(conn, pool, end_revision));
2333 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
2335 return SVN_NO_ERROR;
2339 svn_ra_svn__write_cmd_get_iprops(svn_ra_svn_conn_t *conn,
2342 svn_revnum_t revision)
2344 SVN_ERR(writebuf_write_literal(conn, pool, "( get-iprops ( "));
2345 SVN_ERR(write_tuple_cstring(conn, pool, path));
2346 SVN_ERR(write_tuple_start_list(conn, pool));
2347 SVN_ERR(write_tuple_revision_opt(conn, pool, revision));
2348 SVN_ERR(write_tuple_end_list(conn, pool));
2349 SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
2351 return SVN_NO_ERROR;
2355 svn_ra_svn__write_cmd_finish_replay(svn_ra_svn_conn_t *conn,
2358 return writebuf_write_literal(conn, pool, "( finish-replay ( ) ) ");
2361 svn_error_t *svn_ra_svn__write_cmd_response(svn_ra_svn_conn_t *conn,
2363 const char *fmt, ...)
2368 SVN_ERR(writebuf_write_literal(conn, pool, "( success "));
2370 err = vwrite_tuple(conn, pool, fmt, &ap);
2372 return err ? svn_error_trace(err) : svn_ra_svn__end_list(conn, pool);
2375 svn_error_t *svn_ra_svn__write_cmd_failure(svn_ra_svn_conn_t *conn,
2377 const svn_error_t *err)
2380 SVN_ERR(writebuf_write_literal(conn, pool, "( failure ( "));
2381 for (; err; err = err->child)
2385 #ifdef SVN_ERR__TRACING
2386 if (svn_error__is_tracing_link(err))
2390 msg = svn_err_best_message(err, buffer, sizeof(buffer));
2392 /* The message string should have been optional, but we can't
2393 easily change that, so marshal nonexistent messages as "". */
2394 SVN_ERR(svn_ra_svn__write_tuple(conn, pool, "nccn",
2395 (apr_uint64_t) err->apr_err,
2397 err->file ? err->file : "",
2398 (apr_uint64_t) err->line));
2400 return writebuf_write_literal(conn, pool, ") ) ");
2404 svn_ra_svn__write_data_log_changed_path(svn_ra_svn_conn_t *conn,
2408 const char *copyfrom_path,
2409 svn_revnum_t copyfrom_rev,
2410 svn_node_kind_t node_kind,
2411 svn_boolean_t text_modified,
2412 svn_boolean_t props_modified)
2414 SVN_ERR(write_tuple_start_list(conn, pool));
2416 SVN_ERR(write_tuple_cstring(conn, pool, path));
2417 SVN_ERR(writebuf_writechar(conn, pool, action));
2418 SVN_ERR(writebuf_writechar(conn, pool, ' '));
2419 SVN_ERR(write_tuple_start_list(conn, pool));
2420 SVN_ERR(write_tuple_cstring_opt(conn, pool, copyfrom_path));
2421 SVN_ERR(write_tuple_revision_opt(conn, pool, copyfrom_rev));
2422 SVN_ERR(write_tuple_end_list(conn, pool));
2423 SVN_ERR(write_tuple_start_list(conn, pool));
2424 SVN_ERR(write_tuple_cstring(conn, pool, svn_node_kind_to_word(node_kind)));
2425 SVN_ERR(write_tuple_boolean(conn, pool, text_modified));
2426 SVN_ERR(write_tuple_boolean(conn, pool, props_modified));
2428 return writebuf_write_literal(conn, pool, ") ) ");
2432 svn_ra_svn__write_data_log_entry(svn_ra_svn_conn_t *conn,
2434 svn_revnum_t revision,
2435 const svn_string_t *author,
2436 const svn_string_t *date,
2437 const svn_string_t *message,
2438 svn_boolean_t has_children,
2439 svn_boolean_t invalid_revnum,
2440 unsigned revprop_count)
2442 SVN_ERR(write_tuple_revision(conn, pool, revision));
2443 SVN_ERR(write_tuple_start_list(conn, pool));
2444 SVN_ERR(write_tuple_string_opt(conn, pool, author));
2445 SVN_ERR(write_tuple_end_list(conn, pool));
2446 SVN_ERR(write_tuple_start_list(conn, pool));
2447 SVN_ERR(write_tuple_string_opt(conn, pool, date));
2448 SVN_ERR(write_tuple_end_list(conn, pool));
2449 SVN_ERR(write_tuple_start_list(conn, pool));
2450 SVN_ERR(write_tuple_string_opt(conn, pool, message));
2451 SVN_ERR(write_tuple_end_list(conn, pool));
2452 SVN_ERR(write_tuple_boolean(conn, pool, has_children));
2453 SVN_ERR(write_tuple_boolean(conn, pool, invalid_revnum));
2454 SVN_ERR(svn_ra_svn__write_number(conn, pool, revprop_count));
2456 return SVN_NO_ERROR;
2459 /* If condition COND is not met, return a "malformed network data" error.
2461 #define CHECK_PROTOCOL_COND(cond)\
2463 return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL, \
2464 _("Malformed network data"));
2466 /* In *RESULT, return the SVN-style string at index IDX in tuple ITEMS.
2468 static svn_error_t *
2469 svn_ra_svn__read_string(const apr_array_header_t *items,
2471 svn_string_t **result)
2473 svn_ra_svn_item_t *elt = &APR_ARRAY_IDX(items, idx, svn_ra_svn_item_t);
2474 CHECK_PROTOCOL_COND(elt->kind == SVN_RA_SVN_STRING);
2475 *result = elt->u.string;
2477 return SVN_NO_ERROR;
2480 /* In *RESULT, return the C-style string at index IDX in tuple ITEMS.
2482 static svn_error_t *
2483 svn_ra_svn__read_cstring(const apr_array_header_t *items,
2485 const char **result)
2487 svn_ra_svn_item_t *elt = &APR_ARRAY_IDX(items, idx, svn_ra_svn_item_t);
2488 CHECK_PROTOCOL_COND(elt->kind == SVN_RA_SVN_STRING);
2489 *result = elt->u.string->data;
2491 return SVN_NO_ERROR;
2494 /* In *RESULT, return the word at index IDX in tuple ITEMS.
2496 static svn_error_t *
2497 svn_ra_svn__read_word(const apr_array_header_t *items,
2499 const char **result)
2501 svn_ra_svn_item_t *elt = &APR_ARRAY_IDX(items, idx, svn_ra_svn_item_t);
2502 CHECK_PROTOCOL_COND(elt->kind == SVN_RA_SVN_WORD);
2503 *result = elt->u.word;
2505 return SVN_NO_ERROR;
2508 /* In *RESULT, return the revision at index IDX in tuple ITEMS.
2510 static svn_error_t *
2511 svn_ra_svn__read_revision(const apr_array_header_t *items,
2513 svn_revnum_t *result)
2515 svn_ra_svn_item_t *elt = &APR_ARRAY_IDX(items, idx, svn_ra_svn_item_t);
2516 CHECK_PROTOCOL_COND(elt->kind == SVN_RA_SVN_NUMBER);
2517 *result = (svn_revnum_t)elt->u.number;
2519 return SVN_NO_ERROR;
2522 /* In *RESULT, return the boolean at index IDX in tuple ITEMS.
2524 static svn_error_t *
2525 svn_ra_svn__read_boolean(const apr_array_header_t *items,
2527 apr_uint64_t *result)
2529 svn_ra_svn_item_t *elt = &APR_ARRAY_IDX(items, idx, svn_ra_svn_item_t);
2530 CHECK_PROTOCOL_COND(elt->kind == SVN_RA_SVN_WORD);
2531 if (elt->u.word[0] == 't' && strcmp(elt->u.word, "true") == 0)
2533 else if (strcmp(elt->u.word, "false") == 0)
2536 CHECK_PROTOCOL_COND(FALSE);
2538 return SVN_NO_ERROR;
2541 /* In *RESULT, return the tuple at index IDX in tuple ITEMS.
2543 static svn_error_t *
2544 svn_ra_svn__read_list(const apr_array_header_t *items,
2546 const apr_array_header_t **result)
2548 svn_ra_svn_item_t *elt = &APR_ARRAY_IDX(items, idx, svn_ra_svn_item_t);
2549 CHECK_PROTOCOL_COND(elt->kind == SVN_RA_SVN_LIST);
2551 *result = elt->u.list;
2552 return SVN_NO_ERROR;
2555 /* Verify the tuple ITEMS contains at least MIN and at most MAX elements.
2557 static svn_error_t *
2558 svn_ra_svn__read_check_array_size(const apr_array_header_t *items,
2562 CHECK_PROTOCOL_COND(items->nelts >= min && items->nelts <= max);
2563 return SVN_NO_ERROR;
2567 svn_ra_svn__read_data_log_changed_entry(const apr_array_header_t *items,
2568 svn_string_t **cpath,
2569 const char **action,
2570 const char **copy_path,
2571 svn_revnum_t *copy_rev,
2572 const char **kind_str,
2573 apr_uint64_t *text_mods,
2574 apr_uint64_t *prop_mods)
2576 const apr_array_header_t *sub_items;
2578 /* initialize optional values */
2580 *copy_rev = SVN_INVALID_REVNUM;
2582 *text_mods = SVN_RA_SVN_UNSPECIFIED_NUMBER;
2583 *prop_mods = SVN_RA_SVN_UNSPECIFIED_NUMBER;
2585 /* top-level elements (mandatory) */
2586 SVN_ERR(svn_ra_svn__read_check_array_size(items, 3, INT_MAX));
2587 SVN_ERR(svn_ra_svn__read_string(items, 0, cpath));
2588 SVN_ERR(svn_ra_svn__read_word(items, 1, action));
2590 /* first sub-structure (mandatory) */
2591 SVN_ERR(svn_ra_svn__read_list(items, 2, &sub_items));
2592 if (sub_items->nelts)
2594 SVN_ERR(svn_ra_svn__read_check_array_size(sub_items, 2, 2));
2595 SVN_ERR(svn_ra_svn__read_cstring(sub_items, 0, copy_path));
2596 SVN_ERR(svn_ra_svn__read_revision(sub_items, 1, copy_rev));
2599 /* second sub-structure (optional) */
2600 if (items->nelts >= 4)
2602 SVN_ERR(svn_ra_svn__read_list(items, 3, &sub_items));
2603 switch (MIN(3, sub_items->nelts))
2605 case 3 : SVN_ERR(svn_ra_svn__read_boolean(sub_items, 2, prop_mods));
2606 case 2 : SVN_ERR(svn_ra_svn__read_boolean(sub_items, 1, text_mods));
2607 case 1 : SVN_ERR(svn_ra_svn__read_cstring(sub_items, 0, kind_str));
2612 return SVN_NO_ERROR;