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;