1251881Speter/* 2251881Speter * marshal.c : Marshalling routines for Subversion protocol 3251881Speter * 4251881Speter * ==================================================================== 5251881Speter * Licensed to the Apache Software Foundation (ASF) under one 6251881Speter * or more contributor license agreements. See the NOTICE file 7251881Speter * distributed with this work for additional information 8251881Speter * regarding copyright ownership. The ASF licenses this file 9251881Speter * to you under the Apache License, Version 2.0 (the 10251881Speter * "License"); you may not use this file except in compliance 11251881Speter * with the License. You may obtain a copy of the License at 12251881Speter * 13251881Speter * http://www.apache.org/licenses/LICENSE-2.0 14251881Speter * 15251881Speter * Unless required by applicable law or agreed to in writing, 16251881Speter * software distributed under the License is distributed on an 17251881Speter * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 18251881Speter * KIND, either express or implied. See the License for the 19251881Speter * specific language governing permissions and limitations 20251881Speter * under the License. 21251881Speter * ==================================================================== 22251881Speter */ 23251881Speter 24251881Speter 25251881Speter 26251881Speter#include <assert.h> 27251881Speter#include <stdlib.h> 28251881Speter 29251881Speter#define APR_WANT_STRFUNC 30251881Speter#include <apr_want.h> 31251881Speter#include <apr_general.h> 32251881Speter#include <apr_lib.h> 33251881Speter#include <apr_strings.h> 34251881Speter 35251881Speter#include "svn_hash.h" 36251881Speter#include "svn_types.h" 37251881Speter#include "svn_string.h" 38251881Speter#include "svn_error.h" 39251881Speter#include "svn_pools.h" 40251881Speter#include "svn_ra_svn.h" 41251881Speter#include "svn_private_config.h" 42251881Speter#include "svn_ctype.h" 43251881Speter#include "svn_time.h" 44251881Speter 45251881Speter#include "ra_svn.h" 46251881Speter 47251881Speter#include "private/svn_string_private.h" 48251881Speter#include "private/svn_dep_compat.h" 49251881Speter#include "private/svn_error_private.h" 50251881Speter 51251881Speter#define svn_iswhitespace(c) ((c) == ' ' || (c) == '\n') 52251881Speter 53251881Speter/* If we receive data that *claims* to be followed by a very long string, 54251881Speter * we should not trust that claim right away. But everything up to 1 MB 55251881Speter * should be too small to be instrumental for a DOS attack. */ 56251881Speter 57251881Speter#define SUSPICIOUSLY_HUGE_STRING_SIZE_THRESHOLD (0x100000) 58251881Speter 59251881Speter/* Return the APR socket timeout to be used for the connection depending 60251881Speter * on whether there is a blockage handler or zero copy has been activated. */ 61251881Speterstatic apr_interval_time_t 62251881Speterget_timeout(svn_ra_svn_conn_t *conn) 63251881Speter{ 64251881Speter return conn->block_handler ? 0 : -1; 65251881Speter} 66251881Speter 67251881Speter/* --- CONNECTION INITIALIZATION --- */ 68251881Speter 69251881Spetersvn_ra_svn_conn_t *svn_ra_svn_create_conn3(apr_socket_t *sock, 70251881Speter apr_file_t *in_file, 71251881Speter apr_file_t *out_file, 72251881Speter int compression_level, 73251881Speter apr_size_t zero_copy_limit, 74251881Speter apr_size_t error_check_interval, 75251881Speter apr_pool_t *pool) 76251881Speter{ 77251881Speter svn_ra_svn_conn_t *conn; 78251881Speter void *mem = apr_palloc(pool, sizeof(*conn) + SVN_RA_SVN__PAGE_SIZE); 79251881Speter conn = (void*)APR_ALIGN((apr_uintptr_t)mem, SVN_RA_SVN__PAGE_SIZE); 80251881Speter 81251881Speter assert((sock && !in_file && !out_file) || (!sock && in_file && out_file)); 82251881Speter#ifdef SVN_HAVE_SASL 83251881Speter conn->sock = sock; 84251881Speter conn->encrypted = FALSE; 85251881Speter#endif 86251881Speter conn->session = NULL; 87251881Speter conn->read_ptr = conn->read_buf; 88251881Speter conn->read_end = conn->read_buf; 89251881Speter conn->write_pos = 0; 90251881Speter conn->written_since_error_check = 0; 91251881Speter conn->error_check_interval = error_check_interval; 92251881Speter conn->may_check_for_error = error_check_interval == 0; 93251881Speter conn->block_handler = NULL; 94251881Speter conn->block_baton = NULL; 95251881Speter conn->capabilities = apr_hash_make(pool); 96251881Speter conn->compression_level = compression_level; 97251881Speter conn->zero_copy_limit = zero_copy_limit; 98251881Speter conn->pool = pool; 99251881Speter 100251881Speter if (sock != NULL) 101251881Speter { 102251881Speter apr_sockaddr_t *sa; 103251881Speter conn->stream = svn_ra_svn__stream_from_sock(sock, pool); 104251881Speter if (!(apr_socket_addr_get(&sa, APR_REMOTE, sock) == APR_SUCCESS 105251881Speter && apr_sockaddr_ip_get(&conn->remote_ip, sa) == APR_SUCCESS)) 106251881Speter conn->remote_ip = NULL; 107251881Speter svn_ra_svn__stream_timeout(conn->stream, get_timeout(conn)); 108251881Speter } 109251881Speter else 110251881Speter { 111251881Speter conn->stream = svn_ra_svn__stream_from_files(in_file, out_file, pool); 112251881Speter conn->remote_ip = NULL; 113251881Speter } 114251881Speter 115251881Speter return conn; 116251881Speter} 117251881Speter 118251881Spetersvn_ra_svn_conn_t *svn_ra_svn_create_conn2(apr_socket_t *sock, 119251881Speter apr_file_t *in_file, 120251881Speter apr_file_t *out_file, 121251881Speter int compression_level, 122251881Speter apr_pool_t *pool) 123251881Speter{ 124251881Speter return svn_ra_svn_create_conn3(sock, in_file, out_file, 125251881Speter compression_level, 0, 0, pool); 126251881Speter} 127251881Speter 128251881Speter/* backward-compatible implementation using the default compression level */ 129251881Spetersvn_ra_svn_conn_t *svn_ra_svn_create_conn(apr_socket_t *sock, 130251881Speter apr_file_t *in_file, 131251881Speter apr_file_t *out_file, 132251881Speter apr_pool_t *pool) 133251881Speter{ 134251881Speter return svn_ra_svn_create_conn3(sock, in_file, out_file, 135251881Speter SVN_DELTA_COMPRESSION_LEVEL_DEFAULT, 0, 0, 136251881Speter pool); 137251881Speter} 138251881Speter 139251881Spetersvn_error_t *svn_ra_svn_set_capabilities(svn_ra_svn_conn_t *conn, 140251881Speter const apr_array_header_t *list) 141251881Speter{ 142251881Speter int i; 143251881Speter svn_ra_svn_item_t *item; 144251881Speter const char *word; 145251881Speter 146251881Speter for (i = 0; i < list->nelts; i++) 147251881Speter { 148251881Speter item = &APR_ARRAY_IDX(list, i, svn_ra_svn_item_t); 149251881Speter if (item->kind != SVN_RA_SVN_WORD) 150251881Speter return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL, 151251881Speter _("Capability entry is not a word")); 152251881Speter word = apr_pstrdup(conn->pool, item->u.word); 153251881Speter svn_hash_sets(conn->capabilities, word, word); 154251881Speter } 155251881Speter return SVN_NO_ERROR; 156251881Speter} 157251881Speter 158251881Spetersvn_error_t * 159251881Spetersvn_ra_svn__set_shim_callbacks(svn_ra_svn_conn_t *conn, 160251881Speter svn_delta_shim_callbacks_t *shim_callbacks) 161251881Speter{ 162251881Speter conn->shim_callbacks = shim_callbacks; 163251881Speter return SVN_NO_ERROR; 164251881Speter} 165251881Speter 166251881Spetersvn_boolean_t svn_ra_svn_has_capability(svn_ra_svn_conn_t *conn, 167251881Speter const char *capability) 168251881Speter{ 169251881Speter return (svn_hash_gets(conn->capabilities, capability) != NULL); 170251881Speter} 171251881Speter 172251881Speterint 173251881Spetersvn_ra_svn_compression_level(svn_ra_svn_conn_t *conn) 174251881Speter{ 175251881Speter return conn->compression_level; 176251881Speter} 177251881Speter 178251881Speterapr_size_t 179251881Spetersvn_ra_svn_zero_copy_limit(svn_ra_svn_conn_t *conn) 180251881Speter{ 181251881Speter return conn->zero_copy_limit; 182251881Speter} 183251881Speter 184251881Speterconst char *svn_ra_svn_conn_remote_host(svn_ra_svn_conn_t *conn) 185251881Speter{ 186251881Speter return conn->remote_ip; 187251881Speter} 188251881Speter 189251881Spetervoid 190251881Spetersvn_ra_svn__set_block_handler(svn_ra_svn_conn_t *conn, 191251881Speter ra_svn_block_handler_t handler, 192251881Speter void *baton) 193251881Speter{ 194251881Speter conn->block_handler = handler; 195251881Speter conn->block_baton = baton; 196251881Speter svn_ra_svn__stream_timeout(conn->stream, get_timeout(conn)); 197251881Speter} 198251881Speter 199251881Spetersvn_boolean_t svn_ra_svn__input_waiting(svn_ra_svn_conn_t *conn, 200251881Speter apr_pool_t *pool) 201251881Speter{ 202251881Speter return svn_ra_svn__stream_pending(conn->stream); 203251881Speter} 204251881Speter 205251881Speter/* --- WRITE BUFFER MANAGEMENT --- */ 206251881Speter 207251881Speter/* Write data to socket or output file as appropriate. */ 208251881Speterstatic svn_error_t *writebuf_output(svn_ra_svn_conn_t *conn, apr_pool_t *pool, 209251881Speter const char *data, apr_size_t len) 210251881Speter{ 211251881Speter const char *end = data + len; 212251881Speter apr_size_t count; 213251881Speter apr_pool_t *subpool = NULL; 214251881Speter svn_ra_svn__session_baton_t *session = conn->session; 215251881Speter 216251881Speter while (data < end) 217251881Speter { 218251881Speter count = end - data; 219251881Speter 220251881Speter if (session && session->callbacks && session->callbacks->cancel_func) 221251881Speter SVN_ERR((session->callbacks->cancel_func)(session->callbacks_baton)); 222251881Speter 223251881Speter SVN_ERR(svn_ra_svn__stream_write(conn->stream, data, &count)); 224251881Speter if (count == 0) 225251881Speter { 226251881Speter if (!subpool) 227251881Speter subpool = svn_pool_create(pool); 228251881Speter else 229251881Speter svn_pool_clear(subpool); 230251881Speter SVN_ERR(conn->block_handler(conn, subpool, conn->block_baton)); 231251881Speter } 232251881Speter data += count; 233251881Speter 234251881Speter if (session) 235251881Speter { 236251881Speter const svn_ra_callbacks2_t *cb = session->callbacks; 237251881Speter session->bytes_written += count; 238251881Speter 239251881Speter if (cb && cb->progress_func) 240251881Speter (cb->progress_func)(session->bytes_written + session->bytes_read, 241251881Speter -1, cb->progress_baton, subpool); 242251881Speter } 243251881Speter } 244251881Speter 245251881Speter conn->written_since_error_check += len; 246251881Speter conn->may_check_for_error 247251881Speter = conn->written_since_error_check >= conn->error_check_interval; 248251881Speter 249251881Speter if (subpool) 250251881Speter svn_pool_destroy(subpool); 251251881Speter return SVN_NO_ERROR; 252251881Speter} 253251881Speter 254251881Speter/* Write data from the write buffer out to the socket. */ 255251881Speterstatic svn_error_t *writebuf_flush(svn_ra_svn_conn_t *conn, apr_pool_t *pool) 256251881Speter{ 257251881Speter apr_size_t write_pos = conn->write_pos; 258251881Speter 259251881Speter /* Clear conn->write_pos first in case the block handler does a read. */ 260251881Speter conn->write_pos = 0; 261251881Speter SVN_ERR(writebuf_output(conn, pool, conn->write_buf, write_pos)); 262251881Speter return SVN_NO_ERROR; 263251881Speter} 264251881Speter 265251881Speterstatic svn_error_t *writebuf_write(svn_ra_svn_conn_t *conn, apr_pool_t *pool, 266251881Speter const char *data, apr_size_t len) 267251881Speter{ 268251881Speter /* data >= 8k is sent immediately */ 269251881Speter if (len >= sizeof(conn->write_buf) / 2) 270251881Speter { 271251881Speter if (conn->write_pos > 0) 272251881Speter SVN_ERR(writebuf_flush(conn, pool)); 273251881Speter 274251881Speter return writebuf_output(conn, pool, data, len); 275251881Speter } 276251881Speter 277251881Speter /* ensure room for the data to add */ 278251881Speter if (conn->write_pos + len > sizeof(conn->write_buf)) 279251881Speter SVN_ERR(writebuf_flush(conn, pool)); 280251881Speter 281251881Speter /* buffer the new data block as well */ 282251881Speter memcpy(conn->write_buf + conn->write_pos, data, len); 283251881Speter conn->write_pos += len; 284251881Speter 285251881Speter return SVN_NO_ERROR; 286251881Speter} 287251881Speter 288251881Speterstatic svn_error_t * 289251881Speterwritebuf_write_short_string(svn_ra_svn_conn_t *conn, apr_pool_t *pool, 290251881Speter const char *data, apr_size_t len) 291251881Speter{ 292251881Speter apr_size_t left = sizeof(conn->write_buf) - conn->write_pos; 293251881Speter if (len <= left) 294251881Speter { 295251881Speter memcpy(conn->write_buf + conn->write_pos, data, len); 296251881Speter conn->write_pos += len; 297251881Speter return SVN_NO_ERROR; 298251881Speter } 299251881Speter else 300251881Speter return writebuf_write(conn, pool, data, len); 301251881Speter} 302251881Speter 303251881Speterstatic APR_INLINE svn_error_t * 304251881Speterwritebuf_writechar(svn_ra_svn_conn_t *conn, apr_pool_t *pool, char data) 305251881Speter{ 306251881Speter if (conn->write_pos < sizeof(conn->write_buf)) 307251881Speter { 308251881Speter conn->write_buf[conn->write_pos] = data; 309251881Speter conn->write_pos++; 310251881Speter 311251881Speter return SVN_NO_ERROR; 312251881Speter } 313251881Speter else 314251881Speter { 315251881Speter char temp = data; 316251881Speter return writebuf_write(conn, pool, &temp, 1); 317251881Speter } 318251881Speter} 319251881Speter 320251881Speter/* --- READ BUFFER MANAGEMENT --- */ 321251881Speter 322251881Speter/* Read bytes into DATA until either the read buffer is empty or 323251881Speter * we reach END. */ 324251881Speterstatic char *readbuf_drain(svn_ra_svn_conn_t *conn, char *data, char *end) 325251881Speter{ 326251881Speter apr_ssize_t buflen, copylen; 327251881Speter 328251881Speter buflen = conn->read_end - conn->read_ptr; 329251881Speter copylen = (buflen < end - data) ? buflen : end - data; 330251881Speter memcpy(data, conn->read_ptr, copylen); 331251881Speter conn->read_ptr += copylen; 332251881Speter return data + copylen; 333251881Speter} 334251881Speter 335251881Speter/* Read data from socket or input file as appropriate. */ 336251881Speterstatic svn_error_t *readbuf_input(svn_ra_svn_conn_t *conn, char *data, 337251881Speter apr_size_t *len, apr_pool_t *pool) 338251881Speter{ 339251881Speter svn_ra_svn__session_baton_t *session = conn->session; 340251881Speter 341251881Speter if (session && session->callbacks && session->callbacks->cancel_func) 342251881Speter SVN_ERR((session->callbacks->cancel_func)(session->callbacks_baton)); 343251881Speter 344251881Speter SVN_ERR(svn_ra_svn__stream_read(conn->stream, data, len)); 345251881Speter if (*len == 0) 346251881Speter return svn_error_create(SVN_ERR_RA_SVN_CONNECTION_CLOSED, NULL, NULL); 347251881Speter 348251881Speter if (session) 349251881Speter { 350251881Speter const svn_ra_callbacks2_t *cb = session->callbacks; 351251881Speter session->bytes_read += *len; 352251881Speter 353251881Speter if (cb && cb->progress_func) 354251881Speter (cb->progress_func)(session->bytes_read + session->bytes_written, 355251881Speter -1, cb->progress_baton, pool); 356251881Speter } 357251881Speter 358251881Speter return SVN_NO_ERROR; 359251881Speter} 360251881Speter 361251881Speter/* Treat the next LEN input bytes from CONN as "read" */ 362251881Speterstatic svn_error_t *readbuf_skip(svn_ra_svn_conn_t *conn, apr_uint64_t len) 363251881Speter{ 364251881Speter do 365251881Speter { 366251881Speter apr_size_t buflen = conn->read_end - conn->read_ptr; 367251881Speter apr_size_t copylen = (buflen < len) ? buflen : (apr_size_t)len; 368251881Speter conn->read_ptr += copylen; 369251881Speter len -= copylen; 370251881Speter if (len == 0) 371251881Speter break; 372251881Speter 373251881Speter buflen = sizeof(conn->read_buf); 374251881Speter SVN_ERR(svn_ra_svn__stream_read(conn->stream, conn->read_buf, &buflen)); 375251881Speter if (buflen == 0) 376251881Speter return svn_error_create(SVN_ERR_RA_SVN_CONNECTION_CLOSED, NULL, NULL); 377251881Speter 378251881Speter conn->read_end = conn->read_buf + buflen; 379251881Speter conn->read_ptr = conn->read_buf; 380251881Speter } 381251881Speter while (len > 0); 382251881Speter 383251881Speter return SVN_NO_ERROR; 384251881Speter} 385251881Speter 386251881Speter/* Read data from the socket into the read buffer, which must be empty. */ 387251881Speterstatic svn_error_t *readbuf_fill(svn_ra_svn_conn_t *conn, apr_pool_t *pool) 388251881Speter{ 389251881Speter apr_size_t len; 390251881Speter 391251881Speter SVN_ERR_ASSERT(conn->read_ptr == conn->read_end); 392251881Speter SVN_ERR(writebuf_flush(conn, pool)); 393251881Speter len = sizeof(conn->read_buf); 394251881Speter SVN_ERR(readbuf_input(conn, conn->read_buf, &len, pool)); 395251881Speter conn->read_ptr = conn->read_buf; 396251881Speter conn->read_end = conn->read_buf + len; 397251881Speter return SVN_NO_ERROR; 398251881Speter} 399251881Speter 400251881Speterstatic APR_INLINE svn_error_t * 401251881Speterreadbuf_getchar(svn_ra_svn_conn_t *conn, apr_pool_t *pool, char *result) 402251881Speter{ 403251881Speter if (conn->read_ptr == conn->read_end) 404251881Speter SVN_ERR(readbuf_fill(conn, pool)); 405251881Speter *result = *conn->read_ptr++; 406251881Speter return SVN_NO_ERROR; 407251881Speter} 408251881Speter 409251881Speterstatic svn_error_t *readbuf_getchar_skip_whitespace(svn_ra_svn_conn_t *conn, 410251881Speter apr_pool_t *pool, 411251881Speter char *result) 412251881Speter{ 413251881Speter do 414251881Speter SVN_ERR(readbuf_getchar(conn, pool, result)); 415251881Speter while (svn_iswhitespace(*result)); 416251881Speter return SVN_NO_ERROR; 417251881Speter} 418251881Speter 419251881Speter/* Read the next LEN bytes from CONN and copy them to *DATA. */ 420251881Speterstatic svn_error_t *readbuf_read(svn_ra_svn_conn_t *conn, apr_pool_t *pool, 421251881Speter char *data, apr_size_t len) 422251881Speter{ 423251881Speter char *end = data + len; 424251881Speter apr_size_t count; 425251881Speter 426251881Speter /* Copy in an appropriate amount of data from the buffer. */ 427251881Speter data = readbuf_drain(conn, data, end); 428251881Speter 429251881Speter /* Read large chunks directly into buffer. */ 430251881Speter while (end - data > (apr_ssize_t)sizeof(conn->read_buf)) 431251881Speter { 432251881Speter SVN_ERR(writebuf_flush(conn, pool)); 433251881Speter count = end - data; 434251881Speter SVN_ERR(readbuf_input(conn, data, &count, pool)); 435251881Speter data += count; 436251881Speter } 437251881Speter 438251881Speter while (end > data) 439251881Speter { 440251881Speter /* The remaining amount to read is small; fill the buffer and 441251881Speter * copy from that. */ 442251881Speter SVN_ERR(readbuf_fill(conn, pool)); 443251881Speter data = readbuf_drain(conn, data, end); 444251881Speter } 445251881Speter 446251881Speter return SVN_NO_ERROR; 447251881Speter} 448251881Speter 449251881Speterstatic svn_error_t *readbuf_skip_leading_garbage(svn_ra_svn_conn_t *conn, 450251881Speter apr_pool_t *pool) 451251881Speter{ 452251881Speter char buf[256]; /* Must be smaller than sizeof(conn->read_buf) - 1. */ 453251881Speter const char *p, *end; 454251881Speter apr_size_t len; 455251881Speter svn_boolean_t lparen = FALSE; 456251881Speter 457251881Speter SVN_ERR_ASSERT(conn->read_ptr == conn->read_end); 458251881Speter while (1) 459251881Speter { 460251881Speter /* Read some data directly from the connection input source. */ 461251881Speter len = sizeof(buf); 462251881Speter SVN_ERR(readbuf_input(conn, buf, &len, pool)); 463251881Speter end = buf + len; 464251881Speter 465251881Speter /* Scan the data for '(' WS with a very simple state machine. */ 466251881Speter for (p = buf; p < end; p++) 467251881Speter { 468251881Speter if (lparen && svn_iswhitespace(*p)) 469251881Speter break; 470251881Speter else 471251881Speter lparen = (*p == '('); 472251881Speter } 473251881Speter if (p < end) 474251881Speter break; 475251881Speter } 476251881Speter 477251881Speter /* p now points to the whitespace just after the left paren. Fake 478251881Speter * up the left paren and then copy what we have into the read 479251881Speter * buffer. */ 480251881Speter conn->read_buf[0] = '('; 481251881Speter memcpy(conn->read_buf + 1, p, end - p); 482251881Speter conn->read_ptr = conn->read_buf; 483251881Speter conn->read_end = conn->read_buf + 1 + (end - p); 484251881Speter return SVN_NO_ERROR; 485251881Speter} 486251881Speter 487251881Speter/* --- WRITING DATA ITEMS --- */ 488251881Speter 489251881Speterstatic svn_error_t *write_number(svn_ra_svn_conn_t *conn, apr_pool_t *pool, 490251881Speter apr_uint64_t number, char follow) 491251881Speter{ 492251881Speter apr_size_t written; 493251881Speter 494251881Speter /* SVN_INT64_BUFFER_SIZE includes space for a terminating NUL that 495251881Speter * svn__ui64toa will always append. */ 496251881Speter if (conn->write_pos + SVN_INT64_BUFFER_SIZE >= sizeof(conn->write_buf)) 497251881Speter SVN_ERR(writebuf_flush(conn, pool)); 498251881Speter 499251881Speter written = svn__ui64toa(conn->write_buf + conn->write_pos, number); 500251881Speter conn->write_buf[conn->write_pos + written] = follow; 501251881Speter conn->write_pos += written + 1; 502251881Speter 503251881Speter return SVN_NO_ERROR; 504251881Speter} 505251881Speter 506251881Spetersvn_error_t * 507251881Spetersvn_ra_svn__write_number(svn_ra_svn_conn_t *conn, 508251881Speter apr_pool_t *pool, 509251881Speter apr_uint64_t number) 510251881Speter{ 511251881Speter return write_number(conn, pool, number, ' '); 512251881Speter} 513251881Speter 514251881Spetersvn_error_t * 515251881Spetersvn_ra_svn__write_string(svn_ra_svn_conn_t *conn, 516251881Speter apr_pool_t *pool, 517251881Speter const svn_string_t *str) 518251881Speter{ 519251881Speter if (str->len < 10) 520251881Speter { 521251881Speter SVN_ERR(writebuf_writechar(conn, pool, (char)(str->len + '0'))); 522251881Speter SVN_ERR(writebuf_writechar(conn, pool, ':')); 523251881Speter } 524251881Speter else 525251881Speter SVN_ERR(write_number(conn, pool, str->len, ':')); 526251881Speter 527251881Speter SVN_ERR(writebuf_write(conn, pool, str->data, str->len)); 528251881Speter SVN_ERR(writebuf_writechar(conn, pool, ' ')); 529251881Speter return SVN_NO_ERROR; 530251881Speter} 531251881Speter 532251881Spetersvn_error_t * 533251881Spetersvn_ra_svn__write_cstring(svn_ra_svn_conn_t *conn, 534251881Speter apr_pool_t *pool, 535251881Speter const char *s) 536251881Speter{ 537251881Speter apr_size_t len = strlen(s); 538251881Speter 539251881Speter if (len < 10) 540251881Speter { 541251881Speter SVN_ERR(writebuf_writechar(conn, pool, (char)(len + '0'))); 542251881Speter SVN_ERR(writebuf_writechar(conn, pool, ':')); 543251881Speter } 544251881Speter else 545251881Speter SVN_ERR(write_number(conn, pool, len, ':')); 546251881Speter 547251881Speter SVN_ERR(writebuf_write(conn, pool, s, len)); 548251881Speter SVN_ERR(writebuf_writechar(conn, pool, ' ')); 549251881Speter 550251881Speter return SVN_NO_ERROR; 551251881Speter} 552251881Speter 553251881Spetersvn_error_t * 554251881Spetersvn_ra_svn__write_word(svn_ra_svn_conn_t *conn, 555251881Speter apr_pool_t *pool, 556251881Speter const char *word) 557251881Speter{ 558251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, word, strlen(word))); 559251881Speter SVN_ERR(writebuf_writechar(conn, pool, ' ')); 560251881Speter 561251881Speter return SVN_NO_ERROR; 562251881Speter} 563251881Speter 564251881Spetersvn_error_t * 565251881Spetersvn_ra_svn__write_proplist(svn_ra_svn_conn_t *conn, 566251881Speter apr_pool_t *pool, 567251881Speter apr_hash_t *props) 568251881Speter{ 569251881Speter apr_pool_t *iterpool; 570251881Speter apr_hash_index_t *hi; 571251881Speter const void *key; 572251881Speter void *val; 573251881Speter const char *propname; 574251881Speter svn_string_t *propval; 575251881Speter 576251881Speter if (props) 577251881Speter { 578251881Speter iterpool = svn_pool_create(pool); 579251881Speter for (hi = apr_hash_first(pool, props); hi; hi = apr_hash_next(hi)) 580251881Speter { 581251881Speter svn_pool_clear(iterpool); 582251881Speter apr_hash_this(hi, &key, NULL, &val); 583251881Speter propname = key; 584251881Speter propval = val; 585251881Speter SVN_ERR(svn_ra_svn__write_tuple(conn, iterpool, "cs", 586251881Speter propname, propval)); 587251881Speter } 588251881Speter svn_pool_destroy(iterpool); 589251881Speter } 590251881Speter 591251881Speter return SVN_NO_ERROR; 592251881Speter} 593251881Speter 594251881Spetersvn_error_t * 595251881Spetersvn_ra_svn__start_list(svn_ra_svn_conn_t *conn, 596251881Speter apr_pool_t *pool) 597251881Speter{ 598251881Speter if (conn->write_pos + 2 <= sizeof(conn->write_buf)) 599251881Speter { 600251881Speter conn->write_buf[conn->write_pos] = '('; 601251881Speter conn->write_buf[conn->write_pos+1] = ' '; 602251881Speter conn->write_pos += 2; 603251881Speter return SVN_NO_ERROR; 604251881Speter } 605251881Speter 606251881Speter return writebuf_write(conn, pool, "( ", 2); 607251881Speter} 608251881Speter 609251881Spetersvn_error_t * 610251881Spetersvn_ra_svn__end_list(svn_ra_svn_conn_t *conn, 611251881Speter apr_pool_t *pool) 612251881Speter{ 613251881Speter if (conn->write_pos + 2 <= sizeof(conn->write_buf)) 614251881Speter { 615251881Speter conn->write_buf[conn->write_pos] = ')'; 616251881Speter conn->write_buf[conn->write_pos+1] = ' '; 617251881Speter conn->write_pos += 2; 618251881Speter return SVN_NO_ERROR; 619251881Speter } 620251881Speter 621251881Speter return writebuf_write(conn, pool, ") ", 2); 622251881Speter} 623251881Speter 624251881Spetersvn_error_t * 625251881Spetersvn_ra_svn__flush(svn_ra_svn_conn_t *conn, 626251881Speter apr_pool_t *pool) 627251881Speter{ 628251881Speter SVN_ERR(writebuf_flush(conn, pool)); 629251881Speter conn->may_check_for_error = TRUE; 630251881Speter 631251881Speter return SVN_NO_ERROR; 632251881Speter} 633251881Speter 634251881Speter/* --- WRITING TUPLES --- */ 635251881Speter 636251881Speterstatic svn_error_t * 637251881Spetervwrite_tuple_cstring(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap) 638251881Speter{ 639251881Speter const char *cstr = va_arg(*ap, const char *); 640251881Speter SVN_ERR_ASSERT(cstr); 641251881Speter return svn_ra_svn__write_cstring(conn, pool, cstr); 642251881Speter} 643251881Speter 644251881Speterstatic svn_error_t * 645251881Spetervwrite_tuple_cstring_opt(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap) 646251881Speter{ 647251881Speter const char *cstr = va_arg(*ap, const char *); 648251881Speter return cstr ? svn_ra_svn__write_cstring(conn, pool, cstr) : SVN_NO_ERROR; 649251881Speter} 650251881Speter 651251881Speterstatic svn_error_t * 652251881Spetervwrite_tuple_string(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap) 653251881Speter{ 654251881Speter const svn_string_t *str = va_arg(*ap, const svn_string_t *); 655251881Speter SVN_ERR_ASSERT(str); 656251881Speter return svn_ra_svn__write_string(conn, pool, str); 657251881Speter} 658251881Speter 659251881Speterstatic svn_error_t * 660251881Spetervwrite_tuple_string_opt(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap) 661251881Speter{ 662251881Speter const svn_string_t *str = va_arg(*ap, const svn_string_t *); 663251881Speter return str ? svn_ra_svn__write_string(conn, pool, str) : SVN_NO_ERROR; 664251881Speter} 665251881Speter 666251881Speterstatic svn_error_t * 667251881Spetervwrite_tuple_word(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap) 668251881Speter{ 669251881Speter const char *cstr = va_arg(*ap, const char *); 670251881Speter SVN_ERR_ASSERT(cstr); 671251881Speter return svn_ra_svn__write_word(conn, pool, cstr); 672251881Speter} 673251881Speter 674251881Speterstatic svn_error_t * 675251881Spetervwrite_tuple_word_opt(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap) 676251881Speter{ 677251881Speter const char *cstr = va_arg(*ap, const char *); 678251881Speter return cstr ? svn_ra_svn__write_word(conn, pool, cstr) : SVN_NO_ERROR; 679251881Speter} 680251881Speter 681251881Speterstatic svn_error_t * 682251881Spetervwrite_tuple_revision(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap) 683251881Speter{ 684251881Speter svn_revnum_t rev = va_arg(*ap, svn_revnum_t); 685251881Speter SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(rev)); 686251881Speter return svn_ra_svn__write_number(conn, pool, rev); 687251881Speter} 688251881Speter 689251881Speterstatic svn_error_t * 690251881Spetervwrite_tuple_revision_opt(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap) 691251881Speter{ 692251881Speter svn_revnum_t rev = va_arg(*ap, svn_revnum_t); 693251881Speter return SVN_IS_VALID_REVNUM(rev) 694251881Speter ? svn_ra_svn__write_number(conn, pool, rev) 695251881Speter : SVN_NO_ERROR; 696251881Speter} 697251881Speter 698251881Speterstatic svn_error_t * 699251881Spetervwrite_tuple_number(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap) 700251881Speter{ 701251881Speter return svn_ra_svn__write_number(conn, pool, va_arg(*ap, apr_uint64_t)); 702251881Speter} 703251881Speter 704251881Speterstatic svn_error_t * 705251881Spetervwrite_tuple_boolean(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap) 706251881Speter{ 707251881Speter const char *cstr = va_arg(*ap, svn_boolean_t) ? "true" : "false"; 708251881Speter return svn_ra_svn__write_word(conn, pool, cstr); 709251881Speter} 710251881Speter 711251881Speterstatic svn_error_t * 712251881Speterwrite_tuple_cstring(svn_ra_svn_conn_t *conn, 713251881Speter apr_pool_t *pool, 714251881Speter const char *cstr) 715251881Speter{ 716251881Speter SVN_ERR_ASSERT(cstr); 717251881Speter return svn_ra_svn__write_cstring(conn, pool, cstr); 718251881Speter} 719251881Speter 720251881Speterstatic svn_error_t * 721251881Speterwrite_tuple_cstring_opt(svn_ra_svn_conn_t *conn, 722251881Speter apr_pool_t *pool, 723251881Speter const char *cstr) 724251881Speter{ 725251881Speter return cstr ? svn_ra_svn__write_cstring(conn, pool, cstr) : SVN_NO_ERROR; 726251881Speter} 727251881Speter 728251881Speterstatic svn_error_t * 729251881Speterwrite_tuple_string(svn_ra_svn_conn_t *conn, 730251881Speter apr_pool_t *pool, 731251881Speter const svn_string_t *str) 732251881Speter{ 733251881Speter SVN_ERR_ASSERT(str); 734251881Speter return svn_ra_svn__write_string(conn, pool, str); 735251881Speter} 736251881Speter 737251881Speterstatic svn_error_t * 738251881Speterwrite_tuple_string_opt(svn_ra_svn_conn_t *conn, 739251881Speter apr_pool_t *pool, 740251881Speter const svn_string_t *str) 741251881Speter{ 742251881Speter return str ? svn_ra_svn__write_string(conn, pool, str) : SVN_NO_ERROR; 743251881Speter} 744251881Speter 745251881Speterstatic svn_error_t * 746251881Speterwrite_tuple_start_list(svn_ra_svn_conn_t *conn, 747251881Speter apr_pool_t *pool) 748251881Speter{ 749251881Speter return svn_ra_svn__start_list(conn, pool); 750251881Speter} 751251881Speter 752251881Speterstatic svn_error_t * 753251881Speterwrite_tuple_end_list(svn_ra_svn_conn_t *conn, 754251881Speter apr_pool_t *pool) 755251881Speter{ 756251881Speter return svn_ra_svn__end_list(conn, pool); 757251881Speter} 758251881Speter 759251881Speterstatic svn_error_t * 760251881Speterwrite_tuple_revision(svn_ra_svn_conn_t *conn, 761251881Speter apr_pool_t *pool, 762251881Speter svn_revnum_t rev) 763251881Speter{ 764251881Speter SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(rev)); 765251881Speter return svn_ra_svn__write_number(conn, pool, rev); 766251881Speter} 767251881Speter 768251881Speterstatic svn_error_t * 769251881Speterwrite_tuple_revision_opt(svn_ra_svn_conn_t *conn, 770251881Speter apr_pool_t *pool, 771251881Speter svn_revnum_t rev) 772251881Speter{ 773251881Speter return SVN_IS_VALID_REVNUM(rev) 774251881Speter ? svn_ra_svn__write_number(conn, pool, rev) 775251881Speter : SVN_NO_ERROR; 776251881Speter} 777251881Speter 778251881Speterstatic svn_error_t * 779251881Speterwrite_tuple_boolean(svn_ra_svn_conn_t *conn, 780251881Speter apr_pool_t *pool, 781251881Speter svn_boolean_t value) 782251881Speter{ 783251881Speter const char *cstr = value ? "true" : "false"; 784251881Speter return svn_ra_svn__write_word(conn, pool, cstr); 785251881Speter} 786251881Speter 787251881Speterstatic svn_error_t * 788251881Speterwrite_tuple_depth(svn_ra_svn_conn_t *conn, 789251881Speter apr_pool_t *pool, 790251881Speter svn_depth_t depth) 791251881Speter{ 792251881Speter return svn_ra_svn__write_word(conn, pool, svn_depth_to_word(depth)); 793251881Speter} 794251881Speter 795251881Speter 796251881Speterstatic svn_error_t * 797251881Speterwrite_cmd_add_node(svn_ra_svn_conn_t *conn, 798251881Speter apr_pool_t *pool, 799251881Speter const char *path, 800251881Speter const char *parent_token, 801251881Speter const char *token, 802251881Speter const char *copy_path, 803251881Speter svn_revnum_t copy_rev) 804251881Speter{ 805251881Speter SVN_ERR(write_tuple_cstring(conn, pool, path)); 806251881Speter SVN_ERR(write_tuple_cstring(conn, pool, parent_token)); 807251881Speter SVN_ERR(write_tuple_cstring(conn, pool, token)); 808251881Speter SVN_ERR(write_tuple_start_list(conn, pool)); 809251881Speter SVN_ERR(write_tuple_cstring_opt(conn, pool, copy_path)); 810251881Speter SVN_ERR(write_tuple_revision_opt(conn, pool, copy_rev)); 811251881Speter SVN_ERR(write_tuple_end_list(conn, pool)); 812251881Speter 813251881Speter return SVN_NO_ERROR; 814251881Speter} 815251881Speter 816251881Speterstatic svn_error_t * 817251881Speterwrite_cmd_open_node(svn_ra_svn_conn_t *conn, 818251881Speter apr_pool_t *pool, 819251881Speter const char *path, 820251881Speter const char *parent_token, 821251881Speter const char *token, 822251881Speter svn_revnum_t rev) 823251881Speter{ 824251881Speter SVN_ERR(write_tuple_cstring(conn, pool, path)); 825251881Speter SVN_ERR(write_tuple_cstring(conn, pool, parent_token)); 826251881Speter SVN_ERR(write_tuple_cstring(conn, pool, token)); 827251881Speter SVN_ERR(write_tuple_start_list(conn, pool)); 828251881Speter SVN_ERR(write_tuple_revision_opt(conn, pool, rev)); 829251881Speter SVN_ERR(write_tuple_end_list(conn, pool)); 830251881Speter 831251881Speter return SVN_NO_ERROR; 832251881Speter} 833251881Speter 834251881Speterstatic svn_error_t * 835251881Speterwrite_cmd_change_node_prop(svn_ra_svn_conn_t *conn, 836251881Speter apr_pool_t *pool, 837251881Speter const char *token, 838251881Speter const char *name, 839251881Speter const svn_string_t *value) 840251881Speter{ 841251881Speter SVN_ERR(write_tuple_cstring(conn, pool, token)); 842251881Speter SVN_ERR(write_tuple_cstring(conn, pool, name)); 843251881Speter SVN_ERR(write_tuple_start_list(conn, pool)); 844251881Speter SVN_ERR(write_tuple_string_opt(conn, pool, value)); 845251881Speter SVN_ERR(write_tuple_end_list(conn, pool)); 846251881Speter 847251881Speter return SVN_NO_ERROR; 848251881Speter} 849251881Speter 850251881Speterstatic svn_error_t * 851251881Speterwrite_cmd_absent_node(svn_ra_svn_conn_t *conn, 852251881Speter apr_pool_t *pool, 853251881Speter const char *path, 854251881Speter const char *token) 855251881Speter{ 856251881Speter SVN_ERR(write_tuple_cstring(conn, pool, path)); 857251881Speter SVN_ERR(write_tuple_cstring(conn, pool, token)); 858251881Speter 859251881Speter return SVN_NO_ERROR; 860251881Speter} 861251881Speter 862251881Speter 863251881Speter 864251881Speter 865251881Speterstatic svn_error_t *vwrite_tuple(svn_ra_svn_conn_t *conn, apr_pool_t *pool, 866251881Speter const char *fmt, va_list *ap) 867251881Speter{ 868251881Speter svn_boolean_t opt = FALSE; 869251881Speter 870251881Speter if (*fmt == '!') 871251881Speter fmt++; 872251881Speter else 873251881Speter SVN_ERR(svn_ra_svn__start_list(conn, pool)); 874251881Speter for (; *fmt; fmt++) 875251881Speter { 876251881Speter if (*fmt == 'c') 877251881Speter SVN_ERR(opt ? vwrite_tuple_cstring_opt(conn, pool, ap) 878251881Speter : vwrite_tuple_cstring(conn, pool, ap)); 879251881Speter else if (*fmt == 's') 880251881Speter SVN_ERR(opt ? vwrite_tuple_string_opt(conn, pool, ap) 881251881Speter : vwrite_tuple_string(conn, pool, ap)); 882251881Speter else if (*fmt == '(' && !opt) 883251881Speter SVN_ERR(write_tuple_start_list(conn, pool)); 884251881Speter else if (*fmt == ')') 885251881Speter { 886251881Speter SVN_ERR(write_tuple_end_list(conn, pool)); 887251881Speter opt = FALSE; 888251881Speter } 889251881Speter else if (*fmt == '?') 890251881Speter opt = TRUE; 891251881Speter else if (*fmt == 'w') 892251881Speter SVN_ERR(opt ? vwrite_tuple_word_opt(conn, pool, ap) 893251881Speter : vwrite_tuple_word(conn, pool, ap)); 894251881Speter else if (*fmt == 'r') 895251881Speter SVN_ERR(opt ? vwrite_tuple_revision_opt(conn, pool, ap) 896251881Speter : vwrite_tuple_revision(conn, pool, ap)); 897251881Speter else if (*fmt == 'n' && !opt) 898251881Speter SVN_ERR(vwrite_tuple_number(conn, pool, ap)); 899251881Speter else if (*fmt == 'b' && !opt) 900251881Speter SVN_ERR(vwrite_tuple_boolean(conn, pool, ap)); 901251881Speter else if (*fmt == '!' && !*(fmt + 1)) 902251881Speter return SVN_NO_ERROR; 903251881Speter else 904251881Speter SVN_ERR_MALFUNCTION(); 905251881Speter } 906251881Speter SVN_ERR(svn_ra_svn__end_list(conn, pool)); 907251881Speter return SVN_NO_ERROR; 908251881Speter} 909251881Speter 910251881Spetersvn_error_t * 911251881Spetersvn_ra_svn__write_tuple(svn_ra_svn_conn_t *conn, 912251881Speter apr_pool_t *pool, 913251881Speter const char *fmt, ...) 914251881Speter{ 915251881Speter svn_error_t *err; 916251881Speter va_list ap; 917251881Speter 918251881Speter va_start(ap, fmt); 919251881Speter err = vwrite_tuple(conn, pool, fmt, &ap); 920251881Speter va_end(ap); 921251881Speter return err; 922251881Speter} 923251881Speter 924251881Speter/* --- READING DATA ITEMS --- */ 925251881Speter 926251881Speter/* Read LEN bytes from CONN into already-allocated structure ITEM. 927251881Speter * Afterwards, *ITEM is of type 'SVN_RA_SVN_STRING', and its string 928251881Speter * data is allocated in POOL. */ 929251881Speterstatic svn_error_t *read_string(svn_ra_svn_conn_t *conn, apr_pool_t *pool, 930251881Speter svn_ra_svn_item_t *item, apr_uint64_t len64) 931251881Speter{ 932251881Speter svn_stringbuf_t *stringbuf; 933251881Speter apr_size_t len = (apr_size_t)len64; 934251881Speter apr_size_t readbuf_len; 935251881Speter char *dest; 936251881Speter 937251881Speter /* We can't store strings longer than the maximum size of apr_size_t, 938251881Speter * so check for wrapping */ 939251881Speter if (len64 > APR_SIZE_MAX) 940251881Speter return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL, 941251881Speter _("String length larger than maximum")); 942251881Speter 943251881Speter /* Read the string in chunks. The chunk size is large enough to avoid 944251881Speter * re-allocation in typical cases, and small enough to ensure we do not 945251881Speter * pre-allocate an unreasonable amount of memory if (perhaps due to 946251881Speter * network data corruption or a DOS attack), we receive a bogus claim that 947251881Speter * a very long string is going to follow. In that case, we start small 948251881Speter * and wait for all that data to actually show up. This does not fully 949251881Speter * prevent DOS attacks but makes them harder (you have to actually send 950251881Speter * gigabytes of data). */ 951251881Speter readbuf_len = len < SUSPICIOUSLY_HUGE_STRING_SIZE_THRESHOLD 952251881Speter ? len 953251881Speter : SUSPICIOUSLY_HUGE_STRING_SIZE_THRESHOLD; 954251881Speter stringbuf = svn_stringbuf_create_ensure(readbuf_len, pool); 955251881Speter dest = stringbuf->data; 956251881Speter 957251881Speter /* Read remaining string data directly into the string structure. 958251881Speter * Do it iteratively, if necessary. */ 959251881Speter while (readbuf_len) 960251881Speter { 961251881Speter SVN_ERR(readbuf_read(conn, pool, dest, readbuf_len)); 962251881Speter 963251881Speter stringbuf->len += readbuf_len; 964251881Speter len -= readbuf_len; 965251881Speter 966251881Speter /* Early exit. In most cases, strings can be read in the first 967251881Speter * iteration. */ 968251881Speter if (len == 0) 969251881Speter break; 970251881Speter 971251881Speter /* Prepare next iteration: determine length of chunk to read 972251881Speter * and re-alloc the string buffer. */ 973251881Speter readbuf_len 974251881Speter = len < SUSPICIOUSLY_HUGE_STRING_SIZE_THRESHOLD 975251881Speter ? len 976251881Speter : SUSPICIOUSLY_HUGE_STRING_SIZE_THRESHOLD; 977251881Speter 978251881Speter svn_stringbuf_ensure(stringbuf, stringbuf->len + readbuf_len); 979251881Speter dest = stringbuf->data + stringbuf->len; 980251881Speter } 981251881Speter 982251881Speter /* zero-terminate the string */ 983251881Speter stringbuf->data[stringbuf->len] = '\0'; 984251881Speter 985251881Speter /* Return the string properly wrapped into an RA_SVN item. */ 986251881Speter item->kind = SVN_RA_SVN_STRING; 987251881Speter item->u.string = svn_stringbuf__morph_into_string(stringbuf); 988251881Speter 989251881Speter return SVN_NO_ERROR; 990251881Speter} 991251881Speter 992251881Speter/* Given the first non-whitespace character FIRST_CHAR, read an item 993251881Speter * into the already allocated structure ITEM. LEVEL should be set 994251881Speter * to 0 for the first call and is used to enforce a recurssion limit 995251881Speter * on the parser. */ 996251881Speterstatic svn_error_t *read_item(svn_ra_svn_conn_t *conn, apr_pool_t *pool, 997251881Speter svn_ra_svn_item_t *item, char first_char, 998251881Speter int level) 999251881Speter{ 1000251881Speter char c = first_char; 1001251881Speter apr_uint64_t val; 1002251881Speter svn_stringbuf_t *str; 1003251881Speter svn_ra_svn_item_t *listitem; 1004251881Speter 1005251881Speter if (++level >= 64) 1006251881Speter return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL, 1007251881Speter _("Too many nested items")); 1008251881Speter 1009251881Speter 1010251881Speter /* Determine the item type and read it in. Make sure that c is the 1011251881Speter * first character at the end of the item so we can test to make 1012251881Speter * sure it's whitespace. */ 1013251881Speter if (svn_ctype_isdigit(c)) 1014251881Speter { 1015251881Speter /* It's a number or a string. Read the number part, either way. */ 1016251881Speter val = c - '0'; 1017251881Speter while (1) 1018251881Speter { 1019251881Speter apr_uint64_t prev_val = val; 1020251881Speter SVN_ERR(readbuf_getchar(conn, pool, &c)); 1021251881Speter if (!svn_ctype_isdigit(c)) 1022251881Speter break; 1023251881Speter val = val * 10 + (c - '0'); 1024251881Speter /* val wrapped past maximum value? */ 1025251881Speter if (prev_val >= (APR_UINT64_MAX / 10) && (val / 10) != prev_val) 1026251881Speter return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL, 1027251881Speter _("Number is larger than maximum")); 1028251881Speter } 1029251881Speter if (c == ':') 1030251881Speter { 1031251881Speter /* It's a string. */ 1032251881Speter SVN_ERR(read_string(conn, pool, item, val)); 1033251881Speter SVN_ERR(readbuf_getchar(conn, pool, &c)); 1034251881Speter } 1035251881Speter else 1036251881Speter { 1037251881Speter /* It's a number. */ 1038251881Speter item->kind = SVN_RA_SVN_NUMBER; 1039251881Speter item->u.number = val; 1040251881Speter } 1041251881Speter } 1042251881Speter else if (svn_ctype_isalpha(c)) 1043251881Speter { 1044251881Speter /* It's a word. */ 1045251881Speter str = svn_stringbuf_create_ensure(16, pool); 1046251881Speter svn_stringbuf_appendbyte(str, c); 1047251881Speter while (1) 1048251881Speter { 1049251881Speter SVN_ERR(readbuf_getchar(conn, pool, &c)); 1050251881Speter if (!svn_ctype_isalnum(c) && c != '-') 1051251881Speter break; 1052251881Speter svn_stringbuf_appendbyte(str, c); 1053251881Speter } 1054251881Speter item->kind = SVN_RA_SVN_WORD; 1055251881Speter item->u.word = str->data; 1056251881Speter } 1057251881Speter else if (c == '(') 1058251881Speter { 1059251881Speter /* Read in the list items. */ 1060251881Speter item->kind = SVN_RA_SVN_LIST; 1061251881Speter item->u.list = apr_array_make(pool, 4, sizeof(svn_ra_svn_item_t)); 1062251881Speter while (1) 1063251881Speter { 1064251881Speter SVN_ERR(readbuf_getchar_skip_whitespace(conn, pool, &c)); 1065251881Speter if (c == ')') 1066251881Speter break; 1067251881Speter listitem = apr_array_push(item->u.list); 1068251881Speter SVN_ERR(read_item(conn, pool, listitem, c, level)); 1069251881Speter } 1070251881Speter SVN_ERR(readbuf_getchar(conn, pool, &c)); 1071251881Speter } 1072251881Speter 1073251881Speter if (!svn_iswhitespace(c)) 1074251881Speter return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL, 1075251881Speter _("Malformed network data")); 1076251881Speter return SVN_NO_ERROR; 1077251881Speter} 1078251881Speter 1079251881Speter/* Given the first non-whitespace character FIRST_CHAR, read the first 1080251881Speter * command (word) encountered in CONN into *ITEM. If ITEM is NULL, skip 1081251881Speter * to the end of the current list. Use POOL for allocations. */ 1082251881Speterstatic svn_error_t * 1083251881Speterread_command_only(svn_ra_svn_conn_t *conn, apr_pool_t *pool, 1084251881Speter const char **item, char first_char) 1085251881Speter{ 1086251881Speter char c = first_char; 1087251881Speter 1088251881Speter /* Determine the item type and read it in. Make sure that c is the 1089251881Speter * first character at the end of the item so we can test to make 1090251881Speter * sure it's whitespace. */ 1091251881Speter if (svn_ctype_isdigit(c)) 1092251881Speter { 1093251881Speter /* It's a number or a string. Read the number part, either way. */ 1094251881Speter apr_uint64_t val, prev_val=0; 1095251881Speter val = c - '0'; 1096251881Speter while (1) 1097251881Speter { 1098251881Speter prev_val = val; 1099251881Speter SVN_ERR(readbuf_getchar(conn, pool, &c)); 1100251881Speter if (!svn_ctype_isdigit(c)) 1101251881Speter break; 1102251881Speter val = val * 10 + (c - '0'); 1103251881Speter if (prev_val >= (APR_UINT64_MAX / 10)) /* > maximum value? */ 1104251881Speter return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL, 1105251881Speter _("Number is larger than maximum")); 1106251881Speter } 1107251881Speter if (c == ':') 1108251881Speter { 1109251881Speter /* It's a string. */ 1110251881Speter SVN_ERR(readbuf_skip(conn, val)); 1111251881Speter SVN_ERR(readbuf_getchar(conn, pool, &c)); 1112251881Speter } 1113251881Speter } 1114251881Speter else if (svn_ctype_isalpha(c)) 1115251881Speter { 1116251881Speter /* It's a word. */ 1117251881Speter if (item) 1118251881Speter { 1119251881Speter /* This is the word we want to read */ 1120251881Speter 1121251881Speter char *buf = apr_palloc(pool, 32); 1122251881Speter apr_size_t len = 1; 1123251881Speter buf[0] = c; 1124251881Speter 1125251881Speter while (1) 1126251881Speter { 1127251881Speter SVN_ERR(readbuf_getchar(conn, pool, &c)); 1128251881Speter if (!svn_ctype_isalnum(c) && c != '-') 1129251881Speter break; 1130251881Speter buf[len] = c; 1131251881Speter if (++len == 32) 1132251881Speter return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL, 1133251881Speter _("Word too long")); 1134251881Speter } 1135251881Speter buf[len] = 0; 1136251881Speter *item = buf; 1137251881Speter } 1138251881Speter else 1139251881Speter { 1140251881Speter /* we don't need the actual word, just skip it */ 1141251881Speter do 1142251881Speter { 1143251881Speter SVN_ERR(readbuf_getchar(conn, pool, &c)); 1144251881Speter } 1145251881Speter while (svn_ctype_isalnum(c) || c == '-'); 1146251881Speter } 1147251881Speter } 1148251881Speter else if (c == '(') 1149251881Speter { 1150251881Speter /* Read in the list items. */ 1151251881Speter while (1) 1152251881Speter { 1153251881Speter SVN_ERR(readbuf_getchar_skip_whitespace(conn, pool, &c)); 1154251881Speter if (c == ')') 1155251881Speter break; 1156251881Speter 1157251881Speter if (item && *item == NULL) 1158251881Speter SVN_ERR(read_command_only(conn, pool, item, c)); 1159251881Speter else 1160251881Speter SVN_ERR(read_command_only(conn, pool, NULL, c)); 1161251881Speter } 1162251881Speter SVN_ERR(readbuf_getchar(conn, pool, &c)); 1163251881Speter } 1164251881Speter 1165251881Speter return SVN_NO_ERROR; 1166251881Speter} 1167251881Speter 1168251881Spetersvn_error_t * 1169251881Spetersvn_ra_svn__read_item(svn_ra_svn_conn_t *conn, 1170251881Speter apr_pool_t *pool, 1171251881Speter svn_ra_svn_item_t **item) 1172251881Speter{ 1173251881Speter char c; 1174251881Speter 1175251881Speter /* Allocate space, read the first character, and then do the rest of 1176251881Speter * the work. This makes sense because of the way lists are read. */ 1177251881Speter *item = apr_palloc(pool, sizeof(**item)); 1178251881Speter SVN_ERR(readbuf_getchar_skip_whitespace(conn, pool, &c)); 1179251881Speter return read_item(conn, pool, *item, c, 0); 1180251881Speter} 1181251881Speter 1182251881Spetersvn_error_t * 1183251881Spetersvn_ra_svn__skip_leading_garbage(svn_ra_svn_conn_t *conn, 1184251881Speter apr_pool_t *pool) 1185251881Speter{ 1186251881Speter return readbuf_skip_leading_garbage(conn, pool); 1187251881Speter} 1188251881Speter 1189251881Speter/* --- READING AND PARSING TUPLES --- */ 1190251881Speter 1191251881Speter/* Parse a tuple of svn_ra_svn_item_t *'s. Advance *FMT to the end of the 1192251881Speter * tuple specification and advance AP by the corresponding arguments. */ 1193251881Speterstatic svn_error_t *vparse_tuple(const apr_array_header_t *items, apr_pool_t *pool, 1194251881Speter const char **fmt, va_list *ap) 1195251881Speter{ 1196251881Speter int count, nesting_level; 1197251881Speter svn_ra_svn_item_t *elt; 1198251881Speter 1199251881Speter for (count = 0; **fmt && count < items->nelts; (*fmt)++, count++) 1200251881Speter { 1201251881Speter /* '?' just means the tuple may stop; skip past it. */ 1202251881Speter if (**fmt == '?') 1203251881Speter (*fmt)++; 1204251881Speter elt = &APR_ARRAY_IDX(items, count, svn_ra_svn_item_t); 1205251881Speter if (**fmt == 'n' && elt->kind == SVN_RA_SVN_NUMBER) 1206251881Speter *va_arg(*ap, apr_uint64_t *) = elt->u.number; 1207251881Speter else if (**fmt == 'r' && elt->kind == SVN_RA_SVN_NUMBER) 1208251881Speter *va_arg(*ap, svn_revnum_t *) = (svn_revnum_t) elt->u.number; 1209251881Speter else if (**fmt == 's' && elt->kind == SVN_RA_SVN_STRING) 1210251881Speter *va_arg(*ap, svn_string_t **) = elt->u.string; 1211251881Speter else if (**fmt == 'c' && elt->kind == SVN_RA_SVN_STRING) 1212251881Speter *va_arg(*ap, const char **) = elt->u.string->data; 1213251881Speter else if (**fmt == 'w' && elt->kind == SVN_RA_SVN_WORD) 1214251881Speter *va_arg(*ap, const char **) = elt->u.word; 1215251881Speter else if (**fmt == 'b' && elt->kind == SVN_RA_SVN_WORD) 1216251881Speter { 1217251881Speter if (strcmp(elt->u.word, "true") == 0) 1218251881Speter *va_arg(*ap, svn_boolean_t *) = TRUE; 1219251881Speter else if (strcmp(elt->u.word, "false") == 0) 1220251881Speter *va_arg(*ap, svn_boolean_t *) = FALSE; 1221251881Speter else 1222251881Speter break; 1223251881Speter } 1224251881Speter else if (**fmt == 'B' && elt->kind == SVN_RA_SVN_WORD) 1225251881Speter { 1226251881Speter if (strcmp(elt->u.word, "true") == 0) 1227251881Speter *va_arg(*ap, apr_uint64_t *) = TRUE; 1228251881Speter else if (strcmp(elt->u.word, "false") == 0) 1229251881Speter *va_arg(*ap, apr_uint64_t *) = FALSE; 1230251881Speter else 1231251881Speter break; 1232251881Speter } 1233251881Speter else if (**fmt == 'l' && elt->kind == SVN_RA_SVN_LIST) 1234251881Speter *va_arg(*ap, apr_array_header_t **) = elt->u.list; 1235251881Speter else if (**fmt == '(' && elt->kind == SVN_RA_SVN_LIST) 1236251881Speter { 1237251881Speter (*fmt)++; 1238251881Speter SVN_ERR(vparse_tuple(elt->u.list, pool, fmt, ap)); 1239251881Speter } 1240251881Speter else if (**fmt == ')') 1241251881Speter return SVN_NO_ERROR; 1242251881Speter else 1243251881Speter break; 1244251881Speter } 1245251881Speter if (**fmt == '?') 1246251881Speter { 1247251881Speter nesting_level = 0; 1248251881Speter for (; **fmt; (*fmt)++) 1249251881Speter { 1250251881Speter switch (**fmt) 1251251881Speter { 1252251881Speter case '?': 1253251881Speter break; 1254251881Speter case 'r': 1255251881Speter *va_arg(*ap, svn_revnum_t *) = SVN_INVALID_REVNUM; 1256251881Speter break; 1257251881Speter case 's': 1258251881Speter *va_arg(*ap, svn_string_t **) = NULL; 1259251881Speter break; 1260251881Speter case 'c': 1261251881Speter case 'w': 1262251881Speter *va_arg(*ap, const char **) = NULL; 1263251881Speter break; 1264251881Speter case 'l': 1265251881Speter *va_arg(*ap, apr_array_header_t **) = NULL; 1266251881Speter break; 1267251881Speter case 'B': 1268251881Speter case 'n': 1269251881Speter *va_arg(*ap, apr_uint64_t *) = SVN_RA_SVN_UNSPECIFIED_NUMBER; 1270251881Speter break; 1271251881Speter case '(': 1272251881Speter nesting_level++; 1273251881Speter break; 1274251881Speter case ')': 1275251881Speter if (--nesting_level < 0) 1276251881Speter return SVN_NO_ERROR; 1277251881Speter break; 1278251881Speter default: 1279251881Speter SVN_ERR_MALFUNCTION(); 1280251881Speter } 1281251881Speter } 1282251881Speter } 1283251881Speter if (**fmt && **fmt != ')') 1284251881Speter return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL, 1285251881Speter _("Malformed network data")); 1286251881Speter return SVN_NO_ERROR; 1287251881Speter} 1288251881Speter 1289251881Spetersvn_error_t * 1290251881Spetersvn_ra_svn__parse_tuple(const apr_array_header_t *list, 1291251881Speter apr_pool_t *pool, 1292251881Speter const char *fmt, ...) 1293251881Speter{ 1294251881Speter svn_error_t *err; 1295251881Speter va_list ap; 1296251881Speter 1297251881Speter va_start(ap, fmt); 1298251881Speter err = vparse_tuple(list, pool, &fmt, &ap); 1299251881Speter va_end(ap); 1300251881Speter return err; 1301251881Speter} 1302251881Speter 1303251881Spetersvn_error_t * 1304251881Spetersvn_ra_svn__read_tuple(svn_ra_svn_conn_t *conn, 1305251881Speter apr_pool_t *pool, 1306251881Speter const char *fmt, ...) 1307251881Speter{ 1308251881Speter va_list ap; 1309251881Speter svn_ra_svn_item_t *item; 1310251881Speter svn_error_t *err; 1311251881Speter 1312251881Speter SVN_ERR(svn_ra_svn__read_item(conn, pool, &item)); 1313251881Speter if (item->kind != SVN_RA_SVN_LIST) 1314251881Speter return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL, 1315251881Speter _("Malformed network data")); 1316251881Speter va_start(ap, fmt); 1317251881Speter err = vparse_tuple(item->u.list, pool, &fmt, &ap); 1318251881Speter va_end(ap); 1319251881Speter return err; 1320251881Speter} 1321251881Speter 1322251881Spetersvn_error_t * 1323251881Spetersvn_ra_svn__read_command_only(svn_ra_svn_conn_t *conn, 1324251881Speter apr_pool_t *pool, 1325251881Speter const char **command) 1326251881Speter{ 1327251881Speter char c; 1328251881Speter SVN_ERR(readbuf_getchar_skip_whitespace(conn, pool, &c)); 1329251881Speter 1330251881Speter *command = NULL; 1331251881Speter return read_command_only(conn, pool, command, c); 1332251881Speter} 1333251881Speter 1334251881Speter 1335251881Spetersvn_error_t * 1336251881Spetersvn_ra_svn__parse_proplist(const apr_array_header_t *list, 1337251881Speter apr_pool_t *pool, 1338251881Speter apr_hash_t **props) 1339251881Speter{ 1340251881Speter char *name; 1341251881Speter svn_string_t *value; 1342251881Speter svn_ra_svn_item_t *elt; 1343251881Speter int i; 1344251881Speter 1345251881Speter *props = apr_hash_make(pool); 1346251881Speter for (i = 0; i < list->nelts; i++) 1347251881Speter { 1348251881Speter elt = &APR_ARRAY_IDX(list, i, svn_ra_svn_item_t); 1349251881Speter if (elt->kind != SVN_RA_SVN_LIST) 1350251881Speter return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL, 1351251881Speter _("Proplist element not a list")); 1352251881Speter SVN_ERR(svn_ra_svn__parse_tuple(elt->u.list, pool, "cs", 1353251881Speter &name, &value)); 1354251881Speter svn_hash_sets(*props, name, value); 1355251881Speter } 1356251881Speter 1357251881Speter return SVN_NO_ERROR; 1358251881Speter} 1359251881Speter 1360251881Speter 1361251881Speter/* --- READING AND WRITING COMMANDS AND RESPONSES --- */ 1362251881Speter 1363251881Spetersvn_error_t *svn_ra_svn__locate_real_error_child(svn_error_t *err) 1364251881Speter{ 1365251881Speter svn_error_t *this_link; 1366251881Speter 1367251881Speter SVN_ERR_ASSERT(err); 1368251881Speter 1369251881Speter for (this_link = err; 1370251881Speter this_link && (this_link->apr_err == SVN_ERR_RA_SVN_CMD_ERR); 1371251881Speter this_link = this_link->child) 1372251881Speter ; 1373251881Speter 1374251881Speter SVN_ERR_ASSERT(this_link); 1375251881Speter return this_link; 1376251881Speter} 1377251881Speter 1378251881Spetersvn_error_t *svn_ra_svn__handle_failure_status(const apr_array_header_t *params, 1379251881Speter apr_pool_t *pool) 1380251881Speter{ 1381251881Speter const char *message, *file; 1382251881Speter svn_error_t *err = NULL; 1383251881Speter svn_ra_svn_item_t *elt; 1384251881Speter int i; 1385251881Speter apr_uint64_t apr_err, line; 1386251881Speter apr_pool_t *subpool = svn_pool_create(pool); 1387251881Speter 1388251881Speter if (params->nelts == 0) 1389251881Speter return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL, 1390251881Speter _("Empty error list")); 1391251881Speter 1392251881Speter /* Rebuild the error list from the end, to avoid reversing the order. */ 1393251881Speter for (i = params->nelts - 1; i >= 0; i--) 1394251881Speter { 1395251881Speter svn_pool_clear(subpool); 1396251881Speter elt = &APR_ARRAY_IDX(params, i, svn_ra_svn_item_t); 1397251881Speter if (elt->kind != SVN_RA_SVN_LIST) 1398251881Speter return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL, 1399251881Speter _("Malformed error list")); 1400251881Speter SVN_ERR(svn_ra_svn__parse_tuple(elt->u.list, subpool, "nccn", 1401251881Speter &apr_err, &message, &file, &line)); 1402251881Speter /* The message field should have been optional, but we can't 1403251881Speter easily change that, so "" means a nonexistent message. */ 1404251881Speter if (!*message) 1405251881Speter message = NULL; 1406251881Speter 1407251881Speter /* Skip over links in the error chain that were intended only to 1408251881Speter exist on the server (to wrap real errors intended for the 1409251881Speter client) but accidentally got included in the server's actual 1410251881Speter response. */ 1411251881Speter if ((apr_status_t)apr_err != SVN_ERR_RA_SVN_CMD_ERR) 1412251881Speter { 1413251881Speter err = svn_error_create((apr_status_t)apr_err, err, message); 1414251881Speter err->file = apr_pstrdup(err->pool, file); 1415251881Speter err->line = (long)line; 1416251881Speter } 1417251881Speter } 1418251881Speter 1419251881Speter svn_pool_destroy(subpool); 1420251881Speter 1421251881Speter /* If we get here, then we failed to find a real error in the error 1422251881Speter chain that the server proported to be sending us. That's bad. */ 1423251881Speter if (! err) 1424251881Speter err = svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL, 1425251881Speter _("Malformed error list")); 1426251881Speter 1427251881Speter return err; 1428251881Speter} 1429251881Speter 1430251881Spetersvn_error_t * 1431251881Spetersvn_ra_svn__read_cmd_response(svn_ra_svn_conn_t *conn, 1432251881Speter apr_pool_t *pool, 1433251881Speter const char *fmt, ...) 1434251881Speter{ 1435251881Speter va_list ap; 1436251881Speter const char *status; 1437251881Speter apr_array_header_t *params; 1438251881Speter svn_error_t *err; 1439251881Speter 1440251881Speter SVN_ERR(svn_ra_svn__read_tuple(conn, pool, "wl", &status, ¶ms)); 1441251881Speter if (strcmp(status, "success") == 0) 1442251881Speter { 1443251881Speter va_start(ap, fmt); 1444251881Speter err = vparse_tuple(params, pool, &fmt, &ap); 1445251881Speter va_end(ap); 1446251881Speter return err; 1447251881Speter } 1448251881Speter else if (strcmp(status, "failure") == 0) 1449251881Speter { 1450251881Speter return svn_ra_svn__handle_failure_status(params, pool); 1451251881Speter } 1452251881Speter 1453251881Speter return svn_error_createf(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL, 1454251881Speter _("Unknown status '%s' in command response"), 1455251881Speter status); 1456251881Speter} 1457251881Speter 1458251881Spetersvn_error_t * 1459251881Spetersvn_ra_svn__handle_commands2(svn_ra_svn_conn_t *conn, 1460251881Speter apr_pool_t *pool, 1461251881Speter const svn_ra_svn_cmd_entry_t *commands, 1462251881Speter void *baton, 1463251881Speter svn_boolean_t error_on_disconnect) 1464251881Speter{ 1465251881Speter apr_pool_t *subpool = svn_pool_create(pool); 1466251881Speter apr_pool_t *iterpool = svn_pool_create(subpool); 1467251881Speter const char *cmdname; 1468251881Speter const svn_ra_svn_cmd_entry_t *command; 1469251881Speter svn_error_t *err, *write_err; 1470251881Speter apr_array_header_t *params; 1471251881Speter apr_hash_t *cmd_hash = apr_hash_make(subpool); 1472251881Speter 1473251881Speter for (command = commands; command->cmdname; command++) 1474251881Speter svn_hash_sets(cmd_hash, command->cmdname, command); 1475251881Speter 1476251881Speter while (1) 1477251881Speter { 1478251881Speter svn_pool_clear(iterpool); 1479251881Speter err = svn_ra_svn__read_tuple(conn, iterpool, "wl", &cmdname, ¶ms); 1480251881Speter if (err) 1481251881Speter { 1482251881Speter if (!error_on_disconnect 1483251881Speter && err->apr_err == SVN_ERR_RA_SVN_CONNECTION_CLOSED) 1484251881Speter { 1485251881Speter svn_error_clear(err); 1486251881Speter svn_pool_destroy(subpool); 1487251881Speter return SVN_NO_ERROR; 1488251881Speter } 1489251881Speter return err; 1490251881Speter } 1491251881Speter command = svn_hash_gets(cmd_hash, cmdname); 1492251881Speter 1493251881Speter if (command) 1494251881Speter err = (*command->handler)(conn, iterpool, params, baton); 1495251881Speter else 1496251881Speter { 1497251881Speter err = svn_error_createf(SVN_ERR_RA_SVN_UNKNOWN_CMD, NULL, 1498251881Speter _("Unknown editor command '%s'"), cmdname); 1499251881Speter err = svn_error_create(SVN_ERR_RA_SVN_CMD_ERR, err, NULL); 1500251881Speter } 1501251881Speter 1502251881Speter if (err && err->apr_err == SVN_ERR_RA_SVN_CMD_ERR) 1503251881Speter { 1504251881Speter write_err = svn_ra_svn__write_cmd_failure( 1505251881Speter conn, iterpool, 1506251881Speter svn_ra_svn__locate_real_error_child(err)); 1507251881Speter svn_error_clear(err); 1508251881Speter if (write_err) 1509251881Speter return write_err; 1510251881Speter } 1511251881Speter else if (err) 1512251881Speter return err; 1513251881Speter 1514251881Speter if (command && command->terminate) 1515251881Speter break; 1516251881Speter } 1517251881Speter svn_pool_destroy(iterpool); 1518251881Speter svn_pool_destroy(subpool); 1519251881Speter return SVN_NO_ERROR; 1520251881Speter} 1521251881Speter 1522251881Spetersvn_error_t * 1523251881Spetersvn_ra_svn__write_cmd_target_rev(svn_ra_svn_conn_t *conn, 1524251881Speter apr_pool_t *pool, 1525251881Speter svn_revnum_t rev) 1526251881Speter{ 1527251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, "( target-rev ( ", 15)); 1528251881Speter SVN_ERR(write_tuple_revision(conn, pool, rev)); 1529251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); 1530251881Speter 1531251881Speter return SVN_NO_ERROR; 1532251881Speter} 1533251881Speter 1534251881Spetersvn_error_t * 1535251881Spetersvn_ra_svn__write_cmd_open_root(svn_ra_svn_conn_t *conn, 1536251881Speter apr_pool_t *pool, 1537251881Speter svn_revnum_t rev, 1538251881Speter const char *token) 1539251881Speter{ 1540251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, "( open-root ( ", 14)); 1541251881Speter SVN_ERR(write_tuple_start_list(conn, pool)); 1542251881Speter SVN_ERR(write_tuple_revision_opt(conn, pool, rev)); 1543251881Speter SVN_ERR(write_tuple_end_list(conn, pool)); 1544251881Speter SVN_ERR(write_tuple_cstring(conn, pool, token)); 1545251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); 1546251881Speter 1547251881Speter return SVN_NO_ERROR; 1548251881Speter} 1549251881Speter 1550251881Spetersvn_error_t * 1551251881Spetersvn_ra_svn__write_cmd_delete_entry(svn_ra_svn_conn_t *conn, 1552251881Speter apr_pool_t *pool, 1553251881Speter const char *path, 1554251881Speter svn_revnum_t rev, 1555251881Speter const char *token) 1556251881Speter{ 1557251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, "( delete-entry ( ", 17)); 1558251881Speter SVN_ERR(write_tuple_cstring(conn, pool, path)); 1559251881Speter SVN_ERR(write_tuple_start_list(conn, pool)); 1560251881Speter SVN_ERR(write_tuple_revision_opt(conn, pool, rev)); 1561251881Speter SVN_ERR(write_tuple_end_list(conn, pool)); 1562251881Speter SVN_ERR(write_tuple_cstring(conn, pool, token)); 1563251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); 1564251881Speter 1565251881Speter return SVN_NO_ERROR; 1566251881Speter} 1567251881Speter 1568251881Spetersvn_error_t * 1569251881Spetersvn_ra_svn__write_cmd_add_dir(svn_ra_svn_conn_t *conn, 1570251881Speter apr_pool_t *pool, 1571251881Speter const char *path, 1572251881Speter const char *parent_token, 1573251881Speter const char *token, 1574251881Speter const char *copy_path, 1575251881Speter svn_revnum_t copy_rev) 1576251881Speter{ 1577251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, "( add-dir ( ", 12)); 1578251881Speter SVN_ERR(write_cmd_add_node(conn, pool, path, parent_token, token, 1579251881Speter copy_path, copy_rev)); 1580251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); 1581251881Speter 1582251881Speter return SVN_NO_ERROR; 1583251881Speter} 1584251881Speter 1585251881Spetersvn_error_t * 1586251881Spetersvn_ra_svn__write_cmd_open_dir(svn_ra_svn_conn_t *conn, 1587251881Speter apr_pool_t *pool, 1588251881Speter const char *path, 1589251881Speter const char *parent_token, 1590251881Speter const char *token, 1591251881Speter svn_revnum_t rev) 1592251881Speter{ 1593251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, "( open-dir ( ", 13)); 1594251881Speter SVN_ERR(write_cmd_open_node(conn, pool, path, parent_token, token, rev)); 1595251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); 1596251881Speter 1597251881Speter return SVN_NO_ERROR; 1598251881Speter} 1599251881Speter 1600251881Spetersvn_error_t * 1601251881Spetersvn_ra_svn__write_cmd_change_dir_prop(svn_ra_svn_conn_t *conn, 1602251881Speter apr_pool_t *pool, 1603251881Speter const char *token, 1604251881Speter const char *name, 1605251881Speter const svn_string_t *value) 1606251881Speter{ 1607251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, "( change-dir-prop ( ", 20)); 1608251881Speter SVN_ERR(write_cmd_change_node_prop(conn, pool, token, name, value)); 1609251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); 1610251881Speter 1611251881Speter return SVN_NO_ERROR; 1612251881Speter} 1613251881Speter 1614251881Spetersvn_error_t * 1615251881Spetersvn_ra_svn__write_cmd_close_dir(svn_ra_svn_conn_t *conn, 1616251881Speter apr_pool_t *pool, 1617251881Speter const char *token) 1618251881Speter{ 1619251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, "( close-dir ( ", 14)); 1620251881Speter SVN_ERR(write_tuple_cstring(conn, pool, token)); 1621251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); 1622251881Speter 1623251881Speter return SVN_NO_ERROR; 1624251881Speter} 1625251881Speter 1626251881Spetersvn_error_t * 1627251881Spetersvn_ra_svn__write_cmd_absent_dir(svn_ra_svn_conn_t *conn, 1628251881Speter apr_pool_t *pool, 1629251881Speter const char *path, 1630251881Speter const char *parent_token) 1631251881Speter{ 1632251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, "( absent-dir ( ", 15)); 1633251881Speter SVN_ERR(write_cmd_absent_node(conn, pool, path, parent_token)); 1634251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); 1635251881Speter 1636251881Speter return SVN_NO_ERROR; 1637251881Speter} 1638251881Speter 1639251881Spetersvn_error_t * 1640251881Spetersvn_ra_svn__write_cmd_add_file(svn_ra_svn_conn_t *conn, 1641251881Speter apr_pool_t *pool, 1642251881Speter const char *path, 1643251881Speter const char *parent_token, 1644251881Speter const char *token, 1645251881Speter const char *copy_path, 1646251881Speter svn_revnum_t copy_rev) 1647251881Speter{ 1648251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, "( add-file ( ", 13)); 1649251881Speter SVN_ERR(write_cmd_add_node(conn, pool, path, parent_token, token, 1650251881Speter copy_path, copy_rev)); 1651251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); 1652251881Speter 1653251881Speter return SVN_NO_ERROR; 1654251881Speter} 1655251881Speter 1656251881Spetersvn_error_t * 1657251881Spetersvn_ra_svn__write_cmd_open_file(svn_ra_svn_conn_t *conn, 1658251881Speter apr_pool_t *pool, 1659251881Speter const char *path, 1660251881Speter const char *parent_token, 1661251881Speter const char *token, 1662251881Speter svn_revnum_t rev) 1663251881Speter{ 1664251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, "( open-file ( ", 14)); 1665251881Speter SVN_ERR(write_cmd_open_node(conn, pool, path, parent_token, token, rev)); 1666251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); 1667251881Speter 1668251881Speter return SVN_NO_ERROR; 1669251881Speter} 1670251881Speter 1671251881Spetersvn_error_t * 1672251881Spetersvn_ra_svn__write_cmd_change_file_prop(svn_ra_svn_conn_t *conn, 1673251881Speter apr_pool_t *pool, 1674251881Speter const char *token, 1675251881Speter const char *name, 1676251881Speter const svn_string_t *value) 1677251881Speter{ 1678251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, "( change-file-prop ( ", 21)); 1679251881Speter SVN_ERR(write_cmd_change_node_prop(conn, pool, token, name, value)); 1680251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); 1681251881Speter 1682251881Speter return SVN_NO_ERROR; 1683251881Speter} 1684251881Speter 1685251881Spetersvn_error_t * 1686251881Spetersvn_ra_svn__write_cmd_close_file(svn_ra_svn_conn_t *conn, 1687251881Speter apr_pool_t *pool, 1688251881Speter const char *token, 1689251881Speter const char *text_checksum) 1690251881Speter{ 1691251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, "( close-file ( ", 15)); 1692251881Speter SVN_ERR(write_tuple_cstring(conn, pool, token)); 1693251881Speter SVN_ERR(write_tuple_start_list(conn, pool)); 1694251881Speter SVN_ERR(write_tuple_cstring_opt(conn, pool, text_checksum)); 1695251881Speter SVN_ERR(write_tuple_end_list(conn, pool)); 1696251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); 1697251881Speter 1698251881Speter return SVN_NO_ERROR; 1699251881Speter} 1700251881Speter 1701251881Spetersvn_error_t * 1702251881Spetersvn_ra_svn__write_cmd_absent_file(svn_ra_svn_conn_t *conn, 1703251881Speter apr_pool_t *pool, 1704251881Speter const char *path, 1705251881Speter const char *parent_token) 1706251881Speter{ 1707251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, "( absent-file ( ", 16)); 1708251881Speter SVN_ERR(write_cmd_absent_node(conn, pool, path, parent_token)); 1709251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); 1710251881Speter 1711251881Speter return SVN_NO_ERROR; 1712251881Speter} 1713251881Speter 1714251881Spetersvn_error_t * 1715251881Spetersvn_ra_svn__write_cmd_textdelta_chunk(svn_ra_svn_conn_t *conn, 1716251881Speter apr_pool_t *pool, 1717251881Speter const char *token, 1718251881Speter const svn_string_t *chunk) 1719251881Speter{ 1720251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, "( textdelta-chunk ( ", 20)); 1721251881Speter SVN_ERR(write_tuple_cstring(conn, pool, token)); 1722251881Speter SVN_ERR(write_tuple_string(conn, pool, chunk)); 1723251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); 1724251881Speter 1725251881Speter return SVN_NO_ERROR; 1726251881Speter} 1727251881Speter 1728251881Spetersvn_error_t * 1729251881Spetersvn_ra_svn__write_cmd_textdelta_end(svn_ra_svn_conn_t *conn, 1730251881Speter apr_pool_t *pool, 1731251881Speter const char *token) 1732251881Speter{ 1733251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, "( textdelta-end ( ", 18)); 1734251881Speter SVN_ERR(write_tuple_cstring(conn, pool, token)); 1735251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); 1736251881Speter 1737251881Speter return SVN_NO_ERROR; 1738251881Speter} 1739251881Speter 1740251881Spetersvn_error_t * 1741251881Spetersvn_ra_svn__write_cmd_apply_textdelta(svn_ra_svn_conn_t *conn, 1742251881Speter apr_pool_t *pool, 1743251881Speter const char *token, 1744251881Speter const char *base_checksum) 1745251881Speter{ 1746251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, "( apply-textdelta ( ", 20)); 1747251881Speter SVN_ERR(write_tuple_cstring(conn, pool, token)); 1748251881Speter SVN_ERR(write_tuple_start_list(conn, pool)); 1749251881Speter SVN_ERR(write_tuple_cstring_opt(conn, pool, base_checksum)); 1750251881Speter SVN_ERR(write_tuple_end_list(conn, pool)); 1751251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); 1752251881Speter 1753251881Speter return SVN_NO_ERROR; 1754251881Speter} 1755251881Speter 1756251881Spetersvn_error_t * 1757251881Spetersvn_ra_svn__write_cmd_close_edit(svn_ra_svn_conn_t *conn, 1758251881Speter apr_pool_t *pool) 1759251881Speter{ 1760251881Speter return writebuf_write_short_string(conn, pool, "( close-edit ( ) ) ", 19); 1761251881Speter} 1762251881Speter 1763251881Spetersvn_error_t * 1764251881Spetersvn_ra_svn__write_cmd_abort_edit(svn_ra_svn_conn_t *conn, 1765251881Speter apr_pool_t *pool) 1766251881Speter{ 1767251881Speter return writebuf_write_short_string(conn, pool, "( abort-edit ( ) ) ", 19); 1768251881Speter} 1769251881Speter 1770251881Spetersvn_error_t * 1771251881Spetersvn_ra_svn__write_cmd_set_path(svn_ra_svn_conn_t *conn, 1772251881Speter apr_pool_t *pool, 1773251881Speter const char *path, 1774251881Speter svn_revnum_t rev, 1775251881Speter svn_boolean_t start_empty, 1776251881Speter const char *lock_token, 1777251881Speter svn_depth_t depth) 1778251881Speter{ 1779251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, "( set-path ( ", 13)); 1780251881Speter SVN_ERR(write_tuple_cstring(conn, pool, path)); 1781251881Speter SVN_ERR(write_tuple_revision(conn, pool, rev)); 1782251881Speter SVN_ERR(write_tuple_boolean(conn, pool, start_empty)); 1783251881Speter SVN_ERR(write_tuple_start_list(conn, pool)); 1784251881Speter SVN_ERR(write_tuple_cstring_opt(conn, pool, lock_token)); 1785251881Speter SVN_ERR(write_tuple_end_list(conn, pool)); 1786251881Speter SVN_ERR(write_tuple_depth(conn, pool, depth)); 1787251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); 1788251881Speter 1789251881Speter return SVN_NO_ERROR; 1790251881Speter} 1791251881Speter 1792251881Spetersvn_error_t * 1793251881Spetersvn_ra_svn__write_cmd_delete_path(svn_ra_svn_conn_t *conn, 1794251881Speter apr_pool_t *pool, 1795251881Speter const char *path) 1796251881Speter{ 1797251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, "( delete-path ( ", 16)); 1798251881Speter SVN_ERR(write_tuple_cstring(conn, pool, path)); 1799251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); 1800251881Speter 1801251881Speter return SVN_NO_ERROR; 1802251881Speter} 1803251881Speter 1804251881Spetersvn_error_t * 1805251881Spetersvn_ra_svn__write_cmd_link_path(svn_ra_svn_conn_t *conn, 1806251881Speter apr_pool_t *pool, 1807251881Speter const char *path, 1808251881Speter const char *url, 1809251881Speter svn_revnum_t rev, 1810251881Speter svn_boolean_t start_empty, 1811251881Speter const char *lock_token, 1812251881Speter svn_depth_t depth) 1813251881Speter{ 1814251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, "( link-path ( ", 14)); 1815251881Speter SVN_ERR(write_tuple_cstring(conn, pool, path)); 1816251881Speter SVN_ERR(write_tuple_cstring(conn, pool, url)); 1817251881Speter SVN_ERR(write_tuple_revision(conn, pool, rev)); 1818251881Speter SVN_ERR(write_tuple_boolean(conn, pool, start_empty)); 1819251881Speter SVN_ERR(write_tuple_start_list(conn, pool)); 1820251881Speter SVN_ERR(write_tuple_cstring_opt(conn, pool,lock_token)); 1821251881Speter SVN_ERR(write_tuple_end_list(conn, pool)); 1822251881Speter SVN_ERR(write_tuple_depth(conn, pool, depth)); 1823251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); 1824251881Speter 1825251881Speter return SVN_NO_ERROR; 1826251881Speter} 1827251881Speter 1828251881Spetersvn_error_t * 1829251881Spetersvn_ra_svn__write_cmd_finish_report(svn_ra_svn_conn_t *conn, 1830251881Speter apr_pool_t *pool) 1831251881Speter{ 1832251881Speter return writebuf_write_short_string(conn, pool, "( finish-report ( ) ) ", 22); 1833251881Speter} 1834251881Speter 1835251881Spetersvn_error_t * 1836251881Spetersvn_ra_svn__write_cmd_abort_report(svn_ra_svn_conn_t *conn, 1837251881Speter apr_pool_t *pool) 1838251881Speter{ 1839251881Speter return writebuf_write_short_string(conn, pool, "( abort-report ( ) ) ", 21); 1840251881Speter} 1841251881Speter 1842251881Spetersvn_error_t * 1843251881Spetersvn_ra_svn__write_cmd_reparent(svn_ra_svn_conn_t *conn, 1844251881Speter apr_pool_t *pool, 1845251881Speter const char *url) 1846251881Speter{ 1847251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, "( reparent ( ", 13)); 1848251881Speter SVN_ERR(write_tuple_cstring(conn, pool, url)); 1849251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); 1850251881Speter 1851251881Speter return SVN_NO_ERROR; 1852251881Speter} 1853251881Speter 1854251881Spetersvn_error_t * 1855251881Spetersvn_ra_svn__write_cmd_get_latest_rev(svn_ra_svn_conn_t *conn, 1856251881Speter apr_pool_t *pool) 1857251881Speter{ 1858251881Speter return writebuf_write_short_string(conn, pool, "( get-latest-rev ( ) ) ", 23); 1859251881Speter} 1860251881Speter 1861251881Spetersvn_error_t * 1862251881Spetersvn_ra_svn__write_cmd_get_dated_rev(svn_ra_svn_conn_t *conn, 1863251881Speter apr_pool_t *pool, 1864251881Speter apr_time_t tm) 1865251881Speter{ 1866251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, "( get-dated-rev ( ", 18)); 1867251881Speter SVN_ERR(write_tuple_cstring(conn, pool, svn_time_to_cstring(tm, pool))); 1868251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); 1869251881Speter 1870251881Speter return SVN_NO_ERROR; 1871251881Speter} 1872251881Speter 1873251881Spetersvn_error_t * 1874251881Spetersvn_ra_svn__write_cmd_change_rev_prop2(svn_ra_svn_conn_t *conn, 1875251881Speter apr_pool_t *pool, 1876251881Speter svn_revnum_t rev, 1877251881Speter const char *name, 1878251881Speter const svn_string_t *value, 1879251881Speter svn_boolean_t dont_care, 1880251881Speter const svn_string_t *old_value) 1881251881Speter{ 1882251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, "( change-rev-prop2 ( ", 21)); 1883251881Speter SVN_ERR(write_tuple_revision(conn, pool, rev)); 1884251881Speter SVN_ERR(write_tuple_cstring(conn, pool, name)); 1885251881Speter SVN_ERR(write_tuple_start_list(conn, pool)); 1886251881Speter SVN_ERR(write_tuple_string_opt(conn, pool, value)); 1887251881Speter SVN_ERR(write_tuple_end_list(conn, pool)); 1888251881Speter SVN_ERR(write_tuple_start_list(conn, pool)); 1889251881Speter SVN_ERR(write_tuple_boolean(conn, pool, dont_care)); 1890251881Speter SVN_ERR(write_tuple_string_opt(conn, pool, old_value)); 1891251881Speter SVN_ERR(write_tuple_end_list(conn, pool)); 1892251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); 1893251881Speter 1894251881Speter return SVN_NO_ERROR; 1895251881Speter} 1896251881Speter 1897251881Spetersvn_error_t * 1898251881Spetersvn_ra_svn__write_cmd_change_rev_prop(svn_ra_svn_conn_t *conn, 1899251881Speter apr_pool_t *pool, 1900251881Speter svn_revnum_t rev, 1901251881Speter const char *name, 1902251881Speter const svn_string_t *value) 1903251881Speter{ 1904251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, "( change-rev-prop ( ", 20)); 1905251881Speter SVN_ERR(write_tuple_revision(conn, pool, rev)); 1906251881Speter SVN_ERR(write_tuple_cstring(conn, pool, name)); 1907251881Speter SVN_ERR(write_tuple_string_opt(conn, pool, value)); 1908251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); 1909251881Speter 1910251881Speter return SVN_NO_ERROR; 1911251881Speter} 1912251881Speter 1913251881Spetersvn_error_t * 1914251881Spetersvn_ra_svn__write_cmd_rev_proplist(svn_ra_svn_conn_t *conn, 1915251881Speter apr_pool_t *pool, 1916251881Speter svn_revnum_t rev) 1917251881Speter{ 1918251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, "( rev-proplist ( ", 17)); 1919251881Speter SVN_ERR(write_tuple_revision(conn, pool, rev)); 1920251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); 1921251881Speter 1922251881Speter return SVN_NO_ERROR; 1923251881Speter} 1924251881Speter 1925251881Spetersvn_error_t * 1926251881Spetersvn_ra_svn__write_cmd_rev_prop(svn_ra_svn_conn_t *conn, 1927251881Speter apr_pool_t *pool, 1928251881Speter svn_revnum_t rev, 1929251881Speter const char *name) 1930251881Speter{ 1931251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, "( rev-prop ( ", 13)); 1932251881Speter SVN_ERR(write_tuple_revision(conn, pool, rev)); 1933251881Speter SVN_ERR(write_tuple_cstring(conn, pool, name)); 1934251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); 1935251881Speter 1936251881Speter return SVN_NO_ERROR; 1937251881Speter} 1938251881Speter 1939251881Spetersvn_error_t * 1940251881Spetersvn_ra_svn__write_cmd_get_file(svn_ra_svn_conn_t *conn, 1941251881Speter apr_pool_t *pool, 1942251881Speter const char *path, 1943251881Speter svn_revnum_t rev, 1944251881Speter svn_boolean_t props, 1945251881Speter svn_boolean_t stream) 1946251881Speter{ 1947251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, "( get-file ( ", 13)); 1948251881Speter SVN_ERR(write_tuple_cstring(conn, pool, path)); 1949251881Speter SVN_ERR(write_tuple_start_list(conn, pool)); 1950251881Speter SVN_ERR(write_tuple_revision_opt(conn, pool, rev)); 1951251881Speter SVN_ERR(write_tuple_end_list(conn, pool)); 1952251881Speter SVN_ERR(write_tuple_boolean(conn, pool, props)); 1953251881Speter SVN_ERR(write_tuple_boolean(conn, pool, stream)); 1954251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); 1955251881Speter 1956251881Speter return SVN_NO_ERROR; 1957251881Speter} 1958251881Speter 1959251881Spetersvn_error_t * 1960251881Spetersvn_ra_svn__write_cmd_update(svn_ra_svn_conn_t *conn, 1961251881Speter apr_pool_t *pool, 1962251881Speter svn_revnum_t rev, 1963251881Speter const char *target, 1964251881Speter svn_boolean_t recurse, 1965251881Speter svn_depth_t depth, 1966251881Speter svn_boolean_t send_copyfrom_args, 1967251881Speter svn_boolean_t ignore_ancestry) 1968251881Speter{ 1969251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, "( update ( ", 11)); 1970251881Speter SVN_ERR(write_tuple_start_list(conn, pool)); 1971251881Speter SVN_ERR(write_tuple_revision_opt(conn, pool, rev)); 1972251881Speter SVN_ERR(write_tuple_end_list(conn, pool)); 1973251881Speter SVN_ERR(write_tuple_cstring(conn, pool, target)); 1974251881Speter SVN_ERR(write_tuple_boolean(conn, pool, recurse)); 1975251881Speter SVN_ERR(write_tuple_depth(conn, pool, depth)); 1976251881Speter SVN_ERR(write_tuple_boolean(conn, pool, send_copyfrom_args)); 1977251881Speter SVN_ERR(write_tuple_boolean(conn, pool, ignore_ancestry)); 1978251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); 1979251881Speter 1980251881Speter return SVN_NO_ERROR; 1981251881Speter} 1982251881Speter 1983251881Spetersvn_error_t * 1984251881Spetersvn_ra_svn__write_cmd_switch(svn_ra_svn_conn_t *conn, 1985251881Speter apr_pool_t *pool, 1986251881Speter svn_revnum_t rev, 1987251881Speter const char *target, 1988251881Speter svn_boolean_t recurse, 1989251881Speter const char *switch_url, 1990251881Speter svn_depth_t depth, 1991251881Speter svn_boolean_t send_copyfrom_args, 1992251881Speter svn_boolean_t ignore_ancestry) 1993251881Speter{ 1994251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, "( switch ( ", 11)); 1995251881Speter SVN_ERR(write_tuple_start_list(conn, pool)); 1996251881Speter SVN_ERR(write_tuple_revision_opt(conn, pool, rev)); 1997251881Speter SVN_ERR(write_tuple_end_list(conn, pool)); 1998251881Speter SVN_ERR(write_tuple_cstring(conn, pool, target)); 1999251881Speter SVN_ERR(write_tuple_boolean(conn, pool, recurse)); 2000251881Speter SVN_ERR(write_tuple_cstring(conn, pool, switch_url)); 2001251881Speter SVN_ERR(write_tuple_depth(conn, pool, depth)); 2002251881Speter SVN_ERR(write_tuple_boolean(conn, pool, send_copyfrom_args)); 2003251881Speter SVN_ERR(write_tuple_boolean(conn, pool, ignore_ancestry)); 2004251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); 2005251881Speter 2006251881Speter return SVN_NO_ERROR; 2007251881Speter} 2008251881Speter 2009251881Spetersvn_error_t * 2010251881Spetersvn_ra_svn__write_cmd_status(svn_ra_svn_conn_t *conn, 2011251881Speter apr_pool_t *pool, 2012251881Speter const char *target, 2013251881Speter svn_boolean_t recurse, 2014251881Speter svn_revnum_t rev, 2015251881Speter svn_depth_t depth) 2016251881Speter{ 2017251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, "( status ( ", 11)); 2018251881Speter SVN_ERR(write_tuple_cstring(conn, pool, target)); 2019251881Speter SVN_ERR(write_tuple_boolean(conn, pool, recurse)); 2020251881Speter SVN_ERR(write_tuple_start_list(conn, pool)); 2021251881Speter SVN_ERR(write_tuple_revision_opt(conn, pool, rev)); 2022251881Speter SVN_ERR(write_tuple_end_list(conn, pool)); 2023251881Speter SVN_ERR(write_tuple_depth(conn, pool, depth)); 2024251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); 2025251881Speter 2026251881Speter return SVN_NO_ERROR; 2027251881Speter} 2028251881Speter 2029251881Spetersvn_error_t * 2030251881Spetersvn_ra_svn__write_cmd_diff(svn_ra_svn_conn_t *conn, 2031251881Speter apr_pool_t *pool, 2032251881Speter svn_revnum_t rev, 2033251881Speter const char *target, 2034251881Speter svn_boolean_t recurse, 2035251881Speter svn_boolean_t ignore_ancestry, 2036251881Speter const char *versus_url, 2037251881Speter svn_boolean_t text_deltas, 2038251881Speter svn_depth_t depth) 2039251881Speter{ 2040251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, "( diff ( ", 9)); 2041251881Speter SVN_ERR(write_tuple_start_list(conn, pool)); 2042251881Speter SVN_ERR(write_tuple_revision_opt(conn, pool, rev)); 2043251881Speter SVN_ERR(write_tuple_end_list(conn, pool)); 2044251881Speter SVN_ERR(write_tuple_cstring(conn, pool, target)); 2045251881Speter SVN_ERR(write_tuple_boolean(conn, pool, recurse)); 2046251881Speter SVN_ERR(write_tuple_boolean(conn, pool, ignore_ancestry)); 2047251881Speter SVN_ERR(write_tuple_cstring(conn, pool, versus_url)); 2048251881Speter SVN_ERR(write_tuple_boolean(conn, pool, text_deltas)); 2049251881Speter SVN_ERR(write_tuple_depth(conn, pool, depth)); 2050251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); 2051251881Speter 2052251881Speter return SVN_NO_ERROR; 2053251881Speter} 2054251881Speter 2055251881Spetersvn_error_t * 2056251881Spetersvn_ra_svn__write_cmd_check_path(svn_ra_svn_conn_t *conn, 2057251881Speter apr_pool_t *pool, 2058251881Speter const char *path, 2059251881Speter svn_revnum_t rev) 2060251881Speter{ 2061251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, "( check-path ( ", 15)); 2062251881Speter SVN_ERR(write_tuple_cstring(conn, pool, path)); 2063251881Speter SVN_ERR(write_tuple_start_list(conn, pool)); 2064251881Speter SVN_ERR(write_tuple_revision_opt(conn, pool, rev)); 2065251881Speter SVN_ERR(write_tuple_end_list(conn, pool)); 2066251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); 2067251881Speter 2068251881Speter return SVN_NO_ERROR; 2069251881Speter} 2070251881Speter 2071251881Spetersvn_error_t * 2072251881Spetersvn_ra_svn__write_cmd_stat(svn_ra_svn_conn_t *conn, 2073251881Speter apr_pool_t *pool, 2074251881Speter const char *path, 2075251881Speter svn_revnum_t rev) 2076251881Speter{ 2077251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, "( stat ( ", 9)); 2078251881Speter SVN_ERR(write_tuple_cstring(conn, pool, path)); 2079251881Speter SVN_ERR(write_tuple_start_list(conn, pool)); 2080251881Speter SVN_ERR(write_tuple_revision_opt(conn, pool, rev)); 2081251881Speter SVN_ERR(write_tuple_end_list(conn, pool)); 2082251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); 2083251881Speter 2084251881Speter return SVN_NO_ERROR; 2085251881Speter} 2086251881Speter 2087251881Spetersvn_error_t * 2088251881Spetersvn_ra_svn__write_cmd_get_file_revs(svn_ra_svn_conn_t *conn, 2089251881Speter apr_pool_t *pool, 2090251881Speter const char *path, 2091251881Speter svn_revnum_t start, 2092251881Speter svn_revnum_t end, 2093251881Speter svn_boolean_t include_merged_revisions) 2094251881Speter{ 2095251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, "( get-file-revs ( ", 18)); 2096251881Speter SVN_ERR(write_tuple_cstring(conn, pool, path)); 2097251881Speter SVN_ERR(write_tuple_start_list(conn, pool)); 2098251881Speter SVN_ERR(write_tuple_revision_opt(conn, pool, start)); 2099251881Speter SVN_ERR(write_tuple_end_list(conn, pool)); 2100251881Speter SVN_ERR(write_tuple_start_list(conn, pool)); 2101251881Speter SVN_ERR(write_tuple_revision_opt(conn, pool, end)); 2102251881Speter SVN_ERR(write_tuple_end_list(conn, pool)); 2103251881Speter SVN_ERR(write_tuple_boolean(conn, pool, include_merged_revisions)); 2104251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); 2105251881Speter 2106251881Speter return SVN_NO_ERROR; 2107251881Speter} 2108251881Speter 2109251881Spetersvn_error_t * 2110251881Spetersvn_ra_svn__write_cmd_lock(svn_ra_svn_conn_t *conn, 2111251881Speter apr_pool_t *pool, 2112251881Speter const char *path, 2113251881Speter const char *comment, 2114251881Speter svn_boolean_t steal_lock, 2115251881Speter svn_revnum_t revnum) 2116251881Speter{ 2117251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, "( lock ( ", 9)); 2118251881Speter SVN_ERR(write_tuple_cstring(conn, pool, path)); 2119251881Speter SVN_ERR(write_tuple_start_list(conn, pool)); 2120251881Speter SVN_ERR(write_tuple_cstring_opt(conn, pool, comment)); 2121251881Speter SVN_ERR(write_tuple_end_list(conn, pool)); 2122251881Speter SVN_ERR(write_tuple_boolean(conn, pool, steal_lock)); 2123251881Speter SVN_ERR(write_tuple_start_list(conn, pool)); 2124251881Speter SVN_ERR(write_tuple_revision_opt(conn, pool, revnum)); 2125251881Speter SVN_ERR(write_tuple_end_list(conn, pool)); 2126251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); 2127251881Speter 2128251881Speter return SVN_NO_ERROR; 2129251881Speter} 2130251881Speter 2131251881Spetersvn_error_t * 2132251881Spetersvn_ra_svn__write_cmd_unlock(svn_ra_svn_conn_t *conn, 2133251881Speter apr_pool_t *pool, 2134251881Speter const char *path, 2135251881Speter const char *token, 2136251881Speter svn_boolean_t break_lock) 2137251881Speter{ 2138251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, "( unlock ( ", 11)); 2139251881Speter SVN_ERR(write_tuple_cstring(conn, pool, path)); 2140251881Speter SVN_ERR(write_tuple_start_list(conn, pool)); 2141251881Speter SVN_ERR(write_tuple_cstring_opt(conn, pool, token)); 2142251881Speter SVN_ERR(write_tuple_end_list(conn, pool)); 2143251881Speter SVN_ERR(write_tuple_boolean(conn, pool, break_lock)); 2144251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); 2145251881Speter 2146251881Speter return SVN_NO_ERROR; 2147251881Speter} 2148251881Speter 2149251881Spetersvn_error_t * 2150251881Spetersvn_ra_svn__write_cmd_get_lock(svn_ra_svn_conn_t *conn, 2151251881Speter apr_pool_t *pool, 2152251881Speter const char *path) 2153251881Speter{ 2154251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, "( get-lock ( ", 13)); 2155251881Speter SVN_ERR(write_tuple_cstring(conn, pool, path)); 2156251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); 2157251881Speter 2158251881Speter return SVN_NO_ERROR; 2159251881Speter} 2160251881Speter 2161251881Spetersvn_error_t * 2162251881Spetersvn_ra_svn__write_cmd_get_locks(svn_ra_svn_conn_t *conn, 2163251881Speter apr_pool_t *pool, 2164251881Speter const char *path, 2165251881Speter svn_depth_t depth) 2166251881Speter{ 2167251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, "( get-locks ( ", 14)); 2168251881Speter SVN_ERR(write_tuple_cstring(conn, pool, path)); 2169251881Speter SVN_ERR(write_tuple_start_list(conn, pool)); 2170251881Speter SVN_ERR(write_tuple_depth(conn, pool, depth)); 2171251881Speter SVN_ERR(write_tuple_end_list(conn, pool)); 2172251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); 2173251881Speter 2174251881Speter return SVN_NO_ERROR; 2175251881Speter} 2176251881Speter 2177251881Spetersvn_error_t * 2178251881Spetersvn_ra_svn__write_cmd_replay(svn_ra_svn_conn_t *conn, 2179251881Speter apr_pool_t *pool, 2180251881Speter svn_revnum_t rev, 2181251881Speter svn_revnum_t low_water_mark, 2182251881Speter svn_boolean_t send_deltas) 2183251881Speter{ 2184251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, "( replay ( ", 11)); 2185251881Speter SVN_ERR(write_tuple_revision(conn, pool, rev)); 2186251881Speter SVN_ERR(write_tuple_revision(conn, pool, low_water_mark)); 2187251881Speter SVN_ERR(write_tuple_boolean(conn, pool, send_deltas)); 2188251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); 2189251881Speter 2190251881Speter return SVN_NO_ERROR; 2191251881Speter} 2192251881Speter 2193251881Spetersvn_error_t * 2194251881Spetersvn_ra_svn__write_cmd_replay_range(svn_ra_svn_conn_t *conn, 2195251881Speter apr_pool_t *pool, 2196251881Speter svn_revnum_t start_revision, 2197251881Speter svn_revnum_t end_revision, 2198251881Speter svn_revnum_t low_water_mark, 2199251881Speter svn_boolean_t send_deltas) 2200251881Speter{ 2201251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, "( replay-range ( ", 17)); 2202251881Speter SVN_ERR(write_tuple_revision(conn, pool, start_revision)); 2203251881Speter SVN_ERR(write_tuple_revision(conn, pool, end_revision)); 2204251881Speter SVN_ERR(write_tuple_revision(conn, pool, low_water_mark)); 2205251881Speter SVN_ERR(write_tuple_boolean(conn, pool, send_deltas)); 2206251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); 2207251881Speter 2208251881Speter return SVN_NO_ERROR; 2209251881Speter} 2210251881Speter 2211251881Spetersvn_error_t * 2212251881Spetersvn_ra_svn__write_cmd_get_deleted_rev(svn_ra_svn_conn_t *conn, 2213251881Speter apr_pool_t *pool, 2214251881Speter const char *path, 2215251881Speter svn_revnum_t peg_revision, 2216251881Speter svn_revnum_t end_revision) 2217251881Speter{ 2218251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, "( get-deleted-rev ( ", 20)); 2219251881Speter SVN_ERR(write_tuple_cstring(conn, pool, path)); 2220251881Speter SVN_ERR(write_tuple_revision(conn, pool, peg_revision)); 2221251881Speter SVN_ERR(write_tuple_revision(conn, pool, end_revision)); 2222251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); 2223251881Speter 2224251881Speter return SVN_NO_ERROR; 2225251881Speter} 2226251881Speter 2227251881Spetersvn_error_t * 2228251881Spetersvn_ra_svn__write_cmd_get_iprops(svn_ra_svn_conn_t *conn, 2229251881Speter apr_pool_t *pool, 2230251881Speter const char *path, 2231251881Speter svn_revnum_t revision) 2232251881Speter{ 2233251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, "( get-iprops ( ", 15)); 2234251881Speter SVN_ERR(write_tuple_cstring(conn, pool, path)); 2235251881Speter SVN_ERR(write_tuple_start_list(conn, pool)); 2236251881Speter SVN_ERR(write_tuple_revision_opt(conn, pool, revision)); 2237251881Speter SVN_ERR(write_tuple_end_list(conn, pool)); 2238251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4)); 2239251881Speter 2240251881Speter return SVN_NO_ERROR; 2241251881Speter} 2242251881Speter 2243251881Spetersvn_error_t * 2244251881Spetersvn_ra_svn__write_cmd_finish_replay(svn_ra_svn_conn_t *conn, 2245251881Speter apr_pool_t *pool) 2246251881Speter{ 2247251881Speter return writebuf_write_short_string(conn, pool, "( finish-replay ( ) ) ", 22); 2248251881Speter} 2249251881Speter 2250251881Spetersvn_error_t *svn_ra_svn__write_cmd_response(svn_ra_svn_conn_t *conn, 2251251881Speter apr_pool_t *pool, 2252251881Speter const char *fmt, ...) 2253251881Speter{ 2254251881Speter va_list ap; 2255251881Speter svn_error_t *err; 2256251881Speter 2257251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, "( success ", 10)); 2258251881Speter va_start(ap, fmt); 2259251881Speter err = vwrite_tuple(conn, pool, fmt, &ap); 2260251881Speter va_end(ap); 2261251881Speter return err ? svn_error_trace(err) : svn_ra_svn__end_list(conn, pool); 2262251881Speter} 2263251881Speter 2264251881Spetersvn_error_t *svn_ra_svn__write_cmd_failure(svn_ra_svn_conn_t *conn, 2265251881Speter apr_pool_t *pool, svn_error_t *err) 2266251881Speter{ 2267251881Speter char buffer[128]; 2268251881Speter SVN_ERR(writebuf_write_short_string(conn, pool, "( failure ( ", 12)); 2269251881Speter for (; err; err = err->child) 2270251881Speter { 2271251881Speter const char *msg; 2272251881Speter 2273251881Speter#ifdef SVN_ERR__TRACING 2274251881Speter if (svn_error__is_tracing_link(err)) 2275251881Speter msg = err->message; 2276251881Speter else 2277251881Speter#endif 2278251881Speter msg = svn_err_best_message(err, buffer, sizeof(buffer)); 2279251881Speter 2280251881Speter /* The message string should have been optional, but we can't 2281251881Speter easily change that, so marshal nonexistent messages as "". */ 2282251881Speter SVN_ERR(svn_ra_svn__write_tuple(conn, pool, "nccn", 2283251881Speter (apr_uint64_t) err->apr_err, 2284251881Speter msg ? msg : "", 2285251881Speter err->file ? err->file : "", 2286251881Speter (apr_uint64_t) err->line)); 2287251881Speter } 2288251881Speter return writebuf_write_short_string(conn, pool, ") ) ", 4); 2289251881Speter} 2290