You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by rh...@apache.org on 2015/11/30 11:24:23 UTC
svn commit: r1717223 [29/50] - in /subversion/branches/ra-git: ./ build/
build/ac-macros/ build/generator/ build/generator/templates/
contrib/hook-scripts/ notes/ notes/api-errata/1.9/ notes/move-tracking/
subversion/ subversion/bindings/ctypes-python/...
Modified: subversion/branches/ra-git/subversion/libsvn_ra_svn/marshal.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_ra_svn/marshal.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_ra_svn/marshal.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_ra_svn/marshal.c Mon Nov 30 10:24:16 2015
@@ -60,9 +60,10 @@
/* We don't use "words" longer than this in our protocol. The longest word
* we are currently using is only about 16 chars long but we leave room for
- * longer future capability and command names.
+ * longer future capability and command names. See read_item() to understand
+ * why MAX_WORD_LENGTH - 1 should be a multiple of 8.
*/
-#define MAX_WORD_LENGTH 31
+#define MAX_WORD_LENGTH 25
/* The generic parsers will use the following value to limit the recursion
* depth to some reasonable value. The current protocol implementation
@@ -71,6 +72,10 @@
*/
#define ITEM_NESTING_LIMIT 64
+/* The protocol words for booleans. */
+static const svn_string_t str_true = SVN__STATIC_STRING("true");
+static const svn_string_t str_false = SVN__STATIC_STRING("false");
+
/* Return the APR socket timeout to be used for the connection depending
* on whether there is a blockage handler or zero copy has been activated. */
static apr_interval_time_t
@@ -79,14 +84,109 @@ get_timeout(svn_ra_svn_conn_t *conn)
return conn->block_handler ? 0 : -1;
}
+/* --- Public / private API data conversion --- */
+
+void
+svn_ra_svn__to_public_item(svn_ra_svn_item_t *target,
+ const svn_ra_svn__item_t *source,
+ apr_pool_t *result_pool)
+{
+ target->kind = source->kind;
+ switch (source->kind)
+ {
+ case SVN_RA_SVN_STRING:
+ target->u.string = svn_string_dup(&source->u.string, result_pool);
+ break;
+ case SVN_RA_SVN_NUMBER:
+ target->u.number = source->u.number;
+ break;
+ case SVN_RA_SVN_WORD:
+ target->u.word = source->u.word.data;
+ break;
+ case SVN_RA_SVN_LIST:
+ target->u.list = svn_ra_svn__to_public_array(&source->u.list,
+ result_pool);
+ break;
+ }
+}
+
+apr_array_header_t *
+svn_ra_svn__to_public_array(const svn_ra_svn__list_t *source,
+ apr_pool_t *result_pool)
+{
+ apr_array_header_t *result = apr_array_make(result_pool, source->nelts,
+ sizeof(svn_ra_svn_item_t));
+
+ int i;
+ for (i = 0; i < source->nelts; ++i)
+ {
+ svn_ra_svn_item_t *sub_target = apr_array_push(result);
+ svn_ra_svn__item_t *sub_source = &SVN_RA_SVN__LIST_ITEM(source, i);
+
+ svn_ra_svn__to_public_item(sub_target, sub_source, result_pool);
+ }
+
+ return result;
+}
+
+void
+svn_ra_svn__to_private_item(svn_ra_svn__item_t *target,
+ const svn_ra_svn_item_t *source,
+ apr_pool_t *result_pool)
+{
+ target->kind = source->kind;
+ switch (source->kind)
+ {
+ case SVN_RA_SVN_STRING:
+ target->u.string = *source->u.string;
+ break;
+ case SVN_RA_SVN_NUMBER:
+ target->u.number = source->u.number;
+ break;
+ case SVN_RA_SVN_WORD:
+ target->u.word.data = source->u.word;
+ target->u.word.len = strlen(source->u.word);
+ break;
+ case SVN_RA_SVN_LIST:
+ target->u.list = *svn_ra_svn__to_private_array(source->u.list,
+ result_pool);
+ break;
+ }
+}
+
+svn_ra_svn__list_t *
+svn_ra_svn__to_private_array(const apr_array_header_t *source,
+ apr_pool_t *result_pool)
+{
+ int i;
+
+ svn_ra_svn__list_t *result = apr_pcalloc(result_pool, sizeof(*result));
+ result->nelts = source->nelts;
+ result->items = apr_palloc(result_pool,
+ source->nelts * sizeof(*result->items));
+
+ for (i = 0; i < source->nelts; ++i)
+ {
+ svn_ra_svn__item_t *sub_target = &result->items[i];
+ svn_ra_svn_item_t *sub_source = &APR_ARRAY_IDX(source, i,
+ svn_ra_svn_item_t);
+
+ svn_ra_svn__to_private_item(sub_target, sub_source, result_pool);
+ }
+
+ return result;
+}
+
/* --- CONNECTION INITIALIZATION --- */
-svn_ra_svn_conn_t *svn_ra_svn_create_conn4(apr_socket_t *sock,
+svn_ra_svn_conn_t *svn_ra_svn_create_conn5(apr_socket_t *sock,
svn_stream_t *in_stream,
svn_stream_t *out_stream,
int compression_level,
apr_size_t zero_copy_limit,
apr_size_t error_check_interval,
+ apr_uint64_t max_in,
+ apr_uint64_t max_out,
apr_pool_t *result_pool)
{
svn_ra_svn_conn_t *conn;
@@ -106,6 +206,10 @@ svn_ra_svn_conn_t *svn_ra_svn_create_con
conn->written_since_error_check = 0;
conn->error_check_interval = error_check_interval;
conn->may_check_for_error = error_check_interval == 0;
+ conn->max_in = max_in;
+ conn->current_in = 0;
+ conn->max_out = max_out;
+ conn->current_out = 0;
conn->block_handler = NULL;
conn->block_baton = NULL;
conn->capabilities = apr_hash_make(result_pool);
@@ -132,21 +236,31 @@ svn_ra_svn_conn_t *svn_ra_svn_create_con
return conn;
}
-svn_error_t *svn_ra_svn_set_capabilities(svn_ra_svn_conn_t *conn,
- const apr_array_header_t *list)
+svn_error_t *
+svn_ra_svn_set_capabilities(svn_ra_svn_conn_t *conn,
+ const apr_array_header_t *list)
+{
+ svn_ra_svn__list_t *internal
+ = svn_ra_svn__to_private_array(list, list->pool);
+ return svn_error_trace(svn_ra_svn__set_capabilities(conn, internal));
+}
+
+svn_error_t *
+svn_ra_svn__set_capabilities(svn_ra_svn_conn_t *conn,
+ const svn_ra_svn__list_t *list)
{
int i;
- svn_ra_svn_item_t *item;
+ svn_ra_svn__item_t *item;
const char *word;
for (i = 0; i < list->nelts; i++)
{
- item = &APR_ARRAY_IDX(list, i, svn_ra_svn_item_t);
+ item = &SVN_RA_SVN__LIST_ITEM(list, i);
if (item->kind != SVN_RA_SVN_WORD)
return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
_("Capability entry is not a word"));
- word = apr_pstrdup(conn->pool, item->u.word);
- svn_hash_sets(conn->capabilities, word, word);
+ word = apr_pstrmemdup(conn->pool, item->u.word.data, item->u.word.len);
+ apr_hash_set(conn->capabilities, word, item->u.word.len, word);
}
return SVN_NO_ERROR;
}
@@ -204,8 +318,33 @@ svn_error_t *svn_ra_svn__data_available(
return svn_ra_svn__stream_data_available(conn->stream, data_available);
}
+void
+svn_ra_svn__reset_command_io_counters(svn_ra_svn_conn_t *conn)
+{
+ conn->current_in = 0;
+ conn->current_out = 0;
+}
+
+
/* --- WRITE BUFFER MANAGEMENT --- */
+/* Return an error object if CONN exceeded its send or receive limits. */
+static svn_error_t *
+check_io_limits(svn_ra_svn_conn_t *conn)
+{
+ if (conn->max_in && (conn->current_in > conn->max_in))
+ return svn_error_create(SVN_ERR_RA_SVN_REQUEST_SIZE, NULL,
+ "The client request size exceeds the "
+ "configured limit");
+
+ if (conn->max_out && (conn->current_out > conn->max_out))
+ return svn_error_create(SVN_ERR_RA_SVN_RESPONSE_SIZE, NULL,
+ "The server response size exceeds the "
+ "configured limit");
+
+ return SVN_NO_ERROR;
+}
+
/* Write data to socket or output file as appropriate. */
static svn_error_t *writebuf_output(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
const char *data, apr_size_t len)
@@ -215,6 +354,12 @@ static svn_error_t *writebuf_output(svn_
apr_pool_t *subpool = NULL;
svn_ra_svn__session_baton_t *session = conn->session;
+ /* Limit the size of the response, if a limit has been configured.
+ * This is to limit the server load in case users e.g. accidentally ran
+ * an export on the root folder. */
+ conn->current_out += len;
+ SVN_ERR(check_io_limits(conn));
+
while (data < end)
{
count = end - data;
@@ -333,12 +478,19 @@ static svn_error_t *readbuf_input(svn_ra
{
svn_ra_svn__session_baton_t *session = conn->session;
+ /* First, give the user a chance to cancel the request before we do. */
if (session && session->callbacks && session->callbacks->cancel_func)
SVN_ERR((session->callbacks->cancel_func)(session->callbacks_baton));
+ /* Limit our memory usage, if a limit has been configured. Note that
+ * we first read the whole request into memory before process it. */
+ SVN_ERR(check_io_limits(conn));
+
+ /* Actually fill the buffer. */
SVN_ERR(svn_ra_svn__stream_read(conn->stream, data, len));
if (*len == 0)
return svn_error_create(SVN_ERR_RA_SVN_CONNECTION_CLOSED, NULL, NULL);
+ conn->current_in += *len;
if (session)
{
@@ -384,9 +536,13 @@ static svn_error_t *readbuf_fill(svn_ra_
apr_size_t len;
SVN_ERR_ASSERT(conn->read_ptr == conn->read_end);
+
+ /* Make sure we tell the other side everything we have to say before
+ * reading / waiting for an answer. */
if (conn->write_pos)
SVN_ERR(writebuf_flush(conn, pool));
+ /* Fill (some of the) buffer. */
len = sizeof(conn->read_buf);
SVN_ERR(readbuf_input(conn, conn->read_buf, &len, pool));
conn->read_ptr = conn->read_buf;
@@ -512,22 +668,65 @@ svn_ra_svn__write_number(svn_ra_svn_conn
return write_number(conn, pool, number, ' ');
}
+/* Write string S of length LEN to TARGET and return the first position
+ after the written data.
+
+ NOTE: This function assumes that TARGET has enough room for S, the LEN
+ prefix and the required separators. The available buffer size
+ should be SVN_INT64_BUFFER_SIZE + LEN + 1 to avoid any chance of
+ overflow.
+ */
+static char *
+write_ncstring_quick(char *target,
+ const char *s,
+ apr_size_t len)
+{
+ /* Write string length. */
+ if (len < 10)
+ {
+ *target = (char)(len + '0');
+ target++;
+ }
+ else
+ {
+ target += svn__ui64toa(target, len);
+ }
+
+ /* Separator & contents. */
+ target[0] = ':';
+ memcpy(target + 1, s, len);
+ target[len + 1] = ' ';
+
+ /* First location after the string. */
+ return target + len + 2;
+}
+
+
static svn_error_t *
svn_ra_svn__write_ncstring(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
const char *s,
apr_size_t len)
{
- if (len < 10)
- {
- SVN_ERR(writebuf_writechar(conn, pool, (char)(len + '0')));
- SVN_ERR(writebuf_writechar(conn, pool, ':'));
+ apr_size_t needed = SVN_INT64_BUFFER_SIZE + len + 1;
+
+ /* In most cases, there is enough left room in the WRITE_BUF
+ the we can serialize directly into it. */
+ if (conn->write_pos + needed < sizeof(conn->write_buf))
+ {
+ /* Quick path. */
+ conn->write_pos = write_ncstring_quick(conn->write_buf
+ + conn->write_pos, s, len)
+ - conn->write_buf;
}
else
- SVN_ERR(write_number(conn, pool, len, ':'));
+ {
+ /* Slower fallback code. */
+ SVN_ERR(write_number(conn, pool, len, ':'));
- SVN_ERR(writebuf_write(conn, pool, s, len));
- SVN_ERR(writebuf_writechar(conn, pool, ' '));
+ SVN_ERR(writebuf_write(conn, pool, s, len));
+ SVN_ERR(writebuf_writechar(conn, pool, ' '));
+ }
return SVN_NO_ERROR;
}
@@ -755,6 +954,52 @@ write_tuple_string_opt(svn_ra_svn_conn_t
return str ? svn_ra_svn__write_string(conn, pool, str) : SVN_NO_ERROR;
}
+/* Optimized sending code for the "(s?)" pattern. */
+static svn_error_t *
+write_tuple_string_opt_list(svn_ra_svn_conn_t *conn,
+ apr_pool_t *pool,
+ const svn_string_t *str)
+{
+ apr_size_t needed;
+
+ /* Special case. */
+ if (!str)
+ return writebuf_write(conn, pool, "( ) ", 4);
+
+ /* If there is at least this much the room left in the WRITE_BUF,
+ we can serialize directly into it. */
+ needed = 2 /* open list */
+ + SVN_INT64_BUFFER_SIZE /* string length + separator */
+ + str->len /* string contents */
+ + 2; /* close list */
+
+ if (conn->write_pos + needed <= sizeof(conn->write_buf))
+ {
+ /* Quick path. */
+ /* Open list. */
+ char *p = conn->write_buf + conn->write_pos;
+ p[0] = '(';
+ p[1] = ' ';
+
+ /* Write string. */
+ p = write_ncstring_quick(p + 2, str->data, str->len);
+
+ /* Close list. */
+ p[0] = ')';
+ p[1] = ' ';
+ conn->write_pos = p + 2 - conn->write_buf;
+ }
+ else
+ {
+ /* Standard code path (fallback). */
+ SVN_ERR(svn_ra_svn__start_list(conn, pool));
+ SVN_ERR(svn_ra_svn__write_string(conn, pool, str));
+ SVN_ERR(svn_ra_svn__end_list(conn, pool));
+ }
+
+ return SVN_NO_ERROR;
+}
+
static svn_error_t *
write_tuple_start_list(svn_ra_svn_conn_t *conn,
apr_pool_t *pool)
@@ -809,14 +1054,14 @@ static svn_error_t *
write_cmd_add_node(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
const char *path,
- const char *parent_token,
- const char *token,
+ const svn_string_t *parent_token,
+ const svn_string_t *token,
const char *copy_path,
svn_revnum_t copy_rev)
{
SVN_ERR(write_tuple_cstring(conn, pool, path));
- SVN_ERR(write_tuple_cstring(conn, pool, parent_token));
- SVN_ERR(write_tuple_cstring(conn, pool, token));
+ SVN_ERR(write_tuple_string(conn, pool, parent_token));
+ SVN_ERR(write_tuple_string(conn, pool, token));
SVN_ERR(write_tuple_start_list(conn, pool));
SVN_ERR(write_tuple_cstring_opt(conn, pool, copy_path));
SVN_ERR(write_tuple_revision_opt(conn, pool, copy_rev));
@@ -829,13 +1074,13 @@ static svn_error_t *
write_cmd_open_node(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
const char *path,
- const char *parent_token,
- const char *token,
+ const svn_string_t *parent_token,
+ const svn_string_t *token,
svn_revnum_t rev)
{
SVN_ERR(write_tuple_cstring(conn, pool, path));
- SVN_ERR(write_tuple_cstring(conn, pool, parent_token));
- SVN_ERR(write_tuple_cstring(conn, pool, token));
+ SVN_ERR(write_tuple_string(conn, pool, parent_token));
+ SVN_ERR(write_tuple_string(conn, pool, token));
SVN_ERR(write_tuple_start_list(conn, pool));
SVN_ERR(write_tuple_revision_opt(conn, pool, rev));
SVN_ERR(write_tuple_end_list(conn, pool));
@@ -846,15 +1091,13 @@ write_cmd_open_node(svn_ra_svn_conn_t *c
static svn_error_t *
write_cmd_change_node_prop(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
- const char *token,
+ const svn_string_t *token,
const char *name,
const svn_string_t *value)
{
- SVN_ERR(write_tuple_cstring(conn, pool, token));
+ SVN_ERR(write_tuple_string(conn, pool, token));
SVN_ERR(write_tuple_cstring(conn, pool, name));
- SVN_ERR(write_tuple_start_list(conn, pool));
- SVN_ERR(write_tuple_string_opt(conn, pool, value));
- SVN_ERR(write_tuple_end_list(conn, pool));
+ SVN_ERR(write_tuple_string_opt_list(conn, pool, value));
return SVN_NO_ERROR;
}
@@ -863,10 +1106,10 @@ static svn_error_t *
write_cmd_absent_node(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
const char *path,
- const char *token)
+ const svn_string_t *token)
{
SVN_ERR(write_tuple_cstring(conn, pool, path));
- SVN_ERR(write_tuple_cstring(conn, pool, token));
+ SVN_ERR(write_tuple_string(conn, pool, token));
return SVN_NO_ERROR;
}
@@ -939,14 +1182,14 @@ svn_ra_svn__write_tuple(svn_ra_svn_conn_
* Afterwards, *ITEM is of type 'SVN_RA_SVN_STRING', and its string
* data is allocated in POOL. */
static svn_error_t *read_string(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
- svn_ra_svn_item_t *item, apr_uint64_t len64)
+ svn_ra_svn__item_t *item, apr_uint64_t len64)
{
apr_size_t len = (apr_size_t)len64;
apr_size_t readbuf_len;
char *dest;
/* We can't store strings longer than the maximum size of apr_size_t,
- * so check for wrapping */
+ * so check before using the truncated value. */
if (len64 > APR_SIZE_MAX)
return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
_("String length larger than maximum"));
@@ -955,11 +1198,22 @@ static svn_error_t *read_string(svn_ra_s
if (conn->read_ptr + len <= conn->read_end)
{
item->kind = SVN_RA_SVN_STRING;
- item->u.string = svn_string_ncreate(conn->read_ptr, len, pool);
+ item->u.string.data = apr_pstrmemdup(pool, conn->read_ptr, len);
+ item->u.string.len = len;
conn->read_ptr += len;
}
else
{
+ svn_stringbuf_t *stringbuf;
+
+ /* Don't even attempt to read anything that exceeds the I/O limit.
+ * So, we can terminate the transfer at an early point, saving
+ * everybody's time and resources. */
+ if (conn->max_in && (conn->max_in < len64))
+ return svn_error_create(SVN_ERR_RA_SVN_REQUEST_SIZE, NULL,
+ "The client request size exceeds the "
+ "configured limit");
+
/* Read the string in chunks. The chunk size is large enough to avoid
* re-allocation in typical cases, and small enough to ensure we do
* not pre-allocate an unreasonable amount of memory if (perhaps due
@@ -968,7 +1222,7 @@ static svn_error_t *read_string(svn_ra_s
* start small and wait for all that data to actually show up. This
* does not fully prevent DOS attacks but makes them harder (you have
* to actually send gigabytes of data). */
- svn_stringbuf_t *stringbuf = svn_stringbuf_create_empty(pool);
+ stringbuf = svn_stringbuf_create_empty(pool);
/* Read string data directly into the string structure.
* Do it iteratively. */
@@ -996,7 +1250,8 @@ static svn_error_t *read_string(svn_ra_s
/* Return the string properly wrapped into an RA_SVN item. */
item->kind = SVN_RA_SVN_STRING;
- item->u.string = svn_stringbuf__morph_into_string(stringbuf);
+ item->u.string.data = stringbuf->data;
+ item->u.string.len = stringbuf->len;
}
return SVN_NO_ERROR;
@@ -1007,12 +1262,12 @@ static svn_error_t *read_string(svn_ra_s
* to 0 for the first call and is used to enforce a recursion limit
* on the parser. */
static svn_error_t *read_item(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
- svn_ra_svn_item_t *item, char first_char,
+ svn_ra_svn__item_t *item, char first_char,
int level)
{
char c = first_char;
apr_uint64_t val;
- svn_ra_svn_item_t *listitem;
+ svn_ra_svn__item_t *listitem;
if (++level >= ITEM_NESTING_LIMIT)
return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
@@ -1060,67 +1315,108 @@ static svn_error_t *read_item(svn_ra_svn
char *p = buffer + 1;
buffer[0] = c;
- while (1)
+ if (conn->read_ptr + MAX_WORD_LENGTH <= conn->read_end)
{
- SVN_ERR(readbuf_getchar(conn, pool, p));
- if (!svn_ctype_isalnum(*p) && *p != '-')
- break;
+ /* Fast path: we can simply take a chunk from the read
+ * buffer and inspect it with no overflow checks etc.
+ *
+ * Copying these 24 bytes unconditionally is also faster
+ * than a variable-sized memcpy. Note that P is at BUFFER[1].
+ */
+ memcpy(p, conn->read_ptr, MAX_WORD_LENGTH - 1);
+ *end = 0;
+
+ /* This will terminate at P == END because of *END == NUL. */
+ while (svn_ctype_isalnum(*p) || *p == '-')
+ ++p;
- if (++p == end)
- return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
- _("Word is too long"));
+ /* Only now do we mark data as actually read. */
+ conn->read_ptr += p - buffer;
}
+ else
+ {
+ /* Slow path. Byte-by-byte copying and checking for
+ * input and output buffer boundaries. */
+ for (p = buffer + 1; p != end; ++p)
+ {
+ SVN_ERR(readbuf_getchar(conn, pool, p));
+ if (!svn_ctype_isalnum(*p) && *p != '-')
+ break;
+ }
+ }
+
+ if (p == end)
+ return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
+ _("Word is too long"));
c = *p;
*p = '\0';
+ /* Store the word in ITEM. */
item->kind = SVN_RA_SVN_WORD;
- item->u.word = buffer;
+ item->u.word.data = buffer;
+ item->u.word.len = p - buffer;
}
else if (c == '(')
{
- /* Allocate an APR array with room for (initially) 4 items.
- * We do this manually because lists are the most frequent protocol
- * element, often used to frame a single, optional value. We save
- * about 20% of total protocol handling time. */
- char *buffer = apr_palloc(pool, sizeof(apr_array_header_t)
- + 4 * sizeof(svn_ra_svn_item_t));
- svn_ra_svn_item_t *data
- = (svn_ra_svn_item_t *)(buffer + sizeof(apr_array_header_t));
-
- item->kind = SVN_RA_SVN_LIST;
- item->u.list = (apr_array_header_t *)buffer;
- item->u.list->elts = (char *)data;
- item->u.list->pool = pool;
- item->u.list->elt_size = sizeof(*data);
- item->u.list->nelts = 0;
- item->u.list->nalloc = 4;
-
- listitem = data;
+ /* The largest struct that the protocol currently defines has 10
+ * elements (log-entry) and add some headroom for future extensions.
+ * At a maximum nesting level of 64 this use <= 18kB of stack.
+ *
+ * All system-defined data structures will fit into this and will be
+ * copied into ITEM after a single apr_palloc with no over-provision.
+ * Unbounded lists with more than 12 but less than 25 entries will
+ * also see only a single allocation from POOL. However, there will
+ * be some over-provision. Longer lists will see log N resizes and
+ * O(N) total cost.
+ */
+ svn_ra_svn__item_t stack_items[12];
+ svn_ra_svn__item_t *items = stack_items;
+ int capacity = sizeof(stack_items) / sizeof(stack_items[0]);
+ int count = 0;
/* Read in the list items. */
+ item->kind = SVN_RA_SVN_LIST;
while (1)
{
SVN_ERR(readbuf_getchar_skip_whitespace(conn, pool, &c));
if (c == ')')
break;
- /* increase array capacity if necessary */
- if (item->u.list->nelts == item->u.list->nalloc)
+ /* Auto-expand the list. */
+ if (count == capacity)
{
- data = apr_palloc(pool, 2 * item->u.list->nelts * sizeof(*data));
- memcpy(data, item->u.list->elts, item->u.list->nelts * sizeof(*data));
- item->u.list->elts = (char *)data;
- item->u.list->nalloc *= 2;
- listitem = data + item->u.list->nelts;
+ svn_ra_svn__item_t *new_items
+ = apr_palloc(pool, 2 * capacity * sizeof(*new_items));
+ memcpy(new_items, items, capacity * sizeof(*new_items));
+ items = new_items;
+ capacity = 2 * capacity;
}
- /* read next protocol item */
+ listitem = &items[count];
+ ++count;
+
SVN_ERR(read_item(conn, pool, listitem, c, level));
+ }
+
+ /* Store the list in ITEM - if not empty (= default). */
+ if (count)
+ {
+ item->u.list.nelts = count;
- listitem++;
- item->u.list->nelts++;
+ /* If we haven't allocated from POOL, yet, do it now. */
+ if (items == stack_items)
+ item->u.list.items = apr_pmemdup(pool, items,
+ count * sizeof(*items));
+ else
+ item->u.list.items = items;
}
+ else
+ {
+ item->u.list.items = NULL;
+ item->u.list.nelts = 0;
+ }
+
SVN_ERR(readbuf_getchar(conn, pool, &c));
}
@@ -1222,7 +1518,7 @@ read_command_only(svn_ra_svn_conn_t *con
svn_error_t *
svn_ra_svn__read_item(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
- svn_ra_svn_item_t **item)
+ svn_ra_svn__item_t **item)
{
char c;
@@ -1272,36 +1568,38 @@ svn_ra_svn__skip_leading_garbage(svn_ra_
/* --- READING AND PARSING TUPLES --- */
-/* Parse a tuple of svn_ra_svn_item_t *'s. Advance *FMT to the end of the
+/* Parse a tuple of svn_ra_svn__item_t *'s. Advance *FMT to the end of the
* tuple specification and advance AP by the corresponding arguments. */
-static svn_error_t *vparse_tuple(const apr_array_header_t *items, apr_pool_t *pool,
- const char **fmt, va_list *ap)
+static svn_error_t *
+vparse_tuple(const svn_ra_svn__list_t *items,
+ const char **fmt,
+ va_list *ap)
{
int count, nesting_level;
- svn_ra_svn_item_t *elt;
+ svn_ra_svn__item_t *elt;
for (count = 0; **fmt && count < items->nelts; (*fmt)++, count++)
{
/* '?' just means the tuple may stop; skip past it. */
if (**fmt == '?')
(*fmt)++;
- elt = &APR_ARRAY_IDX(items, count, svn_ra_svn_item_t);
+ elt = &SVN_RA_SVN__LIST_ITEM(items, count);
if (**fmt == '(' && elt->kind == SVN_RA_SVN_LIST)
{
(*fmt)++;
- SVN_ERR(vparse_tuple(elt->u.list, pool, fmt, ap));
+ SVN_ERR(vparse_tuple(&elt->u.list, fmt, ap));
}
else if (**fmt == 'c' && elt->kind == SVN_RA_SVN_STRING)
- *va_arg(*ap, const char **) = elt->u.string->data;
+ *va_arg(*ap, const char **) = elt->u.string.data;
else if (**fmt == 's' && elt->kind == SVN_RA_SVN_STRING)
- *va_arg(*ap, svn_string_t **) = elt->u.string;
+ *va_arg(*ap, svn_string_t **) = &elt->u.string;
else if (**fmt == 'w' && elt->kind == SVN_RA_SVN_WORD)
- *va_arg(*ap, const char **) = elt->u.word;
+ *va_arg(*ap, const char **) = elt->u.word.data;
else if (**fmt == 'b' && elt->kind == SVN_RA_SVN_WORD)
{
- if (strcmp(elt->u.word, "true") == 0)
+ if (svn_string_compare(&elt->u.word, &str_true))
*va_arg(*ap, svn_boolean_t *) = TRUE;
- else if (strcmp(elt->u.word, "false") == 0)
+ else if (svn_string_compare(&elt->u.word, &str_false))
*va_arg(*ap, svn_boolean_t *) = FALSE;
else
break;
@@ -1312,24 +1610,24 @@ static svn_error_t *vparse_tuple(const a
*va_arg(*ap, svn_revnum_t *) = (svn_revnum_t) elt->u.number;
else if (**fmt == 'B' && elt->kind == SVN_RA_SVN_WORD)
{
- if (strcmp(elt->u.word, "true") == 0)
+ if (svn_string_compare(&elt->u.word, &str_true))
*va_arg(*ap, apr_uint64_t *) = TRUE;
- else if (strcmp(elt->u.word, "false") == 0)
+ else if (svn_string_compare(&elt->u.word, &str_false))
*va_arg(*ap, apr_uint64_t *) = FALSE;
else
break;
}
else if (**fmt == '3' && elt->kind == SVN_RA_SVN_WORD)
{
- if (strcmp(elt->u.word, "true") == 0)
+ if (svn_string_compare(&elt->u.word, &str_true))
*va_arg(*ap, svn_tristate_t *) = svn_tristate_true;
- else if (strcmp(elt->u.word, "false") == 0)
+ else if (svn_string_compare(&elt->u.word, &str_false))
*va_arg(*ap, svn_tristate_t *) = svn_tristate_false;
else
break;
}
else if (**fmt == 'l' && elt->kind == SVN_RA_SVN_LIST)
- *va_arg(*ap, apr_array_header_t **) = elt->u.list;
+ *va_arg(*ap, svn_ra_svn__list_t **) = &elt->u.list;
else if (**fmt == ')')
return SVN_NO_ERROR;
else
@@ -1355,7 +1653,7 @@ static svn_error_t *vparse_tuple(const a
*va_arg(*ap, const char **) = NULL;
break;
case 'l':
- *va_arg(*ap, apr_array_header_t **) = NULL;
+ *va_arg(*ap, svn_ra_svn__list_t **) = NULL;
break;
case 'B':
case 'n':
@@ -1383,15 +1681,14 @@ static svn_error_t *vparse_tuple(const a
}
svn_error_t *
-svn_ra_svn__parse_tuple(const apr_array_header_t *list,
- apr_pool_t *pool,
+svn_ra_svn__parse_tuple(const svn_ra_svn__list_t *list,
const char *fmt, ...)
{
svn_error_t *err;
va_list ap;
va_start(ap, fmt);
- err = vparse_tuple(list, pool, &fmt, &ap);
+ err = vparse_tuple(list, &fmt, &ap);
va_end(ap);
return err;
}
@@ -1402,7 +1699,7 @@ svn_ra_svn__read_tuple(svn_ra_svn_conn_t
const char *fmt, ...)
{
va_list ap;
- svn_ra_svn_item_t *item;
+ svn_ra_svn__item_t *item;
svn_error_t *err;
SVN_ERR(svn_ra_svn__read_item(conn, pool, &item));
@@ -1410,7 +1707,7 @@ svn_ra_svn__read_tuple(svn_ra_svn_conn_t
return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
_("Malformed network data"));
va_start(ap, fmt);
- err = vparse_tuple(item->u.list, pool, &fmt, &ap);
+ err = vparse_tuple(&item->u.list, &fmt, &ap);
va_end(ap);
return err;
}
@@ -1429,24 +1726,23 @@ svn_ra_svn__read_command_only(svn_ra_svn
svn_error_t *
-svn_ra_svn__parse_proplist(const apr_array_header_t *list,
+svn_ra_svn__parse_proplist(const svn_ra_svn__list_t *list,
apr_pool_t *pool,
apr_hash_t **props)
{
svn_string_t *name;
svn_string_t *value;
- svn_ra_svn_item_t *elt;
+ svn_ra_svn__item_t *elt;
int i;
*props = svn_hash__make(pool);
for (i = 0; i < list->nelts; i++)
{
- elt = &APR_ARRAY_IDX(list, i, svn_ra_svn_item_t);
+ elt = &SVN_RA_SVN__LIST_ITEM(list, i);
if (elt->kind != SVN_RA_SVN_LIST)
return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
_("Proplist element not a list"));
- SVN_ERR(svn_ra_svn__parse_tuple(elt->u.list, pool, "ss",
- &name, &value));
+ SVN_ERR(svn_ra_svn__parse_tuple(&elt->u.list, "ss", &name, &value));
apr_hash_set(*props, name->data, name->len, value);
}
@@ -1471,15 +1767,14 @@ svn_error_t *svn_ra_svn__locate_real_err
return this_link;
}
-svn_error_t *svn_ra_svn__handle_failure_status(const apr_array_header_t *params,
- apr_pool_t *pool)
+svn_error_t *
+svn_ra_svn__handle_failure_status(const svn_ra_svn__list_t *params)
{
const char *message, *file;
svn_error_t *err = NULL;
- svn_ra_svn_item_t *elt;
+ svn_ra_svn__item_t *elt;
int i;
apr_uint64_t apr_err, line;
- apr_pool_t *subpool = svn_pool_create(pool);
if (params->nelts == 0)
return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
@@ -1488,12 +1783,11 @@ svn_error_t *svn_ra_svn__handle_failure_
/* Rebuild the error list from the end, to avoid reversing the order. */
for (i = params->nelts - 1; i >= 0; i--)
{
- svn_pool_clear(subpool);
- elt = &APR_ARRAY_IDX(params, i, svn_ra_svn_item_t);
+ elt = &SVN_RA_SVN__LIST_ITEM(params, i);
if (elt->kind != SVN_RA_SVN_LIST)
return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
_("Malformed error list"));
- SVN_ERR(svn_ra_svn__parse_tuple(elt->u.list, subpool, "nccn",
+ SVN_ERR(svn_ra_svn__parse_tuple(&elt->u.list, "nccn",
&apr_err, &message, &file, &line));
/* The message field should have been optional, but we can't
easily change that, so "" means a nonexistent message. */
@@ -1512,8 +1806,6 @@ svn_error_t *svn_ra_svn__handle_failure_
}
}
- svn_pool_destroy(subpool);
-
/* If we get here, then we failed to find a real error in the error
chain that the server proported to be sending us. That's bad. */
if (! err)
@@ -1530,20 +1822,20 @@ svn_ra_svn__read_cmd_response(svn_ra_svn
{
va_list ap;
const char *status;
- apr_array_header_t *params;
+ svn_ra_svn__list_t *params;
svn_error_t *err;
SVN_ERR(svn_ra_svn__read_tuple(conn, pool, "wl", &status, ¶ms));
if (strcmp(status, "success") == 0)
{
va_start(ap, fmt);
- err = vparse_tuple(params, pool, &fmt, &ap);
+ err = vparse_tuple(params, &fmt, &ap);
va_end(ap);
return err;
}
else if (strcmp(status, "failure") == 0)
{
- return svn_error_trace(svn_ra_svn__handle_failure_status(params, pool));
+ return svn_error_trace(svn_ra_svn__handle_failure_status(params));
}
return svn_error_createf(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
@@ -1557,7 +1849,12 @@ svn_ra_svn__has_command(svn_boolean_t *h
svn_ra_svn_conn_t *conn,
apr_pool_t *pool)
{
- svn_error_t *err = svn_ra_svn__has_item(has_command, conn, pool);
+ svn_error_t *err;
+
+ /* Don't make whitespace between commands trigger I/O limitiations. */
+ svn_ra_svn__reset_command_io_counters(conn);
+
+ err = svn_ra_svn__has_item(has_command, conn, pool);
if (err && err->apr_err == SVN_ERR_RA_SVN_CONNECTION_CLOSED)
{
*terminated = TRUE;
@@ -1579,10 +1876,14 @@ svn_ra_svn__handle_command(svn_boolean_t
{
const char *cmdname;
svn_error_t *err, *write_err;
- apr_array_header_t *params;
- const svn_ra_svn_cmd_entry_t *command;
+ svn_ra_svn__list_t *params;
+ const svn_ra_svn__cmd_entry_t *command;
*terminate = FALSE;
+
+ /* Limit I/O for every command separately. */
+ svn_ra_svn__reset_command_io_counters(conn);
+
err = svn_ra_svn__read_tuple(conn, pool, "wl", &cmdname, ¶ms);
if (err)
{
@@ -1599,7 +1900,28 @@ svn_ra_svn__handle_command(svn_boolean_t
command = svn_hash_gets(cmd_hash, cmdname);
if (command)
{
- err = (*command->handler)(conn, pool, params, baton);
+ /* Call the standard command handler.
+ * If that is not set, then this is a lecagy API call and we invoke
+ * the legacy command handler. */
+ if (command->handler)
+ {
+ err = (*command->handler)(conn, pool, params, baton);
+ }
+ else
+ {
+ apr_array_header_t *deprecated_params
+ = svn_ra_svn__to_public_array(params, pool);
+ err = (*command->deprecated_handler)(conn, pool, deprecated_params,
+ baton);
+ }
+
+ /* The command implementation may have swallowed or wrapped the I/O
+ * error not knowing that we may no longer be able to send data.
+ *
+ * So, check again for the limit violations and exit the command
+ * processing quickly if we may have truncated data. */
+ err = svn_error_compose_create(check_io_limits(conn), err);
+
*terminate = command->terminate;
}
else
@@ -1624,13 +1946,13 @@ svn_ra_svn__handle_command(svn_boolean_t
svn_error_t *
svn_ra_svn__handle_commands2(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
- const svn_ra_svn_cmd_entry_t *commands,
+ const svn_ra_svn__cmd_entry_t *commands,
void *baton,
svn_boolean_t error_on_disconnect)
{
apr_pool_t *subpool = svn_pool_create(pool);
apr_pool_t *iterpool = svn_pool_create(subpool);
- const svn_ra_svn_cmd_entry_t *command;
+ const svn_ra_svn__cmd_entry_t *command;
apr_hash_t *cmd_hash = apr_hash_make(subpool);
for (command = commands; command->cmdname; command++)
@@ -1673,13 +1995,13 @@ svn_error_t *
svn_ra_svn__write_cmd_open_root(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
svn_revnum_t rev,
- const char *token)
+ const svn_string_t *token)
{
SVN_ERR(writebuf_write_literal(conn, pool, "( open-root ( "));
SVN_ERR(write_tuple_start_list(conn, pool));
SVN_ERR(write_tuple_revision_opt(conn, pool, rev));
SVN_ERR(write_tuple_end_list(conn, pool));
- SVN_ERR(write_tuple_cstring(conn, pool, token));
+ SVN_ERR(write_tuple_string(conn, pool, token));
SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
@@ -1690,14 +2012,14 @@ svn_ra_svn__write_cmd_delete_entry(svn_r
apr_pool_t *pool,
const char *path,
svn_revnum_t rev,
- const char *token)
+ const svn_string_t *token)
{
SVN_ERR(writebuf_write_literal(conn, pool, "( delete-entry ( "));
SVN_ERR(write_tuple_cstring(conn, pool, path));
SVN_ERR(write_tuple_start_list(conn, pool));
SVN_ERR(write_tuple_revision_opt(conn, pool, rev));
SVN_ERR(write_tuple_end_list(conn, pool));
- SVN_ERR(write_tuple_cstring(conn, pool, token));
+ SVN_ERR(write_tuple_string(conn, pool, token));
SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
@@ -1707,8 +2029,8 @@ svn_error_t *
svn_ra_svn__write_cmd_add_dir(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
const char *path,
- const char *parent_token,
- const char *token,
+ const svn_string_t *parent_token,
+ const svn_string_t *token,
const char *copy_path,
svn_revnum_t copy_rev)
{
@@ -1724,8 +2046,8 @@ svn_error_t *
svn_ra_svn__write_cmd_open_dir(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
const char *path,
- const char *parent_token,
- const char *token,
+ const svn_string_t *parent_token,
+ const svn_string_t *token,
svn_revnum_t rev)
{
SVN_ERR(writebuf_write_literal(conn, pool, "( open-dir ( "));
@@ -1738,7 +2060,7 @@ svn_ra_svn__write_cmd_open_dir(svn_ra_sv
svn_error_t *
svn_ra_svn__write_cmd_change_dir_prop(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
- const char *token,
+ const svn_string_t *token,
const char *name,
const svn_string_t *value)
{
@@ -1752,10 +2074,10 @@ svn_ra_svn__write_cmd_change_dir_prop(sv
svn_error_t *
svn_ra_svn__write_cmd_close_dir(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
- const char *token)
+ const svn_string_t *token)
{
SVN_ERR(writebuf_write_literal(conn, pool, "( close-dir ( "));
- SVN_ERR(write_tuple_cstring(conn, pool, token));
+ SVN_ERR(write_tuple_string(conn, pool, token));
SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
@@ -1765,7 +2087,7 @@ svn_error_t *
svn_ra_svn__write_cmd_absent_dir(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
const char *path,
- const char *parent_token)
+ const svn_string_t *parent_token)
{
SVN_ERR(writebuf_write_literal(conn, pool, "( absent-dir ( "));
SVN_ERR(write_cmd_absent_node(conn, pool, path, parent_token));
@@ -1778,8 +2100,8 @@ svn_error_t *
svn_ra_svn__write_cmd_add_file(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
const char *path,
- const char *parent_token,
- const char *token,
+ const svn_string_t *parent_token,
+ const svn_string_t *token,
const char *copy_path,
svn_revnum_t copy_rev)
{
@@ -1795,8 +2117,8 @@ svn_error_t *
svn_ra_svn__write_cmd_open_file(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
const char *path,
- const char *parent_token,
- const char *token,
+ const svn_string_t *parent_token,
+ const svn_string_t *token,
svn_revnum_t rev)
{
SVN_ERR(writebuf_write_literal(conn, pool, "( open-file ( "));
@@ -1809,7 +2131,7 @@ svn_ra_svn__write_cmd_open_file(svn_ra_s
svn_error_t *
svn_ra_svn__write_cmd_change_file_prop(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
- const char *token,
+ const svn_string_t *token,
const char *name,
const svn_string_t *value)
{
@@ -1823,11 +2145,11 @@ svn_ra_svn__write_cmd_change_file_prop(s
svn_error_t *
svn_ra_svn__write_cmd_close_file(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
- const char *token,
+ const svn_string_t *token,
const char *text_checksum)
{
SVN_ERR(writebuf_write_literal(conn, pool, "( close-file ( "));
- SVN_ERR(write_tuple_cstring(conn, pool, token));
+ SVN_ERR(write_tuple_string(conn, pool, token));
SVN_ERR(write_tuple_start_list(conn, pool));
SVN_ERR(write_tuple_cstring_opt(conn, pool, text_checksum));
SVN_ERR(write_tuple_end_list(conn, pool));
@@ -1840,7 +2162,7 @@ svn_error_t *
svn_ra_svn__write_cmd_absent_file(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
const char *path,
- const char *parent_token)
+ const svn_string_t *parent_token)
{
SVN_ERR(writebuf_write_literal(conn, pool, "( absent-file ( "));
SVN_ERR(write_cmd_absent_node(conn, pool, path, parent_token));
@@ -1852,11 +2174,11 @@ svn_ra_svn__write_cmd_absent_file(svn_ra
svn_error_t *
svn_ra_svn__write_cmd_textdelta_chunk(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
- const char *token,
+ const svn_string_t *token,
const svn_string_t *chunk)
{
SVN_ERR(writebuf_write_literal(conn, pool, "( textdelta-chunk ( "));
- SVN_ERR(write_tuple_cstring(conn, pool, token));
+ SVN_ERR(write_tuple_string(conn, pool, token));
SVN_ERR(write_tuple_string(conn, pool, chunk));
SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
@@ -1866,10 +2188,10 @@ svn_ra_svn__write_cmd_textdelta_chunk(sv
svn_error_t *
svn_ra_svn__write_cmd_textdelta_end(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
- const char *token)
+ const svn_string_t *token)
{
SVN_ERR(writebuf_write_literal(conn, pool, "( textdelta-end ( "));
- SVN_ERR(write_tuple_cstring(conn, pool, token));
+ SVN_ERR(write_tuple_string(conn, pool, token));
SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
@@ -1878,11 +2200,11 @@ svn_ra_svn__write_cmd_textdelta_end(svn_
svn_error_t *
svn_ra_svn__write_cmd_apply_textdelta(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
- const char *token,
+ const svn_string_t *token,
const char *base_checksum)
{
SVN_ERR(writebuf_write_literal(conn, pool, "( apply-textdelta ( "));
- SVN_ERR(write_tuple_cstring(conn, pool, token));
+ SVN_ERR(write_tuple_string(conn, pool, token));
SVN_ERR(write_tuple_start_list(conn, pool));
SVN_ERR(write_tuple_cstring_opt(conn, pool, base_checksum));
SVN_ERR(write_tuple_end_list(conn, pool));
@@ -2020,9 +2342,7 @@ svn_ra_svn__write_cmd_change_rev_prop2(s
SVN_ERR(writebuf_write_literal(conn, pool, "( change-rev-prop2 ( "));
SVN_ERR(write_tuple_revision(conn, pool, rev));
SVN_ERR(write_tuple_cstring(conn, pool, name));
- SVN_ERR(write_tuple_start_list(conn, pool));
- SVN_ERR(write_tuple_string_opt(conn, pool, value));
- SVN_ERR(write_tuple_end_list(conn, pool));
+ SVN_ERR(write_tuple_string_opt_list(conn, pool, value));
SVN_ERR(write_tuple_start_list(conn, pool));
SVN_ERR(write_tuple_boolean(conn, pool, dont_care));
SVN_ERR(write_tuple_string_opt(conn, pool, old_value));
@@ -2274,14 +2594,12 @@ svn_error_t *
svn_ra_svn__write_cmd_unlock(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
const char *path,
- const char *token,
+ const svn_string_t *token,
svn_boolean_t break_lock)
{
SVN_ERR(writebuf_write_literal(conn, pool, "( unlock ( "));
SVN_ERR(write_tuple_cstring(conn, pool, path));
- SVN_ERR(write_tuple_start_list(conn, pool));
- SVN_ERR(write_tuple_cstring_opt(conn, pool, token));
- SVN_ERR(write_tuple_end_list(conn, pool));
+ SVN_ERR(write_tuple_string_opt_list(conn, pool, token));
SVN_ERR(write_tuple_boolean(conn, pool, break_lock));
SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
@@ -2431,6 +2749,49 @@ svn_error_t *svn_ra_svn__write_cmd_failu
return writebuf_write_literal(conn, pool, ") ) ");
}
+/* Initializer for static svn_string_t . */
+#define STATIC_SVN_STRING(x) { x, sizeof(x) - 1 }
+
+/* Return a pre-cooked serialized representation for the changed path
+ flags NODE_KIND, TEXT_MODIFIED and PROPS_MODIFIED. If we don't
+ have a suitable pre-cooked string, return an empty string. */
+static const svn_string_t *
+changed_path_flags(svn_node_kind_t node_kind,
+ svn_boolean_t text_modified,
+ svn_boolean_t props_modified)
+{
+ const static svn_string_t file_flags[4]
+ = { STATIC_SVN_STRING(" ) ( 4:file false false ) ) "),
+ STATIC_SVN_STRING(" ) ( 4:file false true ) ) "),
+ STATIC_SVN_STRING(" ) ( 4:file true false ) ) "),
+ STATIC_SVN_STRING(" ) ( 4:file true true ) ) ") };
+
+ const static svn_string_t dir_flags[4]
+ = { STATIC_SVN_STRING(" ) ( 3:dir false false ) ) "),
+ STATIC_SVN_STRING(" ) ( 3:dir false true ) ) "),
+ STATIC_SVN_STRING(" ) ( 3:dir true false ) ) "),
+ STATIC_SVN_STRING(" ) ( 3:dir true true ) ) ") };
+
+ const static svn_string_t no_flags = STATIC_SVN_STRING("");
+
+ /* Select the array based on the NODE_KIND. */
+ const svn_string_t *flags;
+ if (node_kind == svn_node_file)
+ flags = file_flags;
+ else if (node_kind == svn_node_dir)
+ flags = dir_flags;
+ else
+ return &no_flags;
+
+ /* Select the correct array entry. */
+ if (text_modified)
+ flags += 2;
+ if (props_modified)
+ flags++;
+
+ return flags;
+}
+
svn_error_t *
svn_ra_svn__write_data_log_changed_path(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
@@ -2442,21 +2803,77 @@ svn_ra_svn__write_data_log_changed_path(
svn_boolean_t text_modified,
svn_boolean_t props_modified)
{
- SVN_ERR(write_tuple_start_list(conn, pool));
+ apr_size_t path_len = strlen(path);
+ apr_size_t copyfrom_len = copyfrom_path ? strlen(copyfrom_path) : 0;
+ const svn_string_t *flags_str = changed_path_flags(node_kind,
+ text_modified,
+ props_modified);
+
+ /* How much buffer space do we need (worst case)? */
+ apr_size_t needed = 2 /* list start */
+ + path_len + SVN_INT64_BUFFER_SIZE
+ /* path */
+ + 2 /* action */
+ + 2 + copyfrom_len + 2 * SVN_INT64_BUFFER_SIZE
+ /* list start + copy-from info */
+ + flags_str->len; /* flags and closing lists */
+
+ /* If the remaining buffer is big enough and we've got all parts,
+ directly copy into the buffer. */
+ if ( (conn->write_pos + needed <= sizeof(conn->write_buf))
+ && (flags_str->len > 0))
+ {
+ /* Quick path. */
+ /* Open list. */
+ char *p = conn->write_buf + conn->write_pos;
+ p[0] = '(';
+ p[1] = ' ';
+
+ /* Write path. */
+ p = write_ncstring_quick(p + 2, path, path_len);
+
+ /* Action */
+ p[0] = action;
+ p[1] = ' ';
+ p[2] = '(';
+
+ /* Copy-from info (if given) */
+ if (copyfrom_path)
+ {
+ p[3] = ' ';
+ p = write_ncstring_quick(p + 4, copyfrom_path, copyfrom_len);
+ p += svn__ui64toa(p, copyfrom_rev);
+ }
+ else
+ {
+ p += 3;
+ }
- SVN_ERR(write_tuple_cstring(conn, pool, path));
- SVN_ERR(writebuf_writechar(conn, pool, action));
- SVN_ERR(writebuf_writechar(conn, pool, ' '));
- SVN_ERR(write_tuple_start_list(conn, pool));
- SVN_ERR(write_tuple_cstring_opt(conn, pool, copyfrom_path));
- SVN_ERR(write_tuple_revision_opt(conn, pool, copyfrom_rev));
- SVN_ERR(write_tuple_end_list(conn, pool));
- SVN_ERR(write_tuple_start_list(conn, pool));
- SVN_ERR(write_tuple_cstring(conn, pool, svn_node_kind_to_word(node_kind)));
- SVN_ERR(write_tuple_boolean(conn, pool, text_modified));
- SVN_ERR(write_tuple_boolean(conn, pool, props_modified));
+ /* Close with flags. */
+ memcpy(p, flags_str->data, flags_str->len);
+ conn->write_pos = p + flags_str->len - conn->write_buf;
+ }
+ else
+ {
+ /* Standard code path (fallback). */
+ SVN_ERR(write_tuple_start_list(conn, pool));
- return writebuf_write_literal(conn, pool, ") ) ");
+ SVN_ERR(svn_ra_svn__write_ncstring(conn, pool, path, path_len));
+ SVN_ERR(writebuf_writechar(conn, pool, action));
+ SVN_ERR(writebuf_writechar(conn, pool, ' '));
+ SVN_ERR(write_tuple_start_list(conn, pool));
+ SVN_ERR(write_tuple_cstring_opt(conn, pool, copyfrom_path));
+ SVN_ERR(write_tuple_revision_opt(conn, pool, copyfrom_rev));
+ SVN_ERR(write_tuple_end_list(conn, pool));
+ SVN_ERR(write_tuple_start_list(conn, pool));
+ SVN_ERR(write_tuple_cstring(conn, pool, svn_node_kind_to_word(node_kind)));
+ SVN_ERR(write_tuple_boolean(conn, pool, text_modified));
+ SVN_ERR(write_tuple_boolean(conn, pool, props_modified));
+
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
+ }
+
+ return SVN_NO_ERROR;
}
svn_error_t *
@@ -2471,15 +2888,9 @@ svn_ra_svn__write_data_log_entry(svn_ra_
unsigned revprop_count)
{
SVN_ERR(write_tuple_revision(conn, pool, revision));
- SVN_ERR(write_tuple_start_list(conn, pool));
- SVN_ERR(write_tuple_string_opt(conn, pool, author));
- SVN_ERR(write_tuple_end_list(conn, pool));
- SVN_ERR(write_tuple_start_list(conn, pool));
- SVN_ERR(write_tuple_string_opt(conn, pool, date));
- SVN_ERR(write_tuple_end_list(conn, pool));
- SVN_ERR(write_tuple_start_list(conn, pool));
- SVN_ERR(write_tuple_string_opt(conn, pool, message));
- SVN_ERR(write_tuple_end_list(conn, pool));
+ SVN_ERR(write_tuple_string_opt_list(conn, pool, author));
+ SVN_ERR(write_tuple_string_opt_list(conn, pool, date));
+ SVN_ERR(write_tuple_string_opt_list(conn, pool, message));
SVN_ERR(write_tuple_boolean(conn, pool, has_children));
SVN_ERR(write_tuple_boolean(conn, pool, invalid_revnum));
SVN_ERR(svn_ra_svn__write_number(conn, pool, revprop_count));
@@ -2497,13 +2908,13 @@ svn_ra_svn__write_data_log_entry(svn_ra_
/* In *RESULT, return the SVN-style string at index IDX in tuple ITEMS.
*/
static svn_error_t *
-svn_ra_svn__read_string(const apr_array_header_t *items,
+svn_ra_svn__read_string(const svn_ra_svn__list_t *items,
int idx,
svn_string_t **result)
{
- svn_ra_svn_item_t *elt = &APR_ARRAY_IDX(items, idx, svn_ra_svn_item_t);
+ svn_ra_svn__item_t *elt = &SVN_RA_SVN__LIST_ITEM(items, idx);
CHECK_PROTOCOL_COND(elt->kind == SVN_RA_SVN_STRING);
- *result = elt->u.string;
+ *result = &elt->u.string;
return SVN_NO_ERROR;
}
@@ -2511,13 +2922,13 @@ svn_ra_svn__read_string(const apr_array_
/* In *RESULT, return the C-style string at index IDX in tuple ITEMS.
*/
static svn_error_t *
-svn_ra_svn__read_cstring(const apr_array_header_t *items,
+svn_ra_svn__read_cstring(const svn_ra_svn__list_t *items,
int idx,
const char **result)
{
- svn_ra_svn_item_t *elt = &APR_ARRAY_IDX(items, idx, svn_ra_svn_item_t);
+ svn_ra_svn__item_t *elt = &SVN_RA_SVN__LIST_ITEM(items, idx);
CHECK_PROTOCOL_COND(elt->kind == SVN_RA_SVN_STRING);
- *result = elt->u.string->data;
+ *result = elt->u.string.data;
return SVN_NO_ERROR;
}
@@ -2525,13 +2936,13 @@ svn_ra_svn__read_cstring(const apr_array
/* In *RESULT, return the word at index IDX in tuple ITEMS.
*/
static svn_error_t *
-svn_ra_svn__read_word(const apr_array_header_t *items,
+svn_ra_svn__read_word(const svn_ra_svn__list_t *items,
int idx,
const char **result)
{
- svn_ra_svn_item_t *elt = &APR_ARRAY_IDX(items, idx, svn_ra_svn_item_t);
+ svn_ra_svn__item_t *elt = &SVN_RA_SVN__LIST_ITEM(items, idx);
CHECK_PROTOCOL_COND(elt->kind == SVN_RA_SVN_WORD);
- *result = elt->u.word;
+ *result = elt->u.word.data;
return SVN_NO_ERROR;
}
@@ -2539,11 +2950,11 @@ svn_ra_svn__read_word(const apr_array_he
/* In *RESULT, return the revision at index IDX in tuple ITEMS.
*/
static svn_error_t *
-svn_ra_svn__read_revision(const apr_array_header_t *items,
+svn_ra_svn__read_revision(const svn_ra_svn__list_t *items,
int idx,
svn_revnum_t *result)
{
- svn_ra_svn_item_t *elt = &APR_ARRAY_IDX(items, idx, svn_ra_svn_item_t);
+ svn_ra_svn__item_t *elt = &SVN_RA_SVN__LIST_ITEM(items, idx);
CHECK_PROTOCOL_COND(elt->kind == SVN_RA_SVN_NUMBER);
*result = (svn_revnum_t)elt->u.number;
@@ -2553,15 +2964,15 @@ svn_ra_svn__read_revision(const apr_arra
/* In *RESULT, return the boolean at index IDX in tuple ITEMS.
*/
static svn_error_t *
-svn_ra_svn__read_boolean(const apr_array_header_t *items,
+svn_ra_svn__read_boolean(const svn_ra_svn__list_t *items,
int idx,
apr_uint64_t *result)
{
- svn_ra_svn_item_t *elt = &APR_ARRAY_IDX(items, idx, svn_ra_svn_item_t);
+ svn_ra_svn__item_t *elt = &SVN_RA_SVN__LIST_ITEM(items, idx);
CHECK_PROTOCOL_COND(elt->kind == SVN_RA_SVN_WORD);
- if (elt->u.word[0] == 't' && strcmp(elt->u.word, "true") == 0)
+ if (svn_string_compare(&elt->u.word, &str_true))
*result = TRUE;
- else if (strcmp(elt->u.word, "false") == 0)
+ else if (svn_string_compare(&elt->u.word, &str_false))
*result = FALSE;
else
CHECK_PROTOCOL_COND(FALSE);
@@ -2572,21 +2983,21 @@ svn_ra_svn__read_boolean(const apr_array
/* In *RESULT, return the tuple at index IDX in tuple ITEMS.
*/
static svn_error_t *
-svn_ra_svn__read_list(const apr_array_header_t *items,
+svn_ra_svn__read_list(const svn_ra_svn__list_t *items,
int idx,
- const apr_array_header_t **result)
+ const svn_ra_svn__list_t **result)
{
- svn_ra_svn_item_t *elt = &APR_ARRAY_IDX(items, idx, svn_ra_svn_item_t);
+ svn_ra_svn__item_t *elt = &SVN_RA_SVN__LIST_ITEM(items, idx);
CHECK_PROTOCOL_COND(elt->kind == SVN_RA_SVN_LIST);
- *result = elt->u.list;
+ *result = &elt->u.list;
return SVN_NO_ERROR;
}
/* Verify the tuple ITEMS contains at least MIN and at most MAX elements.
*/
static svn_error_t *
-svn_ra_svn__read_check_array_size(const apr_array_header_t *items,
+svn_ra_svn__read_check_array_size(const svn_ra_svn__list_t *items,
int min,
int max)
{
@@ -2595,7 +3006,7 @@ svn_ra_svn__read_check_array_size(const
}
svn_error_t *
-svn_ra_svn__read_data_log_changed_entry(const apr_array_header_t *items,
+svn_ra_svn__read_data_log_changed_entry(const svn_ra_svn__list_t *items,
svn_string_t **cpath,
const char **action,
const char **copy_path,
@@ -2604,7 +3015,7 @@ svn_ra_svn__read_data_log_changed_entry(
apr_uint64_t *text_mods,
apr_uint64_t *prop_mods)
{
- const apr_array_header_t *sub_items;
+ const svn_ra_svn__list_t *sub_items;
/* initialize optional values */
*copy_path = NULL;
Modified: subversion/branches/ra-git/subversion/libsvn_ra_svn/ra_svn.h
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_ra_svn/ra_svn.h?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_ra_svn/ra_svn.h (original)
+++ subversion/branches/ra-git/subversion/libsvn_ra_svn/ra_svn.h Mon Nov 30 10:24:16 2015
@@ -96,6 +96,12 @@ struct svn_ra_svn_conn_st {
apr_size_t error_check_interval;
svn_boolean_t may_check_for_error;
+ /* I/O limits and tracking */
+ apr_uint64_t max_in;
+ apr_uint64_t current_in;
+ apr_uint64_t max_out;
+ apr_uint64_t current_out;
+
/* repository info */
const char *uuid;
const char *repos_root;
@@ -123,6 +129,7 @@ struct svn_ra_svn__session_baton_t {
apr_pool_t *pool;
svn_ra_svn_conn_t *conn;
svn_boolean_t is_tunneled;
+ svn_auth_baton_t *auth_baton;
const char *url;
const char *user;
const char *hostname; /* The remote hostname. */
@@ -150,6 +157,12 @@ void svn_ra_svn__set_block_handler(svn_r
svn_error_t *svn_ra_svn__data_available(svn_ra_svn_conn_t *conn,
svn_boolean_t *data_available);
+/* Signal a new request / response pair on CONN. That resets the I/O
+ * counters we use to limit the size of individual requests / response pairs.
+ */
+void
+svn_ra_svn__reset_command_io_counters(svn_ra_svn_conn_t *conn);
+
/* CRAM-MD5 client implementation. */
svn_error_t *svn_ra_svn__cram_client(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
const char *user, const char *password,
@@ -162,10 +175,9 @@ svn_error_t *svn_ra_svn__locate_real_err
/* Return an error chain based on @a params (which contains a
* command response indicating failure). The error chain will be
- * in the same order as the errors indicated in @a params. Use
- * @a pool for temporary allocations. */
-svn_error_t *svn_ra_svn__handle_failure_status(const apr_array_header_t *params,
- apr_pool_t *pool);
+ * in the same order as the errors indicated in @a params. */
+svn_error_t *
+svn_ra_svn__handle_failure_status(const svn_ra_svn__list_t *params);
/* Returns a stream that reads/writes from/to SOCK. */
svn_ra_svn__stream_t *svn_ra_svn__stream_from_sock(apr_socket_t *sock,
@@ -219,7 +231,7 @@ svn_ra_svn__stream_data_available(svn_ra
* tokens. */
svn_error_t *
svn_ra_svn__do_cyrus_auth(svn_ra_svn__session_baton_t *sess,
- const apr_array_header_t *mechlist,
+ const svn_ra_svn__list_t *mechlist,
const char *realm, apr_pool_t *pool);
/* Same as svn_ra_svn__do_cyrus_auth, but uses the built-in implementation of
@@ -228,7 +240,7 @@ svn_ra_svn__do_cyrus_auth(svn_ra_svn__se
* mechanism with the server. */
svn_error_t *
svn_ra_svn__do_internal_auth(svn_ra_svn__session_baton_t *sess,
- const apr_array_header_t *mechlist,
+ const svn_ra_svn__list_t *mechlist,
const char *realm, apr_pool_t *pool);
/* Having picked a mechanism, start authentication by writing out an
@@ -238,8 +250,8 @@ svn_error_t *svn_ra_svn__auth_response(s
apr_pool_t *pool,
const char *mech, const char *mech_arg);
-/* Looks for MECH as a word in MECHLIST (an array of svn_ra_svn_item_t). */
-svn_boolean_t svn_ra_svn__find_mech(const apr_array_header_t *mechlist,
+/* Looks for MECH as a word in MECHLIST. */
+svn_boolean_t svn_ra_svn__find_mech(const svn_ra_svn__list_t *mechlist,
const char *mech);
/* Initialize the SASL library. */
Modified: subversion/branches/ra-git/subversion/libsvn_repos/commit.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_repos/commit.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_repos/commit.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_repos/commit.c Mon Nov 30 10:24:16 2015
@@ -124,6 +124,7 @@ struct dir_baton
svn_revnum_t base_rev; /* the revision I'm based on */
svn_boolean_t was_copied; /* was this directory added with history? */
apr_pool_t *pool; /* my personal pool, in which I am allocated. */
+ svn_boolean_t checked_write; /* TRUE after successfull write check */
};
@@ -131,6 +132,7 @@ struct file_baton
{
struct edit_baton *edit_baton;
const char *path; /* the -absolute- path to this file in the fs */
+ svn_boolean_t checked_write; /* TRUE after successfull write check */
};
@@ -171,6 +173,30 @@ out_of_date(const char *path, svn_node_k
path);
}
+/* Perform an out of date check for base_rev against created rev,
+ and a sanity check of base_rev. */
+static svn_error_t *
+check_out_of_date(struct edit_baton *eb,
+ const char *path,
+ svn_node_kind_t kind,
+ svn_revnum_t base_rev,
+ svn_revnum_t created_rev)
+{
+ if (base_rev < created_rev)
+ {
+ return out_of_date(path, kind);
+ }
+ else if (base_rev > created_rev)
+ {
+ if (base_rev > svn_fs_txn_base_revision(eb->txn))
+ return svn_error_createf(SVN_ERR_FS_NO_SUCH_REVISION, NULL,
+ _("No such revision %ld"),
+ base_rev);
+ }
+
+ return SVN_NO_ERROR;
+}
+
static svn_error_t *
invoke_commit_cb(svn_commit_callback2_t commit_cb,
@@ -188,11 +214,11 @@ invoke_commit_cb(svn_commit_callback2_t
if (commit_cb == NULL)
return SVN_NO_ERROR;
- SVN_ERR(svn_fs_revision_prop(&date, fs, revision, SVN_PROP_REVISION_DATE,
- scratch_pool));
- SVN_ERR(svn_fs_revision_prop(&author, fs, revision,
- SVN_PROP_REVISION_AUTHOR,
- scratch_pool));
+ SVN_ERR(svn_fs_revision_prop2(&date, fs, revision, SVN_PROP_REVISION_DATE,
+ TRUE, scratch_pool, scratch_pool));
+ SVN_ERR(svn_fs_revision_prop2(&author, fs, revision,
+ SVN_PROP_REVISION_AUTHOR,
+ TRUE, scratch_pool, scratch_pool));
commit_info = svn_create_commit_info(scratch_pool);
@@ -364,14 +390,18 @@ add_file_or_directory(const char *path,
/* Build a new child baton. */
if (is_dir)
{
- *return_baton = make_dir_baton(eb, pb, full_path, was_copied,
- SVN_INVALID_REVNUM, pool);
+ struct dir_baton *new_db = make_dir_baton(eb, pb, full_path, was_copied,
+ SVN_INVALID_REVNUM, pool);
+
+ new_db->checked_write = TRUE; /* Just created */
+ *return_baton = new_db;
}
else
{
struct file_baton *new_fb = apr_pcalloc(pool, sizeof(*new_fb));
new_fb->edit_baton = eb;
new_fb->path = full_path;
+ new_fb->checked_write = TRUE; /* Just created */
*return_baton = new_fb;
}
@@ -392,11 +422,16 @@ open_root(void *edit_baton,
struct edit_baton *eb = edit_baton;
svn_revnum_t youngest;
- /* Ignore BASE_REVISION. We always build our transaction against
- HEAD. However, we will keep it in our dir baton for out of
- dateness checks. */
+ /* We always build our transaction against HEAD. However, we will
+ sanity-check BASE_REVISION and keep it in our dir baton for out
+ of dateness checks. */
SVN_ERR(svn_fs_youngest_rev(&youngest, eb->fs, eb->pool));
+ if (base_revision > youngest)
+ return svn_error_createf(SVN_ERR_FS_NO_SUCH_REVISION, NULL,
+ _("No such revision %ld (HEAD is %ld)"),
+ base_revision, youngest);
+
/* Unless we've been instructed to use a specific transaction, we'll
make our own. */
if (eb->txn_owner)
@@ -443,7 +478,6 @@ delete_entry(const char *path,
struct dir_baton *parent = parent_baton;
struct edit_baton *eb = parent->edit_baton;
svn_node_kind_t kind;
- svn_revnum_t cr_rev;
svn_repos_authz_access_t required = svn_authz_write;
const char *full_path;
@@ -468,14 +502,18 @@ delete_entry(const char *path,
/* Now, make sure we're deleting the node we *think* we're
deleting, else return an out-of-dateness error. */
- SVN_ERR(svn_fs_node_created_rev(&cr_rev, eb->txn_root, full_path, pool));
- if (SVN_IS_VALID_REVNUM(revision) && (revision < cr_rev))
- return svn_error_trace(out_of_date(full_path, kind));
+ if (SVN_IS_VALID_REVNUM(revision))
+ {
+ svn_revnum_t cr_rev;
+
+ SVN_ERR(svn_fs_node_created_rev(&cr_rev, eb->txn_root, full_path, pool));
+ SVN_ERR(check_out_of_date(eb, full_path, kind, revision, cr_rev));
+ }
/* This routine is a mindless wrapper. We call svn_fs_delete()
because that will delete files and recursively delete
directories. */
- return svn_fs_delete(eb->txn_root, full_path, pool);
+ return svn_error_trace(svn_fs_delete(eb->txn_root, full_path, pool));
}
@@ -530,18 +568,23 @@ apply_textdelta(void *file_baton,
void **handler_baton)
{
struct file_baton *fb = file_baton;
+ struct edit_baton *eb = fb->edit_baton;
- /* Check for write authorization. */
- SVN_ERR(check_authz(fb->edit_baton, fb->path,
- fb->edit_baton->txn_root,
- svn_authz_write, pool));
+ if (!fb->checked_write)
+ {
+ /* Check for write authorization. */
+ SVN_ERR(check_authz(eb, fb->path, eb->txn_root,
+ svn_authz_write, pool));
+ fb->checked_write = TRUE;
+ }
- return svn_fs_apply_textdelta(handler, handler_baton,
- fb->edit_baton->txn_root,
- fb->path,
- base_checksum,
- NULL,
- pool);
+ return svn_error_trace(
+ svn_fs_apply_textdelta(handler, handler_baton,
+ eb->txn_root,
+ fb->path,
+ base_checksum,
+ NULL,
+ pool));
}
@@ -585,8 +628,9 @@ open_file(const char *path,
/* If the node our caller has is an older revision number than the
one in our transaction, return an out-of-dateness error. */
- if (SVN_IS_VALID_REVNUM(base_revision) && (base_revision < cr_rev))
- return svn_error_trace(out_of_date(full_path, svn_node_file));
+ if (SVN_IS_VALID_REVNUM(base_revision))
+ SVN_ERR(check_out_of_date(eb, full_path, svn_node_file,
+ base_revision, cr_rev));
/* Build a new file baton */
new_fb = apr_pcalloc(pool, sizeof(*new_fb));
@@ -611,9 +655,13 @@ change_file_prop(void *file_baton,
struct file_baton *fb = file_baton;
struct edit_baton *eb = fb->edit_baton;
- /* Check for write authorization. */
- SVN_ERR(check_authz(eb, fb->path, eb->txn_root,
- svn_authz_write, pool));
+ if (!fb->checked_write)
+ {
+ /* Check for write authorization. */
+ SVN_ERR(check_authz(eb, fb->path, eb->txn_root,
+ svn_authz_write, pool));
+ fb->checked_write = TRUE;
+ }
return svn_repos_fs_change_node_prop(eb->txn_root, fb->path,
name, value, pool);
@@ -658,19 +706,24 @@ change_dir_prop(void *dir_baton,
struct edit_baton *eb = db->edit_baton;
/* Check for write authorization. */
- SVN_ERR(check_authz(eb, db->path, eb->txn_root,
- svn_authz_write, pool));
-
- if (SVN_IS_VALID_REVNUM(db->base_rev))
+ if (!db->checked_write)
{
- /* Subversion rule: propchanges can only happen on a directory
- which is up-to-date. */
- svn_revnum_t created_rev;
- SVN_ERR(svn_fs_node_created_rev(&created_rev,
- eb->txn_root, db->path, pool));
+ SVN_ERR(check_authz(eb, db->path, eb->txn_root,
+ svn_authz_write, pool));
+
+ if (SVN_IS_VALID_REVNUM(db->base_rev))
+ {
+ /* Subversion rule: propchanges can only happen on a directory
+ which is up-to-date. */
+ svn_revnum_t created_rev;
+ SVN_ERR(svn_fs_node_created_rev(&created_rev,
+ eb->txn_root, db->path, pool));
+
+ SVN_ERR(check_out_of_date(eb, db->path, svn_node_dir,
+ db->base_rev, created_rev));
+ }
- if (db->base_rev < created_rev)
- return svn_error_trace(out_of_date(db->path, svn_node_dir));
+ db->checked_write = TRUE; /* Skip on further prop changes */
}
return svn_repos_fs_change_node_prop(eb->txn_root, db->path,
Modified: subversion/branches/ra-git/subversion/libsvn_repos/delta.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_repos/delta.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_repos/delta.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_repos/delta.c Mon Nov 30 10:24:16 2015
@@ -266,6 +266,13 @@ svn_repos_dir_delta2(svn_fs_root_t *src_
_("Invalid editor anchoring; at least one of the "
"input paths is not a directory and there was no source entry"));
+ /* Don't report / compare stale revprops. However, revprop changes that
+ * are made by a 3rd party outside this delta operation, may not be
+ * detected as per our visibility guarantees. Reset the revprop caches
+ * for both roots in case they belong to different svn_fs_t instances. */
+ SVN_ERR(svn_fs_refresh_revision_props(svn_fs_root_fs(tgt_root), pool));
+ SVN_ERR(svn_fs_refresh_revision_props(svn_fs_root_fs(src_root), pool));
+
/* Set the global target revision if one can be determined. */
if (svn_fs_is_revision_root(tgt_root))
{
@@ -321,7 +328,7 @@ svn_repos_dir_delta2(svn_fs_root_t *src_
SVN_ERR(svn_fs_node_relation(&relation, tgt_root, tgt_fullpath,
src_root, src_fullpath, pool));
- if (relation == svn_fs_node_same)
+ if (relation == svn_fs_node_unchanged)
{
/* They are the same node! No-op (you gotta love those). */
goto cleanup;
@@ -491,8 +498,8 @@ delta_proplists(struct context *c,
SVN_ERR(change_fn(c, object, SVN_PROP_ENTRY_COMMITTED_REV,
cr_str, subpool));
- SVN_ERR(svn_fs_revision_proplist(&r_props, fs, committed_rev,
- pool));
+ SVN_ERR(svn_fs_revision_proplist2(&r_props, fs, committed_rev,
+ FALSE, pool, subpool));
/* Transmit the committed-date. */
committed_date = svn_hash_gets(r_props, SVN_PROP_REVISION_DATE);
Modified: subversion/branches/ra-git/subversion/libsvn_repos/deprecated.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_repos/deprecated.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_repos/deprecated.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_repos/deprecated.c Mon Nov 30 10:24:16 2015
@@ -731,6 +731,33 @@ repos_notify_handler(void *baton,
}
}
+svn_error_t *
+svn_repos_dump_fs3(svn_repos_t *repos,
+ svn_stream_t *stream,
+ svn_revnum_t start_rev,
+ svn_revnum_t end_rev,
+ svn_boolean_t incremental,
+ svn_boolean_t use_deltas,
+ svn_repos_notify_func_t notify_func,
+ void *notify_baton,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ apr_pool_t *pool)
+{
+ return svn_error_trace(svn_repos_dump_fs4(repos,
+ stream,
+ start_rev,
+ end_rev,
+ incremental,
+ use_deltas,
+ TRUE,
+ TRUE,
+ notify_func,
+ notify_baton,
+ cancel_func,
+ cancel_baton,
+ pool));
+}
svn_error_t *
svn_repos_dump_fs2(svn_repos_t *repos,
@@ -774,9 +801,9 @@ svn_repos_verify_fs2(svn_repos_t *repos,
end_rev,
FALSE,
FALSE,
- FALSE,
notify_func,
notify_baton,
+ NULL, NULL,
cancel_func,
cancel_baton,
pool));