1/* 2 * marshal.c : Marshalling routines for Subversion protocol 3 * 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 12 * 13 * http://www.apache.org/licenses/LICENSE-2.0 14 * 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 20 * under the License. 21 * ==================================================================== 22 */ 23 24 25 26#include <assert.h> 27#include <stdlib.h> 28 29#define APR_WANT_STRFUNC 30#include <apr_want.h> 31#include <apr_general.h> 32#include <apr_lib.h> 33#include <apr_strings.h> 34 35#include "svn_hash.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_time.h" 44 45#include "ra_svn.h" 46 47#include "private/svn_string_private.h" 48#include "private/svn_dep_compat.h" 49#include "private/svn_error_private.h" 50 51#define svn_iswhitespace(c) ((c) == ' ' || (c) == '\n') 52 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. */ 56 57#define SUSPICIOUSLY_HUGE_STRING_SIZE_THRESHOLD (0x100000) 58 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. */ 61static apr_interval_time_t 62get_timeout(svn_ra_svn_conn_t *conn) 63{ 64 return conn->block_handler ? 0 : -1; 65} 66 67/* --- CONNECTION INITIALIZATION --- */ 68 69svn_ra_svn_conn_t *svn_ra_svn_create_conn3(apr_socket_t *sock, 70 apr_file_t *in_file, 71 apr_file_t *out_file, 72 int compression_level, 73 apr_size_t zero_copy_limit, 74 apr_size_t error_check_interval, 75 apr_pool_t *pool) 76{ 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); 80 81 assert((sock && !in_file && !out_file) || (!sock && in_file && out_file)); 82#ifdef SVN_HAVE_SASL 83 conn->sock = sock; 84 conn->encrypted = FALSE; 85#endif 86 conn->session = NULL; 87 conn->read_ptr = conn->read_buf; 88 conn->read_end = conn->read_buf; 89 conn->write_pos = 0; 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; 98 conn->pool = pool; 99 100 if (sock != NULL) 101 { 102 apr_sockaddr_t *sa; 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)); 108 } 109 else 110 { 111 conn->stream = svn_ra_svn__stream_from_files(in_file, out_file, pool); 112 conn->remote_ip = NULL; 113 } 114 115 return conn; 116} 117 118svn_ra_svn_conn_t *svn_ra_svn_create_conn2(apr_socket_t *sock, 119 apr_file_t *in_file, 120 apr_file_t *out_file, 121 int compression_level, 122 apr_pool_t *pool) 123{ 124 return svn_ra_svn_create_conn3(sock, in_file, out_file, 125 compression_level, 0, 0, pool); 126} 127 128/* backward-compatible implementation using the default compression level */ 129svn_ra_svn_conn_t *svn_ra_svn_create_conn(apr_socket_t *sock, 130 apr_file_t *in_file, 131 apr_file_t *out_file, 132 apr_pool_t *pool) 133{ 134 return svn_ra_svn_create_conn3(sock, in_file, out_file, 135 SVN_DELTA_COMPRESSION_LEVEL_DEFAULT, 0, 0, 136 pool); 137} 138 139svn_error_t *svn_ra_svn_set_capabilities(svn_ra_svn_conn_t *conn, 140 const apr_array_header_t *list) 141{ 142 int i; 143 svn_ra_svn_item_t *item; 144 const char *word; 145 146 for (i = 0; i < list->nelts; i++) 147 { 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); 154 } 155 return SVN_NO_ERROR; 156} 157 158svn_error_t * 159svn_ra_svn__set_shim_callbacks(svn_ra_svn_conn_t *conn, 160 svn_delta_shim_callbacks_t *shim_callbacks) 161{ 162 conn->shim_callbacks = shim_callbacks; 163 return SVN_NO_ERROR; 164} 165 166svn_boolean_t svn_ra_svn_has_capability(svn_ra_svn_conn_t *conn, 167 const char *capability) 168{ 169 return (svn_hash_gets(conn->capabilities, capability) != NULL); 170} 171 172int 173svn_ra_svn_compression_level(svn_ra_svn_conn_t *conn) 174{ 175 return conn->compression_level; 176} 177 178apr_size_t 179svn_ra_svn_zero_copy_limit(svn_ra_svn_conn_t *conn) 180{ 181 return conn->zero_copy_limit; 182} 183 184const char *svn_ra_svn_conn_remote_host(svn_ra_svn_conn_t *conn) 185{ 186 return conn->remote_ip; 187} 188 189void 190svn_ra_svn__set_block_handler(svn_ra_svn_conn_t *conn, 191 ra_svn_block_handler_t handler, 192 void *baton) 193{ 194 conn->block_handler = handler; 195 conn->block_baton = baton; 196 svn_ra_svn__stream_timeout(conn->stream, get_timeout(conn)); 197} 198 199svn_boolean_t svn_ra_svn__input_waiting(svn_ra_svn_conn_t *conn, 200 apr_pool_t *pool) 201{ 202 return svn_ra_svn__stream_pending(conn->stream); 203} 204 205/* --- WRITE BUFFER MANAGEMENT --- */ 206 207/* Write data to socket or output file as appropriate. */ 208static svn_error_t *writebuf_output(svn_ra_svn_conn_t *conn, apr_pool_t *pool, 209 const char *data, apr_size_t len) 210{ 211 const char *end = data + len; 212 apr_size_t count; 213 apr_pool_t *subpool = NULL; 214 svn_ra_svn__session_baton_t *session = conn->session; 215 216 while (data < end) 217 { 218 count = end - data; 219 220 if (session && session->callbacks && session->callbacks->cancel_func) 221 SVN_ERR((session->callbacks->cancel_func)(session->callbacks_baton)); 222 223 SVN_ERR(svn_ra_svn__stream_write(conn->stream, data, &count)); 224 if (count == 0) 225 { 226 if (!subpool) 227 subpool = svn_pool_create(pool); 228 else 229 svn_pool_clear(subpool); 230 SVN_ERR(conn->block_handler(conn, subpool, conn->block_baton)); 231 } 232 data += count; 233 234 if (session) 235 { 236 const svn_ra_callbacks2_t *cb = session->callbacks; 237 session->bytes_written += count; 238 239 if (cb && cb->progress_func) 240 (cb->progress_func)(session->bytes_written + session->bytes_read, 241 -1, cb->progress_baton, subpool); 242 } 243 } 244 245 conn->written_since_error_check += len; 246 conn->may_check_for_error 247 = conn->written_since_error_check >= conn->error_check_interval; 248 249 if (subpool) 250 svn_pool_destroy(subpool); 251 return SVN_NO_ERROR; 252} 253 254/* Write data from the write buffer out to the socket. */ 255static svn_error_t *writebuf_flush(svn_ra_svn_conn_t *conn, apr_pool_t *pool) 256{ 257 apr_size_t write_pos = conn->write_pos; 258 259 /* Clear conn->write_pos first in case the block handler does a read. */ 260 conn->write_pos = 0; 261 SVN_ERR(writebuf_output(conn, pool, conn->write_buf, write_pos)); 262 return SVN_NO_ERROR; 263} 264 265static svn_error_t *writebuf_write(svn_ra_svn_conn_t *conn, apr_pool_t *pool, 266 const char *data, apr_size_t len) 267{ 268 /* data >= 8k is sent immediately */ 269 if (len >= sizeof(conn->write_buf) / 2) 270 { 271 if (conn->write_pos > 0) 272 SVN_ERR(writebuf_flush(conn, pool)); 273 274 return writebuf_output(conn, pool, data, len); 275 } 276 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)); 280 281 /* buffer the new data block as well */ 282 memcpy(conn->write_buf + conn->write_pos, data, len); 283 conn->write_pos += len; 284 285 return SVN_NO_ERROR; 286} 287 288static svn_error_t * 289writebuf_write_short_string(svn_ra_svn_conn_t *conn, apr_pool_t *pool, 290 const char *data, apr_size_t len) 291{ 292 apr_size_t left = sizeof(conn->write_buf) - conn->write_pos; 293 if (len <= left) 294 { 295 memcpy(conn->write_buf + conn->write_pos, data, len); 296 conn->write_pos += len; 297 return SVN_NO_ERROR; 298 } 299 else 300 return writebuf_write(conn, pool, data, len); 301} 302 303static APR_INLINE svn_error_t * 304writebuf_writechar(svn_ra_svn_conn_t *conn, apr_pool_t *pool, char data) 305{ 306 if (conn->write_pos < sizeof(conn->write_buf)) 307 { 308 conn->write_buf[conn->write_pos] = data; 309 conn->write_pos++; 310 311 return SVN_NO_ERROR; 312 } 313 else 314 { 315 char temp = data; 316 return writebuf_write(conn, pool, &temp, 1); 317 } 318} 319 320/* --- READ BUFFER MANAGEMENT --- */ 321 322/* Read bytes into DATA until either the read buffer is empty or 323 * we reach END. */ 324static char *readbuf_drain(svn_ra_svn_conn_t *conn, char *data, char *end) 325{ 326 apr_ssize_t buflen, copylen; 327 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; 333} 334 335/* Read data from socket or input file as appropriate. */ 336static svn_error_t *readbuf_input(svn_ra_svn_conn_t *conn, char *data, 337 apr_size_t *len, apr_pool_t *pool) 338{ 339 svn_ra_svn__session_baton_t *session = conn->session; 340 341 if (session && session->callbacks && session->callbacks->cancel_func) 342 SVN_ERR((session->callbacks->cancel_func)(session->callbacks_baton)); 343 344 SVN_ERR(svn_ra_svn__stream_read(conn->stream, data, len)); 345 if (*len == 0) 346 return svn_error_create(SVN_ERR_RA_SVN_CONNECTION_CLOSED, NULL, NULL); 347 348 if (session) 349 { 350 const svn_ra_callbacks2_t *cb = session->callbacks; 351 session->bytes_read += *len; 352 353 if (cb && cb->progress_func) 354 (cb->progress_func)(session->bytes_read + session->bytes_written, 355 -1, cb->progress_baton, pool); 356 } 357 358 return SVN_NO_ERROR; 359} 360 361/* Treat the next LEN input bytes from CONN as "read" */ 362static svn_error_t *readbuf_skip(svn_ra_svn_conn_t *conn, apr_uint64_t len) 363{ 364 do 365 { 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; 369 len -= copylen; 370 if (len == 0) 371 break; 372 373 buflen = sizeof(conn->read_buf); 374 SVN_ERR(svn_ra_svn__stream_read(conn->stream, conn->read_buf, &buflen)); 375 if (buflen == 0) 376 return svn_error_create(SVN_ERR_RA_SVN_CONNECTION_CLOSED, NULL, NULL); 377 378 conn->read_end = conn->read_buf + buflen; 379 conn->read_ptr = conn->read_buf; 380 } 381 while (len > 0); 382 383 return SVN_NO_ERROR; 384} 385 386/* Read data from the socket into the read buffer, which must be empty. */ 387static svn_error_t *readbuf_fill(svn_ra_svn_conn_t *conn, apr_pool_t *pool) 388{ 389 apr_size_t len; 390 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; 397 return SVN_NO_ERROR; 398} 399 400static APR_INLINE svn_error_t * 401readbuf_getchar(svn_ra_svn_conn_t *conn, apr_pool_t *pool, char *result) 402{ 403 if (conn->read_ptr == conn->read_end) 404 SVN_ERR(readbuf_fill(conn, pool)); 405 *result = *conn->read_ptr++; 406 return SVN_NO_ERROR; 407} 408 409static svn_error_t *readbuf_getchar_skip_whitespace(svn_ra_svn_conn_t *conn, 410 apr_pool_t *pool, 411 char *result) 412{ 413 do 414 SVN_ERR(readbuf_getchar(conn, pool, result)); 415 while (svn_iswhitespace(*result)); 416 return SVN_NO_ERROR; 417} 418 419/* Read the next LEN bytes from CONN and copy them to *DATA. */ 420static svn_error_t *readbuf_read(svn_ra_svn_conn_t *conn, apr_pool_t *pool, 421 char *data, apr_size_t len) 422{ 423 char *end = data + len; 424 apr_size_t count; 425 426 /* Copy in an appropriate amount of data from the buffer. */ 427 data = readbuf_drain(conn, data, end); 428 429 /* Read large chunks directly into buffer. */ 430 while (end - data > (apr_ssize_t)sizeof(conn->read_buf)) 431 { 432 SVN_ERR(writebuf_flush(conn, pool)); 433 count = end - data; 434 SVN_ERR(readbuf_input(conn, data, &count, pool)); 435 data += count; 436 } 437 438 while (end > data) 439 { 440 /* The remaining amount to read is small; fill the buffer and 441 * copy from that. */ 442 SVN_ERR(readbuf_fill(conn, pool)); 443 data = readbuf_drain(conn, data, end); 444 } 445 446 return SVN_NO_ERROR; 447} 448 449static svn_error_t *readbuf_skip_leading_garbage(svn_ra_svn_conn_t *conn, 450 apr_pool_t *pool) 451{ 452 char buf[256]; /* Must be smaller than sizeof(conn->read_buf) - 1. */ 453 const char *p, *end; 454 apr_size_t len; 455 svn_boolean_t lparen = FALSE; 456 457 SVN_ERR_ASSERT(conn->read_ptr == conn->read_end); 458 while (1) 459 { 460 /* Read some data directly from the connection input source. */ 461 len = sizeof(buf); 462 SVN_ERR(readbuf_input(conn, buf, &len, pool)); 463 end = buf + len; 464 465 /* Scan the data for '(' WS with a very simple state machine. */ 466 for (p = buf; p < end; p++) 467 { 468 if (lparen && svn_iswhitespace(*p)) 469 break; 470 else 471 lparen = (*p == '('); 472 } 473 if (p < end) 474 break; 475 } 476 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 479 * buffer. */ 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); 484 return SVN_NO_ERROR; 485} 486 487/* --- WRITING DATA ITEMS --- */ 488 489static svn_error_t *write_number(svn_ra_svn_conn_t *conn, apr_pool_t *pool, 490 apr_uint64_t number, char follow) 491{ 492 apr_size_t written; 493 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)); 498 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; 502 503 return SVN_NO_ERROR; 504} 505 506svn_error_t * 507svn_ra_svn__write_number(svn_ra_svn_conn_t *conn, 508 apr_pool_t *pool, 509 apr_uint64_t number) 510{ 511 return write_number(conn, pool, number, ' '); 512} 513 514svn_error_t * 515svn_ra_svn__write_string(svn_ra_svn_conn_t *conn, 516 apr_pool_t *pool, 517 const svn_string_t *str) 518{ 519 if (str->len < 10) 520 { 521 SVN_ERR(writebuf_writechar(conn, pool, (char)(str->len + '0'))); 522 SVN_ERR(writebuf_writechar(conn, pool, ':')); 523 } 524 else 525 SVN_ERR(write_number(conn, pool, str->len, ':')); 526 527 SVN_ERR(writebuf_write(conn, pool, str->data, str->len)); 528 SVN_ERR(writebuf_writechar(conn, pool, ' ')); 529 return SVN_NO_ERROR; 530} 531 532svn_error_t * 533svn_ra_svn__write_cstring(svn_ra_svn_conn_t *conn, 534 apr_pool_t *pool, 535 const char *s) 536{ 537 apr_size_t len = strlen(s); 538 539 if (len < 10) 540 { 541 SVN_ERR(writebuf_writechar(conn, pool, (char)(len + '0'))); 542 SVN_ERR(writebuf_writechar(conn, pool, ':')); 543 } 544 else 545 SVN_ERR(write_number(conn, pool, len, ':')); 546 547 SVN_ERR(writebuf_write(conn, pool, s, len)); 548 SVN_ERR(writebuf_writechar(conn, pool, ' ')); 549 550 return SVN_NO_ERROR; 551} 552 553svn_error_t * 554svn_ra_svn__write_word(svn_ra_svn_conn_t *conn, 555 apr_pool_t *pool, 556 const char *word) 557{ 558 SVN_ERR(writebuf_write_short_string(conn, pool, word, strlen(word))); 559 SVN_ERR(writebuf_writechar(conn, pool, ' ')); 560 561 return SVN_NO_ERROR; 562} 563 564svn_error_t * 565svn_ra_svn__write_proplist(svn_ra_svn_conn_t *conn, 566 apr_pool_t *pool, 567 apr_hash_t *props) 568{ 569 apr_pool_t *iterpool; 570 apr_hash_index_t *hi; 571 const void *key; 572 void *val; 573 const char *propname; 574 svn_string_t *propval; 575 576 if (props) 577 { 578 iterpool = svn_pool_create(pool); 579 for (hi = apr_hash_first(pool, props); hi; hi = apr_hash_next(hi)) 580 { 581 svn_pool_clear(iterpool); 582 apr_hash_this(hi, &key, NULL, &val); 583 propname = key; 584 propval = val; 585 SVN_ERR(svn_ra_svn__write_tuple(conn, iterpool, "cs", 586 propname, propval)); 587 } 588 svn_pool_destroy(iterpool); 589 } 590 591 return SVN_NO_ERROR; 592} 593 594svn_error_t * 595svn_ra_svn__start_list(svn_ra_svn_conn_t *conn, 596 apr_pool_t *pool) 597{ 598 if (conn->write_pos + 2 <= sizeof(conn->write_buf)) 599 { 600 conn->write_buf[conn->write_pos] = '('; 601 conn->write_buf[conn->write_pos+1] = ' '; 602 conn->write_pos += 2; 603 return SVN_NO_ERROR; 604 } 605 606 return writebuf_write(conn, pool, "( ", 2); 607} 608 609svn_error_t * 610svn_ra_svn__end_list(svn_ra_svn_conn_t *conn, 611 apr_pool_t *pool) 612{ 613 if (conn->write_pos + 2 <= sizeof(conn->write_buf)) 614 { 615 conn->write_buf[conn->write_pos] = ')'; 616 conn->write_buf[conn->write_pos+1] = ' '; 617 conn->write_pos += 2; 618 return SVN_NO_ERROR; 619 } 620 621 return writebuf_write(conn, pool, ") ", 2); 622} 623 624svn_error_t * 625svn_ra_svn__flush(svn_ra_svn_conn_t *conn, 626 apr_pool_t *pool) 627{ 628 SVN_ERR(writebuf_flush(conn, pool)); 629 conn->may_check_for_error = TRUE; 630 631 return SVN_NO_ERROR; 632} 633 634/* --- WRITING TUPLES --- */ 635 636static svn_error_t * 637vwrite_tuple_cstring(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap) 638{ 639 const char *cstr = va_arg(*ap, const char *); 640 SVN_ERR_ASSERT(cstr); 641 return svn_ra_svn__write_cstring(conn, pool, cstr); 642} 643 644static svn_error_t * 645vwrite_tuple_cstring_opt(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap) 646{ 647 const char *cstr = va_arg(*ap, const char *); 648 return cstr ? svn_ra_svn__write_cstring(conn, pool, cstr) : SVN_NO_ERROR; 649} 650 651static svn_error_t * 652vwrite_tuple_string(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap) 653{ 654 const svn_string_t *str = va_arg(*ap, const svn_string_t *); 655 SVN_ERR_ASSERT(str); 656 return svn_ra_svn__write_string(conn, pool, str); 657} 658 659static svn_error_t * 660vwrite_tuple_string_opt(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap) 661{ 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; 664} 665 666static svn_error_t * 667vwrite_tuple_word(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap) 668{ 669 const char *cstr = va_arg(*ap, const char *); 670 SVN_ERR_ASSERT(cstr); 671 return svn_ra_svn__write_word(conn, pool, cstr); 672} 673 674static svn_error_t * 675vwrite_tuple_word_opt(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap) 676{ 677 const char *cstr = va_arg(*ap, const char *); 678 return cstr ? svn_ra_svn__write_word(conn, pool, cstr) : SVN_NO_ERROR; 679} 680 681static svn_error_t * 682vwrite_tuple_revision(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap) 683{ 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); 687} 688 689static svn_error_t * 690vwrite_tuple_revision_opt(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap) 691{ 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) 695 : SVN_NO_ERROR; 696} 697 698static svn_error_t * 699vwrite_tuple_number(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap) 700{ 701 return svn_ra_svn__write_number(conn, pool, va_arg(*ap, apr_uint64_t)); 702} 703 704static svn_error_t * 705vwrite_tuple_boolean(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap) 706{ 707 const char *cstr = va_arg(*ap, svn_boolean_t) ? "true" : "false"; 708 return svn_ra_svn__write_word(conn, pool, cstr); 709} 710 711static svn_error_t * 712write_tuple_cstring(svn_ra_svn_conn_t *conn, 713 apr_pool_t *pool, 714 const char *cstr) 715{ 716 SVN_ERR_ASSERT(cstr); 717 return svn_ra_svn__write_cstring(conn, pool, cstr); 718} 719 720static svn_error_t * 721write_tuple_cstring_opt(svn_ra_svn_conn_t *conn, 722 apr_pool_t *pool, 723 const char *cstr) 724{ 725 return cstr ? svn_ra_svn__write_cstring(conn, pool, cstr) : SVN_NO_ERROR; 726} 727 728static svn_error_t * 729write_tuple_string(svn_ra_svn_conn_t *conn, 730 apr_pool_t *pool, 731 const svn_string_t *str) 732{ 733 SVN_ERR_ASSERT(str); 734 return svn_ra_svn__write_string(conn, pool, str); 735} 736 737static svn_error_t * 738write_tuple_string_opt(svn_ra_svn_conn_t *conn, 739 apr_pool_t *pool, 740 const svn_string_t *str) 741{ 742 return str ? svn_ra_svn__write_string(conn, pool, str) : SVN_NO_ERROR; 743} 744 745static svn_error_t * 746write_tuple_start_list(svn_ra_svn_conn_t *conn, 747 apr_pool_t *pool) 748{ 749 return svn_ra_svn__start_list(conn, pool); 750} 751 752static svn_error_t * 753write_tuple_end_list(svn_ra_svn_conn_t *conn, 754 apr_pool_t *pool) 755{ 756 return svn_ra_svn__end_list(conn, pool); 757} 758 759static svn_error_t * 760write_tuple_revision(svn_ra_svn_conn_t *conn, 761 apr_pool_t *pool, 762 svn_revnum_t rev) 763{ 764 SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(rev)); 765 return svn_ra_svn__write_number(conn, pool, rev); 766} 767 768static svn_error_t * 769write_tuple_revision_opt(svn_ra_svn_conn_t *conn, 770 apr_pool_t *pool, 771 svn_revnum_t rev) 772{ 773 return SVN_IS_VALID_REVNUM(rev) 774 ? svn_ra_svn__write_number(conn, pool, rev) 775 : SVN_NO_ERROR; 776} 777 778static svn_error_t * 779write_tuple_boolean(svn_ra_svn_conn_t *conn, 780 apr_pool_t *pool, 781 svn_boolean_t value) 782{ 783 const char *cstr = value ? "true" : "false"; 784 return svn_ra_svn__write_word(conn, pool, cstr); 785} 786 787static svn_error_t * 788write_tuple_depth(svn_ra_svn_conn_t *conn, 789 apr_pool_t *pool, 790 svn_depth_t depth) 791{ 792 return svn_ra_svn__write_word(conn, pool, svn_depth_to_word(depth)); 793} 794 795 796static svn_error_t * 797write_cmd_add_node(svn_ra_svn_conn_t *conn, 798 apr_pool_t *pool, 799 const char *path, 800 const char *parent_token, 801 const char *token, 802 const char *copy_path, 803 svn_revnum_t copy_rev) 804{ 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)); 812 813 return SVN_NO_ERROR; 814} 815 816static svn_error_t * 817write_cmd_open_node(svn_ra_svn_conn_t *conn, 818 apr_pool_t *pool, 819 const char *path, 820 const char *parent_token, 821 const char *token, 822 svn_revnum_t rev) 823{ 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)); 830 831 return SVN_NO_ERROR; 832} 833 834static svn_error_t * 835write_cmd_change_node_prop(svn_ra_svn_conn_t *conn, 836 apr_pool_t *pool, 837 const char *token, 838 const char *name, 839 const svn_string_t *value) 840{ 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)); 846 847 return SVN_NO_ERROR; 848} 849 850static svn_error_t * 851write_cmd_absent_node(svn_ra_svn_conn_t *conn, 852 apr_pool_t *pool, 853 const char *path, 854 const char *token) 855{ 856 SVN_ERR(write_tuple_cstring(conn, pool, path)); 857 SVN_ERR(write_tuple_cstring(conn, pool, token)); 858 859 return SVN_NO_ERROR; 860} 861 862 863 864 865static svn_error_t *vwrite_tuple(svn_ra_svn_conn_t *conn, apr_pool_t *pool, 866 const char *fmt, va_list *ap) 867{ 868 svn_boolean_t opt = FALSE; 869 870 if (*fmt == '!') 871 fmt++; 872 else 873 SVN_ERR(svn_ra_svn__start_list(conn, pool)); 874 for (; *fmt; fmt++) 875 { 876 if (*fmt == 'c') 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 == ')') 885 { 886 SVN_ERR(write_tuple_end_list(conn, pool)); 887 opt = FALSE; 888 } 889 else if (*fmt == '?') 890 opt = TRUE; 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)) 902 return SVN_NO_ERROR; 903 else 904 SVN_ERR_MALFUNCTION(); 905 } 906 SVN_ERR(svn_ra_svn__end_list(conn, pool)); 907 return SVN_NO_ERROR; 908} 909 910svn_error_t * 911svn_ra_svn__write_tuple(svn_ra_svn_conn_t *conn, 912 apr_pool_t *pool, 913 const char *fmt, ...) 914{ 915 svn_error_t *err; 916 va_list ap; 917 918 va_start(ap, fmt); 919 err = vwrite_tuple(conn, pool, fmt, &ap); 920 va_end(ap); 921 return err; 922} 923 924/* --- READING DATA ITEMS --- */ 925 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. */ 929static 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) 931{ 932 svn_stringbuf_t *stringbuf; 933 apr_size_t len = (apr_size_t)len64; 934 apr_size_t readbuf_len; 935 char *dest; 936 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")); 942 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 952 ? len 953 : SUSPICIOUSLY_HUGE_STRING_SIZE_THRESHOLD; 954 stringbuf = svn_stringbuf_create_ensure(readbuf_len, pool); 955 dest = stringbuf->data; 956 957 /* Read remaining string data directly into the string structure. 958 * Do it iteratively, if necessary. */ 959 while (readbuf_len) 960 { 961 SVN_ERR(readbuf_read(conn, pool, dest, readbuf_len)); 962 963 stringbuf->len += readbuf_len; 964 len -= readbuf_len; 965 966 /* Early exit. In most cases, strings can be read in the first 967 * iteration. */ 968 if (len == 0) 969 break; 970 971 /* Prepare next iteration: determine length of chunk to read 972 * and re-alloc the string buffer. */ 973 readbuf_len 974 = len < SUSPICIOUSLY_HUGE_STRING_SIZE_THRESHOLD 975 ? len 976 : SUSPICIOUSLY_HUGE_STRING_SIZE_THRESHOLD; 977 978 svn_stringbuf_ensure(stringbuf, stringbuf->len + readbuf_len); 979 dest = stringbuf->data + stringbuf->len; 980 } 981 982 /* zero-terminate the string */ 983 stringbuf->data[stringbuf->len] = '\0'; 984 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); 988 989 return SVN_NO_ERROR; 990} 991 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 995 * on the parser. */ 996static 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, 998 int level) 999{ 1000 char c = first_char; 1001 apr_uint64_t val; 1002 svn_stringbuf_t *str; 1003 svn_ra_svn_item_t *listitem; 1004 1005 if (++level >= 64) 1006 return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL, 1007 _("Too many nested items")); 1008 1009 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)) 1014 { 1015 /* It's a number or a string. Read the number part, either way. */ 1016 val = c - '0'; 1017 while (1) 1018 { 1019 apr_uint64_t prev_val = val; 1020 SVN_ERR(readbuf_getchar(conn, pool, &c)); 1021 if (!svn_ctype_isdigit(c)) 1022 break; 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")); 1028 } 1029 if (c == ':') 1030 { 1031 /* It's a string. */ 1032 SVN_ERR(read_string(conn, pool, item, val)); 1033 SVN_ERR(readbuf_getchar(conn, pool, &c)); 1034 } 1035 else 1036 { 1037 /* It's a number. */ 1038 item->kind = SVN_RA_SVN_NUMBER; 1039 item->u.number = val; 1040 } 1041 } 1042 else if (svn_ctype_isalpha(c)) 1043 { 1044 /* It's a word. */ 1045 str = svn_stringbuf_create_ensure(16, pool); 1046 svn_stringbuf_appendbyte(str, c); 1047 while (1) 1048 { 1049 SVN_ERR(readbuf_getchar(conn, pool, &c)); 1050 if (!svn_ctype_isalnum(c) && c != '-') 1051 break; 1052 svn_stringbuf_appendbyte(str, c); 1053 } 1054 item->kind = SVN_RA_SVN_WORD; 1055 item->u.word = str->data; 1056 } 1057 else if (c == '(') 1058 { 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)); 1062 while (1) 1063 { 1064 SVN_ERR(readbuf_getchar_skip_whitespace(conn, pool, &c)); 1065 if (c == ')') 1066 break; 1067 listitem = apr_array_push(item->u.list); 1068 SVN_ERR(read_item(conn, pool, listitem, c, level)); 1069 } 1070 SVN_ERR(readbuf_getchar(conn, pool, &c)); 1071 } 1072 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; 1077} 1078 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. */ 1082static svn_error_t * 1083read_command_only(svn_ra_svn_conn_t *conn, apr_pool_t *pool, 1084 const char **item, char first_char) 1085{ 1086 char c = first_char; 1087 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)) 1092 { 1093 /* It's a number or a string. Read the number part, either way. */ 1094 apr_uint64_t val, prev_val=0; 1095 val = c - '0'; 1096 while (1) 1097 { 1098 prev_val = val; 1099 SVN_ERR(readbuf_getchar(conn, pool, &c)); 1100 if (!svn_ctype_isdigit(c)) 1101 break; 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")); 1106 } 1107 if (c == ':') 1108 { 1109 /* It's a string. */ 1110 SVN_ERR(readbuf_skip(conn, val)); 1111 SVN_ERR(readbuf_getchar(conn, pool, &c)); 1112 } 1113 } 1114 else if (svn_ctype_isalpha(c)) 1115 { 1116 /* It's a word. */ 1117 if (item) 1118 { 1119 /* This is the word we want to read */ 1120 1121 char *buf = apr_palloc(pool, 32); 1122 apr_size_t len = 1; 1123 buf[0] = c; 1124 1125 while (1) 1126 { 1127 SVN_ERR(readbuf_getchar(conn, pool, &c)); 1128 if (!svn_ctype_isalnum(c) && c != '-') 1129 break; 1130 buf[len] = c; 1131 if (++len == 32) 1132 return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL, 1133 _("Word too long")); 1134 } 1135 buf[len] = 0; 1136 *item = buf; 1137 } 1138 else 1139 { 1140 /* we don't need the actual word, just skip it */ 1141 do 1142 { 1143 SVN_ERR(readbuf_getchar(conn, pool, &c)); 1144 } 1145 while (svn_ctype_isalnum(c) || c == '-'); 1146 } 1147 } 1148 else if (c == '(') 1149 { 1150 /* Read in the list items. */ 1151 while (1) 1152 { 1153 SVN_ERR(readbuf_getchar_skip_whitespace(conn, pool, &c)); 1154 if (c == ')') 1155 break; 1156 1157 if (item && *item == NULL) 1158 SVN_ERR(read_command_only(conn, pool, item, c)); 1159 else 1160 SVN_ERR(read_command_only(conn, pool, NULL, c)); 1161 } 1162 SVN_ERR(readbuf_getchar(conn, pool, &c)); 1163 } 1164 1165 return SVN_NO_ERROR; 1166} 1167 1168svn_error_t * 1169svn_ra_svn__read_item(svn_ra_svn_conn_t *conn, 1170 apr_pool_t *pool, 1171 svn_ra_svn_item_t **item) 1172{ 1173 char c; 1174 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); 1180} 1181 1182svn_error_t * 1183svn_ra_svn__skip_leading_garbage(svn_ra_svn_conn_t *conn, 1184 apr_pool_t *pool) 1185{ 1186 return readbuf_skip_leading_garbage(conn, pool); 1187} 1188 1189/* --- READING AND PARSING TUPLES --- */ 1190 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. */ 1193static svn_error_t *vparse_tuple(const apr_array_header_t *items, apr_pool_t *pool, 1194 const char **fmt, va_list *ap) 1195{ 1196 int count, nesting_level; 1197 svn_ra_svn_item_t *elt; 1198 1199 for (count = 0; **fmt && count < items->nelts; (*fmt)++, count++) 1200 { 1201 /* '?' just means the tuple may stop; skip past it. */ 1202 if (**fmt == '?') 1203 (*fmt)++; 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) 1216 { 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; 1221 else 1222 break; 1223 } 1224 else if (**fmt == 'B' && elt->kind == SVN_RA_SVN_WORD) 1225 { 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; 1230 else 1231 break; 1232 } 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) 1236 { 1237 (*fmt)++; 1238 SVN_ERR(vparse_tuple(elt->u.list, pool, fmt, ap)); 1239 } 1240 else if (**fmt == ')') 1241 return SVN_NO_ERROR; 1242 else 1243 break; 1244 } 1245 if (**fmt == '?') 1246 { 1247 nesting_level = 0; 1248 for (; **fmt; (*fmt)++) 1249 { 1250 switch (**fmt) 1251 { 1252 case '?': 1253 break; 1254 case 'r': 1255 *va_arg(*ap, svn_revnum_t *) = SVN_INVALID_REVNUM; 1256 break; 1257 case 's': 1258 *va_arg(*ap, svn_string_t **) = NULL; 1259 break; 1260 case 'c': 1261 case 'w': 1262 *va_arg(*ap, const char **) = NULL; 1263 break; 1264 case 'l': 1265 *va_arg(*ap, apr_array_header_t **) = NULL; 1266 break; 1267 case 'B': 1268 case 'n': 1269 *va_arg(*ap, apr_uint64_t *) = SVN_RA_SVN_UNSPECIFIED_NUMBER; 1270 break; 1271 case '(': 1272 nesting_level++; 1273 break; 1274 case ')': 1275 if (--nesting_level < 0) 1276 return SVN_NO_ERROR; 1277 break; 1278 default: 1279 SVN_ERR_MALFUNCTION(); 1280 } 1281 } 1282 } 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; 1287} 1288 1289svn_error_t * 1290svn_ra_svn__parse_tuple(const apr_array_header_t *list, 1291 apr_pool_t *pool, 1292 const char *fmt, ...) 1293{ 1294 svn_error_t *err; 1295 va_list ap; 1296 1297 va_start(ap, fmt); 1298 err = vparse_tuple(list, pool, &fmt, &ap); 1299 va_end(ap); 1300 return err; 1301} 1302 1303svn_error_t * 1304svn_ra_svn__read_tuple(svn_ra_svn_conn_t *conn, 1305 apr_pool_t *pool, 1306 const char *fmt, ...) 1307{ 1308 va_list ap; 1309 svn_ra_svn_item_t *item; 1310 svn_error_t *err; 1311 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")); 1316 va_start(ap, fmt); 1317 err = vparse_tuple(item->u.list, pool, &fmt, &ap); 1318 va_end(ap); 1319 return err; 1320} 1321 1322svn_error_t * 1323svn_ra_svn__read_command_only(svn_ra_svn_conn_t *conn, 1324 apr_pool_t *pool, 1325 const char **command) 1326{ 1327 char c; 1328 SVN_ERR(readbuf_getchar_skip_whitespace(conn, pool, &c)); 1329 1330 *command = NULL; 1331 return read_command_only(conn, pool, command, c); 1332} 1333 1334 1335svn_error_t * 1336svn_ra_svn__parse_proplist(const apr_array_header_t *list, 1337 apr_pool_t *pool, 1338 apr_hash_t **props) 1339{ 1340 char *name; 1341 svn_string_t *value; 1342 svn_ra_svn_item_t *elt; 1343 int i; 1344 1345 *props = apr_hash_make(pool); 1346 for (i = 0; i < list->nelts; i++) 1347 { 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", 1353 &name, &value)); 1354 svn_hash_sets(*props, name, value); 1355 } 1356 1357 return SVN_NO_ERROR; 1358} 1359 1360 1361/* --- READING AND WRITING COMMANDS AND RESPONSES --- */ 1362 1363svn_error_t *svn_ra_svn__locate_real_error_child(svn_error_t *err) 1364{ 1365 svn_error_t *this_link; 1366 1367 SVN_ERR_ASSERT(err); 1368 1369 for (this_link = err; 1370 this_link && (this_link->apr_err == SVN_ERR_RA_SVN_CMD_ERR); 1371 this_link = this_link->child) 1372 ; 1373 1374 SVN_ERR_ASSERT(this_link); 1375 return this_link; 1376} 1377 1378svn_error_t *svn_ra_svn__handle_failure_status(const apr_array_header_t *params, 1379 apr_pool_t *pool) 1380{ 1381 const char *message, *file; 1382 svn_error_t *err = NULL; 1383 svn_ra_svn_item_t *elt; 1384 int i; 1385 apr_uint64_t apr_err, line; 1386 apr_pool_t *subpool = svn_pool_create(pool); 1387 1388 if (params->nelts == 0) 1389 return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL, 1390 _("Empty error list")); 1391 1392 /* Rebuild the error list from the end, to avoid reversing the order. */ 1393 for (i = params->nelts - 1; i >= 0; i--) 1394 { 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. */ 1404 if (!*message) 1405 message = NULL; 1406 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 1410 response. */ 1411 if ((apr_status_t)apr_err != SVN_ERR_RA_SVN_CMD_ERR) 1412 { 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; 1416 } 1417 } 1418 1419 svn_pool_destroy(subpool); 1420 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. */ 1423 if (! err) 1424 err = svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL, 1425 _("Malformed error list")); 1426 1427 return err; 1428} 1429 1430svn_error_t * 1431svn_ra_svn__read_cmd_response(svn_ra_svn_conn_t *conn, 1432 apr_pool_t *pool, 1433 const char *fmt, ...) 1434{ 1435 va_list ap; 1436 const char *status; 1437 apr_array_header_t *params; 1438 svn_error_t *err; 1439 1440 SVN_ERR(svn_ra_svn__read_tuple(conn, pool, "wl", &status, ¶ms)); 1441 if (strcmp(status, "success") == 0) 1442 { 1443 va_start(ap, fmt); 1444 err = vparse_tuple(params, pool, &fmt, &ap); 1445 va_end(ap); 1446 return err; 1447 } 1448 else if (strcmp(status, "failure") == 0) 1449 { 1450 return svn_ra_svn__handle_failure_status(params, pool); 1451 } 1452 1453 return svn_error_createf(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL, 1454 _("Unknown status '%s' in command response"), 1455 status); 1456} 1457 1458svn_error_t * 1459svn_ra_svn__handle_commands2(svn_ra_svn_conn_t *conn, 1460 apr_pool_t *pool, 1461 const svn_ra_svn_cmd_entry_t *commands, 1462 void *baton, 1463 svn_boolean_t error_on_disconnect) 1464{ 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); 1472 1473 for (command = commands; command->cmdname; command++) 1474 svn_hash_sets(cmd_hash, command->cmdname, command); 1475 1476 while (1) 1477 { 1478 svn_pool_clear(iterpool); 1479 err = svn_ra_svn__read_tuple(conn, iterpool, "wl", &cmdname, ¶ms); 1480 if (err) 1481 { 1482 if (!error_on_disconnect 1483 && err->apr_err == SVN_ERR_RA_SVN_CONNECTION_CLOSED) 1484 { 1485 svn_error_clear(err); 1486 svn_pool_destroy(subpool); 1487 return SVN_NO_ERROR; 1488 } 1489 return err; 1490 } 1491 command = svn_hash_gets(cmd_hash, cmdname); 1492 1493 if (command) 1494 err = (*command->handler)(conn, iterpool, params, baton); 1495 else 1496 { 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); 1500 } 1501 1502 if (err && err->apr_err == SVN_ERR_RA_SVN_CMD_ERR) 1503 { 1504 write_err = svn_ra_svn__write_cmd_failure( 1505 conn, iterpool, 1506 svn_ra_svn__locate_real_error_child(err)); 1507 svn_error_clear(err); 1508 if (write_err) 1509 return write_err; 1510 } 1511 else if (err) 1512 return err; 1513 1514 if (command && command->terminate) 1515 break; 1516 } 1517 svn_pool_destroy(iterpool); 1518 svn_pool_destroy(subpool); 1519 return SVN_NO_ERROR; 1520} 1521 1522svn_error_t * 1523svn_ra_svn__write_cmd_target_rev(svn_ra_svn_conn_t *conn, 1524 apr_pool_t *pool, 1525 svn_revnum_t rev) 1526{ 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)); 1530 1531 return SVN_NO_ERROR; 1532} 1533 1534svn_error_t * 1535svn_ra_svn__write_cmd_open_root(svn_ra_svn_conn_t *conn, 1536 apr_pool_t *pool, 1537 svn_revnum_t rev, 1538 const char *token) 1539{ 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)); 1546 1547 return SVN_NO_ERROR; 1548} 1549 1550svn_error_t * 1551svn_ra_svn__write_cmd_delete_entry(svn_ra_svn_conn_t *conn, 1552 apr_pool_t *pool, 1553 const char *path, 1554 svn_revnum_t rev, 1555 const char *token) 1556{ 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)); 1564 1565 return SVN_NO_ERROR; 1566} 1567 1568svn_error_t * 1569svn_ra_svn__write_cmd_add_dir(svn_ra_svn_conn_t *conn, 1570 apr_pool_t *pool, 1571 const char *path, 1572 const char *parent_token, 1573 const char *token, 1574 const char *copy_path, 1575 svn_revnum_t copy_rev) 1576{ 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)); 1581 1582 return SVN_NO_ERROR; 1583} 1584 1585svn_error_t * 1586svn_ra_svn__write_cmd_open_dir(svn_ra_svn_conn_t *conn, 1587 apr_pool_t *pool, 1588 const char *path, 1589 const char *parent_token, 1590 const char *token, 1591 svn_revnum_t rev) 1592{ 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)); 1596 1597 return SVN_NO_ERROR; 1598} 1599 1600svn_error_t * 1601svn_ra_svn__write_cmd_change_dir_prop(svn_ra_svn_conn_t *conn, 1602 apr_pool_t *pool, 1603 const char *token, 1604 const char *name, 1605 const svn_string_t *value) 1606{ 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)); 1610 1611 return SVN_NO_ERROR; 1612} 1613 1614svn_error_t * 1615svn_ra_svn__write_cmd_close_dir(svn_ra_svn_conn_t *conn, 1616 apr_pool_t *pool, 1617 const char *token) 1618{ 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)); 1622 1623 return SVN_NO_ERROR; 1624} 1625 1626svn_error_t * 1627svn_ra_svn__write_cmd_absent_dir(svn_ra_svn_conn_t *conn, 1628 apr_pool_t *pool, 1629 const char *path, 1630 const char *parent_token) 1631{ 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)); 1635 1636 return SVN_NO_ERROR; 1637} 1638 1639svn_error_t * 1640svn_ra_svn__write_cmd_add_file(svn_ra_svn_conn_t *conn, 1641 apr_pool_t *pool, 1642 const char *path, 1643 const char *parent_token, 1644 const char *token, 1645 const char *copy_path, 1646 svn_revnum_t copy_rev) 1647{ 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)); 1652 1653 return SVN_NO_ERROR; 1654} 1655 1656svn_error_t * 1657svn_ra_svn__write_cmd_open_file(svn_ra_svn_conn_t *conn, 1658 apr_pool_t *pool, 1659 const char *path, 1660 const char *parent_token, 1661 const char *token, 1662 svn_revnum_t rev) 1663{ 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)); 1667 1668 return SVN_NO_ERROR; 1669} 1670 1671svn_error_t * 1672svn_ra_svn__write_cmd_change_file_prop(svn_ra_svn_conn_t *conn, 1673 apr_pool_t *pool, 1674 const char *token, 1675 const char *name, 1676 const svn_string_t *value) 1677{ 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)); 1681 1682 return SVN_NO_ERROR; 1683} 1684 1685svn_error_t * 1686svn_ra_svn__write_cmd_close_file(svn_ra_svn_conn_t *conn, 1687 apr_pool_t *pool, 1688 const char *token, 1689 const char *text_checksum) 1690{ 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)); 1697 1698 return SVN_NO_ERROR; 1699} 1700 1701svn_error_t * 1702svn_ra_svn__write_cmd_absent_file(svn_ra_svn_conn_t *conn, 1703 apr_pool_t *pool, 1704 const char *path, 1705 const char *parent_token) 1706{ 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)); 1710 1711 return SVN_NO_ERROR; 1712} 1713 1714svn_error_t * 1715svn_ra_svn__write_cmd_textdelta_chunk(svn_ra_svn_conn_t *conn, 1716 apr_pool_t *pool, 1717 const char *token, 1718 const svn_string_t *chunk) 1719{ 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)); 1724 1725 return SVN_NO_ERROR; 1726} 1727 1728svn_error_t * 1729svn_ra_svn__write_cmd_textdelta_end(svn_ra_svn_conn_t *conn, 1730 apr_pool_t *pool, 1731 const char *token) 1732{ 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)); 1736 1737 return SVN_NO_ERROR; 1738} 1739 1740svn_error_t * 1741svn_ra_svn__write_cmd_apply_textdelta(svn_ra_svn_conn_t *conn, 1742 apr_pool_t *pool, 1743 const char *token, 1744 const char *base_checksum) 1745{ 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)); 1752 1753 return SVN_NO_ERROR; 1754} 1755 1756svn_error_t * 1757svn_ra_svn__write_cmd_close_edit(svn_ra_svn_conn_t *conn, 1758 apr_pool_t *pool) 1759{ 1760 return writebuf_write_short_string(conn, pool, "( close-edit ( ) ) ", 19); 1761} 1762 1763svn_error_t * 1764svn_ra_svn__write_cmd_abort_edit(svn_ra_svn_conn_t *conn, 1765 apr_pool_t *pool) 1766{ 1767 return writebuf_write_short_string(conn, pool, "( abort-edit ( ) ) ", 19); 1768} 1769 1770svn_error_t * 1771svn_ra_svn__write_cmd_set_path(svn_ra_svn_conn_t *conn, 1772 apr_pool_t *pool, 1773 const char *path, 1774 svn_revnum_t rev, 1775 svn_boolean_t start_empty, 1776 const char *lock_token, 1777 svn_depth_t depth) 1778{ 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)); 1788 1789 return SVN_NO_ERROR; 1790} 1791 1792svn_error_t * 1793svn_ra_svn__write_cmd_delete_path(svn_ra_svn_conn_t *conn, 1794 apr_pool_t *pool, 1795 const char *path) 1796{ 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)); 1800 1801 return SVN_NO_ERROR; 1802} 1803 1804svn_error_t * 1805svn_ra_svn__write_cmd_link_path(svn_ra_svn_conn_t *conn, 1806 apr_pool_t *pool, 1807 const char *path, 1808 const char *url, 1809 svn_revnum_t rev, 1810 svn_boolean_t start_empty, 1811 const char *lock_token, 1812 svn_depth_t depth) 1813{ 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)); 1824 1825 return SVN_NO_ERROR; 1826} 1827 1828svn_error_t * 1829svn_ra_svn__write_cmd_finish_report(svn_ra_svn_conn_t *conn, 1830 apr_pool_t *pool) 1831{ 1832 return writebuf_write_short_string(conn, pool, "( finish-report ( ) ) ", 22); 1833} 1834 1835svn_error_t * 1836svn_ra_svn__write_cmd_abort_report(svn_ra_svn_conn_t *conn, 1837 apr_pool_t *pool) 1838{ 1839 return writebuf_write_short_string(conn, pool, "( abort-report ( ) ) ", 21); 1840} 1841 1842svn_error_t * 1843svn_ra_svn__write_cmd_reparent(svn_ra_svn_conn_t *conn, 1844 apr_pool_t *pool, 1845 const char *url) 1846{ 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)); 1850 1851 return SVN_NO_ERROR; 1852} 1853 1854svn_error_t * 1855svn_ra_svn__write_cmd_get_latest_rev(svn_ra_svn_conn_t *conn, 1856 apr_pool_t *pool) 1857{ 1858 return writebuf_write_short_string(conn, pool, "( get-latest-rev ( ) ) ", 23); 1859} 1860 1861svn_error_t * 1862svn_ra_svn__write_cmd_get_dated_rev(svn_ra_svn_conn_t *conn, 1863 apr_pool_t *pool, 1864 apr_time_t tm) 1865{ 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)); 1869 1870 return SVN_NO_ERROR; 1871} 1872 1873svn_error_t * 1874svn_ra_svn__write_cmd_change_rev_prop2(svn_ra_svn_conn_t *conn, 1875 apr_pool_t *pool, 1876 svn_revnum_t rev, 1877 const char *name, 1878 const svn_string_t *value, 1879 svn_boolean_t dont_care, 1880 const svn_string_t *old_value) 1881{ 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)); 1893 1894 return SVN_NO_ERROR; 1895} 1896 1897svn_error_t * 1898svn_ra_svn__write_cmd_change_rev_prop(svn_ra_svn_conn_t *conn, 1899 apr_pool_t *pool, 1900 svn_revnum_t rev, 1901 const char *name, 1902 const svn_string_t *value) 1903{ 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)); 1909 1910 return SVN_NO_ERROR; 1911} 1912 1913svn_error_t * 1914svn_ra_svn__write_cmd_rev_proplist(svn_ra_svn_conn_t *conn, 1915 apr_pool_t *pool, 1916 svn_revnum_t rev) 1917{ 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)); 1921 1922 return SVN_NO_ERROR; 1923} 1924 1925svn_error_t * 1926svn_ra_svn__write_cmd_rev_prop(svn_ra_svn_conn_t *conn, 1927 apr_pool_t *pool, 1928 svn_revnum_t rev, 1929 const char *name) 1930{ 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)); 1935 1936 return SVN_NO_ERROR; 1937} 1938 1939svn_error_t * 1940svn_ra_svn__write_cmd_get_file(svn_ra_svn_conn_t *conn, 1941 apr_pool_t *pool, 1942 const char *path, 1943 svn_revnum_t rev, 1944 svn_boolean_t props, 1945 svn_boolean_t stream) 1946{ 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)); 1955 1956 return SVN_NO_ERROR; 1957} 1958 1959svn_error_t * 1960svn_ra_svn__write_cmd_update(svn_ra_svn_conn_t *conn, 1961 apr_pool_t *pool, 1962 svn_revnum_t rev, 1963 const char *target, 1964 svn_boolean_t recurse, 1965 svn_depth_t depth, 1966 svn_boolean_t send_copyfrom_args, 1967 svn_boolean_t ignore_ancestry) 1968{ 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)); 1979 1980 return SVN_NO_ERROR; 1981} 1982 1983svn_error_t * 1984svn_ra_svn__write_cmd_switch(svn_ra_svn_conn_t *conn, 1985 apr_pool_t *pool, 1986 svn_revnum_t rev, 1987 const char *target, 1988 svn_boolean_t recurse, 1989 const char *switch_url, 1990 svn_depth_t depth, 1991 svn_boolean_t send_copyfrom_args, 1992 svn_boolean_t ignore_ancestry) 1993{ 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)); 2005 2006 return SVN_NO_ERROR; 2007} 2008 2009svn_error_t * 2010svn_ra_svn__write_cmd_status(svn_ra_svn_conn_t *conn, 2011 apr_pool_t *pool, 2012 const char *target, 2013 svn_boolean_t recurse, 2014 svn_revnum_t rev, 2015 svn_depth_t depth) 2016{ 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)); 2025 2026 return SVN_NO_ERROR; 2027} 2028 2029svn_error_t * 2030svn_ra_svn__write_cmd_diff(svn_ra_svn_conn_t *conn, 2031 apr_pool_t *pool, 2032 svn_revnum_t rev, 2033 const char *target, 2034 svn_boolean_t recurse, 2035 svn_boolean_t ignore_ancestry, 2036 const char *versus_url, 2037 svn_boolean_t text_deltas, 2038 svn_depth_t depth) 2039{ 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)); 2051 2052 return SVN_NO_ERROR; 2053} 2054 2055svn_error_t * 2056svn_ra_svn__write_cmd_check_path(svn_ra_svn_conn_t *conn, 2057 apr_pool_t *pool, 2058 const char *path, 2059 svn_revnum_t rev) 2060{ 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)); 2067 2068 return SVN_NO_ERROR; 2069} 2070 2071svn_error_t * 2072svn_ra_svn__write_cmd_stat(svn_ra_svn_conn_t *conn, 2073 apr_pool_t *pool, 2074 const char *path, 2075 svn_revnum_t rev) 2076{ 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)); 2083 2084 return SVN_NO_ERROR; 2085} 2086 2087svn_error_t * 2088svn_ra_svn__write_cmd_get_file_revs(svn_ra_svn_conn_t *conn, 2089 apr_pool_t *pool, 2090 const char *path, 2091 svn_revnum_t start, 2092 svn_revnum_t end, 2093 svn_boolean_t include_merged_revisions) 2094{ 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)); 2105 2106 return SVN_NO_ERROR; 2107} 2108 2109svn_error_t * 2110svn_ra_svn__write_cmd_lock(svn_ra_svn_conn_t *conn, 2111 apr_pool_t *pool, 2112 const char *path, 2113 const char *comment, 2114 svn_boolean_t steal_lock, 2115 svn_revnum_t revnum) 2116{ 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)); 2127 2128 return SVN_NO_ERROR; 2129} 2130 2131svn_error_t * 2132svn_ra_svn__write_cmd_unlock(svn_ra_svn_conn_t *conn, 2133 apr_pool_t *pool, 2134 const char *path, 2135 const char *token, 2136 svn_boolean_t break_lock) 2137{ 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)); 2145 2146 return SVN_NO_ERROR; 2147} 2148 2149svn_error_t * 2150svn_ra_svn__write_cmd_get_lock(svn_ra_svn_conn_t *conn, 2151 apr_pool_t *pool, 2152 const char *path) 2153{ 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)); 2157 2158 return SVN_NO_ERROR; 2159} 2160 2161svn_error_t * 2162svn_ra_svn__write_cmd_get_locks(svn_ra_svn_conn_t *conn, 2163 apr_pool_t *pool, 2164 const char *path, 2165 svn_depth_t depth) 2166{ 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)); 2173 2174 return SVN_NO_ERROR; 2175} 2176 2177svn_error_t * 2178svn_ra_svn__write_cmd_replay(svn_ra_svn_conn_t *conn, 2179 apr_pool_t *pool, 2180 svn_revnum_t rev, 2181 svn_revnum_t low_water_mark, 2182 svn_boolean_t send_deltas) 2183{ 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)); 2189 2190 return SVN_NO_ERROR; 2191} 2192 2193svn_error_t * 2194svn_ra_svn__write_cmd_replay_range(svn_ra_svn_conn_t *conn, 2195 apr_pool_t *pool, 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) 2200{ 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)); 2207 2208 return SVN_NO_ERROR; 2209} 2210 2211svn_error_t * 2212svn_ra_svn__write_cmd_get_deleted_rev(svn_ra_svn_conn_t *conn, 2213 apr_pool_t *pool, 2214 const char *path, 2215 svn_revnum_t peg_revision, 2216 svn_revnum_t end_revision) 2217{ 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)); 2223 2224 return SVN_NO_ERROR; 2225} 2226 2227svn_error_t * 2228svn_ra_svn__write_cmd_get_iprops(svn_ra_svn_conn_t *conn, 2229 apr_pool_t *pool, 2230 const char *path, 2231 svn_revnum_t revision) 2232{ 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)); 2239 2240 return SVN_NO_ERROR; 2241} 2242 2243svn_error_t * 2244svn_ra_svn__write_cmd_finish_replay(svn_ra_svn_conn_t *conn, 2245 apr_pool_t *pool) 2246{ 2247 return writebuf_write_short_string(conn, pool, "( finish-replay ( ) ) ", 22); 2248} 2249 2250svn_error_t *svn_ra_svn__write_cmd_response(svn_ra_svn_conn_t *conn, 2251 apr_pool_t *pool, 2252 const char *fmt, ...) 2253{ 2254 va_list ap; 2255 svn_error_t *err; 2256 2257 SVN_ERR(writebuf_write_short_string(conn, pool, "( success ", 10)); 2258 va_start(ap, fmt); 2259 err = vwrite_tuple(conn, pool, fmt, &ap); 2260 va_end(ap); 2261 return err ? svn_error_trace(err) : svn_ra_svn__end_list(conn, pool); 2262} 2263 2264svn_error_t *svn_ra_svn__write_cmd_failure(svn_ra_svn_conn_t *conn, 2265 apr_pool_t *pool, svn_error_t *err) 2266{ 2267 char buffer[128]; 2268 SVN_ERR(writebuf_write_short_string(conn, pool, "( failure ( ", 12)); 2269 for (; err; err = err->child) 2270 { 2271 const char *msg; 2272 2273#ifdef SVN_ERR__TRACING 2274 if (svn_error__is_tracing_link(err)) 2275 msg = err->message; 2276 else 2277#endif 2278 msg = svn_err_best_message(err, buffer, sizeof(buffer)); 2279 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, 2284 msg ? msg : "", 2285 err->file ? err->file : "", 2286 (apr_uint64_t) err->line)); 2287 } 2288 return writebuf_write_short_string(conn, pool, ") ) ", 4); 2289} 2290