summaryrefslogtreecommitdiff
path: root/subversion/libsvn_ra_svn
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/libsvn_ra_svn')
-rw-r--r--subversion/libsvn_ra_svn/client.c329
-rw-r--r--subversion/libsvn_ra_svn/cram.c2
-rw-r--r--subversion/libsvn_ra_svn/cyrus_auth.c39
-rw-r--r--subversion/libsvn_ra_svn/deprecated.c49
-rw-r--r--subversion/libsvn_ra_svn/editorp.c120
-rw-r--r--subversion/libsvn_ra_svn/internal_auth.c2
-rw-r--r--subversion/libsvn_ra_svn/libsvn_ra_svn.pc.in12
-rw-r--r--subversion/libsvn_ra_svn/marshal.c900
-rw-r--r--subversion/libsvn_ra_svn/protocol22
-rw-r--r--subversion/libsvn_ra_svn/ra_svn.h29
-rw-r--r--subversion/libsvn_ra_svn/streams.c149
11 files changed, 1103 insertions, 550 deletions
diff --git a/subversion/libsvn_ra_svn/client.c b/subversion/libsvn_ra_svn/client.c
index 335f3215a697c..c83f25db231e3 100644
--- a/subversion/libsvn_ra_svn/client.c
+++ b/subversion/libsvn_ra_svn/client.c
@@ -233,7 +233,7 @@ svn_error_t *svn_ra_svn__auth_response(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
const char *mech, const char *mech_arg)
{
- return svn_ra_svn__write_tuple(conn, pool, "w(?c)", mech, mech_arg);
+ return svn_error_trace(svn_ra_svn__write_tuple(conn, pool, "w(?c)", mech, mech_arg));
}
static svn_error_t *handle_auth_request(svn_ra_svn__session_baton_t *sess,
@@ -368,15 +368,16 @@ ra_svn_get_reporter(svn_ra_svn__session_baton_t *sess_baton,
/* --- RA LAYER IMPLEMENTATION --- */
-/* (Note: *ARGV is an output parameter.) */
+/* (Note: *ARGV_P is an output parameter.) */
static svn_error_t *find_tunnel_agent(const char *tunnel,
const char *hostinfo,
- const char ***argv,
+ const char ***argv_p,
apr_hash_t *config, apr_pool_t *pool)
{
svn_config_t *cfg;
const char *val, *var, *cmd;
char **cmd_argv;
+ const char **argv;
apr_size_t len;
apr_status_t status;
int n;
@@ -430,16 +431,22 @@ static svn_error_t *find_tunnel_agent(const char *tunnel,
if (status != APR_SUCCESS)
return svn_error_wrap_apr(status, _("Can't tokenize command '%s'"), cmd);
- /* Append the fixed arguments to the result. */
+ /* Calc number of the fixed arguments. */
for (n = 0; cmd_argv[n] != NULL; n++)
;
- *argv = apr_palloc(pool, (n + 4) * sizeof(char *));
- memcpy((void *) *argv, cmd_argv, n * sizeof(char *));
- (*argv)[n++] = svn_path_uri_decode(hostinfo, pool);
- (*argv)[n++] = "svnserve";
- (*argv)[n++] = "-t";
- (*argv)[n] = NULL;
+ argv = apr_palloc(pool, (n + 4) * sizeof(char *));
+
+ /* Append the fixed arguments to the result. */
+ for (n = 0; cmd_argv[n] != NULL; n++)
+ argv[n] = cmd_argv[n];
+
+ argv[n++] = svn_path_uri_decode(hostinfo, pool);
+ argv[n++] = "svnserve";
+ argv[n++] = "-t";
+ argv[n] = NULL;
+
+ *argv_p = argv;
return SVN_NO_ERROR;
}
@@ -452,13 +459,17 @@ static void handle_child_process_error(apr_pool_t *pool, apr_status_t status,
{
svn_ra_svn_conn_t *conn;
apr_file_t *in_file, *out_file;
+ svn_stream_t *in_stream, *out_stream;
svn_error_t *err;
if (apr_file_open_stdin(&in_file, pool)
|| apr_file_open_stdout(&out_file, pool))
return;
- conn = svn_ra_svn_create_conn3(NULL, in_file, out_file,
+ in_stream = svn_stream_from_aprfile2(in_file, FALSE, pool);
+ out_stream = svn_stream_from_aprfile2(out_file, FALSE, pool);
+
+ conn = svn_ra_svn_create_conn4(NULL, in_stream, out_stream,
SVN_DELTA_COMPRESSION_LEVEL_DEFAULT, 0,
0, pool);
err = svn_error_wrap_apr(status, _("Error in child process: %s"), desc);
@@ -529,7 +540,11 @@ static svn_error_t *make_tunnel(const char **args, svn_ra_svn_conn_t **conn,
apr_file_inherit_unset(proc->out);
/* Guard against dotfile output to stdout on the server. */
- *conn = svn_ra_svn_create_conn3(NULL, proc->out, proc->in,
+ *conn = svn_ra_svn_create_conn4(NULL,
+ svn_stream_from_aprfile2(proc->out, FALSE,
+ pool),
+ svn_stream_from_aprfile2(proc->in, FALSE,
+ pool),
SVN_DELTA_COMPRESSION_LEVEL_DEFAULT,
0, 0, pool);
err = svn_ra_svn__skip_leading_garbage(*conn, pool);
@@ -556,24 +571,54 @@ static svn_error_t *parse_url(const char *url, apr_uri_t *uri,
return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL,
_("Illegal svn repository URL '%s'"), url);
- if (! uri->port)
- uri->port = SVN_RA_SVN_PORT;
-
return SVN_NO_ERROR;
}
+/* This structure is used as a baton for the pool cleanup function to
+ store tunnel parameters used by the close-tunnel callback. */
+struct tunnel_data_t {
+ void *tunnel_context;
+ void *tunnel_baton;
+ svn_ra_close_tunnel_func_t close_tunnel;
+ svn_stream_t *request;
+ svn_stream_t *response;
+};
+
+/* Pool cleanup function that invokes the close-tunnel callback. */
+static apr_status_t close_tunnel_cleanup(void *baton)
+{
+ const struct tunnel_data_t *const td = baton;
+
+ if (td->close_tunnel)
+ td->close_tunnel(td->tunnel_context, td->tunnel_baton);
+
+ svn_error_clear(svn_stream_close(td->request));
+
+ /* We might have one stream to use for both request and response! */
+ if (td->request != td->response)
+ svn_error_clear(svn_stream_close(td->response));
+
+ return APR_SUCCESS; /* ignored */
+}
+
/* Open a session to URL, returning it in *SESS_P, allocating it in POOL.
URI is a parsed version of URL. CALLBACKS and CALLBACKS_BATON
- are provided by the caller of ra_svn_open. If tunnel_argv is non-null,
- it points to a program argument list to use when invoking the tunnel agent.
+ are provided by the caller of ra_svn_open. If TUNNEL_NAME is not NULL,
+ it is the name of the tunnel type parsed from the URL scheme.
+ If TUNNEL_ARGV is not NULL, it points to a program argument list to use
+ when invoking the tunnel agent.
*/
static svn_error_t *open_session(svn_ra_svn__session_baton_t **sess_p,
const char *url,
const apr_uri_t *uri,
+ const char *tunnel_name,
const char **tunnel_argv,
+ apr_hash_t *config,
const svn_ra_callbacks2_t *callbacks,
void *callbacks_baton,
- apr_pool_t *pool)
+ svn_auth_baton_t *auth_baton,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
svn_ra_svn__session_baton_t *sess;
svn_ra_svn_conn_t *conn;
@@ -581,26 +626,67 @@ static svn_error_t *open_session(svn_ra_svn__session_baton_t **sess_p,
apr_uint64_t minver, maxver;
apr_array_header_t *mechlist, *server_caplist, *repos_caplist;
const char *client_string = NULL;
+ apr_pool_t *pool = result_pool;
sess = apr_palloc(pool, sizeof(*sess));
sess->pool = pool;
- sess->is_tunneled = (tunnel_argv != NULL);
+ sess->is_tunneled = (tunnel_name != NULL);
sess->url = apr_pstrdup(pool, url);
sess->user = uri->user;
sess->hostname = uri->hostname;
- sess->realm_prefix = apr_psprintf(pool, "<svn://%s:%d>", uri->hostname,
- uri->port);
+ sess->tunnel_name = tunnel_name;
sess->tunnel_argv = tunnel_argv;
sess->callbacks = callbacks;
sess->callbacks_baton = callbacks_baton;
sess->bytes_read = sess->bytes_written = 0;
+ sess->auth_baton = auth_baton;
+
+ if (config)
+ SVN_ERR(svn_config_copy_config(&sess->config, config, pool));
+ else
+ sess->config = NULL;
+
+ if (tunnel_name)
+ {
+ sess->realm_prefix = apr_psprintf(pool, "<svn+%s://%s:%d>",
+ tunnel_name,
+ uri->hostname, uri->port);
- if (tunnel_argv)
- SVN_ERR(make_tunnel(tunnel_argv, &conn, pool));
+ if (tunnel_argv)
+ SVN_ERR(make_tunnel(tunnel_argv, &conn, pool));
+ else
+ {
+ struct tunnel_data_t *const td = apr_palloc(pool, sizeof(*td));
+
+ td->tunnel_baton = callbacks->tunnel_baton;
+ td->close_tunnel = NULL;
+
+ SVN_ERR(callbacks->open_tunnel_func(
+ &td->request, &td->response,
+ &td->close_tunnel, &td->tunnel_context,
+ callbacks->tunnel_baton, tunnel_name,
+ uri->user, uri->hostname, uri->port,
+ callbacks->cancel_func, callbacks_baton,
+ pool));
+
+ apr_pool_cleanup_register(pool, td, close_tunnel_cleanup,
+ apr_pool_cleanup_null);
+
+ conn = svn_ra_svn_create_conn4(NULL, td->response, td->request,
+ SVN_DELTA_COMPRESSION_LEVEL_DEFAULT,
+ 0, 0, pool);
+ SVN_ERR(svn_ra_svn__skip_leading_garbage(conn, pool));
+ }
+ }
else
{
- SVN_ERR(make_connection(uri->hostname, uri->port, &sock, pool));
- conn = svn_ra_svn_create_conn3(sock, NULL, NULL,
+ sess->realm_prefix = apr_psprintf(pool, "<svn://%s:%d>", uri->hostname,
+ uri->port ? uri->port : SVN_RA_SVN_PORT);
+
+ SVN_ERR(make_connection(uri->hostname,
+ uri->port ? uri->port : SVN_RA_SVN_PORT,
+ &sock, pool));
+ conn = svn_ra_svn_create_conn4(sock, NULL, NULL,
SVN_DELTA_COMPRESSION_LEVEL_DEFAULT,
0, 0, pool);
}
@@ -618,7 +704,7 @@ static svn_error_t *open_session(svn_ra_svn__session_baton_t **sess_p,
&client_string, pool));
if (client_string)
sess->useragent = apr_pstrcat(pool, SVN_RA_SVN__DEFAULT_USERAGENT " ",
- client_string, (char *)NULL);
+ client_string, SVN_VA_NULL);
else
sess->useragent = SVN_RA_SVN__DEFAULT_USERAGENT;
@@ -722,10 +808,12 @@ static svn_error_t *ra_svn_open(svn_ra_session_t *session,
const char *url,
const svn_ra_callbacks2_t *callbacks,
void *callback_baton,
+ svn_auth_baton_t *auth_baton,
apr_hash_t *config,
- apr_pool_t *pool)
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
- apr_pool_t *sess_pool = svn_pool_create(pool);
+ apr_pool_t *sess_pool = svn_pool_create(result_pool);
svn_ra_svn__session_baton_t *sess;
const char *tunnel, **tunnel_argv;
apr_uri_t uri;
@@ -737,11 +825,18 @@ static svn_error_t *ra_svn_open(svn_ra_session_t *session,
SVN_ERR(parse_url(url, &uri, sess_pool));
- parse_tunnel(url, &tunnel, pool);
+ parse_tunnel(url, &tunnel, result_pool);
- if (tunnel)
+ /* Use the default tunnel implementation if we got a tunnel name,
+ but either do not have tunnel handler callbacks installed, or
+ the handlers don't like the tunnel name. */
+ if (tunnel
+ && (!callbacks->open_tunnel_func
+ || (callbacks->check_tunnel_func && callbacks->open_tunnel_func
+ && !callbacks->check_tunnel_func(callbacks->tunnel_baton,
+ tunnel))))
SVN_ERR(find_tunnel_agent(tunnel, uri.hostinfo, &tunnel_argv, config,
- pool));
+ result_pool));
else
tunnel_argv = NULL;
@@ -749,20 +844,37 @@ static svn_error_t *ra_svn_open(svn_ra_session_t *session,
? svn_hash_gets(config, SVN_CONFIG_CATEGORY_CONFIG)
: NULL;
cfg = config ? svn_hash_gets(config, SVN_CONFIG_CATEGORY_SERVERS) : NULL;
- svn_auth_set_parameter(callbacks->auth_baton,
+ svn_auth_set_parameter(auth_baton,
SVN_AUTH_PARAM_CONFIG_CATEGORY_CONFIG, cfg_client);
- svn_auth_set_parameter(callbacks->auth_baton,
+ svn_auth_set_parameter(auth_baton,
SVN_AUTH_PARAM_CONFIG_CATEGORY_SERVERS, cfg);
/* We open the session in a subpool so we can get rid of it if we
reparent with a server that doesn't support reparenting. */
- SVN_ERR(open_session(&sess, url, &uri, tunnel_argv,
- callbacks, callback_baton, sess_pool));
+ SVN_ERR(open_session(&sess, url, &uri, tunnel, tunnel_argv, config,
+ callbacks, callback_baton,
+ auth_baton, sess_pool, scratch_pool));
session->priv = sess;
return SVN_NO_ERROR;
}
+static svn_error_t *ra_svn_dup_session(svn_ra_session_t *new_session,
+ svn_ra_session_t *old_session,
+ const char *new_session_url,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ svn_ra_svn__session_baton_t *old_sess = old_session->priv;
+
+ SVN_ERR(ra_svn_open(new_session, NULL, new_session_url,
+ old_sess->callbacks, old_sess->callbacks_baton,
+ old_sess->auth_baton, old_sess->config,
+ result_pool, scratch_pool));
+
+ return SVN_NO_ERROR;
+}
+
static svn_error_t *ra_svn_reparent(svn_ra_session_t *ra_session,
const char *url,
apr_pool_t *pool)
@@ -792,8 +904,9 @@ static svn_error_t *ra_svn_reparent(svn_ra_session_t *ra_session,
sess_pool = svn_pool_create(ra_session->pool);
err = parse_url(url, &uri, sess_pool);
if (! err)
- err = open_session(&new_sess, url, &uri, sess->tunnel_argv,
- sess->callbacks, sess->callbacks_baton, sess_pool);
+ err = open_session(&new_sess, url, &uri, sess->tunnel_name, sess->tunnel_argv,
+ sess->config, sess->callbacks, sess->callbacks_baton,
+ sess->auth_baton, sess_pool, sess_pool);
/* We destroy the new session pool on error, since it is allocated in
the main session pool. */
if (err)
@@ -954,6 +1067,9 @@ static svn_error_t *ra_svn_end_commit(void *baton)
&(commit_info->author),
&(commit_info->post_commit_err)));
+ commit_info->repos_root = apr_pstrdup(ccb->pool,
+ ccb->sess_baton->conn->repos_root);
+
if (ccb->callback)
SVN_ERR(ccb->callback(commit_info, ccb->callback_baton, ccb->pool));
@@ -986,11 +1102,11 @@ static svn_error_t *ra_svn_commit(svn_ra_session_t *session,
"a log message with pre-1.5 servers; "
"consider passing an empty one, or upgrading "
"the server"));
- }
+ }
else if (log_msg == NULL)
/* 1.5+ server. Set LOG_MSG to something, since the 'logmsg' argument
to the 'commit' protocol command is non-optional; on the server side,
- only REVPROP_TABLE will be used, and LOG_MSG will be ignored. The
+ only REVPROP_TABLE will be used, and LOG_MSG will be ignored. The
"svn:log" member of REVPROP_TABLE table is NULL, therefore the commit
will have a NULL log message (not just "", really NULL).
@@ -1118,13 +1234,13 @@ parse_iproplist(apr_array_header_t **inherited_props,
new_iprop->path_or_url = svn_path_url_add_component2(repos_root_url,
parent_rel_path,
result_pool);
- new_iprop->prop_hash = apr_hash_make(result_pool);
+ new_iprop->prop_hash = svn_hash__make(result_pool);
for (hi = apr_hash_first(iterpool, iprops);
hi;
hi = apr_hash_next(hi))
{
- const char *name = svn__apr_hash_index_key(hi);
- svn_string_t *value = svn__apr_hash_index_val(hi);
+ const char *name = apr_hash_this_key(hi);
+ svn_string_t *value = apr_hash_this_val(hi);
svn_hash_sets(new_iprop->prop_hash,
apr_pstrdup(result_pool, name),
svn_string_dup(value, result_pool));
@@ -1241,7 +1357,10 @@ static svn_error_t *ra_svn_get_dir(svn_ra_session_t *session,
if (dirent_fields & SVN_DIRENT_LAST_AUTHOR)
SVN_ERR(svn_ra_svn__write_word(conn, pool, SVN_RA_SVN_DIRENT_LAST_AUTHOR));
- SVN_ERR(svn_ra_svn__write_tuple(conn, pool, "!))"));
+ /* Always send the, nominally optional, want-iprops as "false" to
+ workaround a bug in svnserve 1.8.0-1.8.8 that causes the server
+ to see "true" if it is omitted. */
+ SVN_ERR(svn_ra_svn__write_tuple(conn, pool, "!)b)", FALSE));
SVN_ERR(handle_auth_request(sess_baton, pool));
SVN_ERR(svn_ra_svn__read_cmd_response(conn, pool, "rll", &rev, &proplist,
@@ -1257,7 +1376,7 @@ static svn_error_t *ra_svn_get_dir(svn_ra_session_t *session,
return SVN_NO_ERROR;
/* Interpret the directory list. */
- *dirents = apr_hash_make(pool);
+ *dirents = svn_hash__make(pool);
for (i = 0; i < dirlist->nelts; i++)
{
const char *name, *kind, *cdate, *cauthor;
@@ -1273,7 +1392,14 @@ static svn_error_t *ra_svn_get_dir(svn_ra_session_t *session,
SVN_ERR(svn_ra_svn__parse_tuple(elt->u.list, pool, "cwnbr(?c)(?c)",
&name, &kind, &size, &has_props,
&crev, &cdate, &cauthor));
- name = svn_relpath_canonicalize(name, pool);
+
+ /* Nothing to sanitize here. Any multi-segment path is simply
+ illegal in the hash returned by svn_ra_get_dir2. */
+ if (strchr(name, '/'))
+ return svn_error_createf(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
+ _("Invalid directory entry name '%s'"),
+ name);
+
dirent = svn_dirent_create(pool);
dirent->kind = svn_node_kind_from_word(kind);
dirent->size = size;/* FIXME: svn_filesize_t */
@@ -1345,7 +1471,7 @@ static svn_error_t *ra_svn_get_mergeinfo(svn_ra_session_t *session,
*catalog = NULL;
if (mergeinfo_tuple->nelts > 0)
{
- *catalog = apr_hash_make(pool);
+ *catalog = svn_hash__make(pool);
for (i = 0; i < mergeinfo_tuple->nelts; i++)
{
svn_mergeinfo_t for_path;
@@ -1501,6 +1627,10 @@ perform_ra_svn_log(svn_error_t **outer_error,
const char *path;
char *name;
svn_boolean_t want_custom_revprops;
+ svn_boolean_t want_author = FALSE;
+ svn_boolean_t want_message = FALSE;
+ svn_boolean_t want_date = FALSE;
+ int nreceived = 0;
SVN_ERR(svn_ra_svn__write_tuple(conn, pool, "w((!", "log"));
if (paths)
@@ -1523,10 +1653,14 @@ perform_ra_svn_log(svn_error_t **outer_error,
{
name = APR_ARRAY_IDX(revprops, i, char *);
SVN_ERR(svn_ra_svn__write_cstring(conn, pool, name));
- if (!want_custom_revprops
- && strcmp(name, SVN_PROP_REVISION_AUTHOR) != 0
- && strcmp(name, SVN_PROP_REVISION_DATE) != 0
- && strcmp(name, SVN_PROP_REVISION_LOG) != 0)
+
+ if (strcmp(name, SVN_PROP_REVISION_AUTHOR) == 0)
+ want_author = TRUE;
+ else if (strcmp(name, SVN_PROP_REVISION_DATE) == 0)
+ want_date = TRUE;
+ else if (strcmp(name, SVN_PROP_REVISION_LOG) == 0)
+ want_message = TRUE;
+ else
want_custom_revprops = TRUE;
}
SVN_ERR(svn_ra_svn__write_tuple(conn, pool, "!))"));
@@ -1534,6 +1668,10 @@ perform_ra_svn_log(svn_error_t **outer_error,
else
{
SVN_ERR(svn_ra_svn__write_tuple(conn, pool, "!w())", "all-revprops"));
+
+ want_author = TRUE;
+ want_date = TRUE;
+ want_message = TRUE;
want_custom_revprops = TRUE;
}
@@ -1554,7 +1692,6 @@ perform_ra_svn_log(svn_error_t **outer_error,
svn_ra_svn_item_t *item;
apr_hash_t *cphash;
svn_revnum_t rev;
- int nreceived;
svn_pool_clear(iterpool);
SVN_ERR(svn_ra_svn__read_item(conn, iterpool, &item));
@@ -1597,11 +1734,12 @@ perform_ra_svn_log(svn_error_t **outer_error,
if (cplist->nelts > 0)
{
/* Interpret the changed-paths list. */
- cphash = apr_hash_make(iterpool);
+ cphash = svn_hash__make(iterpool);
for (i = 0; i < cplist->nelts; i++)
{
svn_log_changed_path2_t *change;
- const char *copy_path, *action, *cpath, *kind_str;
+ svn_string_t *cpath;
+ const char *copy_path, *action, *kind_str;
apr_uint64_t text_mods, prop_mods;
svn_revnum_t copy_rev;
svn_ra_svn_item_t *elt = &APR_ARRAY_IDX(cplist, i,
@@ -1610,14 +1748,19 @@ perform_ra_svn_log(svn_error_t **outer_error,
if (elt->kind != SVN_RA_SVN_LIST)
return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
_("Changed-path entry not a list"));
- SVN_ERR(svn_ra_svn__parse_tuple(elt->u.list, iterpool,
- "cw(?cr)?(?c?BB)",
+ SVN_ERR(svn_ra_svn__read_data_log_changed_entry(elt->u.list,
&cpath, &action, &copy_path,
&copy_rev, &kind_str,
&text_mods, &prop_mods));
- cpath = svn_fspath__canonicalize(cpath, iterpool);
- if (copy_path)
+
+ if (!svn_fspath__is_canonical(cpath->data))
+ {
+ cpath->data = svn_fspath__canonicalize(cpath->data, iterpool);
+ cpath->len = strlen(cpath->data);
+ }
+ if (copy_path && !svn_fspath__is_canonical(copy_path))
copy_path = svn_fspath__canonicalize(copy_path, iterpool);
+
change = svn_log_changed_path2_create(iterpool);
change->action = *action;
change->copyfrom_path = copy_path;
@@ -1625,13 +1768,16 @@ perform_ra_svn_log(svn_error_t **outer_error,
change->node_kind = svn_node_kind_from_word(kind_str);
change->text_modified = optbool_to_tristate(text_mods);
change->props_modified = optbool_to_tristate(prop_mods);
- svn_hash_sets(cphash, cpath, change);
+ apr_hash_set(cphash, cpath->data, cpath->len, change);
}
}
else
cphash = NULL;
- nreceived = 0;
+ /* Invoke RECEIVER
+ - Except if the server sends more than a >= 1 limit top level items
+ - Or when the callback reported a SVN_ERR_CEASE_INVOCATION
+ in an earlier invocation. */
if (! (limit && (nest_level == 0) && (++nreceived > limit))
&& ! *outer_error)
{
@@ -1647,37 +1793,18 @@ perform_ra_svn_log(svn_error_t **outer_error,
SVN_ERR(svn_ra_svn__parse_proplist(rplist, iterpool,
&log_entry->revprops));
if (log_entry->revprops == NULL)
- log_entry->revprops = apr_hash_make(iterpool);
- if (revprops == NULL)
- {
- /* Caller requested all revprops; set author/date/log. */
- if (author)
- svn_hash_sets(log_entry->revprops, SVN_PROP_REVISION_AUTHOR,
- author);
- if (date)
- svn_hash_sets(log_entry->revprops, SVN_PROP_REVISION_DATE,
- date);
- if (message)
- svn_hash_sets(log_entry->revprops, SVN_PROP_REVISION_LOG,
- message);
- }
- else
- {
- /* Caller requested some; maybe set author/date/log. */
- for (i = 0; i < revprops->nelts; i++)
- {
- name = APR_ARRAY_IDX(revprops, i, char *);
- if (author && strcmp(name, SVN_PROP_REVISION_AUTHOR) == 0)
- svn_hash_sets(log_entry->revprops,
- SVN_PROP_REVISION_AUTHOR, author);
- if (date && strcmp(name, SVN_PROP_REVISION_DATE) == 0)
- svn_hash_sets(log_entry->revprops,
- SVN_PROP_REVISION_DATE, date);
- if (message && strcmp(name, SVN_PROP_REVISION_LOG) == 0)
- svn_hash_sets(log_entry->revprops,
- SVN_PROP_REVISION_LOG, message);
- }
- }
+ log_entry->revprops = svn_hash__make(iterpool);
+
+ if (author && want_author)
+ svn_hash_sets(log_entry->revprops,
+ SVN_PROP_REVISION_AUTHOR, author);
+ if (date && want_date)
+ svn_hash_sets(log_entry->revprops,
+ SVN_PROP_REVISION_DATE, date);
+ if (message && want_message)
+ svn_hash_sets(log_entry->revprops,
+ SVN_PROP_REVISION_LOG, message);
+
err = receiver(receiver_baton, log_entry, iterpool);
if (err && err->apr_err == SVN_ERR_CEASE_INVOCATION)
{
@@ -1863,7 +1990,7 @@ static svn_error_t *ra_svn_get_locations(svn_ra_session_t *session,
/* Read the response. This is so the server would have a chance to
* report an error. */
- return svn_ra_svn__read_cmd_response(conn, pool, "");
+ return svn_error_trace(svn_ra_svn__read_cmd_response(conn, pool, ""));
}
static svn_error_t *
@@ -2009,7 +2136,7 @@ static svn_error_t *ra_svn_get_file_revs(svn_ra_session_t *session,
{
svn_stream_t *stream;
- if (d_handler)
+ if (d_handler && d_handler != svn_delta_noop_window_handler)
stream = svn_txdelta_parse_svndiff(d_handler, d_baton, TRUE,
rev_pool);
else
@@ -2552,7 +2679,7 @@ static svn_error_t *ra_svn_replay(svn_ra_session_t *session,
SVN_ERR(svn_ra_svn_drive_editor2(sess->conn, pool, editor, edit_baton,
NULL, TRUE));
- return svn_ra_svn__read_cmd_response(sess->conn, pool, "");
+ return svn_error_trace(svn_ra_svn__read_cmd_response(sess->conn, pool, ""));
}
@@ -2621,7 +2748,7 @@ ra_svn_replay_range(svn_ra_session_t *session,
}
svn_pool_destroy(iterpool);
- return svn_ra_svn__read_cmd_response(sess->conn, pool, "");
+ return svn_error_trace(svn_ra_svn__read_cmd_response(sess->conn, pool, ""));
}
@@ -2687,7 +2814,8 @@ ra_svn_get_deleted_rev(svn_ra_session_t *session,
SVN_ERR(handle_unsupported_cmd(handle_auth_request(sess_baton, pool),
N_("'get-deleted-rev' not implemented")));
- return svn_ra_svn__read_cmd_response(conn, pool, "r", revision_deleted);
+ return svn_error_trace(svn_ra_svn__read_cmd_response(conn, pool, "r",
+ revision_deleted));
}
static svn_error_t *
@@ -2713,6 +2841,16 @@ ra_svn_get_inherited_props(svn_ra_session_t *session,
svn_ra_svn__session_baton_t *sess_baton = session->priv;
svn_ra_svn_conn_t *conn = sess_baton->conn;
apr_array_header_t *iproplist;
+ svn_boolean_t iprop_capable;
+
+ SVN_ERR(ra_svn_has_capability(session, &iprop_capable,
+ SVN_RA_CAPABILITY_INHERITED_PROPS,
+ scratch_pool));
+
+ /* If we don't support native iprop handling, use the implementation
+ in libsvn_ra */
+ if (!iprop_capable)
+ return svn_error_create(SVN_ERR_RA_NOT_IMPLEMENTED, NULL, NULL);
SVN_ERR(svn_ra_svn__write_cmd_get_iprops(conn, scratch_pool,
path, revision));
@@ -2729,6 +2867,7 @@ static const svn_ra__vtable_t ra_svn_vtable = {
ra_svn_get_description,
ra_svn_get_schemes,
ra_svn_open,
+ ra_svn_dup_session,
ra_svn_reparent,
ra_svn_get_session_url,
ra_svn_get_latest_rev,
diff --git a/subversion/libsvn_ra_svn/cram.c b/subversion/libsvn_ra_svn/cram.c
index 1e54ac812e986..b92f37b4a1727 100644
--- a/subversion/libsvn_ra_svn/cram.c
+++ b/subversion/libsvn_ra_svn/cram.c
@@ -114,7 +114,7 @@ static svn_error_t *fail(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
const char *msg)
{
SVN_ERR(svn_ra_svn__write_tuple(conn, pool, "w(c)", "failure", msg));
- return svn_ra_svn__flush(conn, pool);
+ return svn_error_trace(svn_ra_svn__flush(conn, pool));
}
/* If we can, make the nonce with random bytes. If we can't... well,
diff --git a/subversion/libsvn_ra_svn/cyrus_auth.c b/subversion/libsvn_ra_svn/cyrus_auth.c
index 82e33d364274b..ac94a485a44fd 100644
--- a/subversion/libsvn_ra_svn/cyrus_auth.c
+++ b/subversion/libsvn_ra_svn/cyrus_auth.c
@@ -488,7 +488,7 @@ static svn_error_t *try_auth(svn_ra_svn__session_baton_t *sess,
pmech - mechstring);
const char *tail = pmech + strlen(mech);
- mechstring = apr_pstrcat(pool, head, tail, (char *)NULL);
+ mechstring = apr_pstrcat(pool, head, tail, SVN_VA_NULL);
again = TRUE;
}
}
@@ -704,11 +704,13 @@ static void sasl_timeout_cb(void *baton, apr_interval_time_t interval)
svn_ra_svn__stream_timeout(sasl_baton->stream, interval);
}
-/* Implements ra_svn_pending_fn_t. */
-static svn_boolean_t sasl_pending_cb(void *baton)
+/* Implements svn_stream_data_available_fn_t. */
+static svn_error_t *
+sasl_data_available_cb(void *baton, svn_boolean_t *data_available)
{
sasl_baton_t *sasl_baton = baton;
- return svn_ra_svn__stream_pending(sasl_baton->stream);
+ return svn_error_trace(svn_ra_svn__stream_data_available(sasl_baton->stream,
+ data_available));
}
svn_error_t *svn_ra_svn__enable_sasl_encryption(svn_ra_svn_conn_t *conn,
@@ -766,10 +768,19 @@ svn_error_t *svn_ra_svn__enable_sasl_encryption(svn_ra_svn_conn_t *conn,
/* Wrap the existing stream. */
sasl_baton->stream = conn->stream;
- conn->stream = svn_ra_svn__stream_create(sasl_baton, sasl_read_cb,
- sasl_write_cb,
- sasl_timeout_cb,
- sasl_pending_cb, conn->pool);
+ {
+ svn_stream_t *sasl_in = svn_stream_create(sasl_baton, conn->pool);
+ svn_stream_t *sasl_out = svn_stream_create(sasl_baton, conn->pool);
+
+ svn_stream_set_read2(sasl_in, sasl_read_cb, NULL /* use default */);
+ svn_stream_set_data_available(sasl_in, sasl_data_available_cb);
+ svn_stream_set_write(sasl_out, sasl_write_cb);
+
+ conn->stream = svn_ra_svn__stream_create(sasl_in, sasl_out,
+ sasl_baton,
+ sasl_timeout_cb,
+ conn->pool);
+ }
/* Yay, we have a security layer! */
conn->encrypted = TRUE;
}
@@ -807,10 +818,10 @@ svn_error_t *svn_ra_svn__get_addresses(const char **local_addrport,
/* Format the IP address and port number like this: a.b.c.d;port */
*local_addrport = apr_pstrcat(pool, local_addr, ";",
apr_itoa(pool, (int)local_sa->port),
- (char *)NULL);
+ SVN_VA_NULL);
*remote_addrport = apr_pstrcat(pool, remote_addr, ";",
apr_itoa(pool, (int)remote_sa->port),
- (char *)NULL);
+ SVN_VA_NULL);
}
return SVN_NO_ERROR;
}
@@ -849,14 +860,14 @@ svn_ra_svn__do_cyrus_auth(svn_ra_svn__session_baton_t *sess,
mechstring = apr_pstrcat(pool,
mechstring,
i == 0 ? "" : " ",
- elt->u.word, (char *)NULL);
+ elt->u.word, SVN_VA_NULL);
}
}
realmstring = apr_psprintf(pool, "%s %s", sess->realm_prefix, realm);
/* Initialize the credential baton. */
- cred_baton.auth_baton = sess->callbacks->auth_baton;
+ cred_baton.auth_baton = sess->auth_baton;
cred_baton.realmstring = realmstring;
cred_baton.pool = pool;
@@ -935,8 +946,8 @@ svn_ra_svn__do_cyrus_auth(svn_ra_svn__session_baton_t *sess,
the CRAM-MD5 or ANONYMOUS plugins, in which case we can simply use
the built-in implementation. In all other cases this call will be
useless, but hey, at least we'll get consistent error messages. */
- return svn_ra_svn__do_internal_auth(sess, mechlist,
- realm, pool);
+ return svn_error_trace(svn_ra_svn__do_internal_auth(sess, mechlist,
+ realm, pool));
}
return err;
}
diff --git a/subversion/libsvn_ra_svn/deprecated.c b/subversion/libsvn_ra_svn/deprecated.c
index 8182a4d5a0d88..ad2ad5839a0e1 100644
--- a/subversion/libsvn_ra_svn/deprecated.c
+++ b/subversion/libsvn_ra_svn/deprecated.c
@@ -21,6 +21,10 @@
* ====================================================================
*/
+/* We define this here to remove any further warnings about the usage of
+ deprecated functions in this file. */
+#define SVN_DEPRECATED
+
#include "svn_ra_svn.h"
#include "private/svn_ra_svn_private.h"
@@ -232,3 +236,48 @@ svn_ra_svn_write_cmd_failure(svn_ra_svn_conn_t *conn,
{
return svn_error_trace(svn_ra_svn__write_cmd_failure(conn, pool, err));
}
+
+/* From marshal.c */
+svn_ra_svn_conn_t *
+svn_ra_svn_create_conn3(apr_socket_t *sock,
+ apr_file_t *in_file,
+ apr_file_t *out_file,
+ int compression_level,
+ apr_size_t zero_copy_limit,
+ apr_size_t error_check_interval,
+ apr_pool_t *pool)
+{
+ svn_stream_t *in_stream = NULL;
+ svn_stream_t *out_stream = NULL;
+
+ if (in_file)
+ in_stream = svn_stream_from_aprfile2(in_file, FALSE, pool);
+ if (out_file)
+ out_stream = svn_stream_from_aprfile2(out_file, FALSE, pool);
+
+ return svn_ra_svn_create_conn4(sock, in_stream, out_stream,
+ compression_level, 0, 0, pool);
+}
+
+svn_ra_svn_conn_t *
+svn_ra_svn_create_conn2(apr_socket_t *sock,
+ apr_file_t *in_file,
+ apr_file_t *out_file,
+ int compression_level,
+ apr_pool_t *pool)
+{
+ return svn_ra_svn_create_conn3(sock, in_file, out_file,
+ compression_level, 0, 0, pool);
+}
+
+/* backward-compatible implementation using the default compression level */
+svn_ra_svn_conn_t *
+svn_ra_svn_create_conn(apr_socket_t *sock,
+ apr_file_t *in_file,
+ apr_file_t *out_file,
+ apr_pool_t *pool)
+{
+ return svn_ra_svn_create_conn3(sock, in_file, out_file,
+ SVN_DELTA_COMPRESSION_LEVEL_DEFAULT, 0, 0,
+ pool);
+}
diff --git a/subversion/libsvn_ra_svn/editorp.c b/subversion/libsvn_ra_svn/editorp.c
index cc1d8ab2fd21a..88af89859fc48 100644
--- a/subversion/libsvn_ra_svn/editorp.c
+++ b/subversion/libsvn_ra_svn/editorp.c
@@ -91,7 +91,7 @@ typedef struct ra_svn_driver_state_t {
different purpose instead: at apply-textdelta time, we set it to a
subpool of the file pool, which is destroyed in textdelta-end. */
typedef struct ra_svn_token_entry_t {
- const char *token;
+ svn_string_t *token;
void *baton;
svn_boolean_t is_file;
svn_stream_t *dstream; /* svndiff stream for apply_textdelta */
@@ -126,6 +126,7 @@ static ra_svn_baton_t *ra_svn_make_baton(svn_ra_svn_conn_t *conn,
static svn_error_t *
check_for_error_internal(ra_svn_edit_baton_t *eb, apr_pool_t *pool)
{
+ svn_boolean_t available;
SVN_ERR_ASSERT(!eb->got_status);
/* reset TX counter */
@@ -135,7 +136,8 @@ check_for_error_internal(ra_svn_edit_baton_t *eb, apr_pool_t *pool)
eb->conn->may_check_for_error = eb->conn->error_check_interval == 0;
/* any incoming data? */
- if (svn_ra_svn__input_waiting(eb->conn, pool))
+ SVN_ERR(svn_ra_svn__data_available(eb->conn, &available));
+ if (available)
{
eb->got_status = TRUE;
SVN_ERR(svn_ra_svn__write_cmd_abort_edit(eb->conn, pool));
@@ -393,11 +395,13 @@ static svn_error_t *ra_svn_close_edit(void *edit_baton, apr_pool_t *pool)
SVN_ERR_ASSERT(!eb->got_status);
eb->got_status = TRUE;
SVN_ERR(svn_ra_svn__write_cmd_close_edit(eb->conn, pool));
- err = svn_ra_svn__read_cmd_response(eb->conn, pool, "");
+ err = svn_error_trace(svn_ra_svn__read_cmd_response(eb->conn, pool, ""));
if (err)
{
- svn_error_clear(svn_ra_svn__write_cmd_abort_edit(eb->conn, pool));
- return err;
+ return svn_error_compose_create(
+ err,
+ svn_error_trace(
+ svn_ra_svn__write_cmd_abort_edit(eb->conn, pool)));
}
if (eb->callback)
SVN_ERR(eb->callback(eb->callback_baton));
@@ -461,27 +465,31 @@ void svn_ra_svn_get_editor(const svn_delta_editor_t **editor,
/* Store a token entry. The token string will be copied into pool. */
static ra_svn_token_entry_t *store_token(ra_svn_driver_state_t *ds,
- void *baton, const char *token,
+ void *baton,
+ svn_string_t *token,
svn_boolean_t is_file,
apr_pool_t *pool)
{
ra_svn_token_entry_t *entry;
entry = apr_palloc(pool, sizeof(*entry));
- entry->token = apr_pstrdup(pool, token);
+ entry->token = svn_string_dup(token, pool);
entry->baton = baton;
entry->is_file = is_file;
entry->dstream = NULL;
entry->pool = pool;
- svn_hash_sets(ds->tokens, entry->token, entry);
+
+ apr_hash_set(ds->tokens, entry->token->data, entry->token->len, entry);
+
return entry;
}
-static svn_error_t *lookup_token(ra_svn_driver_state_t *ds, const char *token,
+static svn_error_t *lookup_token(ra_svn_driver_state_t *ds,
+ svn_string_t *token,
svn_boolean_t is_file,
ra_svn_token_entry_t **entry)
{
- *entry = svn_hash_gets(ds->tokens, token);
+ *entry = apr_hash_get(ds->tokens, token->data, token->len);
if (!*entry || (*entry)->is_file != is_file)
return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
_("Invalid file or dir token during edit"));
@@ -507,10 +515,10 @@ static svn_error_t *ra_svn_handle_open_root(svn_ra_svn_conn_t *conn,
{
svn_revnum_t rev;
apr_pool_t *subpool;
- const char *token;
+ svn_string_t *token;
void *root_baton;
- SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "(?r)c", &rev, &token));
+ SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "(?r)s", &rev, &token));
subpool = svn_pool_create(ds->pool);
SVN_CMD_ERR(ds->editor->open_root(ds->edit_baton, rev, subpool,
&root_baton));
@@ -523,11 +531,12 @@ static svn_error_t *ra_svn_handle_delete_entry(svn_ra_svn_conn_t *conn,
const apr_array_header_t *params,
ra_svn_driver_state_t *ds)
{
- const char *path, *token;
+ const char *path;
+ svn_string_t *token;
svn_revnum_t rev;
ra_svn_token_entry_t *entry;
- SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "c(?r)c",
+ SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "c(?r)s",
&path, &rev, &token));
SVN_ERR(lookup_token(ds, token, FALSE, &entry));
path = svn_relpath_canonicalize(path, pool);
@@ -540,13 +549,14 @@ static svn_error_t *ra_svn_handle_add_dir(svn_ra_svn_conn_t *conn,
const apr_array_header_t *params,
ra_svn_driver_state_t *ds)
{
- const char *path, *token, *child_token, *copy_path;
+ const char *path, *copy_path;
+ svn_string_t *token, *child_token;
svn_revnum_t copy_rev;
ra_svn_token_entry_t *entry;
apr_pool_t *subpool;
void *child_baton;
- SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "ccc(?cr)", &path, &token,
+ SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "css(?cr)", &path, &token,
&child_token, &copy_path, &copy_rev));
SVN_ERR(lookup_token(ds, token, FALSE, &entry));
subpool = svn_pool_create(entry->pool);
@@ -573,13 +583,14 @@ static svn_error_t *ra_svn_handle_open_dir(svn_ra_svn_conn_t *conn,
const apr_array_header_t *params,
ra_svn_driver_state_t *ds)
{
- const char *path, *token, *child_token;
+ const char *path;
+ svn_string_t *token, *child_token;
svn_revnum_t rev;
ra_svn_token_entry_t *entry;
apr_pool_t *subpool;
void *child_baton;
- SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "ccc(?r)", &path, &token,
+ SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "css(?r)", &path, &token,
&child_token, &rev));
SVN_ERR(lookup_token(ds, token, FALSE, &entry));
subpool = svn_pool_create(entry->pool);
@@ -595,11 +606,12 @@ static svn_error_t *ra_svn_handle_change_dir_prop(svn_ra_svn_conn_t *conn,
const apr_array_header_t *params,
ra_svn_driver_state_t *ds)
{
- const char *token, *name;
+ svn_string_t *token;
+ const char *name;
svn_string_t *value;
ra_svn_token_entry_t *entry;
- SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "cc(?s)", &token, &name,
+ SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "sc(?s)", &token, &name,
&value));
SVN_ERR(lookup_token(ds, token, FALSE, &entry));
SVN_CMD_ERR(ds->editor->change_dir_prop(entry->baton, name, value,
@@ -612,16 +624,16 @@ static svn_error_t *ra_svn_handle_close_dir(svn_ra_svn_conn_t *conn,
const apr_array_header_t *params,
ra_svn_driver_state_t *ds)
{
- const char *token;
+ svn_string_t *token;
ra_svn_token_entry_t *entry;
/* Parse and look up the directory token. */
- SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "c", &token));
+ SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "s", &token));
SVN_ERR(lookup_token(ds, token, FALSE, &entry));
/* Close the directory and destroy the baton. */
SVN_CMD_ERR(ds->editor->close_directory(entry->baton, pool));
- svn_hash_sets(ds->tokens, token, NULL);
+ apr_hash_set(ds->tokens, token->data, token->len, NULL);
svn_pool_destroy(entry->pool);
return SVN_NO_ERROR;
}
@@ -632,11 +644,11 @@ static svn_error_t *ra_svn_handle_absent_dir(svn_ra_svn_conn_t *conn,
ra_svn_driver_state_t *ds)
{
const char *path;
- const char *token;
+ svn_string_t *token;
ra_svn_token_entry_t *entry;
/* Parse parameters and look up the directory token. */
- SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "cc", &path, &token));
+ SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "cs", &path, &token));
SVN_ERR(lookup_token(ds, token, FALSE, &entry));
/* Call the editor. */
@@ -649,15 +661,19 @@ static svn_error_t *ra_svn_handle_add_file(svn_ra_svn_conn_t *conn,
const apr_array_header_t *params,
ra_svn_driver_state_t *ds)
{
- const char *path, *token, *file_token, *copy_path;
+ const char *path, *copy_path;
+ svn_string_t *token, *file_token;
svn_revnum_t copy_rev;
ra_svn_token_entry_t *entry, *file_entry;
- SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "ccc(?cr)", &path, &token,
+ SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "css(?cr)", &path, &token,
&file_token, &copy_path, &copy_rev));
SVN_ERR(lookup_token(ds, token, FALSE, &entry));
ds->file_refs++;
- path = svn_relpath_canonicalize(path, pool);
+
+ /* The PATH should be canonical .. but never trust incoming data. */
+ if (!svn_relpath_is_canonical(path))
+ path = svn_relpath_canonicalize(path, pool);
/* Some operations pass COPY_PATH as a full URL (commits, etc.).
Others (replay, e.g.) deliver an fspath. That's ... annoying. */
@@ -680,15 +696,20 @@ static svn_error_t *ra_svn_handle_open_file(svn_ra_svn_conn_t *conn,
const apr_array_header_t *params,
ra_svn_driver_state_t *ds)
{
- const char *path, *token, *file_token;
+ const char *path;
+ svn_string_t *token, *file_token;
svn_revnum_t rev;
ra_svn_token_entry_t *entry, *file_entry;
- SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "ccc(?r)", &path, &token,
+ SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "css(?r)", &path, &token,
&file_token, &rev));
SVN_ERR(lookup_token(ds, token, FALSE, &entry));
ds->file_refs++;
- path = svn_relpath_canonicalize(path, pool);
+
+ /* The PATH should be canonical .. but never trust incoming data. */
+ if (!svn_relpath_is_canonical(path))
+ path = svn_relpath_canonicalize(path, pool);
+
file_entry = store_token(ds, NULL, file_token, TRUE, ds->file_pool);
SVN_CMD_ERR(ds->editor->open_file(path, entry->baton, rev, ds->file_pool,
&file_entry->baton));
@@ -700,14 +721,14 @@ static svn_error_t *ra_svn_handle_apply_textdelta(svn_ra_svn_conn_t *conn,
const apr_array_header_t *params,
ra_svn_driver_state_t *ds)
{
- const char *token;
+ svn_string_t *token;
ra_svn_token_entry_t *entry;
svn_txdelta_window_handler_t wh;
void *wh_baton;
char *base_checksum;
/* Parse arguments and look up the token. */
- SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "c(?c)",
+ SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "s(?c)",
&token, &base_checksum));
SVN_ERR(lookup_token(ds, token, TRUE, &entry));
if (entry->dstream)
@@ -725,12 +746,12 @@ static svn_error_t *ra_svn_handle_textdelta_chunk(svn_ra_svn_conn_t *conn,
const apr_array_header_t *params,
ra_svn_driver_state_t *ds)
{
- const char *token;
+ svn_string_t *token;
ra_svn_token_entry_t *entry;
svn_string_t *str;
/* Parse arguments and look up the token. */
- SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "cs", &token, &str));
+ SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "ss", &token, &str));
SVN_ERR(lookup_token(ds, token, TRUE, &entry));
if (!entry->dstream)
return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
@@ -744,11 +765,11 @@ static svn_error_t *ra_svn_handle_textdelta_end(svn_ra_svn_conn_t *conn,
const apr_array_header_t *params,
ra_svn_driver_state_t *ds)
{
- const char *token;
+ svn_string_t *token;
ra_svn_token_entry_t *entry;
/* Parse arguments and look up the token. */
- SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "c", &token));
+ SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "s", &token));
SVN_ERR(lookup_token(ds, token, TRUE, &entry));
if (!entry->dstream)
return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
@@ -764,11 +785,11 @@ static svn_error_t *ra_svn_handle_change_file_prop(svn_ra_svn_conn_t *conn,
const apr_array_header_t *params,
ra_svn_driver_state_t *ds)
{
- const char *token, *name;
- svn_string_t *value;
+ const char *name;
+ svn_string_t *token, *value;
ra_svn_token_entry_t *entry;
- SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "cc(?s)", &token, &name,
+ SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "sc(?s)", &token, &name,
&value));
SVN_ERR(lookup_token(ds, token, TRUE, &entry));
SVN_CMD_ERR(ds->editor->change_file_prop(entry->baton, name, value, pool));
@@ -780,18 +801,18 @@ static svn_error_t *ra_svn_handle_close_file(svn_ra_svn_conn_t *conn,
const apr_array_header_t *params,
ra_svn_driver_state_t *ds)
{
- const char *token;
+ svn_string_t *token;
ra_svn_token_entry_t *entry;
const char *text_checksum;
/* Parse arguments and look up the file token. */
- SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "c(?c)",
+ SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "s(?c)",
&token, &text_checksum));
SVN_ERR(lookup_token(ds, token, TRUE, &entry));
/* Close the file and destroy the baton. */
SVN_CMD_ERR(ds->editor->close_file(entry->baton, text_checksum, pool));
- svn_hash_sets(ds->tokens, token, NULL);
+ apr_hash_set(ds->tokens, token->data, token->len, NULL);
if (--ds->file_refs == 0)
svn_pool_clear(ds->file_pool);
return SVN_NO_ERROR;
@@ -803,11 +824,11 @@ static svn_error_t *ra_svn_handle_absent_file(svn_ra_svn_conn_t *conn,
ra_svn_driver_state_t *ds)
{
const char *path;
- const char *token;
+ svn_string_t *token;
ra_svn_token_entry_t *entry;
/* Parse parameters and look up the parent directory token. */
- SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "cc", &path, &token));
+ SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "cs", &path, &token));
SVN_ERR(lookup_token(ds, token, FALSE, &entry));
/* Call the editor. */
@@ -978,7 +999,12 @@ svn_error_t *svn_ra_svn_drive_editor2(svn_ra_svn_conn_t *conn,
{
/* Abort the edit and use non-blocking I/O to write the error. */
if (editor)
- svn_error_clear(editor->abort_edit(edit_baton, subpool));
+ {
+ err = svn_error_compose_create(
+ err,
+ svn_error_trace(editor->abort_edit(edit_baton,
+ subpool)));
+ }
svn_ra_svn__set_block_handler(conn, blocked_write, &state);
}
write_err = svn_ra_svn__write_cmd_failure(
@@ -987,7 +1013,7 @@ svn_error_t *svn_ra_svn_drive_editor2(svn_ra_svn_conn_t *conn,
if (!write_err)
write_err = svn_ra_svn__flush(conn, subpool);
svn_ra_svn__set_block_handler(conn, NULL, NULL);
- svn_error_clear(err);
+ svn_error_clear(err); /* We just sent this error */
SVN_ERR(write_err);
break;
}
diff --git a/subversion/libsvn_ra_svn/internal_auth.c b/subversion/libsvn_ra_svn/internal_auth.c
index eac2ccdec4aec..8e63ab5b5fc3a 100644
--- a/subversion/libsvn_ra_svn/internal_auth.c
+++ b/subversion/libsvn_ra_svn/internal_auth.c
@@ -95,7 +95,7 @@ svn_ra_svn__do_internal_auth(svn_ra_svn__session_baton_t *sess,
{
SVN_ERR(svn_auth_first_credentials(&creds, &iterstate,
SVN_AUTH_CRED_SIMPLE, realmstring,
- sess->callbacks->auth_baton, pool));
+ sess->auth_baton, pool));
if (!creds)
return svn_error_create(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
_("Can't get password"));
diff --git a/subversion/libsvn_ra_svn/libsvn_ra_svn.pc.in b/subversion/libsvn_ra_svn/libsvn_ra_svn.pc.in
new file mode 100644
index 0000000000000..4d6768986f13d
--- /dev/null
+++ b/subversion/libsvn_ra_svn/libsvn_ra_svn.pc.in
@@ -0,0 +1,12 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libsvn_ra_svn
+Description: Subversion SVN Protocol Repository Access Library
+Version: @PACKAGE_VERSION@
+Requires: apr-util-@SVN_APR_MAJOR_VERSION@ apr-@SVN_APR_MAJOR_VERSION@
+Requires.private: libsvn_delta libsvn_subr
+Libs: -L${libdir} -lsvn_ra_svn @SVN_SASL_LIBS@
+Cflags: -I${includedir}
diff --git a/subversion/libsvn_ra_svn/marshal.c b/subversion/libsvn_ra_svn/marshal.c
index 7cf483f50afc9..55e3c1f1bb6bc 100644
--- a/subversion/libsvn_ra_svn/marshal.c
+++ b/subversion/libsvn_ra_svn/marshal.c
@@ -40,6 +40,7 @@
#include "svn_ra_svn.h"
#include "svn_private_config.h"
#include "svn_ctype.h"
+#include "svn_sorts.h"
#include "svn_time.h"
#include "ra_svn.h"
@@ -47,6 +48,7 @@
#include "private/svn_string_private.h"
#include "private/svn_dep_compat.h"
#include "private/svn_error_private.h"
+#include "private/svn_subr_private.h"
#define svn_iswhitespace(c) ((c) == ' ' || (c) == '\n')
@@ -56,6 +58,19 @@
#define SUSPICIOUSLY_HUGE_STRING_SIZE_THRESHOLD (0x100000)
+/* 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.
+ */
+#define MAX_WORD_LENGTH 31
+
+/* The generic parsers will use the following value to limit the recursion
+ * depth to some reasonable value. The current protocol implementation
+ * actually uses only maximum item nesting level of around 5. So, there is
+ * plenty of headroom here.
+ */
+#define ITEM_NESTING_LIMIT 64
+
/* 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
@@ -66,19 +81,20 @@ get_timeout(svn_ra_svn_conn_t *conn)
/* --- CONNECTION INITIALIZATION --- */
-svn_ra_svn_conn_t *svn_ra_svn_create_conn3(apr_socket_t *sock,
- apr_file_t *in_file,
- apr_file_t *out_file,
+svn_ra_svn_conn_t *svn_ra_svn_create_conn4(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_pool_t *pool)
+ apr_pool_t *result_pool)
{
svn_ra_svn_conn_t *conn;
- void *mem = apr_palloc(pool, sizeof(*conn) + SVN_RA_SVN__PAGE_SIZE);
+ void *mem = apr_palloc(result_pool, sizeof(*conn) + SVN_RA_SVN__PAGE_SIZE);
conn = (void*)APR_ALIGN((apr_uintptr_t)mem, SVN_RA_SVN__PAGE_SIZE);
- assert((sock && !in_file && !out_file) || (!sock && in_file && out_file));
+ assert((sock && !in_stream && !out_stream)
+ || (!sock && in_stream && out_stream));
#ifdef SVN_HAVE_SASL
conn->sock = sock;
conn->encrypted = FALSE;
@@ -92,15 +108,15 @@ svn_ra_svn_conn_t *svn_ra_svn_create_conn3(apr_socket_t *sock,
conn->may_check_for_error = error_check_interval == 0;
conn->block_handler = NULL;
conn->block_baton = NULL;
- conn->capabilities = apr_hash_make(pool);
+ conn->capabilities = apr_hash_make(result_pool);
conn->compression_level = compression_level;
conn->zero_copy_limit = zero_copy_limit;
- conn->pool = pool;
+ conn->pool = result_pool;
if (sock != NULL)
{
apr_sockaddr_t *sa;
- conn->stream = svn_ra_svn__stream_from_sock(sock, pool);
+ conn->stream = svn_ra_svn__stream_from_sock(sock, result_pool);
if (!(apr_socket_addr_get(&sa, APR_REMOTE, sock) == APR_SUCCESS
&& apr_sockaddr_ip_get(&conn->remote_ip, sa) == APR_SUCCESS))
conn->remote_ip = NULL;
@@ -108,34 +124,14 @@ svn_ra_svn_conn_t *svn_ra_svn_create_conn3(apr_socket_t *sock,
}
else
{
- conn->stream = svn_ra_svn__stream_from_files(in_file, out_file, pool);
+ conn->stream = svn_ra_svn__stream_from_streams(in_stream, out_stream,
+ result_pool);
conn->remote_ip = NULL;
}
return conn;
}
-svn_ra_svn_conn_t *svn_ra_svn_create_conn2(apr_socket_t *sock,
- apr_file_t *in_file,
- apr_file_t *out_file,
- int compression_level,
- apr_pool_t *pool)
-{
- return svn_ra_svn_create_conn3(sock, in_file, out_file,
- compression_level, 0, 0, pool);
-}
-
-/* backward-compatible implementation using the default compression level */
-svn_ra_svn_conn_t *svn_ra_svn_create_conn(apr_socket_t *sock,
- apr_file_t *in_file,
- apr_file_t *out_file,
- apr_pool_t *pool)
-{
- return svn_ra_svn_create_conn3(sock, in_file, out_file,
- SVN_DELTA_COMPRESSION_LEVEL_DEFAULT, 0, 0,
- pool);
-}
-
svn_error_t *svn_ra_svn_set_capabilities(svn_ra_svn_conn_t *conn,
const apr_array_header_t *list)
{
@@ -155,6 +151,12 @@ svn_error_t *svn_ra_svn_set_capabilities(svn_ra_svn_conn_t *conn,
return SVN_NO_ERROR;
}
+apr_pool_t *
+svn_ra_svn__get_pool(svn_ra_svn_conn_t *conn)
+{
+ return conn->pool;
+}
+
svn_error_t *
svn_ra_svn__set_shim_callbacks(svn_ra_svn_conn_t *conn,
svn_delta_shim_callbacks_t *shim_callbacks)
@@ -196,10 +198,10 @@ svn_ra_svn__set_block_handler(svn_ra_svn_conn_t *conn,
svn_ra_svn__stream_timeout(conn->stream, get_timeout(conn));
}
-svn_boolean_t svn_ra_svn__input_waiting(svn_ra_svn_conn_t *conn,
- apr_pool_t *pool)
+svn_error_t *svn_ra_svn__data_available(svn_ra_svn_conn_t *conn,
+ svn_boolean_t *data_available)
{
- return svn_ra_svn__stream_pending(conn->stream);
+ return svn_ra_svn__stream_data_available(conn->stream, data_available);
}
/* --- WRITE BUFFER MANAGEMENT --- */
@@ -285,20 +287,13 @@ static svn_error_t *writebuf_write(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
return SVN_NO_ERROR;
}
-static svn_error_t *
-writebuf_write_short_string(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
- const char *data, apr_size_t len)
-{
- apr_size_t left = sizeof(conn->write_buf) - conn->write_pos;
- if (len <= left)
- {
- memcpy(conn->write_buf + conn->write_pos, data, len);
- conn->write_pos += len;
- return SVN_NO_ERROR;
- }
- else
- return writebuf_write(conn, pool, data, len);
-}
+/* Write STRING_LITERAL, which is a string literal argument.
+
+ Note: The purpose of the empty string "" in the macro definition is to
+ assert that STRING_LITERAL is in fact a string literal. Otherwise, the
+ string concatenation attempt should produce a compile-time error. */
+#define writebuf_write_literal(conn, pool, string_literal) \
+ writebuf_write(conn, pool, string_literal, sizeof(string_literal "") - 1)
static APR_INLINE svn_error_t *
writebuf_writechar(svn_ra_svn_conn_t *conn, apr_pool_t *pool, char data)
@@ -389,7 +384,9 @@ static svn_error_t *readbuf_fill(svn_ra_svn_conn_t *conn, apr_pool_t *pool)
apr_size_t len;
SVN_ERR_ASSERT(conn->read_ptr == conn->read_end);
- SVN_ERR(writebuf_flush(conn, pool));
+ if (conn->write_pos)
+ SVN_ERR(writebuf_flush(conn, pool));
+
len = sizeof(conn->read_buf);
SVN_ERR(readbuf_input(conn, conn->read_buf, &len, pool));
conn->read_ptr = conn->read_buf;
@@ -397,7 +394,11 @@ static svn_error_t *readbuf_fill(svn_ra_svn_conn_t *conn, apr_pool_t *pool)
return SVN_NO_ERROR;
}
-static APR_INLINE svn_error_t *
+/* This is a hot function calling a cold function. GCC and others tend to
+ * inline the cold sub-function instead of this hot one. Therefore, be
+ * very insistent on lining this one. It is not a correctness issue, though.
+ */
+static SVN__FORCE_INLINE svn_error_t *
readbuf_getchar(svn_ra_svn_conn_t *conn, apr_pool_t *pool, char *result)
{
if (conn->read_ptr == conn->read_end)
@@ -511,21 +512,32 @@ svn_ra_svn__write_number(svn_ra_svn_conn_t *conn,
return write_number(conn, pool, number, ' ');
}
-svn_error_t *
-svn_ra_svn__write_string(svn_ra_svn_conn_t *conn,
- apr_pool_t *pool,
- const svn_string_t *str)
+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 (str->len < 10)
+ if (len < 10)
{
- SVN_ERR(writebuf_writechar(conn, pool, (char)(str->len + '0')));
+ SVN_ERR(writebuf_writechar(conn, pool, (char)(len + '0')));
SVN_ERR(writebuf_writechar(conn, pool, ':'));
}
else
- SVN_ERR(write_number(conn, pool, str->len, ':'));
+ SVN_ERR(write_number(conn, pool, len, ':'));
- SVN_ERR(writebuf_write(conn, pool, str->data, str->len));
+ SVN_ERR(writebuf_write(conn, pool, s, len));
SVN_ERR(writebuf_writechar(conn, pool, ' '));
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_ra_svn__write_string(svn_ra_svn_conn_t *conn,
+ apr_pool_t *pool,
+ const svn_string_t *str)
+{
+ SVN_ERR(svn_ra_svn__write_ncstring(conn, pool, str->data, str->len));
return SVN_NO_ERROR;
}
@@ -534,19 +546,7 @@ svn_ra_svn__write_cstring(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
const char *s)
{
- apr_size_t len = strlen(s);
-
- if (len < 10)
- {
- SVN_ERR(writebuf_writechar(conn, pool, (char)(len + '0')));
- SVN_ERR(writebuf_writechar(conn, pool, ':'));
- }
- else
- SVN_ERR(write_number(conn, pool, len, ':'));
-
- SVN_ERR(writebuf_write(conn, pool, s, len));
- SVN_ERR(writebuf_writechar(conn, pool, ' '));
-
+ SVN_ERR(svn_ra_svn__write_ncstring(conn, pool, s, strlen(s)));
return SVN_NO_ERROR;
}
@@ -555,38 +555,52 @@ svn_ra_svn__write_word(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
const char *word)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, word, strlen(word)));
+ SVN_ERR(writebuf_write(conn, pool, word, strlen(word)));
SVN_ERR(writebuf_writechar(conn, pool, ' '));
return SVN_NO_ERROR;
}
svn_error_t *
+svn_ra_svn__write_boolean(svn_ra_svn_conn_t *conn,
+ apr_pool_t *pool,
+ svn_boolean_t value)
+{
+ if (value)
+ SVN_ERR(writebuf_write_literal(conn, pool, "true "));
+ else
+ SVN_ERR(writebuf_write_literal(conn, pool, "false "));
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
svn_ra_svn__write_proplist(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
apr_hash_t *props)
{
- apr_pool_t *iterpool;
apr_hash_index_t *hi;
- const void *key;
- void *val;
const char *propname;
svn_string_t *propval;
+ apr_size_t len;
+ /* One might use an iterpool here but that would only be used when the
+ send buffer gets flushed and only by the CONN's progress callback.
+ That should happen at most once for typical prop lists and even then
+ use only a few bytes at best.
+ */
if (props)
- {
- iterpool = svn_pool_create(pool);
- for (hi = apr_hash_first(pool, props); hi; hi = apr_hash_next(hi))
- {
- svn_pool_clear(iterpool);
- apr_hash_this(hi, &key, NULL, &val);
- propname = key;
- propval = val;
- SVN_ERR(svn_ra_svn__write_tuple(conn, iterpool, "cs",
- propname, propval));
- }
- svn_pool_destroy(iterpool);
- }
+ for (hi = apr_hash_first(pool, props); hi; hi = apr_hash_next(hi))
+ {
+ apr_hash_this(hi, (const void **)&propname,
+ (apr_ssize_t *)&len,
+ (void **)&propval);
+
+ SVN_ERR(svn_ra_svn__start_list(conn, pool));
+ SVN_ERR(svn_ra_svn__write_ncstring(conn, pool, propname, len));
+ SVN_ERR(svn_ra_svn__write_string(conn, pool, propval));
+ SVN_ERR(svn_ra_svn__end_list(conn, pool));
+ }
return SVN_NO_ERROR;
}
@@ -704,8 +718,7 @@ vwrite_tuple_number(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
static svn_error_t *
vwrite_tuple_boolean(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
{
- const char *cstr = va_arg(*ap, svn_boolean_t) ? "true" : "false";
- return svn_ra_svn__write_word(conn, pool, cstr);
+ return svn_ra_svn__write_boolean(conn, pool, va_arg(*ap, svn_boolean_t));
}
static svn_error_t *
@@ -780,8 +793,7 @@ write_tuple_boolean(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
svn_boolean_t value)
{
- const char *cstr = value ? "true" : "false";
- return svn_ra_svn__write_word(conn, pool, cstr);
+ return svn_ra_svn__write_boolean(conn, pool, value);
}
static svn_error_t *
@@ -929,7 +941,6 @@ svn_ra_svn__write_tuple(svn_ra_svn_conn_t *conn,
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_stringbuf_t *stringbuf;
apr_size_t len = (apr_size_t)len64;
apr_size_t readbuf_len;
char *dest;
@@ -940,58 +951,60 @@ static svn_error_t *read_string(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
_("String length larger than maximum"));
- /* 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 to
- * network data corruption or a DOS attack), we receive a bogus claim that
- * a very long string is going to follow. In that case, we 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). */
- readbuf_len = len < SUSPICIOUSLY_HUGE_STRING_SIZE_THRESHOLD
- ? len
- : SUSPICIOUSLY_HUGE_STRING_SIZE_THRESHOLD;
- stringbuf = svn_stringbuf_create_ensure(readbuf_len, pool);
- dest = stringbuf->data;
-
- /* Read remaining string data directly into the string structure.
- * Do it iteratively, if necessary. */
- while (readbuf_len)
+ /* Shorter strings can be copied directly from the read buffer. */
+ if (conn->read_ptr + len <= conn->read_end)
{
- SVN_ERR(readbuf_read(conn, pool, dest, readbuf_len));
-
- stringbuf->len += readbuf_len;
- len -= readbuf_len;
+ item->kind = SVN_RA_SVN_STRING;
+ item->u.string = svn_string_ncreate(conn->read_ptr, len, pool);
+ conn->read_ptr += len;
+ }
+ else
+ {
+ /* 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
+ * to network data corruption or a DOS attack), we receive a bogus
+ * claim that a very long string is going to follow. In that case, we
+ * 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);
+
+ /* Read string data directly into the string structure.
+ * Do it iteratively. */
+ do
+ {
+ /* Determine length of chunk to read and re-alloc the buffer. */
+ readbuf_len
+ = len < SUSPICIOUSLY_HUGE_STRING_SIZE_THRESHOLD
+ ? len
+ : SUSPICIOUSLY_HUGE_STRING_SIZE_THRESHOLD;
- /* Early exit. In most cases, strings can be read in the first
- * iteration. */
- if (len == 0)
- break;
+ svn_stringbuf_ensure(stringbuf, stringbuf->len + readbuf_len);
+ dest = stringbuf->data + stringbuf->len;
- /* Prepare next iteration: determine length of chunk to read
- * and re-alloc the string buffer. */
- readbuf_len
- = len < SUSPICIOUSLY_HUGE_STRING_SIZE_THRESHOLD
- ? len
- : SUSPICIOUSLY_HUGE_STRING_SIZE_THRESHOLD;
+ /* read data & update length info */
+ SVN_ERR(readbuf_read(conn, pool, dest, readbuf_len));
- svn_stringbuf_ensure(stringbuf, stringbuf->len + readbuf_len);
- dest = stringbuf->data + stringbuf->len;
- }
+ stringbuf->len += readbuf_len;
+ len -= readbuf_len;
+ }
+ while (len);
- /* zero-terminate the string */
- stringbuf->data[stringbuf->len] = '\0';
+ /* zero-terminate the string */
+ stringbuf->data[stringbuf->len] = '\0';
- /* 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);
+ /* 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);
+ }
return SVN_NO_ERROR;
}
/* Given the first non-whitespace character FIRST_CHAR, read an item
* into the already allocated structure ITEM. LEVEL should be set
- * to 0 for the first call and is used to enforce a recurssion limit
+ * 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,
@@ -999,12 +1012,11 @@ static svn_error_t *read_item(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
{
char c = first_char;
apr_uint64_t val;
- svn_stringbuf_t *str;
svn_ra_svn_item_t *listitem;
- if (++level >= 64)
+ if (++level >= ITEM_NESTING_LIMIT)
return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
- _("Too many nested items"));
+ _("Items are nested too deeply"));
/* Determine the item type and read it in. Make sure that c is the
@@ -1022,7 +1034,8 @@ static svn_error_t *read_item(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
break;
val = val * 10 + (c - '0');
/* val wrapped past maximum value? */
- if (prev_val >= (APR_UINT64_MAX / 10) && (val / 10) != prev_val)
+ if ((prev_val >= (APR_UINT64_MAX / 10))
+ && (val < APR_UINT64_MAX - 10))
return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
_("Number is larger than maximum"));
}
@@ -1041,18 +1054,28 @@ static svn_error_t *read_item(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
}
else if (svn_ctype_isalpha(c))
{
- /* It's a word. */
- str = svn_stringbuf_create_ensure(16, pool);
- svn_stringbuf_appendbyte(str, c);
+ /* It's a word. Read it into a buffer of limited size. */
+ char *buffer = apr_palloc(pool, MAX_WORD_LENGTH + 1);
+ char *end = buffer + MAX_WORD_LENGTH;
+ char *p = buffer + 1;
+
+ buffer[0] = c;
while (1)
{
- SVN_ERR(readbuf_getchar(conn, pool, &c));
- if (!svn_ctype_isalnum(c) && c != '-')
+ SVN_ERR(readbuf_getchar(conn, pool, p));
+ if (!svn_ctype_isalnum(*p) && *p != '-')
break;
- svn_stringbuf_appendbyte(str, c);
+
+ if (++p == end)
+ return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
+ _("Word is too long"));
}
+
+ c = *p;
+ *p = '\0';
+
item->kind = SVN_RA_SVN_WORD;
- item->u.word = str->data;
+ item->u.word = buffer;
}
else if (c == '(')
{
@@ -1179,6 +1202,36 @@ svn_ra_svn__read_item(svn_ra_svn_conn_t *conn,
return read_item(conn, pool, *item, c, 0);
}
+/* Drain existing whitespace from the receive buffer of CONN until either
+ there is no data in the underlying receive socket anymore or we found
+ a non-whitespace char. Set *HAS_ITEM to TRUE in the latter case.
+ */
+static svn_error_t *
+svn_ra_svn__has_item(svn_boolean_t *has_item,
+ svn_ra_svn_conn_t *conn,
+ apr_pool_t *pool)
+{
+ do
+ {
+ if (conn->read_ptr == conn->read_end)
+ {
+ svn_boolean_t available;
+ if (conn->write_pos)
+ SVN_ERR(writebuf_flush(conn, pool));
+
+ SVN_ERR(svn_ra_svn__data_available(conn, &available));
+ if (!available)
+ break;
+
+ SVN_ERR(readbuf_fill(conn, pool));
+ }
+ }
+ while (svn_iswhitespace(*conn->read_ptr) && ++conn->read_ptr);
+
+ *has_item = conn->read_ptr != conn->read_end;
+ return SVN_NO_ERROR;
+}
+
svn_error_t *
svn_ra_svn__skip_leading_garbage(svn_ra_svn_conn_t *conn,
apr_pool_t *pool)
@@ -1202,14 +1255,15 @@ static svn_error_t *vparse_tuple(const apr_array_header_t *items, apr_pool_t *po
if (**fmt == '?')
(*fmt)++;
elt = &APR_ARRAY_IDX(items, count, svn_ra_svn_item_t);
- if (**fmt == 'n' && elt->kind == SVN_RA_SVN_NUMBER)
- *va_arg(*ap, apr_uint64_t *) = elt->u.number;
- else if (**fmt == 'r' && elt->kind == SVN_RA_SVN_NUMBER)
- *va_arg(*ap, svn_revnum_t *) = (svn_revnum_t) elt->u.number;
- else if (**fmt == 's' && elt->kind == SVN_RA_SVN_STRING)
- *va_arg(*ap, svn_string_t **) = elt->u.string;
+ if (**fmt == '(' && elt->kind == SVN_RA_SVN_LIST)
+ {
+ (*fmt)++;
+ SVN_ERR(vparse_tuple(elt->u.list, pool, fmt, ap));
+ }
else if (**fmt == 'c' && elt->kind == SVN_RA_SVN_STRING)
*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;
else if (**fmt == 'w' && elt->kind == SVN_RA_SVN_WORD)
*va_arg(*ap, const char **) = elt->u.word;
else if (**fmt == 'b' && elt->kind == SVN_RA_SVN_WORD)
@@ -1221,6 +1275,10 @@ static svn_error_t *vparse_tuple(const apr_array_header_t *items, apr_pool_t *po
else
break;
}
+ else if (**fmt == 'n' && elt->kind == SVN_RA_SVN_NUMBER)
+ *va_arg(*ap, apr_uint64_t *) = elt->u.number;
+ else if (**fmt == 'r' && elt->kind == SVN_RA_SVN_NUMBER)
+ *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)
@@ -1230,13 +1288,17 @@ static svn_error_t *vparse_tuple(const apr_array_header_t *items, apr_pool_t *po
else
break;
}
- else if (**fmt == 'l' && elt->kind == SVN_RA_SVN_LIST)
- *va_arg(*ap, apr_array_header_t **) = elt->u.list;
- else if (**fmt == '(' && elt->kind == SVN_RA_SVN_LIST)
+ else if (**fmt == '3' && elt->kind == SVN_RA_SVN_WORD)
{
- (*fmt)++;
- SVN_ERR(vparse_tuple(elt->u.list, pool, fmt, ap));
+ if (strcmp(elt->u.word, "true") == 0)
+ *va_arg(*ap, svn_tristate_t *) = svn_tristate_true;
+ else if (strcmp(elt->u.word, "false") == 0)
+ *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;
else if (**fmt == ')')
return SVN_NO_ERROR;
else
@@ -1268,6 +1330,9 @@ static svn_error_t *vparse_tuple(const apr_array_header_t *items, apr_pool_t *po
case 'n':
*va_arg(*ap, apr_uint64_t *) = SVN_RA_SVN_UNSPECIFIED_NUMBER;
break;
+ case '3':
+ *va_arg(*ap, svn_tristate_t *) = svn_tristate_unknown;
+ break;
case '(':
nesting_level++;
break;
@@ -1337,21 +1402,21 @@ svn_ra_svn__parse_proplist(const apr_array_header_t *list,
apr_pool_t *pool,
apr_hash_t **props)
{
- char *name;
+ svn_string_t *name;
svn_string_t *value;
svn_ra_svn_item_t *elt;
int i;
- *props = apr_hash_make(pool);
+ *props = svn_hash__make(pool);
for (i = 0; i < list->nelts; i++)
{
elt = &APR_ARRAY_IDX(list, i, svn_ra_svn_item_t);
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, "cs",
+ SVN_ERR(svn_ra_svn__parse_tuple(elt->u.list, pool, "ss",
&name, &value));
- svn_hash_sets(*props, name, value);
+ apr_hash_set(*props, name->data, name->len, value);
}
return SVN_NO_ERROR;
@@ -1447,7 +1512,7 @@ svn_ra_svn__read_cmd_response(svn_ra_svn_conn_t *conn,
}
else if (strcmp(status, "failure") == 0)
{
- return svn_ra_svn__handle_failure_status(params, pool);
+ return svn_error_trace(svn_ra_svn__handle_failure_status(params, pool));
}
return svn_error_createf(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
@@ -1456,6 +1521,76 @@ svn_ra_svn__read_cmd_response(svn_ra_svn_conn_t *conn,
}
svn_error_t *
+svn_ra_svn__has_command(svn_boolean_t *has_command,
+ svn_boolean_t *terminated,
+ svn_ra_svn_conn_t *conn,
+ apr_pool_t *pool)
+{
+ svn_error_t *err = svn_ra_svn__has_item(has_command, conn, pool);
+ if (err && err->apr_err == SVN_ERR_RA_SVN_CONNECTION_CLOSED)
+ {
+ *terminated = TRUE;
+ svn_error_clear(err);
+ return SVN_NO_ERROR;
+ }
+
+ *terminated = FALSE;
+ return svn_error_trace(err);
+}
+
+svn_error_t *
+svn_ra_svn__handle_command(svn_boolean_t *terminate,
+ apr_hash_t *cmd_hash,
+ void *baton,
+ svn_ra_svn_conn_t *conn,
+ svn_boolean_t error_on_disconnect,
+ apr_pool_t *pool)
+{
+ const char *cmdname;
+ svn_error_t *err, *write_err;
+ apr_array_header_t *params;
+ const svn_ra_svn_cmd_entry_t *command;
+
+ *terminate = FALSE;
+ err = svn_ra_svn__read_tuple(conn, pool, "wl", &cmdname, &params);
+ if (err)
+ {
+ if (!error_on_disconnect
+ && err->apr_err == SVN_ERR_RA_SVN_CONNECTION_CLOSED)
+ {
+ svn_error_clear(err);
+ *terminate = TRUE;
+ return SVN_NO_ERROR;
+ }
+ return err;
+ }
+
+ command = svn_hash_gets(cmd_hash, cmdname);
+ if (command)
+ {
+ err = (*command->handler)(conn, pool, params, baton);
+ *terminate = command->terminate;
+ }
+ else
+ {
+ err = svn_error_createf(SVN_ERR_RA_SVN_UNKNOWN_CMD, NULL,
+ _("Unknown editor command '%s'"), cmdname);
+ err = svn_error_create(SVN_ERR_RA_SVN_CMD_ERR, err, NULL);
+ }
+
+ if (err && err->apr_err == SVN_ERR_RA_SVN_CMD_ERR)
+ {
+ write_err = svn_ra_svn__write_cmd_failure(
+ conn, pool,
+ svn_ra_svn__locate_real_error_child(err));
+ svn_error_clear(err);
+ return write_err ? write_err : SVN_NO_ERROR;
+ }
+
+ return err;
+}
+
+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,
@@ -1464,10 +1599,7 @@ svn_ra_svn__handle_commands2(svn_ra_svn_conn_t *conn,
{
apr_pool_t *subpool = svn_pool_create(pool);
apr_pool_t *iterpool = svn_pool_create(subpool);
- const char *cmdname;
const svn_ra_svn_cmd_entry_t *command;
- svn_error_t *err, *write_err;
- apr_array_header_t *params;
apr_hash_t *cmd_hash = apr_hash_make(subpool);
for (command = commands; command->cmdname; command++)
@@ -1475,43 +1607,18 @@ svn_ra_svn__handle_commands2(svn_ra_svn_conn_t *conn,
while (1)
{
+ svn_boolean_t terminate;
+ svn_error_t *err;
svn_pool_clear(iterpool);
- err = svn_ra_svn__read_tuple(conn, iterpool, "wl", &cmdname, &params);
- if (err)
- {
- if (!error_on_disconnect
- && err->apr_err == SVN_ERR_RA_SVN_CONNECTION_CLOSED)
- {
- svn_error_clear(err);
- svn_pool_destroy(subpool);
- return SVN_NO_ERROR;
- }
- return err;
- }
- command = svn_hash_gets(cmd_hash, cmdname);
- if (command)
- err = (*command->handler)(conn, iterpool, params, baton);
- else
- {
- err = svn_error_createf(SVN_ERR_RA_SVN_UNKNOWN_CMD, NULL,
- _("Unknown editor command '%s'"), cmdname);
- err = svn_error_create(SVN_ERR_RA_SVN_CMD_ERR, err, NULL);
- }
-
- if (err && err->apr_err == SVN_ERR_RA_SVN_CMD_ERR)
+ err = svn_ra_svn__handle_command(&terminate, cmd_hash, baton, conn,
+ error_on_disconnect, iterpool);
+ if (err)
{
- write_err = svn_ra_svn__write_cmd_failure(
- conn, iterpool,
- svn_ra_svn__locate_real_error_child(err));
- svn_error_clear(err);
- if (write_err)
- return write_err;
+ svn_pool_destroy(subpool);
+ return svn_error_trace(err);
}
- else if (err)
- return err;
-
- if (command && command->terminate)
+ if (terminate)
break;
}
svn_pool_destroy(iterpool);
@@ -1524,9 +1631,9 @@ svn_ra_svn__write_cmd_target_rev(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
svn_revnum_t rev)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( target-rev ( ", 15));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( target-rev ( "));
SVN_ERR(write_tuple_revision(conn, pool, rev));
- SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -1537,12 +1644,12 @@ svn_ra_svn__write_cmd_open_root(svn_ra_svn_conn_t *conn,
svn_revnum_t rev,
const char *token)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( open-root ( ", 14));
+ 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(writebuf_write_short_string(conn, pool, ") ) ", 4));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -1554,13 +1661,13 @@ svn_ra_svn__write_cmd_delete_entry(svn_ra_svn_conn_t *conn,
svn_revnum_t rev,
const char *token)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( delete-entry ( ", 17));
+ 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(writebuf_write_short_string(conn, pool, ") ) ", 4));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -1574,10 +1681,10 @@ svn_ra_svn__write_cmd_add_dir(svn_ra_svn_conn_t *conn,
const char *copy_path,
svn_revnum_t copy_rev)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( add-dir ( ", 12));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( add-dir ( "));
SVN_ERR(write_cmd_add_node(conn, pool, path, parent_token, token,
copy_path, copy_rev));
- SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -1590,9 +1697,9 @@ svn_ra_svn__write_cmd_open_dir(svn_ra_svn_conn_t *conn,
const char *token,
svn_revnum_t rev)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( open-dir ( ", 13));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( open-dir ( "));
SVN_ERR(write_cmd_open_node(conn, pool, path, parent_token, token, rev));
- SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -1604,9 +1711,9 @@ svn_ra_svn__write_cmd_change_dir_prop(svn_ra_svn_conn_t *conn,
const char *name,
const svn_string_t *value)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( change-dir-prop ( ", 20));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( change-dir-prop ( "));
SVN_ERR(write_cmd_change_node_prop(conn, pool, token, name, value));
- SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -1616,9 +1723,9 @@ svn_ra_svn__write_cmd_close_dir(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
const char *token)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( close-dir ( ", 14));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( close-dir ( "));
SVN_ERR(write_tuple_cstring(conn, pool, token));
- SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -1629,9 +1736,9 @@ svn_ra_svn__write_cmd_absent_dir(svn_ra_svn_conn_t *conn,
const char *path,
const char *parent_token)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( absent-dir ( ", 15));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( absent-dir ( "));
SVN_ERR(write_cmd_absent_node(conn, pool, path, parent_token));
- SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -1645,10 +1752,10 @@ svn_ra_svn__write_cmd_add_file(svn_ra_svn_conn_t *conn,
const char *copy_path,
svn_revnum_t copy_rev)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( add-file ( ", 13));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( add-file ( "));
SVN_ERR(write_cmd_add_node(conn, pool, path, parent_token, token,
copy_path, copy_rev));
- SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -1661,9 +1768,9 @@ svn_ra_svn__write_cmd_open_file(svn_ra_svn_conn_t *conn,
const char *token,
svn_revnum_t rev)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( open-file ( ", 14));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( open-file ( "));
SVN_ERR(write_cmd_open_node(conn, pool, path, parent_token, token, rev));
- SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -1675,9 +1782,9 @@ svn_ra_svn__write_cmd_change_file_prop(svn_ra_svn_conn_t *conn,
const char *name,
const svn_string_t *value)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( change-file-prop ( ", 21));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( change-file-prop ( "));
SVN_ERR(write_cmd_change_node_prop(conn, pool, token, name, value));
- SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -1688,12 +1795,12 @@ svn_ra_svn__write_cmd_close_file(svn_ra_svn_conn_t *conn,
const char *token,
const char *text_checksum)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( close-file ( ", 15));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( close-file ( "));
SVN_ERR(write_tuple_cstring(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));
- SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -1704,9 +1811,9 @@ svn_ra_svn__write_cmd_absent_file(svn_ra_svn_conn_t *conn,
const char *path,
const char *parent_token)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( absent-file ( ", 16));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( absent-file ( "));
SVN_ERR(write_cmd_absent_node(conn, pool, path, parent_token));
- SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -1717,10 +1824,10 @@ svn_ra_svn__write_cmd_textdelta_chunk(svn_ra_svn_conn_t *conn,
const char *token,
const svn_string_t *chunk)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( textdelta-chunk ( ", 20));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( textdelta-chunk ( "));
SVN_ERR(write_tuple_cstring(conn, pool, token));
SVN_ERR(write_tuple_string(conn, pool, chunk));
- SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -1730,9 +1837,9 @@ svn_ra_svn__write_cmd_textdelta_end(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
const char *token)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( textdelta-end ( ", 18));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( textdelta-end ( "));
SVN_ERR(write_tuple_cstring(conn, pool, token));
- SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -1743,12 +1850,12 @@ svn_ra_svn__write_cmd_apply_textdelta(svn_ra_svn_conn_t *conn,
const char *token,
const char *base_checksum)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( apply-textdelta ( ", 20));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( apply-textdelta ( "));
SVN_ERR(write_tuple_cstring(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));
- SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -1757,14 +1864,14 @@ svn_error_t *
svn_ra_svn__write_cmd_close_edit(svn_ra_svn_conn_t *conn,
apr_pool_t *pool)
{
- return writebuf_write_short_string(conn, pool, "( close-edit ( ) ) ", 19);
+ return writebuf_write_literal(conn, pool, "( close-edit ( ) ) ");
}
svn_error_t *
svn_ra_svn__write_cmd_abort_edit(svn_ra_svn_conn_t *conn,
apr_pool_t *pool)
{
- return writebuf_write_short_string(conn, pool, "( abort-edit ( ) ) ", 19);
+ return writebuf_write_literal(conn, pool, "( abort-edit ( ) ) ");
}
svn_error_t *
@@ -1776,7 +1883,7 @@ svn_ra_svn__write_cmd_set_path(svn_ra_svn_conn_t *conn,
const char *lock_token,
svn_depth_t depth)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( set-path ( ", 13));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( set-path ( "));
SVN_ERR(write_tuple_cstring(conn, pool, path));
SVN_ERR(write_tuple_revision(conn, pool, rev));
SVN_ERR(write_tuple_boolean(conn, pool, start_empty));
@@ -1784,7 +1891,7 @@ svn_ra_svn__write_cmd_set_path(svn_ra_svn_conn_t *conn,
SVN_ERR(write_tuple_cstring_opt(conn, pool, lock_token));
SVN_ERR(write_tuple_end_list(conn, pool));
SVN_ERR(write_tuple_depth(conn, pool, depth));
- SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -1794,9 +1901,9 @@ svn_ra_svn__write_cmd_delete_path(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
const char *path)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( delete-path ( ", 16));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( delete-path ( "));
SVN_ERR(write_tuple_cstring(conn, pool, path));
- SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -1811,7 +1918,7 @@ svn_ra_svn__write_cmd_link_path(svn_ra_svn_conn_t *conn,
const char *lock_token,
svn_depth_t depth)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( link-path ( ", 14));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( link-path ( "));
SVN_ERR(write_tuple_cstring(conn, pool, path));
SVN_ERR(write_tuple_cstring(conn, pool, url));
SVN_ERR(write_tuple_revision(conn, pool, rev));
@@ -1820,7 +1927,7 @@ svn_ra_svn__write_cmd_link_path(svn_ra_svn_conn_t *conn,
SVN_ERR(write_tuple_cstring_opt(conn, pool,lock_token));
SVN_ERR(write_tuple_end_list(conn, pool));
SVN_ERR(write_tuple_depth(conn, pool, depth));
- SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -1829,14 +1936,14 @@ svn_error_t *
svn_ra_svn__write_cmd_finish_report(svn_ra_svn_conn_t *conn,
apr_pool_t *pool)
{
- return writebuf_write_short_string(conn, pool, "( finish-report ( ) ) ", 22);
+ return writebuf_write_literal(conn, pool, "( finish-report ( ) ) ");
}
svn_error_t *
svn_ra_svn__write_cmd_abort_report(svn_ra_svn_conn_t *conn,
apr_pool_t *pool)
{
- return writebuf_write_short_string(conn, pool, "( abort-report ( ) ) ", 21);
+ return writebuf_write_literal(conn, pool, "( abort-report ( ) ) ");
}
svn_error_t *
@@ -1844,9 +1951,9 @@ svn_ra_svn__write_cmd_reparent(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
const char *url)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( reparent ( ", 13));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( reparent ( "));
SVN_ERR(write_tuple_cstring(conn, pool, url));
- SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -1855,7 +1962,7 @@ svn_error_t *
svn_ra_svn__write_cmd_get_latest_rev(svn_ra_svn_conn_t *conn,
apr_pool_t *pool)
{
- return writebuf_write_short_string(conn, pool, "( get-latest-rev ( ) ) ", 23);
+ return writebuf_write_literal(conn, pool, "( get-latest-rev ( ) ) ");
}
svn_error_t *
@@ -1863,9 +1970,9 @@ svn_ra_svn__write_cmd_get_dated_rev(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
apr_time_t tm)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( get-dated-rev ( ", 18));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( get-dated-rev ( "));
SVN_ERR(write_tuple_cstring(conn, pool, svn_time_to_cstring(tm, pool)));
- SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -1879,7 +1986,7 @@ svn_ra_svn__write_cmd_change_rev_prop2(svn_ra_svn_conn_t *conn,
svn_boolean_t dont_care,
const svn_string_t *old_value)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( change-rev-prop2 ( ", 21));
+ 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));
@@ -1889,7 +1996,7 @@ svn_ra_svn__write_cmd_change_rev_prop2(svn_ra_svn_conn_t *conn,
SVN_ERR(write_tuple_boolean(conn, pool, dont_care));
SVN_ERR(write_tuple_string_opt(conn, pool, old_value));
SVN_ERR(write_tuple_end_list(conn, pool));
- SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -1901,11 +2008,11 @@ svn_ra_svn__write_cmd_change_rev_prop(svn_ra_svn_conn_t *conn,
const char *name,
const svn_string_t *value)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( change-rev-prop ( ", 20));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( change-rev-prop ( "));
SVN_ERR(write_tuple_revision(conn, pool, rev));
SVN_ERR(write_tuple_cstring(conn, pool, name));
SVN_ERR(write_tuple_string_opt(conn, pool, value));
- SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -1915,9 +2022,9 @@ svn_ra_svn__write_cmd_rev_proplist(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
svn_revnum_t rev)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( rev-proplist ( ", 17));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( rev-proplist ( "));
SVN_ERR(write_tuple_revision(conn, pool, rev));
- SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -1928,10 +2035,10 @@ svn_ra_svn__write_cmd_rev_prop(svn_ra_svn_conn_t *conn,
svn_revnum_t rev,
const char *name)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( rev-prop ( ", 13));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( rev-prop ( "));
SVN_ERR(write_tuple_revision(conn, pool, rev));
SVN_ERR(write_tuple_cstring(conn, pool, name));
- SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -1944,14 +2051,18 @@ svn_ra_svn__write_cmd_get_file(svn_ra_svn_conn_t *conn,
svn_boolean_t props,
svn_boolean_t stream)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( get-file ( ", 13));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( get-file ( "));
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_boolean(conn, pool, props));
SVN_ERR(write_tuple_boolean(conn, pool, stream));
- SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
+
+ /* Always send the, nominally optional, want-iprops as "false" to
+ workaround a bug in svnserve 1.8.0-1.8.8 that causes the server
+ to see "true" if it is omitted. */
+ SVN_ERR(writebuf_write_literal(conn, pool, " false ) ) "));
return SVN_NO_ERROR;
}
@@ -1966,7 +2077,7 @@ svn_ra_svn__write_cmd_update(svn_ra_svn_conn_t *conn,
svn_boolean_t send_copyfrom_args,
svn_boolean_t ignore_ancestry)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( update ( ", 11));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( update ( "));
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));
@@ -1975,7 +2086,7 @@ svn_ra_svn__write_cmd_update(svn_ra_svn_conn_t *conn,
SVN_ERR(write_tuple_depth(conn, pool, depth));
SVN_ERR(write_tuple_boolean(conn, pool, send_copyfrom_args));
SVN_ERR(write_tuple_boolean(conn, pool, ignore_ancestry));
- SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -1991,7 +2102,7 @@ svn_ra_svn__write_cmd_switch(svn_ra_svn_conn_t *conn,
svn_boolean_t send_copyfrom_args,
svn_boolean_t ignore_ancestry)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( switch ( ", 11));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( switch ( "));
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));
@@ -2001,7 +2112,7 @@ svn_ra_svn__write_cmd_switch(svn_ra_svn_conn_t *conn,
SVN_ERR(write_tuple_depth(conn, pool, depth));
SVN_ERR(write_tuple_boolean(conn, pool, send_copyfrom_args));
SVN_ERR(write_tuple_boolean(conn, pool, ignore_ancestry));
- SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -2014,14 +2125,14 @@ svn_ra_svn__write_cmd_status(svn_ra_svn_conn_t *conn,
svn_revnum_t rev,
svn_depth_t depth)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( status ( ", 11));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( status ( "));
SVN_ERR(write_tuple_cstring(conn, pool, target));
SVN_ERR(write_tuple_boolean(conn, pool, recurse));
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_depth(conn, pool, depth));
- SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -2037,7 +2148,7 @@ svn_ra_svn__write_cmd_diff(svn_ra_svn_conn_t *conn,
svn_boolean_t text_deltas,
svn_depth_t depth)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( diff ( ", 9));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( diff ( "));
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));
@@ -2047,7 +2158,7 @@ svn_ra_svn__write_cmd_diff(svn_ra_svn_conn_t *conn,
SVN_ERR(write_tuple_cstring(conn, pool, versus_url));
SVN_ERR(write_tuple_boolean(conn, pool, text_deltas));
SVN_ERR(write_tuple_depth(conn, pool, depth));
- SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -2058,12 +2169,12 @@ svn_ra_svn__write_cmd_check_path(svn_ra_svn_conn_t *conn,
const char *path,
svn_revnum_t rev)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( check-path ( ", 15));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( check-path ( "));
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(writebuf_write_short_string(conn, pool, ") ) ", 4));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -2074,12 +2185,12 @@ svn_ra_svn__write_cmd_stat(svn_ra_svn_conn_t *conn,
const char *path,
svn_revnum_t rev)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( stat ( ", 9));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( stat ( "));
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(writebuf_write_short_string(conn, pool, ") ) ", 4));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -2092,7 +2203,7 @@ svn_ra_svn__write_cmd_get_file_revs(svn_ra_svn_conn_t *conn,
svn_revnum_t end,
svn_boolean_t include_merged_revisions)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( get-file-revs ( ", 18));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( get-file-revs ( "));
SVN_ERR(write_tuple_cstring(conn, pool, path));
SVN_ERR(write_tuple_start_list(conn, pool));
SVN_ERR(write_tuple_revision_opt(conn, pool, start));
@@ -2101,7 +2212,7 @@ svn_ra_svn__write_cmd_get_file_revs(svn_ra_svn_conn_t *conn,
SVN_ERR(write_tuple_revision_opt(conn, pool, end));
SVN_ERR(write_tuple_end_list(conn, pool));
SVN_ERR(write_tuple_boolean(conn, pool, include_merged_revisions));
- SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -2114,7 +2225,7 @@ svn_ra_svn__write_cmd_lock(svn_ra_svn_conn_t *conn,
svn_boolean_t steal_lock,
svn_revnum_t revnum)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( lock ( ", 9));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( lock ( "));
SVN_ERR(write_tuple_cstring(conn, pool, path));
SVN_ERR(write_tuple_start_list(conn, pool));
SVN_ERR(write_tuple_cstring_opt(conn, pool, comment));
@@ -2123,7 +2234,7 @@ svn_ra_svn__write_cmd_lock(svn_ra_svn_conn_t *conn,
SVN_ERR(write_tuple_start_list(conn, pool));
SVN_ERR(write_tuple_revision_opt(conn, pool, revnum));
SVN_ERR(write_tuple_end_list(conn, pool));
- SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -2135,13 +2246,13 @@ svn_ra_svn__write_cmd_unlock(svn_ra_svn_conn_t *conn,
const char *token,
svn_boolean_t break_lock)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( unlock ( ", 11));
+ 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_boolean(conn, pool, break_lock));
- SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -2151,9 +2262,9 @@ svn_ra_svn__write_cmd_get_lock(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
const char *path)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( get-lock ( ", 13));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( get-lock ( "));
SVN_ERR(write_tuple_cstring(conn, pool, path));
- SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -2164,12 +2275,12 @@ svn_ra_svn__write_cmd_get_locks(svn_ra_svn_conn_t *conn,
const char *path,
svn_depth_t depth)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( get-locks ( ", 14));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( get-locks ( "));
SVN_ERR(write_tuple_cstring(conn, pool, path));
SVN_ERR(write_tuple_start_list(conn, pool));
SVN_ERR(write_tuple_depth(conn, pool, depth));
SVN_ERR(write_tuple_end_list(conn, pool));
- SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -2181,11 +2292,11 @@ svn_ra_svn__write_cmd_replay(svn_ra_svn_conn_t *conn,
svn_revnum_t low_water_mark,
svn_boolean_t send_deltas)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( replay ( ", 11));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( replay ( "));
SVN_ERR(write_tuple_revision(conn, pool, rev));
SVN_ERR(write_tuple_revision(conn, pool, low_water_mark));
SVN_ERR(write_tuple_boolean(conn, pool, send_deltas));
- SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -2198,12 +2309,12 @@ svn_ra_svn__write_cmd_replay_range(svn_ra_svn_conn_t *conn,
svn_revnum_t low_water_mark,
svn_boolean_t send_deltas)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( replay-range ( ", 17));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( replay-range ( "));
SVN_ERR(write_tuple_revision(conn, pool, start_revision));
SVN_ERR(write_tuple_revision(conn, pool, end_revision));
SVN_ERR(write_tuple_revision(conn, pool, low_water_mark));
SVN_ERR(write_tuple_boolean(conn, pool, send_deltas));
- SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -2215,11 +2326,11 @@ svn_ra_svn__write_cmd_get_deleted_rev(svn_ra_svn_conn_t *conn,
svn_revnum_t peg_revision,
svn_revnum_t end_revision)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( get-deleted-rev ( ", 20));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( get-deleted-rev ( "));
SVN_ERR(write_tuple_cstring(conn, pool, path));
SVN_ERR(write_tuple_revision(conn, pool, peg_revision));
SVN_ERR(write_tuple_revision(conn, pool, end_revision));
- SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -2230,12 +2341,12 @@ svn_ra_svn__write_cmd_get_iprops(svn_ra_svn_conn_t *conn,
const char *path,
svn_revnum_t revision)
{
- SVN_ERR(writebuf_write_short_string(conn, pool, "( get-iprops ( ", 15));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( get-iprops ( "));
SVN_ERR(write_tuple_cstring(conn, pool, path));
SVN_ERR(write_tuple_start_list(conn, pool));
SVN_ERR(write_tuple_revision_opt(conn, pool, revision));
SVN_ERR(write_tuple_end_list(conn, pool));
- SVN_ERR(writebuf_write_short_string(conn, pool, ") ) ", 4));
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
}
@@ -2244,7 +2355,7 @@ svn_error_t *
svn_ra_svn__write_cmd_finish_replay(svn_ra_svn_conn_t *conn,
apr_pool_t *pool)
{
- return writebuf_write_short_string(conn, pool, "( finish-replay ( ) ) ", 22);
+ return writebuf_write_literal(conn, pool, "( finish-replay ( ) ) ");
}
svn_error_t *svn_ra_svn__write_cmd_response(svn_ra_svn_conn_t *conn,
@@ -2254,7 +2365,7 @@ svn_error_t *svn_ra_svn__write_cmd_response(svn_ra_svn_conn_t *conn,
va_list ap;
svn_error_t *err;
- SVN_ERR(writebuf_write_short_string(conn, pool, "( success ", 10));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( success "));
va_start(ap, fmt);
err = vwrite_tuple(conn, pool, fmt, &ap);
va_end(ap);
@@ -2262,10 +2373,11 @@ svn_error_t *svn_ra_svn__write_cmd_response(svn_ra_svn_conn_t *conn,
}
svn_error_t *svn_ra_svn__write_cmd_failure(svn_ra_svn_conn_t *conn,
- apr_pool_t *pool, svn_error_t *err)
+ apr_pool_t *pool,
+ const svn_error_t *err)
{
char buffer[128];
- SVN_ERR(writebuf_write_short_string(conn, pool, "( failure ( ", 12));
+ SVN_ERR(writebuf_write_literal(conn, pool, "( failure ( "));
for (; err; err = err->child)
{
const char *msg;
@@ -2285,5 +2397,217 @@ svn_error_t *svn_ra_svn__write_cmd_failure(svn_ra_svn_conn_t *conn,
err->file ? err->file : "",
(apr_uint64_t) err->line));
}
- return writebuf_write_short_string(conn, pool, ") ) ", 4);
+ return writebuf_write_literal(conn, pool, ") ) ");
+}
+
+svn_error_t *
+svn_ra_svn__write_data_log_changed_path(svn_ra_svn_conn_t *conn,
+ apr_pool_t *pool,
+ const char *path,
+ char action,
+ const char *copyfrom_path,
+ svn_revnum_t copyfrom_rev,
+ svn_node_kind_t node_kind,
+ svn_boolean_t text_modified,
+ svn_boolean_t props_modified)
+{
+ SVN_ERR(write_tuple_start_list(conn, pool));
+
+ 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));
+
+ return writebuf_write_literal(conn, pool, ") ) ");
+}
+
+svn_error_t *
+svn_ra_svn__write_data_log_entry(svn_ra_svn_conn_t *conn,
+ apr_pool_t *pool,
+ svn_revnum_t revision,
+ const svn_string_t *author,
+ const svn_string_t *date,
+ const svn_string_t *message,
+ svn_boolean_t has_children,
+ svn_boolean_t invalid_revnum,
+ 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_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));
+
+ return SVN_NO_ERROR;
+}
+
+/* If condition COND is not met, return a "malformed network data" error.
+ */
+#define CHECK_PROTOCOL_COND(cond)\
+ if (!(cond)) \
+ return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL, \
+ _("Malformed network data"));
+
+/* 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,
+ int idx,
+ svn_string_t **result)
+{
+ svn_ra_svn_item_t *elt = &APR_ARRAY_IDX(items, idx, svn_ra_svn_item_t);
+ CHECK_PROTOCOL_COND(elt->kind == SVN_RA_SVN_STRING);
+ *result = elt->u.string;
+
+ return SVN_NO_ERROR;
+}
+
+/* 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,
+ int idx,
+ const char **result)
+{
+ svn_ra_svn_item_t *elt = &APR_ARRAY_IDX(items, idx, svn_ra_svn_item_t);
+ CHECK_PROTOCOL_COND(elt->kind == SVN_RA_SVN_STRING);
+ *result = elt->u.string->data;
+
+ return SVN_NO_ERROR;
+}
+
+/* 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,
+ int idx,
+ const char **result)
+{
+ svn_ra_svn_item_t *elt = &APR_ARRAY_IDX(items, idx, svn_ra_svn_item_t);
+ CHECK_PROTOCOL_COND(elt->kind == SVN_RA_SVN_WORD);
+ *result = elt->u.word;
+
+ return SVN_NO_ERROR;
+}
+
+/* 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,
+ int idx,
+ svn_revnum_t *result)
+{
+ svn_ra_svn_item_t *elt = &APR_ARRAY_IDX(items, idx, svn_ra_svn_item_t);
+ CHECK_PROTOCOL_COND(elt->kind == SVN_RA_SVN_NUMBER);
+ *result = (svn_revnum_t)elt->u.number;
+
+ return SVN_NO_ERROR;
+}
+
+/* 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,
+ int idx,
+ apr_uint64_t *result)
+{
+ svn_ra_svn_item_t *elt = &APR_ARRAY_IDX(items, idx, svn_ra_svn_item_t);
+ CHECK_PROTOCOL_COND(elt->kind == SVN_RA_SVN_WORD);
+ if (elt->u.word[0] == 't' && strcmp(elt->u.word, "true") == 0)
+ *result = TRUE;
+ else if (strcmp(elt->u.word, "false") == 0)
+ *result = FALSE;
+ else
+ CHECK_PROTOCOL_COND(FALSE);
+
+ return SVN_NO_ERROR;
+}
+
+/* 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,
+ int idx,
+ const apr_array_header_t **result)
+{
+ svn_ra_svn_item_t *elt = &APR_ARRAY_IDX(items, idx, svn_ra_svn_item_t);
+ CHECK_PROTOCOL_COND(elt->kind == SVN_RA_SVN_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,
+ int min,
+ int max)
+{
+ CHECK_PROTOCOL_COND(items->nelts >= min && items->nelts <= max);
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_ra_svn__read_data_log_changed_entry(const apr_array_header_t *items,
+ svn_string_t **cpath,
+ const char **action,
+ const char **copy_path,
+ svn_revnum_t *copy_rev,
+ const char **kind_str,
+ apr_uint64_t *text_mods,
+ apr_uint64_t *prop_mods)
+{
+ const apr_array_header_t *sub_items;
+
+ /* initialize optional values */
+ *copy_path = NULL;
+ *copy_rev = SVN_INVALID_REVNUM;
+ *kind_str = NULL;
+ *text_mods = SVN_RA_SVN_UNSPECIFIED_NUMBER;
+ *prop_mods = SVN_RA_SVN_UNSPECIFIED_NUMBER;
+
+ /* top-level elements (mandatory) */
+ SVN_ERR(svn_ra_svn__read_check_array_size(items, 3, INT_MAX));
+ SVN_ERR(svn_ra_svn__read_string(items, 0, cpath));
+ SVN_ERR(svn_ra_svn__read_word(items, 1, action));
+
+ /* first sub-structure (mandatory) */
+ SVN_ERR(svn_ra_svn__read_list(items, 2, &sub_items));
+ if (sub_items->nelts)
+ {
+ SVN_ERR(svn_ra_svn__read_check_array_size(sub_items, 2, 2));
+ SVN_ERR(svn_ra_svn__read_cstring(sub_items, 0, copy_path));
+ SVN_ERR(svn_ra_svn__read_revision(sub_items, 1, copy_rev));
+ }
+
+ /* second sub-structure (optional) */
+ if (items->nelts >= 4)
+ {
+ SVN_ERR(svn_ra_svn__read_list(items, 3, &sub_items));
+ switch (MIN(3, sub_items->nelts))
+ {
+ case 3 : SVN_ERR(svn_ra_svn__read_boolean(sub_items, 2, prop_mods));
+ case 2 : SVN_ERR(svn_ra_svn__read_boolean(sub_items, 1, text_mods));
+ case 1 : SVN_ERR(svn_ra_svn__read_cstring(sub_items, 0, kind_str));
+ default: break;
+ }
+ }
+
+ return SVN_NO_ERROR;
}
diff --git a/subversion/libsvn_ra_svn/protocol b/subversion/libsvn_ra_svn/protocol
index 4d98b2bb19d56..dfc1f3dc16591 100644
--- a/subversion/libsvn_ra_svn/protocol
+++ b/subversion/libsvn_ra_svn/protocol
@@ -303,18 +303,20 @@ second place for auth-request point as noted below.
get-file
params: ( path:string [ rev:number ] want-props:bool want-contents:bool
- [ want-iprops:bool ] )
+ ? want-iprops:bool )
response: ( [ checksum:string ] rev:number props:proplist
[ inherited-props:iproplist ] )
If want-contents is specified, then after sending response, server
sends file contents as a series of strings, terminated by the empty
string, followed by a second empty command response to indicate
whether an error occurred during the sending of the file.
- NOTE: the standard client never sends want-iprops, it uses get-iprops.
+ NOTE: the standard client doesn't send want-iprops as true, it uses
+ get-iprops, but does send want-iprops as false to workaround a server
+ bug in 1.8.0-1.8.8.
get-dir
params: ( path:string [ rev:number ] want-props:bool want-contents:bool
- ? ( field:dirent-field ... ) [ want-iprops:bool ] )
+ ? ( field:dirent-field ... ) ? want-iprops:bool )
response: ( rev:number props:proplist ( entry:dirent ... )
[ inherited-props:iproplist ] )]
dirent: ( name:string kind:node-kind size:number has-props:bool
@@ -322,7 +324,9 @@ second place for auth-request point as noted below.
[ last-author:string ] )
dirent-field: kind | size | has-props | created-rev | time | last-author
| word
- NOTE: the standard client never sends want-iprops, it uses get-iprops.
+ NOTE: the standard client doesn't send want-iprops as true, it uses
+ get-iprops, but does send want-iprops as false to workaround a server
+ bug in 1.8.0-1.8.8.
check-path
params: ( path:string [ rev:number ] )
@@ -339,7 +343,7 @@ second place for auth-request point as noted below.
get-mergeinfo
params: ( ( path:string ... ) [ rev:number ] inherit:word
- descendents:bool)
+ descendants:bool)
response: ( ( ( path:string merge-info:string ) ... ) )
New in svn 1.5. If no paths are specified, an empty response is
returned. If rev is not specified, the youngest revision is used.
@@ -597,7 +601,13 @@ desirability:
* The protocol version may be bumped. Clients and servers can then
choose to any range of protocol versions.
-4.1. Extending existing commands
+4.1. Limitations
+
+The current implementation limits the length of a word to 31 characters.
+Longer words, such as capability names, will be cause an error on the
+receiver side.
+
+4.2. Extending existing commands
Extending an existing command is normally done by indicating that its
tuple is allowed to end where it currently ends, for backwards
diff --git a/subversion/libsvn_ra_svn/ra_svn.h b/subversion/libsvn_ra_svn/ra_svn.h
index dc70eb72fb31f..d9fe1b2758c9d 100644
--- a/subversion/libsvn_ra_svn/ra_svn.h
+++ b/subversion/libsvn_ra_svn/ra_svn.h
@@ -123,13 +123,16 @@ 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. */
const char *realm_prefix;
+ const char *tunnel_name;
const char **tunnel_argv;
const svn_ra_callbacks2_t *callbacks;
void *callbacks_baton;
+ apr_hash_t *config;
apr_off_t bytes_read, bytes_written; /* apr_off_t's because that's what
the callback interface uses */
const char *useragent;
@@ -145,8 +148,8 @@ void svn_ra_svn__set_block_handler(svn_ra_svn_conn_t *conn,
void *baton);
/* Return true if there is input waiting on conn. */
-svn_boolean_t svn_ra_svn__input_waiting(svn_ra_svn_conn_t *conn,
- apr_pool_t *pool);
+svn_error_t *svn_ra_svn__data_available(svn_ra_svn_conn_t *conn,
+ svn_boolean_t *data_available);
/* CRAM-MD5 client implementation. */
svn_error_t *svn_ra_svn__cram_client(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
@@ -169,20 +172,20 @@ svn_error_t *svn_ra_svn__handle_failure_status(const apr_array_header_t *params,
svn_ra_svn__stream_t *svn_ra_svn__stream_from_sock(apr_socket_t *sock,
apr_pool_t *pool);
-/* Returns a stream that reads from IN_FILE and writes to OUT_FILE. */
-svn_ra_svn__stream_t *svn_ra_svn__stream_from_files(apr_file_t *in_file,
- apr_file_t *out_file,
- apr_pool_t *pool);
+/* Returns a stream that reads from IN_STREAM and writes to OUT_STREAM,
+ creating a timeout callback for OUT_STREAM if possible */
+svn_ra_svn__stream_t *svn_ra_svn__stream_from_streams(svn_stream_t *in_stream,
+ svn_stream_t *out_stream,
+ apr_pool_t *pool);
/* Create an svn_ra_svn__stream_t using READ_CB, WRITE_CB, TIMEOUT_CB,
* PENDING_CB, and BATON.
*/
-svn_ra_svn__stream_t *svn_ra_svn__stream_create(void *baton,
- svn_read_fn_t read_cb,
- svn_write_fn_t write_cb,
+svn_ra_svn__stream_t *svn_ra_svn__stream_create(svn_stream_t *in_stream,
+ svn_stream_t *out_stream,
+ void *timeout_baton,
ra_svn_timeout_fn_t timeout_cb,
- ra_svn_pending_fn_t pending_cb,
- apr_pool_t *pool);
+ apr_pool_t *result_pool);
/* Write *LEN bytes from DATA to STREAM, returning the number of bytes
* written in *LEN.
@@ -208,7 +211,9 @@ void svn_ra_svn__stream_timeout(svn_ra_svn__stream_t *stream,
apr_interval_time_t interval);
/* Return whether or not there is data pending on STREAM. */
-svn_boolean_t svn_ra_svn__stream_pending(svn_ra_svn__stream_t *stream);
+svn_error_t *
+svn_ra_svn__stream_data_available(svn_ra_svn__stream_t *stream,
+ svn_boolean_t *data_available);
/* Respond to an auth request and perform authentication. Use the Cyrus
* SASL library for mechanism negotiation and for creating authentication
diff --git a/subversion/libsvn_ra_svn/streams.c b/subversion/libsvn_ra_svn/streams.c
index 4ae93d5750030..3ad792bcdeb50 100644
--- a/subversion/libsvn_ra_svn/streams.c
+++ b/subversion/libsvn_ra_svn/streams.c
@@ -33,12 +33,14 @@
#include "svn_io.h"
#include "svn_private_config.h"
+#include "private/svn_io_private.h"
+
#include "ra_svn.h"
struct svn_ra_svn__stream_st {
- svn_stream_t *stream;
- void *baton;
- ra_svn_pending_fn_t pending_fn;
+ svn_stream_t *in_stream;
+ svn_stream_t *out_stream;
+ void *timeout_baton;
ra_svn_timeout_fn_t timeout_fn;
};
@@ -47,11 +49,6 @@ typedef struct sock_baton_t {
apr_pool_t *pool;
} sock_baton_t;
-typedef struct file_baton_t {
- apr_file_t *in_file;
- apr_file_t *out_file;
- apr_pool_t *pool;
-} file_baton_t;
/* Returns TRUE if PFD has pending data, FALSE otherwise. */
static svn_boolean_t pending(apr_pollfd_t *pfd, apr_pool_t *pool)
@@ -67,65 +64,34 @@ static svn_boolean_t pending(apr_pollfd_t *pfd, apr_pool_t *pool)
/* Functions to implement a file backed svn_ra_svn__stream_t. */
-/* Implements svn_read_fn_t */
-static svn_error_t *
-file_read_cb(void *baton, char *buffer, apr_size_t *len)
-{
- file_baton_t *b = baton;
- apr_status_t status = apr_file_read(b->in_file, buffer, len);
-
- if (status && !APR_STATUS_IS_EOF(status))
- return svn_error_wrap_apr(status, _("Can't read from connection"));
- if (*len == 0)
- return svn_error_create(SVN_ERR_RA_SVN_CONNECTION_CLOSED, NULL, NULL);
- return SVN_NO_ERROR;
-}
-
-/* Implements svn_write_fn_t */
-static svn_error_t *
-file_write_cb(void *baton, const char *buffer, apr_size_t *len)
-{
- file_baton_t *b = baton;
- apr_status_t status = apr_file_write(b->out_file, buffer, len);
- if (status)
- return svn_error_wrap_apr(status, _("Can't write to connection"));
- return SVN_NO_ERROR;
-}
-
/* Implements ra_svn_timeout_fn_t */
static void
file_timeout_cb(void *baton, apr_interval_time_t interval)
{
- file_baton_t *b = baton;
- apr_file_pipe_timeout_set(b->out_file, interval);
-}
-
-/* Implements ra_svn_pending_fn_t */
-static svn_boolean_t
-file_pending_cb(void *baton)
-{
- file_baton_t *b = baton;
- apr_pollfd_t pfd;
-
- pfd.desc_type = APR_POLL_FILE;
- pfd.desc.f = b->in_file;
+ apr_file_t *f = baton;
- return pending(&pfd, b->pool);
+ if (f)
+ apr_file_pipe_timeout_set(f, interval);
}
svn_ra_svn__stream_t *
-svn_ra_svn__stream_from_files(apr_file_t *in_file,
- apr_file_t *out_file,
- apr_pool_t *pool)
+svn_ra_svn__stream_from_streams(svn_stream_t *in_stream,
+ svn_stream_t *out_stream,
+ apr_pool_t *pool)
{
- file_baton_t *b = apr_palloc(pool, sizeof(*b));
+ apr_file_t *file;
+
+ /* If out_stream is backed by an apr_file (e.g. an PIPE) we
+ provide a working callback, otherwise the callback ignores
+ the timeout.
- b->in_file = in_file;
- b->out_file = out_file;
- b->pool = pool;
+ The callback is used to make the write non-blocking on
+ some error scenarios. ### This (legacy) usage
+ breaks the stream promise */
+ file = svn_stream__aprfile(out_stream);
- return svn_ra_svn__stream_create(b, file_read_cb, file_write_cb,
- file_timeout_cb, file_pending_cb,
+ return svn_ra_svn__stream_create(in_stream, out_stream,
+ file, file_timeout_cb,
pool);
}
@@ -155,8 +121,6 @@ sock_read_cb(void *baton, char *buffer, apr_size_t *len)
if (status && !APR_STATUS_IS_EOF(status))
return svn_error_wrap_apr(status, _("Can't read from connection"));
- if (*len == 0)
- return svn_error_create(SVN_ERR_RA_SVN_CONNECTION_CLOSED, NULL, NULL);
return SVN_NO_ERROR;
}
@@ -179,9 +143,10 @@ sock_timeout_cb(void *baton, apr_interval_time_t interval)
apr_socket_timeout_set(b->sock, interval);
}
-/* Implements ra_svn_pending_fn_t */
-static svn_boolean_t
-sock_pending_cb(void *baton)
+/* Implements svn_stream_data_available_fn_t */
+static svn_error_t *
+sock_pending_cb(void *baton,
+ svn_boolean_t *data_available)
{
sock_baton_t *b = baton;
apr_pollfd_t pfd;
@@ -189,41 +154,45 @@ sock_pending_cb(void *baton)
pfd.desc_type = APR_POLL_SOCKET;
pfd.desc.s = b->sock;
- return pending(&pfd, b->pool);
+ *data_available = pending(&pfd, b->pool);
+
+ svn_pool_clear(b->pool);
+
+ return SVN_NO_ERROR;
}
svn_ra_svn__stream_t *
svn_ra_svn__stream_from_sock(apr_socket_t *sock,
- apr_pool_t *pool)
+ apr_pool_t *result_pool)
{
- sock_baton_t *b = apr_palloc(pool, sizeof(*b));
+ sock_baton_t *b = apr_palloc(result_pool, sizeof(*b));
+ svn_stream_t *sock_stream;
b->sock = sock;
- b->pool = pool;
+ b->pool = svn_pool_create(result_pool);
- return svn_ra_svn__stream_create(b, sock_read_cb, sock_write_cb,
- sock_timeout_cb, sock_pending_cb,
- pool);
+ sock_stream = svn_stream_create(b, result_pool);
+
+ svn_stream_set_read2(sock_stream, sock_read_cb, NULL /* use default */);
+ svn_stream_set_write(sock_stream, sock_write_cb);
+ svn_stream_set_data_available(sock_stream, sock_pending_cb);
+
+ return svn_ra_svn__stream_create(sock_stream, sock_stream,
+ b, sock_timeout_cb, result_pool);
}
svn_ra_svn__stream_t *
-svn_ra_svn__stream_create(void *baton,
- svn_read_fn_t read_cb,
- svn_write_fn_t write_cb,
+svn_ra_svn__stream_create(svn_stream_t *in_stream,
+ svn_stream_t *out_stream,
+ void *timeout_baton,
ra_svn_timeout_fn_t timeout_cb,
- ra_svn_pending_fn_t pending_cb,
apr_pool_t *pool)
{
svn_ra_svn__stream_t *s = apr_palloc(pool, sizeof(*s));
- s->stream = svn_stream_empty(pool);
- svn_stream_set_baton(s->stream, baton);
- if (read_cb)
- svn_stream_set_read(s->stream, read_cb);
- if (write_cb)
- svn_stream_set_write(s->stream, write_cb);
- s->baton = baton;
+ s->in_stream = in_stream;
+ s->out_stream = out_stream;
+ s->timeout_baton = timeout_baton;
s->timeout_fn = timeout_cb;
- s->pending_fn = pending_cb;
return s;
}
@@ -231,25 +200,33 @@ svn_error_t *
svn_ra_svn__stream_write(svn_ra_svn__stream_t *stream,
const char *data, apr_size_t *len)
{
- return svn_stream_write(stream->stream, data, len);
+ return svn_error_trace(svn_stream_write(stream->out_stream, data, len));
}
svn_error_t *
svn_ra_svn__stream_read(svn_ra_svn__stream_t *stream, char *data,
apr_size_t *len)
{
- return svn_stream_read(stream->stream, data, len);
+ SVN_ERR(svn_stream_read2(stream->in_stream, data, len));
+
+ if (*len == 0)
+ return svn_error_create(SVN_ERR_RA_SVN_CONNECTION_CLOSED, NULL, NULL);
+
+ return SVN_NO_ERROR;
}
void
svn_ra_svn__stream_timeout(svn_ra_svn__stream_t *stream,
apr_interval_time_t interval)
{
- stream->timeout_fn(stream->baton, interval);
+ stream->timeout_fn(stream->timeout_baton, interval);
}
-svn_boolean_t
-svn_ra_svn__stream_pending(svn_ra_svn__stream_t *stream)
+svn_error_t *
+svn_ra_svn__stream_data_available(svn_ra_svn__stream_t *stream,
+ svn_boolean_t *data_available)
{
- return stream->pending_fn(stream->baton);
+ return svn_error_trace(
+ svn_stream_data_available(stream->in_stream,
+ data_available));
}