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"
47 #include "private/svn_string_private.h"
48 #include "private/svn_dep_compat.h"
49 #include "private/svn_error_private.h"
51 #define svn_iswhitespace(c) ((c) == ' ' || (c) == '\n')
53 /* If we receive data that *claims* to be followed by a very long string,
54 * we should not trust that claim right away. But everything up to 1 MB
55 * should be too small to be instrumental for a DOS attack. */
57 #define SUSPICIOUSLY_HUGE_STRING_SIZE_THRESHOLD (0x100000)
59 /* Return the APR socket timeout to be used for the connection depending
60 * on whether there is a blockage handler or zero copy has been activated. */
61 static apr_interval_time_t
62 get_timeout(svn_ra_svn_conn_t *conn)
64 return conn->block_handler ? 0 : -1;
67 /* --- CONNECTION INITIALIZATION --- */
69 svn_ra_svn_conn_t *svn_ra_svn_create_conn3(apr_socket_t *sock,
72 int compression_level,
73 apr_size_t zero_copy_limit,
74 apr_size_t error_check_interval,
77 svn_ra_svn_conn_t *conn;
78 void *mem = apr_palloc(pool, sizeof(*conn) + SVN_RA_SVN__PAGE_SIZE);
79 conn = (void*)APR_ALIGN((apr_uintptr_t)mem, SVN_RA_SVN__PAGE_SIZE);
81 assert((sock && !in_file && !out_file) || (!sock && in_file && out_file));
84 conn->encrypted = FALSE;
87 conn->read_ptr = conn->read_buf;
88 conn->read_end = conn->read_buf;
90 conn->written_since_error_check = 0;
91 conn->error_check_interval = error_check_interval;
92 conn->may_check_for_error = error_check_interval == 0;
93 conn->block_handler = NULL;
94 conn->block_baton = NULL;
95 conn->capabilities = apr_hash_make(pool);
96 conn->compression_level = compression_level;
97 conn->zero_copy_limit = zero_copy_limit;
103 conn->stream = svn_ra_svn__stream_from_sock(sock, pool);
104 if (!(apr_socket_addr_get(&sa, APR_REMOTE, sock) == APR_SUCCESS
105 && apr_sockaddr_ip_get(&conn->remote_ip, sa) == APR_SUCCESS))
106 conn->remote_ip = NULL;
107 svn_ra_svn__stream_timeout(conn->stream, get_timeout(conn));
111 conn->stream = svn_ra_svn__stream_from_files(in_file, out_file, pool);
112 conn->remote_ip = NULL;
118 svn_ra_svn_conn_t *svn_ra_svn_create_conn2(apr_socket_t *sock,
120 apr_file_t *out_file,
121 int compression_level,
124 return svn_ra_svn_create_conn3(sock, in_file, out_file,
125 compression_level, 0, 0, pool);
128 /* backward-compatible implementation using the default compression level */
129 svn_ra_svn_conn_t *svn_ra_svn_create_conn(apr_socket_t *sock,
131 apr_file_t *out_file,
134 return svn_ra_svn_create_conn3(sock, in_file, out_file,
135 SVN_DELTA_COMPRESSION_LEVEL_DEFAULT, 0, 0,
139 svn_error_t *svn_ra_svn_set_capabilities(svn_ra_svn_conn_t *conn,
140 const apr_array_header_t *list)
143 svn_ra_svn_item_t *item;
146 for (i = 0; i < list->nelts; i++)
148 item = &APR_ARRAY_IDX(list, i, svn_ra_svn_item_t);
149 if (item->kind != SVN_RA_SVN_WORD)
150 return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
151 _("Capability entry is not a word"));
152 word = apr_pstrdup(conn->pool, item->u.word);
153 svn_hash_sets(conn->capabilities, word, word);
159 svn_ra_svn__set_shim_callbacks(svn_ra_svn_conn_t *conn,
160 svn_delta_shim_callbacks_t *shim_callbacks)
162 conn->shim_callbacks = shim_callbacks;
166 svn_boolean_t svn_ra_svn_has_capability(svn_ra_svn_conn_t *conn,
167 const char *capability)
169 return (svn_hash_gets(conn->capabilities, capability) != NULL);
173 svn_ra_svn_compression_level(svn_ra_svn_conn_t *conn)
175 return conn->compression_level;
179 svn_ra_svn_zero_copy_limit(svn_ra_svn_conn_t *conn)
181 return conn->zero_copy_limit;
184 const char *svn_ra_svn_conn_remote_host(svn_ra_svn_conn_t *conn)
186 return conn->remote_ip;
190 svn_ra_svn__set_block_handler(svn_ra_svn_conn_t *conn,
191 ra_svn_block_handler_t handler,
194 conn->block_handler = handler;
195 conn->block_baton = baton;
196 svn_ra_svn__stream_timeout(conn->stream, get_timeout(conn));
199 svn_boolean_t svn_ra_svn__input_waiting(svn_ra_svn_conn_t *conn,
202 return svn_ra_svn__stream_pending(conn->stream);
205 /* --- WRITE BUFFER MANAGEMENT --- */
207 /* Write data to socket or output file as appropriate. */
208 static svn_error_t *writebuf_output(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
209 const char *data, apr_size_t len)
211 const char *end = data + len;
213 apr_pool_t *subpool = NULL;
214 svn_ra_svn__session_baton_t *session = conn->session;
220 if (session && session->callbacks && session->callbacks->cancel_func)
221 SVN_ERR((session->callbacks->cancel_func)(session->callbacks_baton));
223 SVN_ERR(svn_ra_svn__stream_write(conn->stream, data, &count));
227 subpool = svn_pool_create(pool);
229 svn_pool_clear(subpool);
230 SVN_ERR(conn->block_handler(conn, subpool, conn->block_baton));
236 const svn_ra_callbacks2_t *cb = session->callbacks;
237 session->bytes_written += count;
239 if (cb && cb->progress_func)
240 (cb->progress_func)(session->bytes_written + session->bytes_read,
241 -1, cb->progress_baton, subpool);
245 conn->written_since_error_check += len;
246 conn->may_check_for_error
247 = conn->written_since_error_check >= conn->error_check_interval;
250 svn_pool_destroy(subpool);
254 /* Write data from the write buffer out to the socket. */
255 static svn_error_t *writebuf_flush(svn_ra_svn_conn_t *conn, apr_pool_t *pool)
257 apr_size_t write_pos = conn->write_pos;
259 /* Clear conn->write_pos first in case the block handler does a read. */
261 SVN_ERR(writebuf_output(conn, pool, conn->write_buf, write_pos));
265 static svn_error_t *writebuf_write(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
266 const char *data, apr_size_t len)
268 /* data >= 8k is sent immediately */
269 if (len >= sizeof(conn->write_buf) / 2)
271 if (conn->write_pos > 0)
272 SVN_ERR(writebuf_flush(conn, pool));
274 return writebuf_output(conn, pool, data, len);
277 /* ensure room for the data to add */
278 if (conn->write_pos + len > sizeof(conn->write_buf))
279 SVN_ERR(writebuf_flush(conn, pool));
281 /* buffer the new data block as well */
282 memcpy(conn->write_buf + conn->write_pos, data, len);
283 conn->write_pos += len;
289 writebuf_write_short_string(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
290 const char *data, apr_size_t len)
292 apr_size_t left = sizeof(conn->write_buf) - conn->write_pos;
295 memcpy(conn->write_buf + conn->write_pos, data, len);
296 conn->write_pos += len;
300 return writebuf_write(conn, pool, data, len);
303 static APR_INLINE svn_error_t *
304 writebuf_writechar(svn_ra_svn_conn_t *conn, apr_pool_t *pool, char data)
306 if (conn->write_pos < sizeof(conn->write_buf))
308 conn->write_buf[conn->write_pos] = data;
316 return writebuf_write(conn, pool, &temp, 1);
320 /* --- READ BUFFER MANAGEMENT --- */
322 /* Read bytes into DATA until either the read buffer is empty or
324 static char *readbuf_drain(svn_ra_svn_conn_t *conn, char *data, char *end)
326 apr_ssize_t buflen, copylen;
328 buflen = conn->read_end - conn->read_ptr;
329 copylen = (buflen < end - data) ? buflen : end - data;
330 memcpy(data, conn->read_ptr, copylen);
331 conn->read_ptr += copylen;
332 return data + copylen;
335 /* Read data from socket or input file as appropriate. */
336 static svn_error_t *readbuf_input(svn_ra_svn_conn_t *conn, char *data,
337 apr_size_t *len, apr_pool_t *pool)
339 svn_ra_svn__session_baton_t *session = conn->session;
341 if (session && session->callbacks && session->callbacks->cancel_func)
342 SVN_ERR((session->callbacks->cancel_func)(session->callbacks_baton));
344 SVN_ERR(svn_ra_svn__stream_read(conn->stream, data, len));
346 return svn_error_create(SVN_ERR_RA_SVN_CONNECTION_CLOSED, NULL, NULL);
350 const svn_ra_callbacks2_t *cb = session->callbacks;
351 session->bytes_read += *len;
353 if (cb && cb->progress_func)
354 (cb->progress_func)(session->bytes_read + session->bytes_written,
355 -1, cb->progress_baton, pool);
361 /* Treat the next LEN input bytes from CONN as "read" */
362 static svn_error_t *readbuf_skip(svn_ra_svn_conn_t *conn, apr_uint64_t len)
366 apr_size_t buflen = conn->read_end - conn->read_ptr;
367 apr_size_t copylen = (buflen < len) ? buflen : (apr_size_t)len;
368 conn->read_ptr += copylen;
373 buflen = sizeof(conn->read_buf);
374 SVN_ERR(svn_ra_svn__stream_read(conn->stream, conn->read_buf, &buflen));
376 return svn_error_create(SVN_ERR_RA_SVN_CONNECTION_CLOSED, NULL, NULL);
378 conn->read_end = conn->read_buf + buflen;
379 conn->read_ptr = conn->read_buf;
386 /* Read data from the socket into the read buffer, which must be empty. */
387 static svn_error_t *readbuf_fill(svn_ra_svn_conn_t *conn, apr_pool_t *pool)
391 SVN_ERR_ASSERT(conn->read_ptr == conn->read_end);
392 SVN_ERR(writebuf_flush(conn, pool));
393 len = sizeof(conn->read_buf);
394 SVN_ERR(readbuf_input(conn, conn->read_buf, &len, pool));
395 conn->read_ptr = conn->read_buf;
396 conn->read_end = conn->read_buf + len;
400 static APR_INLINE svn_error_t *
401 readbuf_getchar(svn_ra_svn_conn_t *conn, apr_pool_t *pool, char *result)
403 if (conn->read_ptr == conn->read_end)
404 SVN_ERR(readbuf_fill(conn, pool));
405 *result = *conn->read_ptr++;
409 static svn_error_t *readbuf_getchar_skip_whitespace(svn_ra_svn_conn_t *conn,
414 SVN_ERR(readbuf_getchar(conn, pool, result));
415 while (svn_iswhitespace(*result));
419 /* Read the next LEN bytes from CONN and copy them to *DATA. */
420 static svn_error_t *readbuf_read(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
421 char *data, apr_size_t len)
423 char *end = data + len;
426 /* Copy in an appropriate amount of data from the buffer. */
427 data = readbuf_drain(conn, data, end);
429 /* Read large chunks directly into buffer. */
430 while (end - data > (apr_ssize_t)sizeof(conn->read_buf))
432 SVN_ERR(writebuf_flush(conn, pool));
434 SVN_ERR(readbuf_input(conn, data, &count, pool));
440 /* The remaining amount to read is small; fill the buffer and
442 SVN_ERR(readbuf_fill(conn, pool));
443 data = readbuf_drain(conn, data, end);
449 static svn_error_t *readbuf_skip_leading_garbage(svn_ra_svn_conn_t *conn,
452 char buf[256]; /* Must be smaller than sizeof(conn->read_buf) - 1. */
455 svn_boolean_t lparen = FALSE;
457 SVN_ERR_ASSERT(conn->read_ptr == conn->read_end);
460 /* Read some data directly from the connection input source. */
462 SVN_ERR(readbuf_input(conn, buf, &len, pool));
465 /* Scan the data for '(' WS with a very simple state machine. */
466 for (p = buf; p < end; p++)
468 if (lparen && svn_iswhitespace(*p))
471 lparen = (*p == '(');
477 /* p now points to the whitespace just after the left paren. Fake
478 * up the left paren and then copy what we have into the read
480 conn->read_buf[0] = '(';
481 memcpy(conn->read_buf + 1, p, end - p);
482 conn->read_ptr = conn->read_buf;
483 conn->read_end = conn->read_buf + 1 + (end - p);
487 /* --- WRITING DATA ITEMS --- */
489 static svn_error_t *write_number(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
490 apr_uint64_t number, char follow)
494 /* SVN_INT64_BUFFER_SIZE includes space for a terminating NUL that
495 * svn__ui64toa will always append. */
496 if (conn->write_pos + SVN_INT64_BUFFER_SIZE >= sizeof(conn->write_buf))
497 SVN_ERR(writebuf_flush(conn, pool));
499 written = svn__ui64toa(conn->write_buf + conn->write_pos, number);
500 conn->write_buf[conn->write_pos + written] = follow;
501 conn->write_pos += written + 1;
507 svn_ra_svn__write_number(svn_ra_svn_conn_t *conn,
511 return write_number(conn, pool, number, ' ');
515 svn_ra_svn__write_string(svn_ra_svn_conn_t *conn,
517 const svn_string_t *str)
521 SVN_ERR(writebuf_writechar(conn, pool, (char)(str->len + '0')));
522 SVN_ERR(writebuf_writechar(conn, pool, ':'));
525 SVN_ERR(write_number(conn, pool, str->len, ':'));
527 SVN_ERR(writebuf_write(conn, pool, str->data, str->len));
528 SVN_ERR(writebuf_writechar(conn, pool, ' '));
533 svn_ra_svn__write_cstring(svn_ra_svn_conn_t *conn,
537 apr_size_t len = strlen(s);
541 SVN_ERR(writebuf_writechar(conn, pool, (char)(len + '0')));
542 SVN_ERR(writebuf_writechar(conn, pool, ':'));
545 SVN_ERR(write_number(conn, pool, len, ':'));
547 SVN_ERR(writebuf_write(conn, pool, s, len));
548 SVN_ERR(writebuf_writechar(conn, pool, ' '));
554 svn_ra_svn__write_word(svn_ra_svn_conn_t *conn,
558 SVN_ERR(writebuf_write_short_string(conn, pool, word, strlen(word)));
559 SVN_ERR(writebuf_writechar(conn, pool, ' '));
565 svn_ra_svn__write_proplist(svn_ra_svn_conn_t *conn,
569 apr_pool_t *iterpool;
570 apr_hash_index_t *hi;
573 const char *propname;
574 svn_string_t *propval;
578 iterpool = svn_pool_create(pool);
579 for (hi = apr_hash_first(pool, props); hi; hi = apr_hash_next(hi))
581 svn_pool_clear(iterpool);
582 apr_hash_this(hi, &key, NULL, &val);
585 SVN_ERR(svn_ra_svn__write_tuple(conn, iterpool, "cs",
588 svn_pool_destroy(iterpool);
595 svn_ra_svn__start_list(svn_ra_svn_conn_t *conn,
598 if (conn->write_pos + 2 <= sizeof(conn->write_buf))
600 conn->write_buf[conn->write_pos] = '(';
601 conn->write_buf[conn->write_pos+1] = ' ';
602 conn->write_pos += 2;
606 return writebuf_write(conn, pool, "( ", 2);
610 svn_ra_svn__end_list(svn_ra_svn_conn_t *conn,
613 if (conn->write_pos + 2 <= sizeof(conn->write_buf))
615 conn->write_buf[conn->write_pos] = ')';
616 conn->write_buf[conn->write_pos+1] = ' ';
617 conn->write_pos += 2;
621 return writebuf_write(conn, pool, ") ", 2);
625 svn_ra_svn__flush(svn_ra_svn_conn_t *conn,
628 SVN_ERR(writebuf_flush(conn, pool));
629 conn->may_check_for_error = TRUE;
634 /* --- WRITING TUPLES --- */
637 vwrite_tuple_cstring(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
639 const char *cstr = va_arg(*ap, const char *);
640 SVN_ERR_ASSERT(cstr);
641 return svn_ra_svn__write_cstring(conn, pool, cstr);
645 vwrite_tuple_cstring_opt(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
647 const char *cstr = va_arg(*ap, const char *);
648 return cstr ? svn_ra_svn__write_cstring(conn, pool, cstr) : SVN_NO_ERROR;
652 vwrite_tuple_string(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
654 const svn_string_t *str = va_arg(*ap, const svn_string_t *);
656 return svn_ra_svn__write_string(conn, pool, str);
660 vwrite_tuple_string_opt(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
662 const svn_string_t *str = va_arg(*ap, const svn_string_t *);
663 return str ? svn_ra_svn__write_string(conn, pool, str) : SVN_NO_ERROR;
667 vwrite_tuple_word(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
669 const char *cstr = va_arg(*ap, const char *);
670 SVN_ERR_ASSERT(cstr);
671 return svn_ra_svn__write_word(conn, pool, cstr);
675 vwrite_tuple_word_opt(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
677 const char *cstr = va_arg(*ap, const char *);
678 return cstr ? svn_ra_svn__write_word(conn, pool, cstr) : SVN_NO_ERROR;
682 vwrite_tuple_revision(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
684 svn_revnum_t rev = va_arg(*ap, svn_revnum_t);
685 SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(rev));
686 return svn_ra_svn__write_number(conn, pool, rev);
690 vwrite_tuple_revision_opt(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
692 svn_revnum_t rev = va_arg(*ap, svn_revnum_t);
693 return SVN_IS_VALID_REVNUM(rev)
694 ? svn_ra_svn__write_number(conn, pool, rev)
699 vwrite_tuple_number(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
701 return svn_ra_svn__write_number(conn, pool, va_arg(*ap, apr_uint64_t));
705 vwrite_tuple_boolean(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
707 const char *cstr = va_arg(*ap, svn_boolean_t) ? "true" : "false";
708 return svn_ra_svn__write_word(conn, pool, cstr);
712 write_tuple_cstring(svn_ra_svn_conn_t *conn,
716 SVN_ERR_ASSERT(cstr);
717 return svn_ra_svn__write_cstring(conn, pool, cstr);
721 write_tuple_cstring_opt(svn_ra_svn_conn_t *conn,
725 return cstr ? svn_ra_svn__write_cstring(conn, pool, cstr) : SVN_NO_ERROR;
729 write_tuple_string(svn_ra_svn_conn_t *conn,
731 const svn_string_t *str)
734 return svn_ra_svn__write_string(conn, pool, str);
738 write_tuple_string_opt(svn_ra_svn_conn_t *conn,
740 const svn_string_t *str)
742 return str ? svn_ra_svn__write_string(conn, pool, str) : SVN_NO_ERROR;
746 write_tuple_start_list(svn_ra_svn_conn_t *conn,
749 return svn_ra_svn__start_list(conn, pool);
753 write_tuple_end_list(svn_ra_svn_conn_t *conn,
756 return svn_ra_svn__end_list(conn, pool);
760 write_tuple_revision(svn_ra_svn_conn_t *conn,
764 SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(rev));
765 return svn_ra_svn__write_number(conn, pool, rev);
769 write_tuple_revision_opt(svn_ra_svn_conn_t *conn,
773 return SVN_IS_VALID_REVNUM(rev)
774 ? svn_ra_svn__write_number(conn, pool, rev)
779 write_tuple_boolean(svn_ra_svn_conn_t *conn,
783 const char *cstr = value ? "true" : "false";
784 return svn_ra_svn__write_word(conn, pool, cstr);
788 write_tuple_depth(svn_ra_svn_conn_t *conn,
792 return svn_ra_svn__write_word(conn, pool, svn_depth_to_word(depth));
797 write_cmd_add_node(svn_ra_svn_conn_t *conn,
800 const char *parent_token,
802 const char *copy_path,
803 svn_revnum_t copy_rev)
805 SVN_ERR(write_tuple_cstring(conn, pool, path));
806 SVN_ERR(write_tuple_cstring(conn, pool, parent_token));
807 SVN_ERR(write_tuple_cstring(conn, pool, token));
808 SVN_ERR(write_tuple_start_list(conn, pool));
809 SVN_ERR(write_tuple_cstring_opt(conn, pool, copy_path));
810 SVN_ERR(write_tuple_revision_opt(conn, pool, copy_rev));
811 SVN_ERR(write_tuple_end_list(conn, pool));
817 write_cmd_open_node(svn_ra_svn_conn_t *conn,
820 const char *parent_token,
824 SVN_ERR(write_tuple_cstring(conn, pool, path));
825 SVN_ERR(write_tuple_cstring(conn, pool, parent_token));
826 SVN_ERR(write_tuple_cstring(conn, pool, token));
827 SVN_ERR(write_tuple_start_list(conn, pool));
828 SVN_ERR(write_tuple_revision_opt(conn, pool, rev));
829 SVN_ERR(write_tuple_end_list(conn, pool));
835 write_cmd_change_node_prop(svn_ra_svn_conn_t *conn,
839 const svn_string_t *value)
841 SVN_ERR(write_tuple_cstring(conn, pool, token));
842 SVN_ERR(write_tuple_cstring(conn, pool, name));
843 SVN_ERR(write_tuple_start_list(conn, pool));
844 SVN_ERR(write_tuple_string_opt(conn, pool, value));
845 SVN_ERR(write_tuple_end_list(conn, pool));
851 write_cmd_absent_node(svn_ra_svn_conn_t *conn,
856 SVN_ERR(write_tuple_cstring(conn, pool, path));
857 SVN_ERR(write_tuple_cstring(conn, pool, token));
865 static svn_error_t *vwrite_tuple(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
866 const char *fmt, va_list *ap)
868 svn_boolean_t opt = FALSE;
873 SVN_ERR(svn_ra_svn__start_list(conn, pool));
877 SVN_ERR(opt ? vwrite_tuple_cstring_opt(conn, pool, ap)
878 : vwrite_tuple_cstring(conn, pool, ap));
879 else if (*fmt == 's')
880 SVN_ERR(opt ? vwrite_tuple_string_opt(conn, pool, ap)
881 : vwrite_tuple_string(conn, pool, ap));
882 else if (*fmt == '(' && !opt)
883 SVN_ERR(write_tuple_start_list(conn, pool));
884 else if (*fmt == ')')
886 SVN_ERR(write_tuple_end_list(conn, pool));
889 else if (*fmt == '?')
891 else if (*fmt == 'w')
892 SVN_ERR(opt ? vwrite_tuple_word_opt(conn, pool, ap)
893 : vwrite_tuple_word(conn, pool, ap));
894 else if (*fmt == 'r')
895 SVN_ERR(opt ? vwrite_tuple_revision_opt(conn, pool, ap)
896 : vwrite_tuple_revision(conn, pool, ap));
897 else if (*fmt == 'n' && !opt)
898 SVN_ERR(vwrite_tuple_number(conn, pool, ap));
899 else if (*fmt == 'b' && !opt)
900 SVN_ERR(vwrite_tuple_boolean(conn, pool, ap));
901 else if (*fmt == '!' && !*(fmt + 1))
904 SVN_ERR_MALFUNCTION();
906 SVN_ERR(svn_ra_svn__end_list(conn, pool));
911 svn_ra_svn__write_tuple(svn_ra_svn_conn_t *conn,
913 const char *fmt, ...)
919 err = vwrite_tuple(conn, pool, fmt, &ap);
924 /* --- READING DATA ITEMS --- */
926 /* Read LEN bytes from CONN into already-allocated structure ITEM.
927 * Afterwards, *ITEM is of type 'SVN_RA_SVN_STRING', and its string
928 * data is allocated in POOL. */
929 static svn_error_t *read_string(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
930 svn_ra_svn_item_t *item, apr_uint64_t len64)
932 svn_stringbuf_t *stringbuf;
933 apr_size_t len = (apr_size_t)len64;
934 apr_size_t readbuf_len;
937 /* We can't store strings longer than the maximum size of apr_size_t,
938 * so check for wrapping */
939 if (len64 > APR_SIZE_MAX)
940 return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
941 _("String length larger than maximum"));
943 /* Read the string in chunks. The chunk size is large enough to avoid
944 * re-allocation in typical cases, and small enough to ensure we do not
945 * pre-allocate an unreasonable amount of memory if (perhaps due to
946 * network data corruption or a DOS attack), we receive a bogus claim that
947 * a very long string is going to follow. In that case, we start small
948 * and wait for all that data to actually show up. This does not fully
949 * prevent DOS attacks but makes them harder (you have to actually send
950 * gigabytes of data). */
951 readbuf_len = len < SUSPICIOUSLY_HUGE_STRING_SIZE_THRESHOLD
953 : SUSPICIOUSLY_HUGE_STRING_SIZE_THRESHOLD;
954 stringbuf = svn_stringbuf_create_ensure(readbuf_len, pool);
955 dest = stringbuf->data;
957 /* Read remaining string data directly into the string structure.
958 * Do it iteratively, if necessary. */
961 SVN_ERR(readbuf_read(conn, pool, dest, readbuf_len));
963 stringbuf->len += readbuf_len;
966 /* Early exit. In most cases, strings can be read in the first
971 /* Prepare next iteration: determine length of chunk to read
972 * and re-alloc the string buffer. */
974 = len < SUSPICIOUSLY_HUGE_STRING_SIZE_THRESHOLD
976 : SUSPICIOUSLY_HUGE_STRING_SIZE_THRESHOLD;
978 svn_stringbuf_ensure(stringbuf, stringbuf->len + readbuf_len);
979 dest = stringbuf->data + stringbuf->len;
982 /* zero-terminate the string */
983 stringbuf->data[stringbuf->len] = '\0';
985 /* Return the string properly wrapped into an RA_SVN item. */
986 item->kind = SVN_RA_SVN_STRING;
987 item->u.string = svn_stringbuf__morph_into_string(stringbuf);
992 /* Given the first non-whitespace character FIRST_CHAR, read an item
993 * into the already allocated structure ITEM. LEVEL should be set
994 * to 0 for the first call and is used to enforce a recurssion limit
996 static svn_error_t *read_item(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
997 svn_ra_svn_item_t *item, char first_char,
1000 char c = first_char;
1002 svn_stringbuf_t *str;
1003 svn_ra_svn_item_t *listitem;
1006 return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
1007 _("Too many nested items"));
1010 /* Determine the item type and read it in. Make sure that c is the
1011 * first character at the end of the item so we can test to make
1012 * sure it's whitespace. */
1013 if (svn_ctype_isdigit(c))
1015 /* It's a number or a string. Read the number part, either way. */
1019 apr_uint64_t prev_val = val;
1020 SVN_ERR(readbuf_getchar(conn, pool, &c));
1021 if (!svn_ctype_isdigit(c))
1023 val = val * 10 + (c - '0');
1024 /* val wrapped past maximum value? */
1025 if (prev_val >= (APR_UINT64_MAX / 10) && (val / 10) != prev_val)
1026 return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
1027 _("Number is larger than maximum"));
1031 /* It's a string. */
1032 SVN_ERR(read_string(conn, pool, item, val));
1033 SVN_ERR(readbuf_getchar(conn, pool, &c));
1037 /* It's a number. */
1038 item->kind = SVN_RA_SVN_NUMBER;
1039 item->u.number = val;
1042 else if (svn_ctype_isalpha(c))
1045 str = svn_stringbuf_create_ensure(16, pool);
1046 svn_stringbuf_appendbyte(str, c);
1049 SVN_ERR(readbuf_getchar(conn, pool, &c));
1050 if (!svn_ctype_isalnum(c) && c != '-')
1052 svn_stringbuf_appendbyte(str, c);
1054 item->kind = SVN_RA_SVN_WORD;
1055 item->u.word = str->data;
1059 /* Read in the list items. */
1060 item->kind = SVN_RA_SVN_LIST;
1061 item->u.list = apr_array_make(pool, 4, sizeof(svn_ra_svn_item_t));
1064 SVN_ERR(readbuf_getchar_skip_whitespace(conn, pool, &c));
1067 listitem = apr_array_push(item->u.list);
1068 SVN_ERR(read_item(conn, pool, listitem, c, level));
1070 SVN_ERR(readbuf_getchar(conn, pool, &c));
1073 if (!svn_iswhitespace(c))
1074 return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
1075 _("Malformed network data"));
1076 return SVN_NO_ERROR;
1079 /* Given the first non-whitespace character FIRST_CHAR, read the first
1080 * command (word) encountered in CONN into *ITEM. If ITEM is NULL, skip
1081 * to the end of the current list. Use POOL for allocations. */
1082 static svn_error_t *
1083 read_command_only(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
1084 const char **item, char first_char)
1086 char c = first_char;
1088 /* Determine the item type and read it in. Make sure that c is the
1089 * first character at the end of the item so we can test to make
1090 * sure it's whitespace. */
1091 if (svn_ctype_isdigit(c))
1093 /* It's a number or a string. Read the number part, either way. */
1094 apr_uint64_t val, prev_val=0;
1099 SVN_ERR(readbuf_getchar(conn, pool, &c));
1100 if (!svn_ctype_isdigit(c))
1102 val = val * 10 + (c - '0');
1103 if (prev_val >= (APR_UINT64_MAX / 10)) /* > maximum value? */
1104 return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
1105 _("Number is larger than maximum"));
1109 /* It's a string. */
1110 SVN_ERR(readbuf_skip(conn, val));
1111 SVN_ERR(readbuf_getchar(conn, pool, &c));
1114 else if (svn_ctype_isalpha(c))
1119 /* This is the word we want to read */
1121 char *buf = apr_palloc(pool, 32);
1127 SVN_ERR(readbuf_getchar(conn, pool, &c));
1128 if (!svn_ctype_isalnum(c) && c != '-')
1132 return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
1133 _("Word too long"));
1140 /* we don't need the actual word, just skip it */
1143 SVN_ERR(readbuf_getchar(conn, pool, &c));
1145 while (svn_ctype_isalnum(c) || c == '-');
1150 /* Read in the list items. */
1153 SVN_ERR(readbuf_getchar_skip_whitespace(conn, pool, &c));
1157 if (item && *item == NULL)
1158 SVN_ERR(read_command_only(conn, pool, item, c));
1160 SVN_ERR(read_command_only(conn, pool, NULL, c));
1162 SVN_ERR(readbuf_getchar(conn, pool, &c));
1165 return SVN_NO_ERROR;
1169 svn_ra_svn__read_item(svn_ra_svn_conn_t *conn,
1171 svn_ra_svn_item_t **item)
1175 /* Allocate space, read the first character, and then do the rest of
1176 * the work. This makes sense because of the way lists are read. */
1177 *item = apr_palloc(pool, sizeof(**item));
1178 SVN_ERR(readbuf_getchar_skip_whitespace(conn, pool, &c));
1179 return read_item(conn, pool, *item, c, 0);
1183 svn_ra_svn__skip_leading_garbage(svn_ra_svn_conn_t *conn,
1186 return readbuf_skip_leading_garbage(conn, pool);
1189 /* --- READING AND PARSING TUPLES --- */
1191 /* Parse a tuple of svn_ra_svn_item_t *'s. Advance *FMT to the end of the
1192 * tuple specification and advance AP by the corresponding arguments. */
1193 static svn_error_t *vparse_tuple(const apr_array_header_t *items, apr_pool_t *pool,
1194 const char **fmt, va_list *ap)
1196 int count, nesting_level;
1197 svn_ra_svn_item_t *elt;
1199 for (count = 0; **fmt && count < items->nelts; (*fmt)++, count++)
1201 /* '?' just means the tuple may stop; skip past it. */
1204 elt = &APR_ARRAY_IDX(items, count, svn_ra_svn_item_t);
1205 if (**fmt == 'n' && elt->kind == SVN_RA_SVN_NUMBER)
1206 *va_arg(*ap, apr_uint64_t *) = elt->u.number;
1207 else if (**fmt == 'r' && elt->kind == SVN_RA_SVN_NUMBER)
1208 *va_arg(*ap, svn_revnum_t *) = (svn_revnum_t) elt->u.number;
1209 else if (**fmt == 's' && elt->kind == SVN_RA_SVN_STRING)
1210 *va_arg(*ap, svn_string_t **) = elt->u.string;
1211 else if (**fmt == 'c' && elt->kind == SVN_RA_SVN_STRING)
1212 *va_arg(*ap, const char **) = elt->u.string->data;
1213 else if (**fmt == 'w' && elt->kind == SVN_RA_SVN_WORD)
1214 *va_arg(*ap, const char **) = elt->u.word;
1215 else if (**fmt == 'b' && elt->kind == SVN_RA_SVN_WORD)
1217 if (strcmp(elt->u.word, "true") == 0)
1218 *va_arg(*ap, svn_boolean_t *) = TRUE;
1219 else if (strcmp(elt->u.word, "false") == 0)
1220 *va_arg(*ap, svn_boolean_t *) = FALSE;
1224 else if (**fmt == 'B' && elt->kind == SVN_RA_SVN_WORD)
1226 if (strcmp(elt->u.word, "true") == 0)
1227 *va_arg(*ap, apr_uint64_t *) = TRUE;
1228 else if (strcmp(elt->u.word, "false") == 0)
1229 *va_arg(*ap, apr_uint64_t *) = FALSE;
1233 else if (**fmt == 'l' && elt->kind == SVN_RA_SVN_LIST)
1234 *va_arg(*ap, apr_array_header_t **) = elt->u.list;
1235 else if (**fmt == '(' && elt->kind == SVN_RA_SVN_LIST)
1238 SVN_ERR(vparse_tuple(elt->u.list, pool, fmt, ap));
1240 else if (**fmt == ')')
1241 return SVN_NO_ERROR;
1248 for (; **fmt; (*fmt)++)
1255 *va_arg(*ap, svn_revnum_t *) = SVN_INVALID_REVNUM;
1258 *va_arg(*ap, svn_string_t **) = NULL;
1262 *va_arg(*ap, const char **) = NULL;
1265 *va_arg(*ap, apr_array_header_t **) = NULL;
1269 *va_arg(*ap, apr_uint64_t *) = SVN_RA_SVN_UNSPECIFIED_NUMBER;
1275 if (--nesting_level < 0)
1276 return SVN_NO_ERROR;
1279 SVN_ERR_MALFUNCTION();
1283 if (**fmt && **fmt != ')')
1284 return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
1285 _("Malformed network data"));
1286 return SVN_NO_ERROR;
1290 svn_ra_svn__parse_tuple(const apr_array_header_t *list,
1292 const char *fmt, ...)
1298 err = vparse_tuple(list, pool, &fmt, &ap);
1304 svn_ra_svn__read_tuple(svn_ra_svn_conn_t *conn,
1306 const char *fmt, ...)
1309 svn_ra_svn_item_t *item;
1312 SVN_ERR(svn_ra_svn__read_item(conn, pool, &item));
1313 if (item->kind != SVN_RA_SVN_LIST)
1314 return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
1315 _("Malformed network data"));
1317 err = vparse_tuple(item->u.list, pool, &fmt, &ap);
1323 svn_ra_svn__read_command_only(svn_ra_svn_conn_t *conn,
1325 const char **command)
1328 SVN_ERR(readbuf_getchar_skip_whitespace(conn, pool, &c));
1331 return read_command_only(conn, pool, command, c);
1336 svn_ra_svn__parse_proplist(const apr_array_header_t *list,
1341 svn_string_t *value;
1342 svn_ra_svn_item_t *elt;
1345 *props = apr_hash_make(pool);
1346 for (i = 0; i < list->nelts; i++)
1348 elt = &APR_ARRAY_IDX(list, i, svn_ra_svn_item_t);
1349 if (elt->kind != SVN_RA_SVN_LIST)
1350 return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
1351 _("Proplist element not a list"));
1352 SVN_ERR(svn_ra_svn__parse_tuple(elt->u.list, pool, "cs",
1354 svn_hash_sets(*props, name, value);
1357 return SVN_NO_ERROR;
1361 /* --- READING AND WRITING COMMANDS AND RESPONSES --- */
1363 svn_error_t *svn_ra_svn__locate_real_error_child(svn_error_t *err)
1365 svn_error_t *this_link;
1367 SVN_ERR_ASSERT(err);
1369 for (this_link = err;
1370 this_link && (this_link->apr_err == SVN_ERR_RA_SVN_CMD_ERR);
1371 this_link = this_link->child)
1374 SVN_ERR_ASSERT(this_link);
1378 svn_error_t *svn_ra_svn__handle_failure_status(const apr_array_header_t *params,
1381 const char *message, *file;
1382 svn_error_t *err = NULL;
1383 svn_ra_svn_item_t *elt;
1385 apr_uint64_t apr_err, line;
1386 apr_pool_t *subpool = svn_pool_create(pool);
1388 if (params->nelts == 0)
1389 return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
1390 _("Empty error list"));
1392 /* Rebuild the error list from the end, to avoid reversing the order. */
1393 for (i = params->nelts - 1; i >= 0; i--)
1395 svn_pool_clear(subpool);
1396 elt = &APR_ARRAY_IDX(params, i, svn_ra_svn_item_t);
1397 if (elt->kind != SVN_RA_SVN_LIST)
1398 return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
1399 _("Malformed error list"));
1400 SVN_ERR(svn_ra_svn__parse_tuple(elt->u.list, subpool, "nccn",
1401 &apr_err, &message, &file, &line));
1402 /* The message field should have been optional, but we can't
1403 easily change that, so "" means a nonexistent message. */
1407 /* Skip over links in the error chain that were intended only to
1408 exist on the server (to wrap real errors intended for the
1409 client) but accidentally got included in the server's actual
1411 if ((apr_status_t)apr_err != SVN_ERR_RA_SVN_CMD_ERR)
1413 err = svn_error_create((apr_status_t)apr_err, err, message);
1414 err->file = apr_pstrdup(err->pool, file);
1415 err->line = (long)line;
1419 svn_pool_destroy(subpool);
1421 /* If we get here, then we failed to find a real error in the error
1422 chain that the server proported to be sending us. That's bad. */
1424 err = svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
1425 _("Malformed error list"));
1431 svn_ra_svn__read_cmd_response(svn_ra_svn_conn_t *conn,
1433 const char *fmt, ...)
1437 apr_array_header_t *params;
1440 SVN_ERR(svn_ra_svn__read_tuple(conn, pool, "wl", &status, ¶ms));
1441 if (strcmp(status, "success") == 0)
1444 err = vparse_tuple(params, pool, &fmt, &ap);
1448 else if (strcmp(status, "failure") == 0)
1450 return svn_ra_svn__handle_failure_status(params, pool);
1453 return svn_error_createf(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
1454 _("Unknown status '%s' in command response"),
1459 svn_ra_svn__handle_commands2(svn_ra_svn_conn_t *conn,
1461 const svn_ra_svn_cmd_entry_t *commands,
1463 svn_boolean_t error_on_disconnect)
1465 apr_pool_t *subpool = svn_pool_create(pool);
1466 apr_pool_t *iterpool = svn_pool_create(subpool);
1467 const char *cmdname;
1468 const svn_ra_svn_cmd_entry_t *command;
1469 svn_error_t *err, *write_err;
1470 apr_array_header_t *params;
1471 apr_hash_t *cmd_hash = apr_hash_make(subpool);
1473 for (command = commands; command->cmdname; command++)
1474 svn_hash_sets(cmd_hash, command->cmdname, command);
1478 svn_pool_clear(iterpool);
1479 err = svn_ra_svn__read_tuple(conn, iterpool, "wl", &cmdname, ¶ms);
1482 if (!error_on_disconnect
1483 && err->apr_err == SVN_ERR_RA_SVN_CONNECTION_CLOSED)
1485 svn_error_clear(err);
1486 svn_pool_destroy(subpool);
1487 return SVN_NO_ERROR;
1491 command = svn_hash_gets(cmd_hash, cmdname);
1494 err = (*command->handler)(conn, iterpool, params, baton);
1497 err = svn_error_createf(SVN_ERR_RA_SVN_UNKNOWN_CMD, NULL,
1498 _("Unknown editor command '%s'"), cmdname);
1499 err = svn_error_create(SVN_ERR_RA_SVN_CMD_ERR, err, NULL);
1502 if (err && err->apr_err == SVN_ERR_RA_SVN_CMD_ERR)
1504 write_err = svn_ra_svn__write_cmd_failure(
1506 svn_ra_svn__locate_real_error_child(err));
1507 svn_error_clear(err);
1514 if (command && command->terminate)
1517 svn_pool_destroy(iterpool);
1518 svn_pool_destroy(subpool);
1519 return SVN_NO_ERROR;
1523 svn_ra_svn__write_cmd_target_rev(svn_ra_svn_conn_t *conn,
1527 SVN_ERR(writebuf_write_short_string(conn, pool, "( target-rev ( ", 15));
1528 SVN_ERR(write_tuple_revision(conn, pool, rev));
1529 SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
1531 return SVN_NO_ERROR;
1535 svn_ra_svn__write_cmd_open_root(svn_ra_svn_conn_t *conn,
1540 SVN_ERR(writebuf_write_short_string(conn, pool, "( open-root ( ", 14));
1541 SVN_ERR(write_tuple_start_list(conn, pool));
1542 SVN_ERR(write_tuple_revision_opt(conn, pool, rev));
1543 SVN_ERR(write_tuple_end_list(conn, pool));
1544 SVN_ERR(write_tuple_cstring(conn, pool, token));
1545 SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
1547 return SVN_NO_ERROR;
1551 svn_ra_svn__write_cmd_delete_entry(svn_ra_svn_conn_t *conn,
1557 SVN_ERR(writebuf_write_short_string(conn, pool, "( delete-entry ( ", 17));
1558 SVN_ERR(write_tuple_cstring(conn, pool, path));
1559 SVN_ERR(write_tuple_start_list(conn, pool));
1560 SVN_ERR(write_tuple_revision_opt(conn, pool, rev));
1561 SVN_ERR(write_tuple_end_list(conn, pool));
1562 SVN_ERR(write_tuple_cstring(conn, pool, token));
1563 SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
1565 return SVN_NO_ERROR;
1569 svn_ra_svn__write_cmd_add_dir(svn_ra_svn_conn_t *conn,
1572 const char *parent_token,
1574 const char *copy_path,
1575 svn_revnum_t copy_rev)
1577 SVN_ERR(writebuf_write_short_string(conn, pool, "( add-dir ( ", 12));
1578 SVN_ERR(write_cmd_add_node(conn, pool, path, parent_token, token,
1579 copy_path, copy_rev));
1580 SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
1582 return SVN_NO_ERROR;
1586 svn_ra_svn__write_cmd_open_dir(svn_ra_svn_conn_t *conn,
1589 const char *parent_token,
1593 SVN_ERR(writebuf_write_short_string(conn, pool, "( open-dir ( ", 13));
1594 SVN_ERR(write_cmd_open_node(conn, pool, path, parent_token, token, rev));
1595 SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
1597 return SVN_NO_ERROR;
1601 svn_ra_svn__write_cmd_change_dir_prop(svn_ra_svn_conn_t *conn,
1605 const svn_string_t *value)
1607 SVN_ERR(writebuf_write_short_string(conn, pool, "( change-dir-prop ( ", 20));
1608 SVN_ERR(write_cmd_change_node_prop(conn, pool, token, name, value));
1609 SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
1611 return SVN_NO_ERROR;
1615 svn_ra_svn__write_cmd_close_dir(svn_ra_svn_conn_t *conn,
1619 SVN_ERR(writebuf_write_short_string(conn, pool, "( close-dir ( ", 14));
1620 SVN_ERR(write_tuple_cstring(conn, pool, token));
1621 SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
1623 return SVN_NO_ERROR;
1627 svn_ra_svn__write_cmd_absent_dir(svn_ra_svn_conn_t *conn,
1630 const char *parent_token)
1632 SVN_ERR(writebuf_write_short_string(conn, pool, "( absent-dir ( ", 15));
1633 SVN_ERR(write_cmd_absent_node(conn, pool, path, parent_token));
1634 SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
1636 return SVN_NO_ERROR;
1640 svn_ra_svn__write_cmd_add_file(svn_ra_svn_conn_t *conn,
1643 const char *parent_token,
1645 const char *copy_path,
1646 svn_revnum_t copy_rev)
1648 SVN_ERR(writebuf_write_short_string(conn, pool, "( add-file ( ", 13));
1649 SVN_ERR(write_cmd_add_node(conn, pool, path, parent_token, token,
1650 copy_path, copy_rev));
1651 SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
1653 return SVN_NO_ERROR;
1657 svn_ra_svn__write_cmd_open_file(svn_ra_svn_conn_t *conn,
1660 const char *parent_token,
1664 SVN_ERR(writebuf_write_short_string(conn, pool, "( open-file ( ", 14));
1665 SVN_ERR(write_cmd_open_node(conn, pool, path, parent_token, token, rev));
1666 SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
1668 return SVN_NO_ERROR;
1672 svn_ra_svn__write_cmd_change_file_prop(svn_ra_svn_conn_t *conn,
1676 const svn_string_t *value)
1678 SVN_ERR(writebuf_write_short_string(conn, pool, "( change-file-prop ( ", 21));
1679 SVN_ERR(write_cmd_change_node_prop(conn, pool, token, name, value));
1680 SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
1682 return SVN_NO_ERROR;
1686 svn_ra_svn__write_cmd_close_file(svn_ra_svn_conn_t *conn,
1689 const char *text_checksum)
1691 SVN_ERR(writebuf_write_short_string(conn, pool, "( close-file ( ", 15));
1692 SVN_ERR(write_tuple_cstring(conn, pool, token));
1693 SVN_ERR(write_tuple_start_list(conn, pool));
1694 SVN_ERR(write_tuple_cstring_opt(conn, pool, text_checksum));
1695 SVN_ERR(write_tuple_end_list(conn, pool));
1696 SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
1698 return SVN_NO_ERROR;
1702 svn_ra_svn__write_cmd_absent_file(svn_ra_svn_conn_t *conn,
1705 const char *parent_token)
1707 SVN_ERR(writebuf_write_short_string(conn, pool, "( absent-file ( ", 16));
1708 SVN_ERR(write_cmd_absent_node(conn, pool, path, parent_token));
1709 SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
1711 return SVN_NO_ERROR;
1715 svn_ra_svn__write_cmd_textdelta_chunk(svn_ra_svn_conn_t *conn,
1718 const svn_string_t *chunk)
1720 SVN_ERR(writebuf_write_short_string(conn, pool, "( textdelta-chunk ( ", 20));
1721 SVN_ERR(write_tuple_cstring(conn, pool, token));
1722 SVN_ERR(write_tuple_string(conn, pool, chunk));
1723 SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
1725 return SVN_NO_ERROR;
1729 svn_ra_svn__write_cmd_textdelta_end(svn_ra_svn_conn_t *conn,
1733 SVN_ERR(writebuf_write_short_string(conn, pool, "( textdelta-end ( ", 18));
1734 SVN_ERR(write_tuple_cstring(conn, pool, token));
1735 SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
1737 return SVN_NO_ERROR;
1741 svn_ra_svn__write_cmd_apply_textdelta(svn_ra_svn_conn_t *conn,
1744 const char *base_checksum)
1746 SVN_ERR(writebuf_write_short_string(conn, pool, "( apply-textdelta ( ", 20));
1747 SVN_ERR(write_tuple_cstring(conn, pool, token));
1748 SVN_ERR(write_tuple_start_list(conn, pool));
1749 SVN_ERR(write_tuple_cstring_opt(conn, pool, base_checksum));
1750 SVN_ERR(write_tuple_end_list(conn, pool));
1751 SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
1753 return SVN_NO_ERROR;
1757 svn_ra_svn__write_cmd_close_edit(svn_ra_svn_conn_t *conn,
1760 return writebuf_write_short_string(conn, pool, "( close-edit ( ) ) ", 19);
1764 svn_ra_svn__write_cmd_abort_edit(svn_ra_svn_conn_t *conn,
1767 return writebuf_write_short_string(conn, pool, "( abort-edit ( ) ) ", 19);
1771 svn_ra_svn__write_cmd_set_path(svn_ra_svn_conn_t *conn,
1775 svn_boolean_t start_empty,
1776 const char *lock_token,
1779 SVN_ERR(writebuf_write_short_string(conn, pool, "( set-path ( ", 13));
1780 SVN_ERR(write_tuple_cstring(conn, pool, path));
1781 SVN_ERR(write_tuple_revision(conn, pool, rev));
1782 SVN_ERR(write_tuple_boolean(conn, pool, start_empty));
1783 SVN_ERR(write_tuple_start_list(conn, pool));
1784 SVN_ERR(write_tuple_cstring_opt(conn, pool, lock_token));
1785 SVN_ERR(write_tuple_end_list(conn, pool));
1786 SVN_ERR(write_tuple_depth(conn, pool, depth));
1787 SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
1789 return SVN_NO_ERROR;
1793 svn_ra_svn__write_cmd_delete_path(svn_ra_svn_conn_t *conn,
1797 SVN_ERR(writebuf_write_short_string(conn, pool, "( delete-path ( ", 16));
1798 SVN_ERR(write_tuple_cstring(conn, pool, path));
1799 SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
1801 return SVN_NO_ERROR;
1805 svn_ra_svn__write_cmd_link_path(svn_ra_svn_conn_t *conn,
1810 svn_boolean_t start_empty,
1811 const char *lock_token,
1814 SVN_ERR(writebuf_write_short_string(conn, pool, "( link-path ( ", 14));
1815 SVN_ERR(write_tuple_cstring(conn, pool, path));
1816 SVN_ERR(write_tuple_cstring(conn, pool, url));
1817 SVN_ERR(write_tuple_revision(conn, pool, rev));
1818 SVN_ERR(write_tuple_boolean(conn, pool, start_empty));
1819 SVN_ERR(write_tuple_start_list(conn, pool));
1820 SVN_ERR(write_tuple_cstring_opt(conn, pool,lock_token));
1821 SVN_ERR(write_tuple_end_list(conn, pool));
1822 SVN_ERR(write_tuple_depth(conn, pool, depth));
1823 SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
1825 return SVN_NO_ERROR;
1829 svn_ra_svn__write_cmd_finish_report(svn_ra_svn_conn_t *conn,
1832 return writebuf_write_short_string(conn, pool, "( finish-report ( ) ) ", 22);
1836 svn_ra_svn__write_cmd_abort_report(svn_ra_svn_conn_t *conn,
1839 return writebuf_write_short_string(conn, pool, "( abort-report ( ) ) ", 21);
1843 svn_ra_svn__write_cmd_reparent(svn_ra_svn_conn_t *conn,
1847 SVN_ERR(writebuf_write_short_string(conn, pool, "( reparent ( ", 13));
1848 SVN_ERR(write_tuple_cstring(conn, pool, url));
1849 SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
1851 return SVN_NO_ERROR;
1855 svn_ra_svn__write_cmd_get_latest_rev(svn_ra_svn_conn_t *conn,
1858 return writebuf_write_short_string(conn, pool, "( get-latest-rev ( ) ) ", 23);
1862 svn_ra_svn__write_cmd_get_dated_rev(svn_ra_svn_conn_t *conn,
1866 SVN_ERR(writebuf_write_short_string(conn, pool, "( get-dated-rev ( ", 18));
1867 SVN_ERR(write_tuple_cstring(conn, pool, svn_time_to_cstring(tm, pool)));
1868 SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
1870 return SVN_NO_ERROR;
1874 svn_ra_svn__write_cmd_change_rev_prop2(svn_ra_svn_conn_t *conn,
1878 const svn_string_t *value,
1879 svn_boolean_t dont_care,
1880 const svn_string_t *old_value)
1882 SVN_ERR(writebuf_write_short_string(conn, pool, "( change-rev-prop2 ( ", 21));
1883 SVN_ERR(write_tuple_revision(conn, pool, rev));
1884 SVN_ERR(write_tuple_cstring(conn, pool, name));
1885 SVN_ERR(write_tuple_start_list(conn, pool));
1886 SVN_ERR(write_tuple_string_opt(conn, pool, value));
1887 SVN_ERR(write_tuple_end_list(conn, pool));
1888 SVN_ERR(write_tuple_start_list(conn, pool));
1889 SVN_ERR(write_tuple_boolean(conn, pool, dont_care));
1890 SVN_ERR(write_tuple_string_opt(conn, pool, old_value));
1891 SVN_ERR(write_tuple_end_list(conn, pool));
1892 SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
1894 return SVN_NO_ERROR;
1898 svn_ra_svn__write_cmd_change_rev_prop(svn_ra_svn_conn_t *conn,
1902 const svn_string_t *value)
1904 SVN_ERR(writebuf_write_short_string(conn, pool, "( change-rev-prop ( ", 20));
1905 SVN_ERR(write_tuple_revision(conn, pool, rev));
1906 SVN_ERR(write_tuple_cstring(conn, pool, name));
1907 SVN_ERR(write_tuple_string_opt(conn, pool, value));
1908 SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
1910 return SVN_NO_ERROR;
1914 svn_ra_svn__write_cmd_rev_proplist(svn_ra_svn_conn_t *conn,
1918 SVN_ERR(writebuf_write_short_string(conn, pool, "( rev-proplist ( ", 17));
1919 SVN_ERR(write_tuple_revision(conn, pool, rev));
1920 SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
1922 return SVN_NO_ERROR;
1926 svn_ra_svn__write_cmd_rev_prop(svn_ra_svn_conn_t *conn,
1931 SVN_ERR(writebuf_write_short_string(conn, pool, "( rev-prop ( ", 13));
1932 SVN_ERR(write_tuple_revision(conn, pool, rev));
1933 SVN_ERR(write_tuple_cstring(conn, pool, name));
1934 SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
1936 return SVN_NO_ERROR;
1940 svn_ra_svn__write_cmd_get_file(svn_ra_svn_conn_t *conn,
1944 svn_boolean_t props,
1945 svn_boolean_t stream)
1947 SVN_ERR(writebuf_write_short_string(conn, pool, "( get-file ( ", 13));
1948 SVN_ERR(write_tuple_cstring(conn, pool, path));
1949 SVN_ERR(write_tuple_start_list(conn, pool));
1950 SVN_ERR(write_tuple_revision_opt(conn, pool, rev));
1951 SVN_ERR(write_tuple_end_list(conn, pool));
1952 SVN_ERR(write_tuple_boolean(conn, pool, props));
1953 SVN_ERR(write_tuple_boolean(conn, pool, stream));
1954 SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
1956 return SVN_NO_ERROR;
1960 svn_ra_svn__write_cmd_update(svn_ra_svn_conn_t *conn,
1964 svn_boolean_t recurse,
1966 svn_boolean_t send_copyfrom_args,
1967 svn_boolean_t ignore_ancestry)
1969 SVN_ERR(writebuf_write_short_string(conn, pool, "( update ( ", 11));
1970 SVN_ERR(write_tuple_start_list(conn, pool));
1971 SVN_ERR(write_tuple_revision_opt(conn, pool, rev));
1972 SVN_ERR(write_tuple_end_list(conn, pool));
1973 SVN_ERR(write_tuple_cstring(conn, pool, target));
1974 SVN_ERR(write_tuple_boolean(conn, pool, recurse));
1975 SVN_ERR(write_tuple_depth(conn, pool, depth));
1976 SVN_ERR(write_tuple_boolean(conn, pool, send_copyfrom_args));
1977 SVN_ERR(write_tuple_boolean(conn, pool, ignore_ancestry));
1978 SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
1980 return SVN_NO_ERROR;
1984 svn_ra_svn__write_cmd_switch(svn_ra_svn_conn_t *conn,
1988 svn_boolean_t recurse,
1989 const char *switch_url,
1991 svn_boolean_t send_copyfrom_args,
1992 svn_boolean_t ignore_ancestry)
1994 SVN_ERR(writebuf_write_short_string(conn, pool, "( switch ( ", 11));
1995 SVN_ERR(write_tuple_start_list(conn, pool));
1996 SVN_ERR(write_tuple_revision_opt(conn, pool, rev));
1997 SVN_ERR(write_tuple_end_list(conn, pool));
1998 SVN_ERR(write_tuple_cstring(conn, pool, target));
1999 SVN_ERR(write_tuple_boolean(conn, pool, recurse));
2000 SVN_ERR(write_tuple_cstring(conn, pool, switch_url));
2001 SVN_ERR(write_tuple_depth(conn, pool, depth));
2002 SVN_ERR(write_tuple_boolean(conn, pool, send_copyfrom_args));
2003 SVN_ERR(write_tuple_boolean(conn, pool, ignore_ancestry));
2004 SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
2006 return SVN_NO_ERROR;
2010 svn_ra_svn__write_cmd_status(svn_ra_svn_conn_t *conn,
2013 svn_boolean_t recurse,
2017 SVN_ERR(writebuf_write_short_string(conn, pool, "( status ( ", 11));
2018 SVN_ERR(write_tuple_cstring(conn, pool, target));
2019 SVN_ERR(write_tuple_boolean(conn, pool, recurse));
2020 SVN_ERR(write_tuple_start_list(conn, pool));
2021 SVN_ERR(write_tuple_revision_opt(conn, pool, rev));
2022 SVN_ERR(write_tuple_end_list(conn, pool));
2023 SVN_ERR(write_tuple_depth(conn, pool, depth));
2024 SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
2026 return SVN_NO_ERROR;
2030 svn_ra_svn__write_cmd_diff(svn_ra_svn_conn_t *conn,
2034 svn_boolean_t recurse,
2035 svn_boolean_t ignore_ancestry,
2036 const char *versus_url,
2037 svn_boolean_t text_deltas,
2040 SVN_ERR(writebuf_write_short_string(conn, pool, "( diff ( ", 9));
2041 SVN_ERR(write_tuple_start_list(conn, pool));
2042 SVN_ERR(write_tuple_revision_opt(conn, pool, rev));
2043 SVN_ERR(write_tuple_end_list(conn, pool));
2044 SVN_ERR(write_tuple_cstring(conn, pool, target));
2045 SVN_ERR(write_tuple_boolean(conn, pool, recurse));
2046 SVN_ERR(write_tuple_boolean(conn, pool, ignore_ancestry));
2047 SVN_ERR(write_tuple_cstring(conn, pool, versus_url));
2048 SVN_ERR(write_tuple_boolean(conn, pool, text_deltas));
2049 SVN_ERR(write_tuple_depth(conn, pool, depth));
2050 SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
2052 return SVN_NO_ERROR;
2056 svn_ra_svn__write_cmd_check_path(svn_ra_svn_conn_t *conn,
2061 SVN_ERR(writebuf_write_short_string(conn, pool, "( check-path ( ", 15));
2062 SVN_ERR(write_tuple_cstring(conn, pool, path));
2063 SVN_ERR(write_tuple_start_list(conn, pool));
2064 SVN_ERR(write_tuple_revision_opt(conn, pool, rev));
2065 SVN_ERR(write_tuple_end_list(conn, pool));
2066 SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
2068 return SVN_NO_ERROR;
2072 svn_ra_svn__write_cmd_stat(svn_ra_svn_conn_t *conn,
2077 SVN_ERR(writebuf_write_short_string(conn, pool, "( stat ( ", 9));
2078 SVN_ERR(write_tuple_cstring(conn, pool, path));
2079 SVN_ERR(write_tuple_start_list(conn, pool));
2080 SVN_ERR(write_tuple_revision_opt(conn, pool, rev));
2081 SVN_ERR(write_tuple_end_list(conn, pool));
2082 SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
2084 return SVN_NO_ERROR;
2088 svn_ra_svn__write_cmd_get_file_revs(svn_ra_svn_conn_t *conn,
2093 svn_boolean_t include_merged_revisions)
2095 SVN_ERR(writebuf_write_short_string(conn, pool, "( get-file-revs ( ", 18));
2096 SVN_ERR(write_tuple_cstring(conn, pool, path));
2097 SVN_ERR(write_tuple_start_list(conn, pool));
2098 SVN_ERR(write_tuple_revision_opt(conn, pool, start));
2099 SVN_ERR(write_tuple_end_list(conn, pool));
2100 SVN_ERR(write_tuple_start_list(conn, pool));
2101 SVN_ERR(write_tuple_revision_opt(conn, pool, end));
2102 SVN_ERR(write_tuple_end_list(conn, pool));
2103 SVN_ERR(write_tuple_boolean(conn, pool, include_merged_revisions));
2104 SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
2106 return SVN_NO_ERROR;
2110 svn_ra_svn__write_cmd_lock(svn_ra_svn_conn_t *conn,
2113 const char *comment,
2114 svn_boolean_t steal_lock,
2115 svn_revnum_t revnum)
2117 SVN_ERR(writebuf_write_short_string(conn, pool, "( lock ( ", 9));
2118 SVN_ERR(write_tuple_cstring(conn, pool, path));
2119 SVN_ERR(write_tuple_start_list(conn, pool));
2120 SVN_ERR(write_tuple_cstring_opt(conn, pool, comment));
2121 SVN_ERR(write_tuple_end_list(conn, pool));
2122 SVN_ERR(write_tuple_boolean(conn, pool, steal_lock));
2123 SVN_ERR(write_tuple_start_list(conn, pool));
2124 SVN_ERR(write_tuple_revision_opt(conn, pool, revnum));
2125 SVN_ERR(write_tuple_end_list(conn, pool));
2126 SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
2128 return SVN_NO_ERROR;
2132 svn_ra_svn__write_cmd_unlock(svn_ra_svn_conn_t *conn,
2136 svn_boolean_t break_lock)
2138 SVN_ERR(writebuf_write_short_string(conn, pool, "( unlock ( ", 11));
2139 SVN_ERR(write_tuple_cstring(conn, pool, path));
2140 SVN_ERR(write_tuple_start_list(conn, pool));
2141 SVN_ERR(write_tuple_cstring_opt(conn, pool, token));
2142 SVN_ERR(write_tuple_end_list(conn, pool));
2143 SVN_ERR(write_tuple_boolean(conn, pool, break_lock));
2144 SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
2146 return SVN_NO_ERROR;
2150 svn_ra_svn__write_cmd_get_lock(svn_ra_svn_conn_t *conn,
2154 SVN_ERR(writebuf_write_short_string(conn, pool, "( get-lock ( ", 13));
2155 SVN_ERR(write_tuple_cstring(conn, pool, path));
2156 SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
2158 return SVN_NO_ERROR;
2162 svn_ra_svn__write_cmd_get_locks(svn_ra_svn_conn_t *conn,
2167 SVN_ERR(writebuf_write_short_string(conn, pool, "( get-locks ( ", 14));
2168 SVN_ERR(write_tuple_cstring(conn, pool, path));
2169 SVN_ERR(write_tuple_start_list(conn, pool));
2170 SVN_ERR(write_tuple_depth(conn, pool, depth));
2171 SVN_ERR(write_tuple_end_list(conn, pool));
2172 SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
2174 return SVN_NO_ERROR;
2178 svn_ra_svn__write_cmd_replay(svn_ra_svn_conn_t *conn,
2181 svn_revnum_t low_water_mark,
2182 svn_boolean_t send_deltas)
2184 SVN_ERR(writebuf_write_short_string(conn, pool, "( replay ( ", 11));
2185 SVN_ERR(write_tuple_revision(conn, pool, rev));
2186 SVN_ERR(write_tuple_revision(conn, pool, low_water_mark));
2187 SVN_ERR(write_tuple_boolean(conn, pool, send_deltas));
2188 SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
2190 return SVN_NO_ERROR;
2194 svn_ra_svn__write_cmd_replay_range(svn_ra_svn_conn_t *conn,
2196 svn_revnum_t start_revision,
2197 svn_revnum_t end_revision,
2198 svn_revnum_t low_water_mark,
2199 svn_boolean_t send_deltas)
2201 SVN_ERR(writebuf_write_short_string(conn, pool, "( replay-range ( ", 17));
2202 SVN_ERR(write_tuple_revision(conn, pool, start_revision));
2203 SVN_ERR(write_tuple_revision(conn, pool, end_revision));
2204 SVN_ERR(write_tuple_revision(conn, pool, low_water_mark));
2205 SVN_ERR(write_tuple_boolean(conn, pool, send_deltas));
2206 SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
2208 return SVN_NO_ERROR;
2212 svn_ra_svn__write_cmd_get_deleted_rev(svn_ra_svn_conn_t *conn,
2215 svn_revnum_t peg_revision,
2216 svn_revnum_t end_revision)
2218 SVN_ERR(writebuf_write_short_string(conn, pool, "( get-deleted-rev ( ", 20));
2219 SVN_ERR(write_tuple_cstring(conn, pool, path));
2220 SVN_ERR(write_tuple_revision(conn, pool, peg_revision));
2221 SVN_ERR(write_tuple_revision(conn, pool, end_revision));
2222 SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
2224 return SVN_NO_ERROR;
2228 svn_ra_svn__write_cmd_get_iprops(svn_ra_svn_conn_t *conn,
2231 svn_revnum_t revision)
2233 SVN_ERR(writebuf_write_short_string(conn, pool, "( get-iprops ( ", 15));
2234 SVN_ERR(write_tuple_cstring(conn, pool, path));
2235 SVN_ERR(write_tuple_start_list(conn, pool));
2236 SVN_ERR(write_tuple_revision_opt(conn, pool, revision));
2237 SVN_ERR(write_tuple_end_list(conn, pool));
2238 SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
2240 return SVN_NO_ERROR;
2244 svn_ra_svn__write_cmd_finish_replay(svn_ra_svn_conn_t *conn,
2247 return writebuf_write_short_string(conn, pool, "( finish-replay ( ) ) ", 22);
2250 svn_error_t *svn_ra_svn__write_cmd_response(svn_ra_svn_conn_t *conn,
2252 const char *fmt, ...)
2257 SVN_ERR(writebuf_write_short_string(conn, pool, "( success ", 10));
2259 err = vwrite_tuple(conn, pool, fmt, &ap);
2261 return err ? svn_error_trace(err) : svn_ra_svn__end_list(conn, pool);
2264 svn_error_t *svn_ra_svn__write_cmd_failure(svn_ra_svn_conn_t *conn,
2265 apr_pool_t *pool, svn_error_t *err)
2268 SVN_ERR(writebuf_write_short_string(conn, pool, "( failure ( ", 12));
2269 for (; err; err = err->child)
2273 #ifdef SVN_ERR__TRACING
2274 if (svn_error__is_tracing_link(err))
2278 msg = svn_err_best_message(err, buffer, sizeof(buffer));
2280 /* The message string should have been optional, but we can't
2281 easily change that, so marshal nonexistent messages as "". */
2282 SVN_ERR(svn_ra_svn__write_tuple(conn, pool, "nccn",
2283 (apr_uint64_t) err->apr_err,
2285 err->file ? err->file : "",
2286 (apr_uint64_t) err->line));
2288 return writebuf_write_short_string(conn, pool, ") ) ", 4);