You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by ju...@apache.org on 2013/01/06 03:33:39 UTC
svn commit: r1429457 [7/21] - in /subversion/branches/tree-read-api: ./
build/ build/ac-macros/ build/generator/templates/ build/win32/
contrib/server-side/svncutter/ doc/ subversion/bindings/cxxhl/include/
subversion/bindings/cxxhl/include/svncxxhl/ s...
Modified: subversion/branches/tree-read-api/subversion/libsvn_ra_serf/serf.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_ra_serf/serf.c?rev=1429457&r1=1429456&r2=1429457&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_ra_serf/serf.c (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_ra_serf/serf.c Sun Jan 6 02:33:34 2013
@@ -148,7 +148,6 @@ load_config(svn_ra_serf__session_t *sess
const char *timeout_str = NULL;
const char *exceptions;
apr_port_t proxy_port;
- svn_boolean_t is_exception = FALSE;
if (config_hash)
{
@@ -191,23 +190,21 @@ load_config(svn_ra_serf__session_t *sess
SVN_CONFIG_OPTION_HTTP_PROXY_EXCEPTIONS, NULL);
if (exceptions)
{
- apr_array_header_t *l = svn_cstring_split(exceptions, ",", TRUE, pool);
- is_exception = svn_cstring_match_glob_list(session->session_url.hostname,
- l);
- }
- if (! is_exception)
- {
- /* Load the global proxy server settings, if set. */
- svn_config_get(config, &proxy_host, SVN_CONFIG_SECTION_GLOBAL,
- SVN_CONFIG_OPTION_HTTP_PROXY_HOST, NULL);
- svn_config_get(config, &port_str, SVN_CONFIG_SECTION_GLOBAL,
- SVN_CONFIG_OPTION_HTTP_PROXY_PORT, NULL);
- svn_config_get(config, &session->proxy_username,
- SVN_CONFIG_SECTION_GLOBAL,
- SVN_CONFIG_OPTION_HTTP_PROXY_USERNAME, NULL);
- svn_config_get(config, &session->proxy_password,
- SVN_CONFIG_SECTION_GLOBAL,
- SVN_CONFIG_OPTION_HTTP_PROXY_PASSWORD, NULL);
+ if (! svn_cstring_match_glob_list(session->session_url.hostname,
+ svn_cstring_split(exceptions, ",",
+ TRUE, pool)))
+ {
+ svn_config_get(config, &proxy_host, SVN_CONFIG_SECTION_GLOBAL,
+ SVN_CONFIG_OPTION_HTTP_PROXY_HOST, NULL);
+ svn_config_get(config, &port_str, SVN_CONFIG_SECTION_GLOBAL,
+ SVN_CONFIG_OPTION_HTTP_PROXY_PORT, NULL);
+ svn_config_get(config, &session->proxy_username,
+ SVN_CONFIG_SECTION_GLOBAL,
+ SVN_CONFIG_OPTION_HTTP_PROXY_USERNAME, NULL);
+ svn_config_get(config, &session->proxy_password,
+ SVN_CONFIG_SECTION_GLOBAL,
+ SVN_CONFIG_OPTION_HTTP_PROXY_PASSWORD, NULL);
+ }
}
/* Load the global ssl settings, if set. */
@@ -218,6 +215,19 @@ load_config(svn_ra_serf__session_t *sess
svn_config_get(config, &session->ssl_authorities, SVN_CONFIG_SECTION_GLOBAL,
SVN_CONFIG_OPTION_SSL_AUTHORITY_FILES, NULL);
+ /* If set, read the flag that tells us to do bulk updates or not. Defaults
+ to skelta updates. */
+ SVN_ERR(svn_config_get_bool(config, &session->bulk_updates,
+ SVN_CONFIG_SECTION_GLOBAL,
+ SVN_CONFIG_OPTION_HTTP_BULK_UPDATES,
+ FALSE));
+
+ /* Load the maximum number of parallel session connections. */
+ svn_config_get_int64(config, &session->max_connections,
+ SVN_CONFIG_SECTION_GLOBAL,
+ SVN_CONFIG_OPTION_HTTP_MAX_CONNECTIONS,
+ SVN_CONFIG_DEFAULT_OPTION_HTTP_MAX_CONNECTIONS);
+
if (config)
server_group = svn_config_find_group(config,
session->session_url.hostname,
@@ -237,24 +247,50 @@ load_config(svn_ra_serf__session_t *sess
svn_auth_set_parameter(session->wc_callbacks->auth_baton,
SVN_AUTH_PARAM_SERVER_GROUP, server_group);
- /* Load the group proxy server settings, overriding global settings. */
+ /* Load the group proxy server settings, overriding global
+ settings. We intentionally ignore 'http-proxy-exceptions'
+ here because, well, if this site was an exception, why is
+ there a per-server proxy configuration for it? */
svn_config_get(config, &proxy_host, server_group,
- SVN_CONFIG_OPTION_HTTP_PROXY_HOST, NULL);
+ SVN_CONFIG_OPTION_HTTP_PROXY_HOST, proxy_host);
svn_config_get(config, &port_str, server_group,
- SVN_CONFIG_OPTION_HTTP_PROXY_PORT, NULL);
+ SVN_CONFIG_OPTION_HTTP_PROXY_PORT, port_str);
svn_config_get(config, &session->proxy_username, server_group,
- SVN_CONFIG_OPTION_HTTP_PROXY_USERNAME, NULL);
+ SVN_CONFIG_OPTION_HTTP_PROXY_USERNAME,
+ session->proxy_username);
svn_config_get(config, &session->proxy_password, server_group,
- SVN_CONFIG_OPTION_HTTP_PROXY_PASSWORD, NULL);
+ SVN_CONFIG_OPTION_HTTP_PROXY_PASSWORD,
+ session->proxy_password);
/* Load the group ssl settings. */
SVN_ERR(svn_config_get_bool(config, &session->trust_default_ca,
server_group,
SVN_CONFIG_OPTION_SSL_TRUST_DEFAULT_CA,
- TRUE));
+ session->trust_default_ca));
svn_config_get(config, &session->ssl_authorities, server_group,
- SVN_CONFIG_OPTION_SSL_AUTHORITY_FILES, NULL);
- }
+ SVN_CONFIG_OPTION_SSL_AUTHORITY_FILES,
+ session->ssl_authorities);
+
+ /* Load the group bulk updates flag. */
+ SVN_ERR(svn_config_get_bool(config, &session->bulk_updates,
+ server_group,
+ SVN_CONFIG_OPTION_HTTP_BULK_UPDATES,
+ session->bulk_updates));
+
+ /* Load the maximum number of parallel session connections,
+ overriding global values. */
+ svn_config_get_int64(config, &session->max_connections,
+ server_group, SVN_CONFIG_OPTION_HTTP_MAX_CONNECTIONS,
+ session->max_connections);
+ }
+
+ /* Don't allow the http-max-connections value to be larger than our
+ compiled-in limit, or to be too small to operate. Broken
+ functionality and angry administrators are equally undesirable. */
+ if (session->max_connections > SVN_RA_SERF__MAX_CONNECTIONS_LIMIT)
+ session->max_connections = SVN_RA_SERF__MAX_CONNECTIONS_LIMIT;
+ if (session->max_connections < 2)
+ session->max_connections = 2;
/* Parse the connection timeout value, if any. */
session->timeout = apr_time_from_sec(DEFAULT_HTTP_TIMEOUT);
@@ -294,7 +330,9 @@ load_config(svn_ra_serf__session_t *sess
proxy_port = (apr_port_t) port;
}
else
- proxy_port = 80;
+ {
+ proxy_port = 80;
+ }
if (proxy_host)
{
@@ -314,7 +352,9 @@ load_config(svn_ra_serf__session_t *sess
serf_config_proxy(session->context, proxy_addr);
}
else
- session->using_proxy = FALSE;
+ {
+ session->using_proxy = FALSE;
+ }
/* Setup authentication. */
SVN_ERR(load_http_auth_types(pool, config, server_group,
Modified: subversion/branches/tree-read-api/subversion/libsvn_ra_serf/update.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_ra_serf/update.c?rev=1429457&r1=1429456&r2=1429457&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_ra_serf/update.c (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_ra_serf/update.c Sun Jan 6 02:33:34 2013
@@ -74,7 +74,8 @@ typedef enum report_state_e {
ABSENT_FILE,
PROP,
IGNORE_PROP_NAME,
- NEED_PROP_NAME
+ NEED_PROP_NAME,
+ TXDELTA
} report_state_e;
@@ -228,6 +229,8 @@ typedef struct report_info_t
const char *final_sha1_checksum;
svn_txdelta_window_handler_t textdelta;
void *textdelta_baton;
+ svn_stream_t *svndiff_decoder;
+ svn_stream_t *base64_decoder;
/* Checksum for close_file */
const char *final_checksum;
@@ -318,6 +321,9 @@ struct report_context_t {
/* Do we want the server to send copyfrom args or not? */
svn_boolean_t send_copyfrom_args;
+ /* Is the server sending everything in one response? */
+ svn_boolean_t send_all_mode;
+
/* Is the server including properties inline for newly added
files/dirs? */
svn_boolean_t add_props_included;
@@ -497,26 +503,42 @@ update_cdata(svn_ra_serf__xml_estate_t *
static svn_ra_serf__connection_t *
get_best_connection(report_context_t *ctx)
{
- svn_ra_serf__connection_t * conn;
- int first_conn;
+ svn_ra_serf__connection_t *conn;
+ int first_conn = 1;
/* Skip the first connection if the REPORT response hasn't been completely
- received yet. */
- first_conn = ctx->report_received ? 0: 1;
-
+ received yet or if we're being told to limit our connections to
+ 2 (because this could be an attempt to ensure that we do all our
+ auxiliary GETs/PROPFINDs on a single connection).
+
+ ### FIXME: This latter requirement (max_connections > 2) is
+ ### really just a hack to work around the fact that some update
+ ### editor implementations (such as svnrdump's dump editor)
+ ### simply can't handle the way ra_serf violates the editor v1
+ ### drive ordering requirements.
+ ###
+ ### See http://subversion.tigris.org/issues/show_bug.cgi?id=4116.
+ */
+ if (ctx->report_received && (ctx->sess->max_connections > 2))
+ first_conn = 0;
+
+ /* Currently, we just cycle connections. In the future we could
+ store the number of pending requests on each connection, or
+ perform other heuristics, to achieve better connection usage.
+ (As an optimization, if there's only one available auxiliary
+ connection to use, don't bother doing all the cur_conn math --
+ just return that one connection.) */
if (ctx->sess->num_conns - first_conn == 1)
- return ctx->sess->conns[first_conn];
-
- /* Currently just cycle connections. In future we could store number of
- * pending requests on each connection for better connection usage. */
- conn = ctx->sess->conns[ctx->sess->cur_conn];
-
- /* Switch our connection. */
- ctx->sess->cur_conn++;
-
- if (ctx->sess->cur_conn >= ctx->sess->num_conns)
- ctx->sess->cur_conn = first_conn;
-
+ {
+ conn = ctx->sess->conns[first_conn];
+ }
+ else
+ {
+ conn = ctx->sess->conns[ctx->sess->cur_conn];
+ ctx->sess->cur_conn++;
+ if (ctx->sess->cur_conn >= ctx->sess->num_conns)
+ ctx->sess->cur_conn = first_conn;
+ }
return conn;
}
@@ -1448,17 +1470,6 @@ fetch_file(report_context_t *ctx, report
/* What connection should we go on? */
conn = get_best_connection(ctx);
- /* go fetch info->name from DAV:checked-in */
- info->url = svn_ra_serf__get_ver_prop(info->props, info->base_name,
- info->base_rev, "DAV:", "checked-in");
-
- if (!info->url)
- {
- return svn_error_create(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
- _("The REPORT or PROPFIND response did not "
- "include the requested checked-in value"));
- }
-
/* If needed, create the PROPFIND to retrieve the file's properties. */
info->propfind_handler = NULL;
if (info->fetch_props)
@@ -1625,9 +1636,15 @@ start_report(svn_ra_serf__xml_parser_t *
if (state == NONE && strcmp(name.name, "update-report") == 0)
{
- const char *val = svn_xml_get_attr_value("inline-props", attrs);
+ const char *val;
+
+ val = svn_xml_get_attr_value("inline-props", attrs);
if (val && (strcmp(val, "true") == 0))
ctx->add_props_included = TRUE;
+
+ val = svn_xml_get_attr_value("send-all", attrs);
+ if (val && (strcmp(val, "true") == 0))
+ ctx->send_all_mode = TRUE;
}
else if (state == NONE && strcmp(name.name, "target-revision") == 0)
{
@@ -1830,7 +1847,11 @@ start_report(svn_ra_serf__xml_parser_t *
info = push_state(parser, ctx, ADD_FILE);
info->base_rev = SVN_INVALID_REVNUM;
- info->fetch_file = TRUE;
+
+ /* If the server isn't in "send-all" mode, we should expect to
+ fetch contents for added files. */
+ if (! ctx->send_all_mode)
+ info->fetch_file = TRUE;
/* If the server isn't included properties for added items,
we'll need to fetch them ourselves. */
@@ -2070,7 +2091,31 @@ start_report(svn_ra_serf__xml_parser_t *
addition to <fetch-file>s and such) when *not* in
"send-all" mode. As a client, we're smart enough to know
that's wrong, so we'll just ignore these tags. */
- ;
+ if (ctx->send_all_mode)
+ {
+ const svn_delta_editor_t *update_editor = ctx->update_editor;
+
+ info = push_state(parser, ctx, TXDELTA);
+
+ if (! info->file_baton)
+ {
+ SVN_ERR(open_updated_file(info, FALSE, info->pool));
+ }
+
+ info->base_checksum = svn_xml_get_attr_value("base-checksum",
+ attrs);
+ SVN_ERR(update_editor->apply_textdelta(info->file_baton,
+ info->base_checksum,
+ info->editor_pool,
+ &info->textdelta,
+ &info->textdelta_baton));
+ info->svndiff_decoder = svn_txdelta_parse_svndiff(
+ info->textdelta,
+ info->textdelta_baton,
+ TRUE, info->pool);
+ info->base64_decoder = svn_base64_decode(info->svndiff_decoder,
+ info->pool);
+ }
}
else
{
@@ -2264,13 +2309,89 @@ end_report(svn_ra_serf__xml_parser_t *pa
info->delta_base = value ? value->data : NULL;
}
- SVN_ERR(fetch_file(ctx, info));
+ /* go fetch info->name from DAV:checked-in */
+ info->url = svn_ra_serf__get_ver_prop(info->props, info->base_name,
+ info->base_rev, "DAV:", "checked-in");
+ if (!info->url)
+ {
+ return svn_error_create(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
+ _("The REPORT or PROPFIND response did not "
+ "include the requested checked-in value"));
+ }
+
+ /* If the server is in "send-all" mode, we might have opened the
+ file when we started seeing content for it. If we didn't get
+ any content for it, we still need to open the file. But in
+ any case, we can then immediately close it. */
+ if (ctx->send_all_mode)
+ {
+ if (! info->file_baton)
+ {
+ SVN_ERR(open_updated_file(info, FALSE, info->pool));
+ }
+ SVN_ERR(close_updated_file(info, info->pool));
+ info->dir->ref_count--;
+ }
+ /* Otherwise, if the server is *not* in "send-all" mode, we
+ should be at a point where we can queue up any auxiliary
+ content-fetching requests. */
+ else
+ {
+ SVN_ERR(fetch_file(ctx, info));
+ }
+
svn_ra_serf__xml_pop_state(parser);
}
else if (state == ADD_FILE && strcmp(name.name, "add-file") == 0)
{
- /* We should have everything we need to fetch the file. */
- SVN_ERR(fetch_file(ctx, parser->state->private));
+ report_info_t *info = parser->state->private;
+
+ /* go fetch info->name from DAV:checked-in */
+ info->url = svn_ra_serf__get_ver_prop(info->props, info->base_name,
+ info->base_rev, "DAV:", "checked-in");
+ if (!info->url)
+ {
+ return svn_error_create(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
+ _("The REPORT or PROPFIND response did not "
+ "include the requested checked-in value"));
+ }
+
+ /* If the server is in "send-all" mode, we might have opened the
+ file when we started seeing content for it. If we didn't get
+ any content for it, we still need to open the file. But in
+ any case, we can then immediately close it. */
+ if (ctx->send_all_mode)
+ {
+ if (! info->file_baton)
+ {
+ SVN_ERR(open_updated_file(info, FALSE, info->pool));
+ }
+ SVN_ERR(close_updated_file(info, info->pool));
+ info->dir->ref_count--;
+ }
+ /* Otherwise, if the server is *not* in "send-all" mode, we
+ should be at a point where we can queue up any auxiliary
+ content-fetching requests. */
+ else
+ {
+ SVN_ERR(fetch_file(ctx, info));
+ }
+
+ svn_ra_serf__xml_pop_state(parser);
+ }
+ else if (state == TXDELTA && strcmp(name.name, "txdelta") == 0)
+ {
+ report_info_t *info = parser->state->private;
+
+ /* Pre 1.2, mod_dav_svn was using <txdelta> tags (in addition to
+ <fetch-file>s and such) when *not* in "send-all" mode. As a
+ client, we're smart enough to know that's wrong, so when not
+ in "receiving-all" mode, we'll ignore these tags. */
+ if (ctx->send_all_mode)
+ {
+ SVN_ERR(svn_stream_close(info->base64_decoder));
+ }
+
svn_ra_serf__xml_pop_state(parser);
}
else if (state == PROP)
@@ -2397,6 +2518,27 @@ cdata_report(svn_ra_serf__xml_parser_t *
svn_stringbuf_appendbytes(info->prop_value, data, len);
}
+ else if (parser->state->current_state == TXDELTA)
+ {
+ /* Pre 1.2, mod_dav_svn was using <txdelta> tags (in addition to
+ <fetch-file>s and such) when *not* in "send-all" mode. As a
+ client, we're smart enough to know that's wrong, so when not
+ in "receiving-all" mode, we'll ignore these tags. */
+ if (ctx->send_all_mode)
+ {
+ apr_size_t nlen = len;
+ report_info_t *info = parser->state->private;
+
+ SVN_ERR(svn_stream_write(info->base64_decoder, data, &nlen));
+ if (nlen != len)
+ {
+ /* Short write without associated error? "Can't happen." */
+ return svn_error_createf(SVN_ERR_STREAM_UNEXPECTED_EOF, NULL,
+ _("Error writing to '%s': unexpected EOF"),
+ info->name);
+ }
+ }
+ }
return SVN_NO_ERROR;
}
@@ -2732,7 +2874,7 @@ finish_report(void *report_baton,
}
/* Open extra connections if we have enough requests to send. */
- if (sess->num_conns < MAX_NR_OF_CONNS)
+ if (sess->num_conns < sess->max_connections)
SVN_ERR(open_connection_if_needed(sess, report->num_active_fetches +
report->num_active_propfinds));
@@ -3035,9 +3177,47 @@ make_update_reporter(svn_ra_session_t *r
svn_io_file_del_on_pool_cleanup,
report->pool, scratch_pool));
- svn_xml_make_open_tag(&buf, scratch_pool, svn_xml_normal, "S:update-report",
- "xmlns:S", SVN_XML_NAMESPACE,
- NULL);
+ if (sess->server_allows_bulk)
+ {
+ if (apr_strnatcasecmp(sess->server_allows_bulk, "off") == 0)
+ {
+ /* Server doesn't want bulk updates */
+ sess->bulk_updates = FALSE;
+ }
+ else if (apr_strnatcasecmp(sess->server_allows_bulk, "prefer") == 0)
+ {
+ /* Server prefers bulk updates, and we respect that */
+ sess->bulk_updates = TRUE;
+ }
+ else
+ {
+ /* Server allows bulk updates, but doesn't dictate its use. Do
+ whatever is the default or what the user defined in the config. */
+ }
+ }
+ else
+ {
+ /* Pre-1.8 server didn't send the bulk_updates header. Do
+ whatever is the default or what the user defined in the config. */
+ }
+
+ if (sess->bulk_updates)
+ {
+ svn_xml_make_open_tag(&buf, scratch_pool, svn_xml_normal,
+ "S:update-report",
+ "xmlns:S", SVN_XML_NAMESPACE, "send-all", "true",
+ NULL);
+ }
+ else
+ {
+ svn_xml_make_open_tag(&buf, scratch_pool, svn_xml_normal,
+ "S:update-report",
+ "xmlns:S", SVN_XML_NAMESPACE,
+ NULL);
+ /* Subversion 1.8+ servers can be told to send properties for newly
+ added items inline even when doing a skelta response. */
+ make_simple_xml_tag(&buf, "S:include-props", "yes", scratch_pool);
+ }
make_simple_xml_tag(&buf, "S:src-path", report->source, scratch_pool);
@@ -3076,9 +3256,20 @@ make_update_reporter(svn_ra_session_t *r
make_simple_xml_tag(&buf, "S:recursive", "no", scratch_pool);
}
- /* Subversion 1.8+ servers can be told to send properties for newly
- added items inline even when doing a skelta response. */
- make_simple_xml_tag(&buf, "S:include-props", "yes", scratch_pool);
+ /* When in 'send-all' mode, mod_dav_svn will assume that it should
+ calculate and transmit real text-deltas (instead of empty windows
+ that merely indicate "text is changed") unless it finds this
+ element.
+
+ NOTE: Do NOT count on servers actually obeying this, as some exist
+ which obey send-all, but do not check for this directive at all!
+
+ NOTE 2: When not in 'send-all' mode, mod_dav_svn can still be configured to
+ override our request and send text-deltas. */
+ if (! text_deltas)
+ {
+ make_simple_xml_tag(&buf, "S:text-deltas", "no", scratch_pool);
+ }
make_simple_xml_tag(&buf, "S:depth", svn_depth_to_word(depth), scratch_pool);
Modified: subversion/branches/tree-read-api/subversion/libsvn_ra_svn/cyrus_auth.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_ra_svn/cyrus_auth.c?rev=1429457&r1=1429456&r2=1429457&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_ra_svn/cyrus_auth.c (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_ra_svn/cyrus_auth.c Sun Jan 6 02:33:34 2013
@@ -179,7 +179,7 @@ svn_ra_svn__sasl_common_init(apr_pool_t
sasl_mutex_unlock_cb,
sasl_mutex_free_cb);
free_mutexes = apr_array_make(sasl_pool, 0, sizeof(svn_mutex__t *));
- return svn_mutex__init(&array_mutex, TRUE, sasl_pool);
+ SVN_ERR(svn_mutex__init(&array_mutex, TRUE, sasl_pool));
#endif /* APR_HAS_THREADS */
Modified: subversion/branches/tree-read-api/subversion/libsvn_repos/authz.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_repos/authz.c?rev=1429457&r1=1429456&r2=1429457&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_repos/authz.c (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_repos/authz.c Sun Jan 6 02:33:34 2013
@@ -34,6 +34,7 @@
#include "svn_config.h"
#include "svn_ctype.h"
#include "private/svn_fspath.h"
+#include "repos.h"
/*** Structures. ***/
@@ -751,27 +752,222 @@ static svn_boolean_t authz_validate_sect
}
-
-/*** Public functions. ***/
-
-svn_error_t *
-svn_repos_authz_read(svn_authz_t **authz_p, const char *file,
- svn_boolean_t must_exist, apr_pool_t *pool)
+/* Walk the configuration in AUTHZ looking for any errors. */
+static svn_error_t *
+authz_validate(svn_authz_t *authz, apr_pool_t *pool)
{
- svn_authz_t *authz = apr_palloc(pool, sizeof(*authz));
struct authz_validate_baton baton = { 0 };
baton.err = SVN_NO_ERROR;
-
- /* Load the rule file. */
- SVN_ERR(svn_config_read2(&authz->cfg, file, must_exist, TRUE, pool));
baton.config = authz->cfg;
- /* Step through the entire rule file, stopping on error. */
+ /* Step through the entire rule file stopping on error. */
svn_config_enumerate_sections2(authz->cfg, authz_validate_section,
&baton, pool);
SVN_ERR(baton.err);
+ return SVN_NO_ERROR;
+}
+
+
+/* Retrieve the file at DIRENT (contained in a repo) then parse it as a config
+ * file placing the result into CFG_P allocated in POOL.
+ *
+ * If DIRENT is not a valid authz rule file then return SVN_AUTHZ_INVALD_CONFIG
+ * as the error. The contents of CFG_P is then undefined. If MUST_EXIST is
+ * TRUE, a missing authz file is also an error.
+ *
+ * SCRATCH_POOL will be used for temporary allocations. */
+static svn_error_t *
+authz_retrieve_config_repo(svn_config_t **cfg_p, const char *dirent,
+ svn_boolean_t must_exist,
+ apr_pool_t *result_pool, apr_pool_t *scratch_pool)
+{
+ svn_error_t *err;
+ svn_repos_t *repos;
+ const char *repos_root_dirent;
+ const char *fs_path;
+ svn_fs_t *fs;
+ svn_fs_root_t *root;
+ svn_revnum_t youngest_rev;
+ svn_node_kind_t node_kind;
+ svn_stream_t *contents;
+
+ /* Search for a repository in the full path. */
+ repos_root_dirent = svn_repos_find_root_path(dirent, scratch_pool);
+ if (!repos_root_dirent)
+ return svn_error_createf(SVN_ERR_AUTHZ_INVALID_CONFIG, NULL,
+ "Unable to find repository at '%s'", dirent);
+
+ /* Attempt to open a repository at repos_root_dirent. */
+ SVN_ERR(svn_repos_open2(&repos, repos_root_dirent, NULL, scratch_pool));
+
+ fs_path = &dirent[strlen(repos_root_dirent)];
+
+ /* Root path is always a directory so no reason to go any further */
+ if (*fs_path == '\0')
+ return svn_error_createf(SVN_ERR_AUTHZ_INVALID_CONFIG, NULL,
+ "'/' is not a file in repo '%s'",
+ repos_root_dirent);
+
+ /* We skip some things that are non-important for how we're going to use
+ * this repo connection. We do not set any capabilities since none of
+ * the current ones are important for what we're doing. We also do not
+ * setup the environment that repos hooks would run under since we won't
+ * be triggering any. */
+
+ /* Get the filesystem. */
+ fs = svn_repos_fs(repos);
+
+ /* Find HEAD and the revision root */
+ SVN_ERR(svn_fs_youngest_rev(&youngest_rev, fs, scratch_pool));
+ SVN_ERR(svn_fs_revision_root(&root, fs, youngest_rev, scratch_pool));
+
+ SVN_ERR(svn_fs_check_path(&node_kind, root, fs_path, scratch_pool));
+ if (node_kind == svn_node_none)
+ {
+ if (!must_exist)
+ {
+ SVN_ERR(svn_config_create(cfg_p, TRUE, scratch_pool));
+ return SVN_NO_ERROR;
+ }
+ else
+ {
+ return svn_error_createf(SVN_ERR_AUTHZ_INVALID_CONFIG, NULL,
+ "'%s' path not found in repo '%s'", fs_path,
+ repos_root_dirent);
+ }
+ }
+ else if (node_kind != svn_node_file)
+ {
+ return svn_error_createf(SVN_ERR_AUTHZ_INVALID_CONFIG, NULL,
+ "'%s' is not a file in repo '%s'", fs_path,
+ repos_root_dirent);
+ }
+
+ SVN_ERR(svn_fs_file_contents(&contents, root, fs_path, scratch_pool));
+ err = svn_config_parse(cfg_p, contents, TRUE, result_pool);
+
+ /* Add the URL to the error stack since the parser doesn't have it. */
+ if (err != SVN_NO_ERROR)
+ return svn_error_createf(err->apr_err, err,
+ "Error parsing config file: '%s' in repo '%s':",
+ fs_path, repos_root_dirent);
+
+ return SVN_NO_ERROR;
+}
+
+/* Given a PATH which might be a realative repo URL (^/), an absolute
+ * local repo URL (file://), an absolute path outside of the repo
+ * or a location in the Windows registry.
+ *
+ * Retrieve the configuration data that PATH points at and parse it into
+ * CFG_P allocated in POOL.
+ *
+ * If PATH is not a valid authz rule file then return SVN_AUTHZ_INVALD_CONFIG
+ * as the error. The contents of CFG_P is then undefined. If MUST_EXIST is
+ * TRUE, a missing authz file is also an error.
+ *
+ * REPOS_ROOT points at the root of the repos you are
+ * going to apply the authz against, can be NULL if you are sure that you
+ * don't have a repos relative URL in PATH. */
+static svn_error_t *
+authz_retrieve_config(svn_config_t **cfg_p, const char *path,
+ svn_boolean_t must_exist, const char *repos_root,
+ apr_pool_t *pool)
+{
+ if (svn_path_is_repos_relative_url(path))
+ {
+ const char *dirent;
+ svn_error_t *err;
+ apr_pool_t *scratch_pool = svn_pool_create(pool);
+
+ err = svn_path_resolve_repos_relative_url(&dirent, path,
+ repos_root, scratch_pool);
+ dirent = svn_dirent_canonicalize(dirent, scratch_pool);
+
+ if (err == SVN_NO_ERROR)
+ err = authz_retrieve_config_repo(cfg_p, dirent, must_exist, pool,
+ scratch_pool);
+
+ /* Close the repos and streams we opened. */
+ svn_pool_destroy(scratch_pool);
+
+ return err;
+ }
+ else if (svn_path_is_url(path))
+ {
+ const char *dirent;
+ svn_error_t *err;
+ apr_pool_t *scratch_pool = svn_pool_create(pool);
+
+ err = svn_uri_get_dirent_from_file_url(&dirent, path, scratch_pool);
+
+ if (err == SVN_NO_ERROR)
+ err = authz_retrieve_config_repo(cfg_p, dirent, must_exist, pool,
+ scratch_pool);
+
+ /* Close the repos and streams we opened. */
+ svn_pool_destroy(scratch_pool);
+
+ return err;
+ }
+ else
+ {
+ /* Outside of repo file or Windows registry*/
+ SVN_ERR(svn_config_read2(cfg_p, path, must_exist, TRUE, pool));
+ }
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_repos__authz_read(svn_authz_t **authz_p, const char *path,
+ svn_boolean_t must_exist, svn_boolean_t accept_urls,
+ const char *repos_root, apr_pool_t *pool)
+{
+ svn_authz_t *authz = apr_palloc(pool, sizeof(*authz));
+
+ /* Load the rule file */
+ if (accept_urls)
+ SVN_ERR(authz_retrieve_config(&authz->cfg, path, must_exist, repos_root,
+ pool));
+ else
+ SVN_ERR(svn_config_read2(&authz->cfg, path, must_exist, TRUE, pool));
+
+ /* Make sure there are no errors in the configuration. */
+ SVN_ERR(authz_validate(authz, pool));
+
+ *authz_p = authz;
+ return SVN_NO_ERROR;
+}
+
+
+
+/*** Public functions. ***/
+
+svn_error_t *
+svn_repos_authz_read2(svn_authz_t **authz_p, const char *path,
+ svn_boolean_t must_exist, const char *repos_root,
+ apr_pool_t *pool)
+{
+ return svn_repos__authz_read(authz_p, path, must_exist, TRUE, repos_root,
+ pool);
+}
+
+
+svn_error_t *
+svn_repos_authz_parse(svn_authz_t **authz_p, svn_stream_t *stream,
+ apr_pool_t *pool)
+{
+ svn_authz_t *authz = apr_palloc(pool, sizeof(*authz));
+
+ /* Parse the stream */
+ SVN_ERR(svn_config_parse(&authz->cfg, stream, TRUE, pool));
+
+ /* Make sure there are no errors in the configuration. */
+ SVN_ERR(authz_validate(authz, pool));
+
*authz_p = authz;
return SVN_NO_ERROR;
}
Modified: subversion/branches/tree-read-api/subversion/libsvn_repos/deprecated.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_repos/deprecated.c?rev=1429457&r1=1429456&r2=1429457&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_repos/deprecated.c (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_repos/deprecated.c Sun Jan 6 02:33:34 2013
@@ -1006,3 +1006,12 @@ svn_repos_fs_begin_txn_for_update(svn_fs
return SVN_NO_ERROR;
}
+
+/*** From authz.c ***/
+
+svn_error_t *
+svn_repos_authz_read(svn_authz_t **authz_p, const char *file,
+ svn_boolean_t must_exist, apr_pool_t *pool)
+{
+ return svn_repos__authz_read(authz_p, file, must_exist, FALSE, NULL, pool);
+}
Modified: subversion/branches/tree-read-api/subversion/libsvn_repos/fs-wrap.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_repos/fs-wrap.c?rev=1429457&r1=1429456&r2=1429457&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_repos/fs-wrap.c (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_repos/fs-wrap.c Sun Jan 6 02:33:34 2013
@@ -743,6 +743,7 @@ svn_error_t *
svn_repos_fs_get_inherited_props(apr_array_header_t **inherited_props_p,
svn_fs_root_t *root,
const char *path,
+ const char *propname,
svn_repos_authz_func_t authz_read_func,
void *authz_read_baton,
apr_pool_t *result_pool,
@@ -757,7 +758,7 @@ svn_repos_fs_get_inherited_props(apr_arr
while (!(parent_path[0] == '/' && parent_path[1] == '\0'))
{
svn_boolean_t allowed = TRUE;
- apr_hash_t *parent_properties;
+ apr_hash_t *parent_properties = NULL;
svn_pool_clear(iterpool);
parent_path = svn_fspath__dirname(parent_path, scratch_pool);
@@ -767,8 +768,25 @@ svn_repos_fs_get_inherited_props(apr_arr
authz_read_baton, iterpool));
if (allowed)
{
- SVN_ERR(svn_fs_node_proplist(&parent_properties, root,
- parent_path, result_pool));
+ if (propname)
+ {
+ svn_string_t *propval;
+
+ SVN_ERR(svn_fs_node_prop(&propval, root, parent_path, propname,
+ result_pool));
+ if (propval)
+ {
+ parent_properties = apr_hash_make(result_pool);
+ apr_hash_set(parent_properties, propname,
+ APR_HASH_KEY_STRING, propval);
+ }
+ }
+ else
+ {
+ SVN_ERR(svn_fs_node_proplist(&parent_properties, root,
+ parent_path, result_pool));
+ }
+
if (parent_properties && apr_hash_count(parent_properties))
{
svn_prop_inherited_item_t *i_props =
Modified: subversion/branches/tree-read-api/subversion/libsvn_repos/repos.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_repos/repos.c?rev=1429457&r1=1429456&r2=1429457&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_repos/repos.c (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_repos/repos.c Sun Jan 6 02:33:34 2013
@@ -1019,8 +1019,10 @@ create_conf(svn_repos_t *repos, apr_pool
"### The authz-db option controls the location of the authorization" NL
"### rules for path-based access control. Unless you specify a path" NL
"### starting with a /, the file's location is relative to the" NL
-"### directory containing this file. If you don't specify an" NL
-"### authz-db, no path-based access control is done." NL
+"### directory containing this file. The specified path may be a" NL
+"### repository relative URL (^/) or an absolute file:// URL to a text" NL
+"### file in a Subversion repository. If you don't specify an authz-db," NL
+"### no path-based access control is done." NL
"### Uncomment the line below to use the default authorization file." NL
"# authz-db = " SVN_REPOS__CONF_AUTHZ NL
"### This option specifies the authentication realm of the repository." NL
Modified: subversion/branches/tree-read-api/subversion/libsvn_repos/repos.h
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_repos/repos.h?rev=1429457&r1=1429456&r2=1429457&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_repos/repos.h (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_repos/repos.h Sun Jan 6 02:33:34 2013
@@ -304,6 +304,31 @@ svn_repos__hooks_post_unlock(svn_repos_t
apr_pool_t *pool);
+/*** Authz Functions ***/
+
+/* Read authz configuration data from PATH into *AUTHZ_P, allocated
+ in POOL.
+
+ PATH may be a file or a registry path and iff ACCEPT_URLS is set
+ it may also be a repos relative url or an absolute file url. When
+ ACCEPT_URLS is FALSE REPOS_ROOT can be NULL.
+
+ If PATH is not a valid authz rule file, then return
+ SVN_AUTHZ_INVALID_CONFIG. The contents of *AUTHZ_P is then
+ undefined. If MUST_EXIST is TRUE, a missing authz file is also
+ an error.
+
+ If PATH is a repos relative URL then REPOS_ROOT must be set to
+ the root of the repository the authz configuration will be used with. */
+svn_error_t *
+svn_repos__authz_read(svn_authz_t **authz_p,
+ const char *path,
+ svn_boolean_t must_exist,
+ svn_boolean_t accept_urls,
+ const char *repos_root,
+ apr_pool_t *pool);
+
+
/*** Utility Functions ***/
/* Set *CHANGED_P to TRUE if ROOT1/PATH1 and ROOT2/PATH2 have
Modified: subversion/branches/tree-read-api/subversion/libsvn_subr/auth.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_subr/auth.c?rev=1429457&r1=1429456&r2=1429457&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_subr/auth.c (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_subr/auth.c Sun Jan 6 02:33:34 2013
@@ -422,9 +422,9 @@ svn_auth_get_platform_specific_provider(
const char *library_label, *library_name;
const char *provider_function_name, *version_function_name;
library_name = apr_psprintf(pool,
- "libsvn_auth_%s-%d.so.0",
+ "libsvn_auth_%s-%d.so.%d",
provider_name,
- SVN_VER_MAJOR);
+ SVN_VER_MAJOR, SVN_SOVERSION);
library_label = apr_psprintf(pool, "svn_%s", provider_name);
provider_function_name = apr_psprintf(pool,
"svn_auth_get_%s_%s_provider",
Modified: subversion/branches/tree-read-api/subversion/libsvn_subr/cache-membuffer.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_subr/cache-membuffer.c?rev=1429457&r1=1429456&r2=1429457&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_subr/cache-membuffer.c (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_subr/cache-membuffer.c Sun Jan 6 02:33:34 2013
@@ -1973,7 +1973,7 @@ svn_membuffer_cache_get(void **value_p,
*/
if (++cache->alloc_counter > ALLOCATIONS_PER_POOL_CLEAR)
{
- apr_pool_clear(cache->pool);
+ svn_pool_clear(cache->pool);
cache->alloc_counter = 0;
}
@@ -2004,7 +2004,7 @@ svn_membuffer_cache_set(void *cache_void
cache->alloc_counter += 3;
if (cache->alloc_counter > ALLOCATIONS_PER_POOL_CLEAR)
{
- apr_pool_clear(cache->pool);
+ svn_pool_clear(cache->pool);
cache->alloc_counter = 0;
}
@@ -2062,7 +2062,7 @@ svn_membuffer_cache_get_partial(void **v
if (++cache->alloc_counter > ALLOCATIONS_PER_POOL_CLEAR)
{
- apr_pool_clear(cache->pool);
+ svn_pool_clear(cache->pool);
cache->alloc_counter = 0;
}
Modified: subversion/branches/tree-read-api/subversion/libsvn_subr/cache_config.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_subr/cache_config.c?rev=1429457&r1=1429456&r2=1429457&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_subr/cache_config.c (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_subr/cache_config.c Sun Jan 6 02:33:34 2013
@@ -131,7 +131,7 @@ svn_cache__get_global_membuffer_cache(vo
{
/* Memory and error cleanup */
svn_error_clear(err);
- apr_pool_destroy(pool);
+ svn_pool_destroy(pool);
/* Prevent future attempts to create the cache. However, an
* existing cache instance (see next comment) remains valid.
@@ -155,7 +155,7 @@ svn_cache__get_global_membuffer_cache(vo
*/
old_cache = apr_atomic_casptr((volatile void **)&cache, new_cache, NULL);
if (old_cache != NULL)
- apr_pool_destroy(pool);
+ svn_pool_destroy(pool);
}
return cache;
Modified: subversion/branches/tree-read-api/subversion/libsvn_subr/cmdline.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_subr/cmdline.c?rev=1429457&r1=1429456&r2=1429457&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_subr/cmdline.c (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_subr/cmdline.c Sun Jan 6 02:33:34 2013
@@ -33,14 +33,17 @@
#include <unistd.h>
#else
#include <crtdbg.h>
+#include <io.h>
#endif
+#include <apr.h> /* for STDIN_FILENO */
#include <apr_errno.h> /* for apr_strerror */
#include <apr_general.h> /* for apr_initialize/apr_terminate */
#include <apr_strings.h> /* for apr_snprintf */
#include <apr_pools.h>
#include "svn_cmdline.h"
+#include "svn_ctype.h"
#include "svn_dso.h"
#include "svn_dirent_uri.h"
#include "svn_path.h"
@@ -52,9 +55,13 @@
#include "svn_xml.h"
#include "svn_base64.h"
#include "svn_config.h"
+#include "svn_sorts.h"
+#include "svn_props.h"
+#include "svn_subst.h"
#include "private/svn_cmdline_private.h"
#include "private/svn_utf_private.h"
+#include "private/svn_string_private.h"
#include "svn_private_config.h"
@@ -758,3 +765,546 @@ svn_cmdline__apply_config_options(apr_ha
return SVN_NO_ERROR;
}
+
+/* Return a copy, allocated in POOL, of the next line of text from *STR
+ * up to and including a CR and/or an LF. Change *STR to point to the
+ * remainder of the string after the returned part. If there are no
+ * characters to be returned, return NULL; never return an empty string.
+ */
+static const char *
+next_line(const char **str, apr_pool_t *pool)
+{
+ const char *start = *str;
+ const char *p = *str;
+
+ /* n.b. Throughout this fn, we never read any character after a '\0'. */
+ /* Skip over all non-EOL characters, if any. */
+ while (*p != '\r' && *p != '\n' && *p != '\0')
+ p++;
+ /* Skip over \r\n or \n\r or \r or \n, if any. */
+ if (*p == '\r' || *p == '\n')
+ {
+ char c = *p++;
+
+ if ((c == '\r' && *p == '\n') || (c == '\n' && *p == '\r'))
+ p++;
+ }
+
+ /* Now p points after at most one '\n' and/or '\r'. */
+ *str = p;
+
+ if (p == start)
+ return NULL;
+
+ return svn_string_ncreate(start, p - start, pool)->data;
+}
+
+const char *
+svn_cmdline__indent_string(const char *str,
+ const char *indent,
+ apr_pool_t *pool)
+{
+ svn_stringbuf_t *out = svn_stringbuf_create_empty(pool);
+ const char *line;
+
+ while ((line = next_line(&str, pool)))
+ {
+ svn_stringbuf_appendcstr(out, indent);
+ svn_stringbuf_appendcstr(out, line);
+ }
+ return out->data;
+}
+
+svn_error_t *
+svn_cmdline__print_prop_hash(svn_stream_t *out,
+ apr_hash_t *prop_hash,
+ svn_boolean_t names_only,
+ apr_pool_t *pool)
+{
+ apr_array_header_t *sorted_props;
+ int i;
+
+ sorted_props = svn_sort__hash(prop_hash, svn_sort_compare_items_lexically,
+ pool);
+ for (i = 0; i < sorted_props->nelts; i++)
+ {
+ svn_sort__item_t item = APR_ARRAY_IDX(sorted_props, i, svn_sort__item_t);
+ const char *pname = item.key;
+ svn_string_t *propval = item.value;
+ const char *pname_stdout;
+
+ if (svn_prop_needs_translation(pname))
+ SVN_ERR(svn_subst_detranslate_string(&propval, propval,
+ TRUE, pool));
+
+ SVN_ERR(svn_cmdline_cstring_from_utf8(&pname_stdout, pname, pool));
+
+ if (out)
+ {
+ pname_stdout = apr_psprintf(pool, " %s\n", pname_stdout);
+ SVN_ERR(svn_subst_translate_cstring2(pname_stdout, &pname_stdout,
+ APR_EOL_STR, /* 'native' eol */
+ FALSE, /* no repair */
+ NULL, /* no keywords */
+ FALSE, /* no expansion */
+ pool));
+
+ SVN_ERR(svn_stream_puts(out, pname_stdout));
+ }
+ else
+ {
+ /* ### We leave these printfs for now, since if propval wasn't
+ translated above, we don't know anything about its encoding.
+ In fact, it might be binary data... */
+ printf(" %s\n", pname_stdout);
+ }
+
+ if (!names_only)
+ {
+ /* Add an extra newline to the value before indenting, so that
+ * every line of output has the indentation whether the value
+ * already ended in a newline or not. */
+ const char *newval = apr_psprintf(pool, "%s\n", propval->data);
+ const char *indented_newval = svn_cmdline__indent_string(newval,
+ " ",
+ pool);
+ if (out)
+ {
+ SVN_ERR(svn_stream_puts(out, indented_newval));
+ }
+ else
+ {
+ printf("%s", indented_newval);
+ }
+ }
+ }
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_cmdline__print_xml_prop_hash(svn_stringbuf_t **outstr,
+ apr_hash_t *prop_hash,
+ svn_boolean_t names_only,
+ svn_boolean_t inherited_props,
+ apr_pool_t *pool)
+{
+ apr_array_header_t *sorted_props;
+ int i;
+
+ if (*outstr == NULL)
+ *outstr = svn_stringbuf_create_empty(pool);
+
+ sorted_props = svn_sort__hash(prop_hash, svn_sort_compare_items_lexically,
+ pool);
+ for (i = 0; i < sorted_props->nelts; i++)
+ {
+ svn_sort__item_t item = APR_ARRAY_IDX(sorted_props, i, svn_sort__item_t);
+ const char *pname = item.key;
+ svn_string_t *propval = item.value;
+
+ if (names_only)
+ {
+ svn_xml_make_open_tag(
+ outstr, pool, svn_xml_self_closing,
+ inherited_props ? "inherited_property" : "property",
+ "name", pname, NULL);
+ }
+ else
+ {
+ const char *pname_out;
+
+ if (svn_prop_needs_translation(pname))
+ SVN_ERR(svn_subst_detranslate_string(&propval, propval,
+ TRUE, pool));
+
+ SVN_ERR(svn_cmdline_cstring_from_utf8(&pname_out, pname, pool));
+
+ svn_cmdline__print_xml_prop(outstr, pname_out, propval,
+ inherited_props, pool);
+ }
+ }
+
+ return SVN_NO_ERROR;
+}
+
+svn_boolean_t
+svn_cmdline__be_interactive(svn_boolean_t non_interactive,
+ svn_boolean_t force_interactive)
+{
+ /* If neither --non-interactive nor --force-interactive was passed,
+ * be interactive if stdin is a terminal.
+ * If --force-interactive was passed, always be interactive. */
+ if (!force_interactive && !non_interactive)
+ {
+#ifdef WIN32
+ return (_isatty(STDIN_FILENO) != 0);
+#else
+ return (isatty(STDIN_FILENO) != 0);
+#endif
+ }
+ else if (force_interactive)
+ return TRUE;
+
+ return !non_interactive;
+}
+
+
+/* Helper for the next two functions. Set *EDITOR to some path to an
+ editor binary. Sources to search include: the EDITOR_CMD argument
+ (if not NULL), $SVN_EDITOR, the runtime CONFIG variable (if CONFIG
+ is not NULL), $VISUAL, $EDITOR. Return
+ SVN_ERR_CL_NO_EXTERNAL_EDITOR if no binary can be found. */
+static svn_error_t *
+find_editor_binary(const char **editor,
+ const char *editor_cmd,
+ apr_hash_t *config)
+{
+ const char *e;
+ struct svn_config_t *cfg;
+
+ /* Use the editor specified on the command line via --editor-cmd, if any. */
+ e = editor_cmd;
+
+ /* Otherwise look for the Subversion-specific environment variable. */
+ if (! e)
+ e = getenv("SVN_EDITOR");
+
+ /* If not found then fall back on the config file. */
+ if (! e)
+ {
+ cfg = config ? apr_hash_get(config, SVN_CONFIG_CATEGORY_CONFIG,
+ APR_HASH_KEY_STRING) : NULL;
+ svn_config_get(cfg, &e, SVN_CONFIG_SECTION_HELPERS,
+ SVN_CONFIG_OPTION_EDITOR_CMD, NULL);
+ }
+
+ /* If not found yet then try general purpose environment variables. */
+ if (! e)
+ e = getenv("VISUAL");
+ if (! e)
+ e = getenv("EDITOR");
+
+#ifdef SVN_CLIENT_EDITOR
+ /* If still not found then fall back on the hard-coded default. */
+ if (! e)
+ e = SVN_CLIENT_EDITOR;
+#endif
+
+ /* Error if there is no editor specified */
+ if (e)
+ {
+ const char *c;
+
+ for (c = e; *c; c++)
+ if (!svn_ctype_isspace(*c))
+ break;
+
+ if (! *c)
+ return svn_error_create
+ (SVN_ERR_CL_NO_EXTERNAL_EDITOR, NULL,
+ _("The EDITOR, SVN_EDITOR or VISUAL environment variable or "
+ "'editor-cmd' run-time configuration option is empty or "
+ "consists solely of whitespace. Expected a shell command."));
+ }
+ else
+ return svn_error_create
+ (SVN_ERR_CL_NO_EXTERNAL_EDITOR, NULL,
+ _("None of the environment variables SVN_EDITOR, VISUAL or EDITOR are "
+ "set, and no 'editor-cmd' run-time configuration option was found"));
+
+ *editor = e;
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_cmdline__edit_file_externally(const char *path,
+ const char *editor_cmd,
+ apr_hash_t *config,
+ apr_pool_t *pool)
+{
+ const char *editor, *cmd, *base_dir, *file_name, *base_dir_apr;
+ char *old_cwd;
+ int sys_err;
+ apr_status_t apr_err;
+
+ svn_dirent_split(&base_dir, &file_name, path, pool);
+
+ SVN_ERR(find_editor_binary(&editor, editor_cmd, config));
+
+ apr_err = apr_filepath_get(&old_cwd, APR_FILEPATH_NATIVE, pool);
+ if (apr_err)
+ return svn_error_wrap_apr(apr_err, _("Can't get working directory"));
+
+ /* APR doesn't like "" directories */
+ if (base_dir[0] == '\0')
+ base_dir_apr = ".";
+ else
+ SVN_ERR(svn_path_cstring_from_utf8(&base_dir_apr, base_dir, pool));
+
+ apr_err = apr_filepath_set(base_dir_apr, pool);
+ if (apr_err)
+ return svn_error_wrap_apr
+ (apr_err, _("Can't change working directory to '%s'"), base_dir);
+
+ cmd = apr_psprintf(pool, "%s %s", editor, file_name);
+ sys_err = system(cmd);
+
+ apr_err = apr_filepath_set(old_cwd, pool);
+ if (apr_err)
+ svn_handle_error2(svn_error_wrap_apr
+ (apr_err, _("Can't restore working directory")),
+ stderr, TRUE /* fatal */, "svn: ");
+
+ if (sys_err)
+ /* Extracting any meaning from sys_err is platform specific, so just
+ use the raw value. */
+ return svn_error_createf(SVN_ERR_EXTERNAL_PROGRAM, NULL,
+ _("system('%s') returned %d"), cmd, sys_err);
+
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_cmdline__edit_string_externally(svn_string_t **edited_contents /* UTF-8! */,
+ const char **tmpfile_left /* UTF-8! */,
+ const char *editor_cmd,
+ const char *base_dir /* UTF-8! */,
+ const svn_string_t *contents /* UTF-8! */,
+ const char *filename,
+ apr_hash_t *config,
+ svn_boolean_t as_text,
+ const char *encoding,
+ apr_pool_t *pool)
+{
+ const char *editor;
+ const char *cmd;
+ apr_file_t *tmp_file;
+ const char *tmpfile_name;
+ const char *tmpfile_native;
+ const char *tmpfile_apr, *base_dir_apr;
+ svn_string_t *translated_contents;
+ apr_status_t apr_err, apr_err2;
+ apr_size_t written;
+ apr_finfo_t finfo_before, finfo_after;
+ svn_error_t *err = SVN_NO_ERROR, *err2;
+ char *old_cwd;
+ int sys_err;
+ svn_boolean_t remove_file = TRUE;
+
+ SVN_ERR(find_editor_binary(&editor, editor_cmd, config));
+
+ /* Convert file contents from UTF-8/LF if desired. */
+ if (as_text)
+ {
+ const char *translated;
+ SVN_ERR(svn_subst_translate_cstring2(contents->data, &translated,
+ APR_EOL_STR, FALSE,
+ NULL, FALSE, pool));
+ translated_contents = svn_string_create_empty(pool);
+ if (encoding)
+ SVN_ERR(svn_utf_cstring_from_utf8_ex2(&translated_contents->data,
+ translated, encoding, pool));
+ else
+ SVN_ERR(svn_utf_cstring_from_utf8(&translated_contents->data,
+ translated, pool));
+ translated_contents->len = strlen(translated_contents->data);
+ }
+ else
+ translated_contents = svn_string_dup(contents, pool);
+
+ /* Move to BASE_DIR to avoid getting characters that need quoting
+ into tmpfile_name */
+ apr_err = apr_filepath_get(&old_cwd, APR_FILEPATH_NATIVE, pool);
+ if (apr_err)
+ return svn_error_wrap_apr(apr_err, _("Can't get working directory"));
+
+ /* APR doesn't like "" directories */
+ if (base_dir[0] == '\0')
+ base_dir_apr = ".";
+ else
+ SVN_ERR(svn_path_cstring_from_utf8(&base_dir_apr, base_dir, pool));
+ apr_err = apr_filepath_set(base_dir_apr, pool);
+ if (apr_err)
+ {
+ return svn_error_wrap_apr
+ (apr_err, _("Can't change working directory to '%s'"), base_dir);
+ }
+
+ /*** From here on, any problems that occur require us to cd back!! ***/
+
+ /* Ask the working copy for a temporary file named FILENAME-something. */
+ err = svn_io_open_uniquely_named(&tmp_file, &tmpfile_name,
+ "" /* dirpath */,
+ filename,
+ ".tmp",
+ svn_io_file_del_none, pool, pool);
+
+ if (err && (APR_STATUS_IS_EACCES(err->apr_err) || err->apr_err == EROFS))
+ {
+ const char *temp_dir_apr;
+
+ svn_error_clear(err);
+
+ SVN_ERR(svn_io_temp_dir(&base_dir, pool));
+
+ SVN_ERR(svn_path_cstring_from_utf8(&temp_dir_apr, base_dir, pool));
+ apr_err = apr_filepath_set(temp_dir_apr, pool);
+ if (apr_err)
+ {
+ return svn_error_wrap_apr
+ (apr_err, _("Can't change working directory to '%s'"), base_dir);
+ }
+
+ err = svn_io_open_uniquely_named(&tmp_file, &tmpfile_name,
+ "" /* dirpath */,
+ filename,
+ ".tmp",
+ svn_io_file_del_none, pool, pool);
+ }
+
+ if (err)
+ goto cleanup2;
+
+ /*** From here on, any problems that occur require us to cleanup
+ the file we just created!! ***/
+
+ /* Dump initial CONTENTS to TMP_FILE. */
+ apr_err = apr_file_write_full(tmp_file, translated_contents->data,
+ translated_contents->len, &written);
+
+ apr_err2 = apr_file_close(tmp_file);
+ if (! apr_err)
+ apr_err = apr_err2;
+
+ /* Make sure the whole CONTENTS were written, else return an error. */
+ if (apr_err)
+ {
+ err = svn_error_wrap_apr(apr_err, _("Can't write to '%s'"),
+ tmpfile_name);
+ goto cleanup;
+ }
+
+ err = svn_path_cstring_from_utf8(&tmpfile_apr, tmpfile_name, pool);
+ if (err)
+ goto cleanup;
+
+ /* Get information about the temporary file before the user has
+ been allowed to edit its contents. */
+ apr_err = apr_stat(&finfo_before, tmpfile_apr,
+ APR_FINFO_MTIME, pool);
+ if (apr_err)
+ {
+ err = svn_error_wrap_apr(apr_err, _("Can't stat '%s'"), tmpfile_name);
+ goto cleanup;
+ }
+
+ /* Backdate the file a little bit in case the editor is very fast
+ and doesn't change the size. (Use two seconds, since some
+ filesystems have coarse granularity.) It's OK if this call
+ fails, so we don't check its return value.*/
+ apr_file_mtime_set(tmpfile_apr, finfo_before.mtime - 2000, pool);
+
+ /* Stat it again to get the mtime we actually set. */
+ apr_err = apr_stat(&finfo_before, tmpfile_apr,
+ APR_FINFO_MTIME | APR_FINFO_SIZE, pool);
+ if (apr_err)
+ {
+ err = svn_error_wrap_apr(apr_err, _("Can't stat '%s'"), tmpfile_name);
+ goto cleanup;
+ }
+
+ /* Prepare the editor command line. */
+ err = svn_utf_cstring_from_utf8(&tmpfile_native, tmpfile_name, pool);
+ if (err)
+ goto cleanup;
+ cmd = apr_psprintf(pool, "%s %s", editor, tmpfile_native);
+
+ /* If the caller wants us to leave the file around, return the path
+ of the file we'll use, and make a note not to destroy it. */
+ if (tmpfile_left)
+ {
+ *tmpfile_left = svn_dirent_join(base_dir, tmpfile_name, pool);
+ remove_file = FALSE;
+ }
+
+ /* Now, run the editor command line. */
+ sys_err = system(cmd);
+ if (sys_err != 0)
+ {
+ /* Extracting any meaning from sys_err is platform specific, so just
+ use the raw value. */
+ err = svn_error_createf(SVN_ERR_EXTERNAL_PROGRAM, NULL,
+ _("system('%s') returned %d"), cmd, sys_err);
+ goto cleanup;
+ }
+
+ /* Get information about the temporary file after the assumed editing. */
+ apr_err = apr_stat(&finfo_after, tmpfile_apr,
+ APR_FINFO_MTIME | APR_FINFO_SIZE, pool);
+ if (apr_err)
+ {
+ err = svn_error_wrap_apr(apr_err, _("Can't stat '%s'"), tmpfile_name);
+ goto cleanup;
+ }
+
+ /* If the file looks changed... */
+ if ((finfo_before.mtime != finfo_after.mtime) ||
+ (finfo_before.size != finfo_after.size))
+ {
+ svn_stringbuf_t *edited_contents_s;
+ err = svn_stringbuf_from_file2(&edited_contents_s, tmpfile_name, pool);
+ if (err)
+ goto cleanup;
+
+ *edited_contents = svn_stringbuf__morph_into_string(edited_contents_s);
+
+ /* Translate back to UTF8/LF if desired. */
+ if (as_text)
+ {
+ err = svn_subst_translate_string2(edited_contents, FALSE, FALSE,
+ *edited_contents, encoding, FALSE,
+ pool, pool);
+ if (err)
+ {
+ err = svn_error_quick_wrap
+ (err,
+ _("Error normalizing edited contents to internal format"));
+ goto cleanup;
+ }
+ }
+ }
+ else
+ {
+ /* No edits seem to have been made */
+ *edited_contents = NULL;
+ }
+
+ cleanup:
+ if (remove_file)
+ {
+ /* Remove the file from disk. */
+ err2 = svn_io_remove_file2(tmpfile_name, FALSE, pool);
+
+ /* Only report remove error if there was no previous error. */
+ if (! err && err2)
+ err = err2;
+ else
+ svn_error_clear(err2);
+ }
+
+ cleanup2:
+ /* If we against all probability can't cd back, all further relative
+ file references would be screwed up, so we have to abort. */
+ apr_err = apr_filepath_set(old_cwd, pool);
+ if (apr_err)
+ {
+ svn_handle_error2(svn_error_wrap_apr
+ (apr_err, _("Can't restore working directory")),
+ stderr, TRUE /* fatal */, "svn: ");
+ }
+
+ return svn_error_trace(err);
+}
Modified: subversion/branches/tree-read-api/subversion/libsvn_subr/config.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_subr/config.c?rev=1429457&r1=1429456&r2=1429457&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_subr/config.c (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_subr/config.c Sun Jan 6 02:33:34 2013
@@ -129,7 +129,27 @@ svn_config_read2(svn_config_t **cfgp, co
return SVN_NO_ERROR;
}
+svn_error_t *
+svn_config_parse(svn_config_t **cfgp, svn_stream_t *stream,
+ svn_boolean_t section_names_case_sensitive,
+ apr_pool_t *result_pool)
+{
+ svn_config_t *cfg;
+ svn_error_t *err;
+ apr_pool_t *scratch_pool = svn_pool_create(result_pool);
+
+ err = svn_config_create(&cfg, section_names_case_sensitive, result_pool);
+ if (err == SVN_NO_ERROR)
+ err = svn_config__parse_stream(cfg, stream, result_pool, scratch_pool);
+
+ if (err == SVN_NO_ERROR)
+ *cfgp = cfg;
+
+ svn_pool_destroy(scratch_pool);
+
+ return err;
+}
/* Read various configuration sources into *CFGP, in this order, with
* later reads overriding the results of earlier ones:
Modified: subversion/branches/tree-read-api/subversion/libsvn_subr/config_file.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_subr/config_file.c?rev=1429457&r1=1429456&r2=1429457&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_subr/config_file.c (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_subr/config_file.c Sun Jan 6 02:33:34 2013
@@ -50,11 +50,10 @@
/* File parsing context */
typedef struct parse_context_t
{
- /* This config struct and file */
+ /* This config struct */
svn_config_t *cfg;
- const char *file;
- /* The file descriptor */
+ /* The stream struct */
svn_stream_t *stream;
/* The current line in the file */
@@ -296,8 +295,7 @@ parse_option(int *pch, parse_context_t *
{
ch = EOF;
err = svn_error_createf(SVN_ERR_MALFORMED_FILE, NULL,
- "%s:%d: Option must end with ':' or '='",
- svn_dirent_local_style(ctx->file, scratch_pool),
+ "line %d: Option must end with ':' or '='",
ctx->line);
}
else
@@ -340,8 +338,7 @@ parse_section_name(int *pch, parse_conte
{
ch = EOF;
err = svn_error_createf(SVN_ERR_MALFORMED_FILE, NULL,
- "%s:%d: Section header must end with ']'",
- svn_dirent_local_style(ctx->file, scratch_pool),
+ "line %d: Section header must end with ']'",
ctx->line);
}
else
@@ -404,8 +401,6 @@ svn_config__parse_file(svn_config_t *cfg
svn_boolean_t must_exist, apr_pool_t *result_pool)
{
svn_error_t *err = SVN_NO_ERROR;
- parse_context_t *ctx;
- int ch, count;
svn_stream_t *stream;
apr_pool_t *scratch_pool = svn_pool_create(result_pool);
@@ -420,10 +415,32 @@ svn_config__parse_file(svn_config_t *cfg
else
SVN_ERR(err);
+ err = svn_config__parse_stream(cfg, stream, result_pool, scratch_pool);
+
+ if (err != SVN_NO_ERROR)
+ {
+ /* Add the filename to the error stack. */
+ err = svn_error_createf(err->apr_err, err,
+ "Error while parsing config file: %s:",
+ svn_dirent_local_style(file, scratch_pool));
+ }
+
+ /* Close the streams (and other cleanup): */
+ svn_pool_destroy(scratch_pool);
+
+ return err;
+}
+
+svn_error_t *
+svn_config__parse_stream(svn_config_t *cfg, svn_stream_t *stream,
+ apr_pool_t *result_pool, apr_pool_t *scratch_pool)
+{
+ parse_context_t *ctx;
+ int ch, count;
+
ctx = apr_palloc(scratch_pool, sizeof(*ctx));
ctx->cfg = cfg;
- ctx->file = file;
ctx->stream = stream;
ctx->line = 1;
ctx->ungotten_char = EOF;
@@ -444,10 +461,8 @@ svn_config__parse_file(svn_config_t *cfg
SVN_ERR(parse_section_name(&ch, ctx, scratch_pool));
else
return svn_error_createf(SVN_ERR_MALFORMED_FILE, NULL,
- "%s:%d: Section header"
+ "line %d: Section header"
" must start in the first column",
- svn_dirent_local_style(file,
- scratch_pool),
ctx->line);
break;
@@ -459,10 +474,8 @@ svn_config__parse_file(svn_config_t *cfg
}
else
return svn_error_createf(SVN_ERR_MALFORMED_FILE, NULL,
- "%s:%d: Comment"
+ "line %d: Comment"
" must start in the first column",
- svn_dirent_local_style(file,
- scratch_pool),
ctx->line);
break;
@@ -476,15 +489,11 @@ svn_config__parse_file(svn_config_t *cfg
default:
if (svn_stringbuf_isempty(ctx->section))
return svn_error_createf(SVN_ERR_MALFORMED_FILE, NULL,
- "%s:%d: Section header expected",
- svn_dirent_local_style(file,
- scratch_pool),
+ "line %d: Section header expected",
ctx->line);
else if (count != 0)
return svn_error_createf(SVN_ERR_MALFORMED_FILE, NULL,
- "%s:%d: Option expected",
- svn_dirent_local_style(file,
- scratch_pool),
+ "line %d: Option expected",
ctx->line);
else
SVN_ERR(parse_option(&ch, ctx, scratch_pool));
@@ -493,8 +502,6 @@ svn_config__parse_file(svn_config_t *cfg
}
while (ch != EOF);
- /* Close the streams (and other cleanup): */
- svn_pool_destroy(scratch_pool);
return SVN_NO_ERROR;
}
@@ -796,6 +803,9 @@ svn_config_ensure(const char *config_dir
"### http-timeout Timeout for HTTP requests in seconds"
NL
"### http-compression Whether to compress HTTP requests" NL
+ "### http-max-connections Maximum number of parallel server" NL
+ "### connections to use for any given" NL
+ "### HTTP operation." NL
"### neon-debug-mask Debug mask for Neon HTTP library" NL
"### ssl-authority-files List of files, each of a trusted CA"
NL
@@ -807,6 +817,9 @@ svn_config_ensure(const char *config_dir
"### http-library Which library to use for http/https"
NL
"### connections." NL
+ "### http-bulk-updates Whether to request bulk update" NL
+ "### responses or to fetch each file" NL
+ "### in an individual request. " NL
"### store-passwords Specifies whether passwords used" NL
"### to authenticate against a" NL
"### Subversion server may be cached" NL
@@ -826,8 +839,7 @@ svn_config_ensure(const char *config_dir
"### unencrypted (i.e., as plaintext)." NL
#endif
"### store-auth-creds Specifies whether any auth info" NL
- "### (passwords as well as server certs)"
- NL
+ "### (passwords, server certs, etc.)" NL
"### may be cached to disk." NL
"### username Specifies the default username." NL
"###" NL
Modified: subversion/branches/tree-read-api/subversion/libsvn_subr/config_impl.h
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_subr/config_impl.h?rev=1429457&r1=1429456&r2=1429457&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_subr/config_impl.h (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_subr/config_impl.h Sun Jan 6 02:33:34 2013
@@ -32,6 +32,7 @@
#include <apr_hash.h>
#include "svn_types.h"
#include "svn_string.h"
+#include "svn_io.h"
#include "svn_config.h"
#include "svn_private_config.h"
@@ -75,6 +76,12 @@ svn_error_t *svn_config__parse_file(svn_
svn_boolean_t must_exist,
apr_pool_t *pool);
+/* Read sections and options from a stream. */
+svn_error_t *svn_config__parse_stream(svn_config_t *cfg,
+ svn_stream_t *stream,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
+
/* The name of the magic [DEFAULT] section. */
#define SVN_CONFIG__DEFAULT_SECTION "DEFAULT"
Modified: subversion/branches/tree-read-api/subversion/libsvn_subr/deprecated.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_subr/deprecated.c?rev=1429457&r1=1429456&r2=1429457&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_subr/deprecated.c (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_subr/deprecated.c Sun Jan 6 02:33:34 2013
@@ -45,6 +45,7 @@
#include "opt.h"
#include "private/svn_opt_private.h"
+#include "private/svn_mergeinfo_private.h"
#include "svn_private_config.h"
@@ -1122,8 +1123,11 @@ svn_rangelist_merge(svn_rangelist_t **ra
const svn_rangelist_t *changes,
apr_pool_t *pool)
{
- return svn_error_trace(svn_rangelist_merge2(*rangelist, changes,
- pool, pool));
+ SVN_ERR(svn_rangelist_merge2(*rangelist, changes,
+ pool, pool));
+
+ return svn_error_trace(
+ svn_rangelist__combine_adjacent_ranges(*rangelist, pool));
}
svn_error_t *
Modified: subversion/branches/tree-read-api/subversion/libsvn_subr/error.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_subr/error.c?rev=1429457&r1=1429456&r2=1429457&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_subr/error.c (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_subr/error.c Sun Jan 6 02:33:34 2013
@@ -221,6 +221,8 @@ svn_error_quick_wrap(svn_error_t *child,
new_msg);
}
+/* Messages in tracing errors all point to this static string. */
+static const char error_tracing_link[] = "traced call";
svn_error_t *
svn_error__trace(const char *file, long line, svn_error_t *err)
@@ -235,8 +237,11 @@ svn_error__trace(const char *file, long
/* Only do the work when an error occurs. */
if (err)
{
+ svn_error_t *trace;
svn_error__locate(file, line);
- return svn_error_quick_wrap(err, SVN_ERR__TRACED);
+ trace = make_error_internal(err->apr_err, err);
+ trace->message = error_tracing_link;
+ return trace;
}
return SVN_NO_ERROR;
@@ -383,7 +388,7 @@ svn_error__is_tracing_link(svn_error_t *
### we add a boolean field to svn_error_t that's set only for
### these "placeholder error chain" items. Not such a bad idea,
### really... */
- return (err && err->message && !strcmp(err->message, SVN_ERR__TRACED));
+ return (err && err->message && !strcmp(err->message, error_tracing_link));
#else
return FALSE;
#endif
Modified: subversion/branches/tree-read-api/subversion/libsvn_subr/io.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_subr/io.c?rev=1429457&r1=1429456&r2=1429457&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_subr/io.c (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_subr/io.c Sun Jan 6 02:33:34 2013
@@ -834,7 +834,7 @@ svn_io_copy_file(const char *src,
return SVN_NO_ERROR;
#endif
- SVN_ERR(svn_io_file_open(&from_file, src, APR_READ | APR_BINARY,
+ SVN_ERR(svn_io_file_open(&from_file, src, APR_READ,
APR_OS_DEFAULT, pool));
/* For atomicity, we copy to a tmp file and then rename the tmp
@@ -1536,7 +1536,7 @@ io_set_file_perms(const char *path,
/* Get the perms for the original file so we'll have any other bits
* that were already set (like the execute bits, for example). */
- SVN_ERR(svn_io_file_open(&fd, path, APR_READ | APR_BINARY,
+ SVN_ERR(svn_io_file_open(&fd, path, APR_READ,
APR_OS_DEFAULT, pool));
SVN_ERR(merge_default_file_perms(fd, &perms_to_set, pool));
SVN_ERR(svn_io_file_close(fd, pool));
Modified: subversion/branches/tree-read-api/subversion/libsvn_subr/mergeinfo.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_subr/mergeinfo.c?rev=1429457&r1=1429456&r2=1429457&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_subr/mergeinfo.c (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_subr/mergeinfo.c Sun Jan 6 02:33:34 2013
@@ -611,6 +611,58 @@ svn_rangelist__parse(svn_rangelist_t **r
return SVN_NO_ERROR;
}
+svn_error_t *
+svn_rangelist__combine_adjacent_ranges(svn_rangelist_t *rangelist,
+ apr_pool_t *scratch_pool)
+{
+ int i;
+ svn_merge_range_t *range, *lastrange;
+
+ lastrange = APR_ARRAY_IDX(rangelist, 0, svn_merge_range_t *);
+
+ for (i = 1; i < rangelist->nelts; i++)
+ {
+ range = APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *);
+ if (lastrange->start <= range->end
+ && range->start <= lastrange->end)
+ {
+ /* The ranges are adjacent or intersect. */
+
+ /* svn_mergeinfo_parse promises to combine overlapping
+ ranges as long as their inheritability is the same. */
+ if (range->start < lastrange->end
+ && range->inheritable != lastrange->inheritable)
+ {
+ return svn_error_createf(SVN_ERR_MERGEINFO_PARSE_ERROR, NULL,
+ _("Unable to parse overlapping "
+ "revision ranges '%s' and '%s' "
+ "with different inheritance "
+ "types"),
+ range_to_string(lastrange,
+ scratch_pool),
+ range_to_string(range,
+ scratch_pool));
+ }
+
+ /* Combine overlapping or adjacent ranges with the
+ same inheritability. */
+ if (lastrange->inheritable == range->inheritable)
+ {
+ lastrange->end = MAX(range->end, lastrange->end);
+ if (i + 1 < rangelist->nelts)
+ memmove(rangelist->elts + (rangelist->elt_size * i),
+ rangelist->elts + (rangelist->elt_size * (i + 1)),
+ rangelist->elt_size * (rangelist->nelts - i));
+ rangelist->nelts--;
+ i--;
+ }
+ }
+ lastrange = APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *);
+ }
+
+ return SVN_NO_ERROR;
+}
+
/* revisionline -> PATHNAME COLON revisionlist */
static svn_error_t *
parse_revision_line(const char **input, const char *end, svn_mergeinfo_t hash,
@@ -648,52 +700,10 @@ parse_revision_line(const char **input,
and make sure there are no overlapping ranges. */
if (rangelist->nelts > 1)
{
- int i;
- svn_merge_range_t *range, *lastrange;
-
qsort(rangelist->elts, rangelist->nelts, rangelist->elt_size,
svn_sort_compare_ranges);
- lastrange = APR_ARRAY_IDX(rangelist, 0, svn_merge_range_t *);
-
- for (i = 1; i < rangelist->nelts; i++)
- {
- range = APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *);
- if (lastrange->start <= range->end
- && range->start <= lastrange->end)
- {
- /* The ranges are adjacent or intersect. */
- /* svn_mergeinfo_parse promises to combine overlapping
- ranges as long as their inheritability is the same. */
- if (range->start < lastrange->end
- && range->inheritable != lastrange->inheritable)
- {
- return svn_error_createf(SVN_ERR_MERGEINFO_PARSE_ERROR, NULL,
- _("Unable to parse overlapping "
- "revision ranges '%s' and '%s' "
- "with different inheritance "
- "types"),
- range_to_string(lastrange,
- scratch_pool),
- range_to_string(range,
- scratch_pool));
- }
-
- /* Combine overlapping or adjacent ranges with the
- same inheritability. */
- if (lastrange->inheritable == range->inheritable)
- {
- lastrange->end = MAX(range->end, lastrange->end);
- if (i + 1 < rangelist->nelts)
- memmove(rangelist->elts + (rangelist->elt_size * i),
- rangelist->elts + (rangelist->elt_size * (i + 1)),
- rangelist->elt_size * (rangelist->nelts - i));
- rangelist->nelts--;
- i--;
- }
- }
- lastrange = APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *);
- }
+ SVN_ERR(svn_rangelist__combine_adjacent_ranges(rangelist, scratch_pool));
}
/* Handle any funky mergeinfo with relative merge source paths that
@@ -1753,7 +1763,7 @@ svn_mergeinfo_merge2(svn_mergeinfo_t mer
{
SVN_ERR(svn_rangelist_merge2(target, to_insert, result_pool,
iterpool));
- apr_pool_clear(iterpool);
+ svn_pool_clear(iterpool);
}
else
apr_hash_set(mergeinfo, key, klen, to_insert);
Modified: subversion/branches/tree-read-api/subversion/libsvn_subr/path.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_subr/path.c?rev=1429457&r1=1429456&r2=1429457&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_subr/path.c (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_subr/path.c Sun Jan 6 02:33:34 2013
@@ -1281,3 +1281,34 @@ svn_path_splitext(const char **path_root
if (path_ext)
*path_ext = "";
}
+
+
+/* Repository relative URLs (^/). */
+
+svn_boolean_t
+svn_path_is_repos_relative_url(const char *path)
+{
+ return (0 == strncmp("^/", path, 2));
+}
+
+svn_error_t *
+svn_path_resolve_repos_relative_url(const char **absolute_url,
+ const char *relative_url,
+ const char *repos_root_url,
+ apr_pool_t *pool)
+{
+ if (! svn_path_is_repos_relative_url(relative_url))
+ return svn_error_createf(SVN_ERR_BAD_URL, NULL,
+ _("Improper relative URL '%s'"),
+ relative_url);
+
+ /* No assumptions are made about the canonicalization of the inut
+ * arguments, it is presumed that the output will be canonicalized after
+ * this function, which will remove any duplicate path separator.
+ */
+ *absolute_url = apr_pstrcat(pool, repos_root_url, relative_url + 1,
+ (char *)NULL);
+
+ return SVN_NO_ERROR;
+}
+
Modified: subversion/branches/tree-read-api/subversion/libsvn_subr/properties.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_subr/properties.c?rev=1429457&r1=1429456&r2=1429457&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_subr/properties.c (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_subr/properties.c Sun Jan 6 02:33:34 2013
@@ -31,6 +31,7 @@
#include "svn_props.h"
#include "svn_error.h"
#include "svn_ctype.h"
+#include "private/svn_subr_private.h"
/* All Subversion-specific versioned node properties
@@ -244,8 +245,8 @@ svn_categorize_props(const apr_array_hea
svn_error_t *
svn_prop_diffs(apr_array_header_t **propdiffs,
- apr_hash_t *target_props,
- apr_hash_t *source_props,
+ const apr_hash_t *target_props,
+ const apr_hash_t *source_props,
apr_pool_t *pool)
{
apr_hash_index_t *hi;
@@ -257,7 +258,8 @@ svn_prop_diffs(apr_array_header_t **prop
/* Loop over SOURCE_PROPS and examine each key. This will allow us to
detect any `deletion' events or `set-modification' events. */
- for (hi = apr_hash_first(pool, source_props); hi; hi = apr_hash_next(hi))
+ for (hi = apr_hash_first(pool, (apr_hash_t *)source_props); hi;
+ hi = apr_hash_next(hi))
{
const void *key;
apr_ssize_t klen;
@@ -269,7 +271,7 @@ svn_prop_diffs(apr_array_header_t **prop
propval1 = val;
/* Does property name exist in TARGET_PROPS? */
- propval2 = apr_hash_get(target_props, key, klen);
+ propval2 = apr_hash_get((apr_hash_t *)target_props, key, klen);
if (propval2 == NULL)
{
@@ -289,7 +291,8 @@ svn_prop_diffs(apr_array_header_t **prop
/* Loop over TARGET_PROPS and examine each key. This allows us to
detect `set-creation' events */
- for (hi = apr_hash_first(pool, target_props); hi; hi = apr_hash_next(hi))
+ for (hi = apr_hash_first(pool, (apr_hash_t *)target_props); hi;
+ hi = apr_hash_next(hi))
{
const void *key;
apr_ssize_t klen;
@@ -301,7 +304,7 @@ svn_prop_diffs(apr_array_header_t **prop
propval = val;
/* Does property name exist in SOURCE_PROPS? */
- if (NULL == apr_hash_get(source_props, key, klen))
+ if (NULL == apr_hash_get((apr_hash_t *)source_props, key, klen))
{
/* Add a set (creation) event to the array */
svn_prop_t *p = apr_array_push(ary);
@@ -316,6 +319,23 @@ svn_prop_diffs(apr_array_header_t **prop
return SVN_NO_ERROR;
}
+apr_hash_t *
+svn_prop__patch(const apr_hash_t *original_props,
+ const apr_array_header_t *prop_changes,
+ apr_pool_t *pool)
+{
+ apr_hash_t *props = apr_hash_copy(pool, original_props);
+ int i;
+
+ for (i = 0; i < prop_changes->nelts; i++)
+ {
+ const svn_prop_t *p = &APR_ARRAY_IDX(prop_changes, i, svn_prop_t);
+
+ apr_hash_set(props, p->name, APR_HASH_KEY_STRING, p->value);
+ }
+ return props;
+}
+
/**
* Reallocate the members of PROP using POOL.
*/
@@ -354,13 +374,16 @@ svn_prop_array_dup(const apr_array_heade
}
apr_array_header_t *
-svn_prop_hash_to_array(apr_hash_t *hash, apr_pool_t *pool)
+svn_prop_hash_to_array(const apr_hash_t *hash,
+ apr_pool_t *pool)
{
apr_hash_index_t *hi;
- apr_array_header_t *array = apr_array_make(pool, apr_hash_count(hash),
+ apr_array_header_t *array = apr_array_make(pool,
+ apr_hash_count((apr_hash_t *)hash),
sizeof(svn_prop_t));
- for (hi = apr_hash_first(pool, hash); hi; hi = apr_hash_next(hi))
+ for (hi = apr_hash_first(pool, (apr_hash_t *)hash); hi;
+ hi = apr_hash_next(hi))
{
const void *key;
void *val;
@@ -376,13 +399,14 @@ svn_prop_hash_to_array(apr_hash_t *hash,
}
apr_hash_t *
-svn_prop_hash_dup(apr_hash_t *hash,
+svn_prop_hash_dup(const apr_hash_t *hash,
apr_pool_t *pool)
{
apr_hash_index_t *hi;
apr_hash_t *new_hash = apr_hash_make(pool);
- for (hi = apr_hash_first(pool, hash); hi; hi = apr_hash_next(hi))
+ for (hi = apr_hash_first(pool, (apr_hash_t *)hash); hi;
+ hi = apr_hash_next(hi))
{
const void *key;
apr_ssize_t klen;
@@ -465,7 +489,7 @@ svn_prop_name_is_valid(const char *prop_
}
const char *
-svn_prop_get_value(apr_hash_t *props,
+svn_prop_get_value(const apr_hash_t *props,
const char *prop_name)
{
svn_string_t *str;
@@ -473,7 +497,7 @@ svn_prop_get_value(apr_hash_t *props,
if (!props)
return NULL;
- str = apr_hash_get(props, prop_name, APR_HASH_KEY_STRING);
+ str = apr_hash_get((apr_hash_t *)props, prop_name, APR_HASH_KEY_STRING);
if (str)
return str->data;