You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2013/10/30 02:33:40 UTC

svn commit: r1536950 [3/6] - in /subversion/branches/log-addressing: ./ build/ build/ac-macros/ build/generator/ notes/http-and-webdav/ subversion/bindings/javahl/ subversion/bindings/javahl/native/ subversion/bindings/javahl/src/org/apache/subversion/...

Modified: subversion/branches/log-addressing/subversion/libsvn_ra_serf/util.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_ra_serf/util.c?rev=1536950&r1=1536949&r2=1536950&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_ra_serf/util.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_ra_serf/util.c Wed Oct 30 01:33:37 2013
@@ -48,6 +48,7 @@
 #include "private/svn_dep_compat.h"
 #include "private/svn_fspath.h"
 #include "private/svn_subr_private.h"
+#include "private/svn_auth_private.h"
 
 #include "ra_serf.h"
 
@@ -270,26 +271,70 @@ ssl_server_cert(void *baton, int failure
   svn_auth_iterstate_t *state;
   const char *realmstring;
   apr_uint32_t svn_failures;
-  apr_hash_t *issuer, *subject, *serf_cert;
-  apr_array_header_t *san;
+  apr_hash_t *issuer;
+  apr_hash_t *subject = NULL;
+  apr_hash_t *serf_cert = NULL;
   void *creds;
   int found_matching_hostname = 0;
 
-  /* Implicitly approve any non-server certs. */
-  if (serf_ssl_cert_depth(cert) > 0)
+  svn_failures = (ssl_convert_serf_failures(failures)
+      | conn->server_cert_failures);
+
+  if (serf_ssl_cert_depth(cert) == 0)
     {
-      if (failures)
-        conn->server_cert_failures |= ssl_convert_serf_failures(failures);
-      return APR_SUCCESS;
+      /* If the depth is 0, the hostname must match the certificate.
+
+      ### This should really be handled by serf, which should pass an error
+          for this case, but that has backwards compatibility issues. */
+      apr_array_header_t *san;
+
+      serf_cert = serf_ssl_cert_certificate(cert, scratch_pool);
+
+      san = svn_hash_gets(serf_cert, "subjectAltName");
+      /* Try to find matching server name via subjectAltName first... */
+      if (san) {
+          int i;
+          for (i = 0; i < san->nelts; i++) {
+              const char *s = APR_ARRAY_IDX(san, i, const char*);
+              if (apr_fnmatch(s, conn->session->session_url.hostname,
+                  APR_FNM_PERIOD | APR_FNM_CASE_BLIND) == APR_SUCCESS)
+              {
+                  found_matching_hostname = 1;
+                  break;
+              }
+          }
+      }
+
+      /* Match server certificate CN with the hostname of the server */
+      if (!found_matching_hostname)
+        {
+          const char *hostname = NULL;
+
+          subject = serf_ssl_cert_subject(cert, scratch_pool);
+
+          if (subject)
+            hostname = svn_hash_gets(subject, "CN");
+
+          if (!hostname
+              || apr_fnmatch(hostname, conn->session->session_url.hostname,
+                             APR_FNM_PERIOD | APR_FNM_CASE_BLIND) != APR_SUCCESS)
+          {
+              svn_failures |= SVN_AUTH_SSL_CNMISMATCH;
+          }
+      }
     }
 
+  if (!svn_failures)
+    return SVN_NO_ERROR;
+
   /* Extract the info from the certificate */
-  subject = serf_ssl_cert_subject(cert, scratch_pool);
+  if (! subject)
+    subject = serf_ssl_cert_subject(cert, scratch_pool);
   issuer = serf_ssl_cert_issuer(cert, scratch_pool);
-  serf_cert = serf_ssl_cert_certificate(cert, scratch_pool);
+  if (! serf_cert)
+    serf_cert = serf_ssl_cert_certificate(cert, scratch_pool);
 
   cert_info.hostname = svn_hash_gets(subject, "CN");
-  san = svn_hash_gets(serf_cert, "subjectAltName");
   cert_info.fingerprint = svn_hash_gets(serf_cert, "sha1");
   if (! cert_info.fingerprint)
     cert_info.fingerprint = apr_pstrdup(scratch_pool, "<unknown>");
@@ -302,32 +347,56 @@ ssl_server_cert(void *baton, int failure
   cert_info.issuer_dname = convert_organisation_to_str(issuer, scratch_pool);
   cert_info.ascii_cert = serf_ssl_cert_export(cert, scratch_pool);
 
-  svn_failures = (ssl_convert_serf_failures(failures)
-                  | conn->server_cert_failures);
+  /* Handle any non-server certs. */
+  if (serf_ssl_cert_depth(cert) > 0)
+    {
+      svn_error_t *err;
 
-  /* Try to find matching server name via subjectAltName first... */
-  if (san) {
-      int i;
-      for (i = 0; i < san->nelts; i++) {
-          char *s = APR_ARRAY_IDX(san, i, char*);
-          if (apr_fnmatch(s, conn->session->session_url.hostname,
-                          APR_FNM_PERIOD | APR_FNM_CASE_BLIND) == APR_SUCCESS)
-            {
-              found_matching_hostname = 1;
-              cert_info.hostname = s;
-              break;
-            }
-      }
-  }
+      svn_auth_set_parameter(conn->session->wc_callbacks->auth_baton,
+                             SVN_AUTH_PARAM_SSL_SERVER_CERT_INFO,
+                             &cert_info);
+
+      svn_auth_set_parameter(conn->session->wc_callbacks->auth_baton,
+                             SVN_AUTH_PARAM_SSL_SERVER_FAILURES,
+                             &svn_failures);
+
+      realmstring = apr_psprintf(scratch_pool, "AUTHORITY:%s",
+                                 cert_info.fingerprint);
+
+      err = svn_auth_first_credentials(&creds, &state,
+                                       SVN_AUTH_CRED_SSL_SERVER_AUTHORITY,
+                                       realmstring,
+                                       conn->session->wc_callbacks->auth_baton,
+                                       scratch_pool);
 
-  /* Match server certificate CN with the hostname of the server */
-  if (!found_matching_hostname && cert_info.hostname)
-    {
-      if (apr_fnmatch(cert_info.hostname, conn->session->session_url.hostname,
-                      APR_FNM_PERIOD | APR_FNM_CASE_BLIND) == APR_FNM_NOMATCH)
+      svn_auth_set_parameter(conn->session->wc_callbacks->auth_baton,
+                             SVN_AUTH_PARAM_SSL_SERVER_CERT_INFO, NULL);
+
+      svn_auth_set_parameter(conn->session->wc_callbacks->auth_baton,
+                             SVN_AUTH_PARAM_SSL_SERVER_FAILURES, NULL);
+
+      if (err)
+        {
+          if (err->apr_err != SVN_ERR_AUTHN_NO_PROVIDER)
+            return svn_error_trace(err);
+
+          /* No provider registered that handles server authorities */
+          svn_error_clear(err);
+          creds = NULL;
+        }
+
+      if (creds)
         {
-          svn_failures |= SVN_AUTH_SSL_CNMISMATCH;
+          server_creds = creds;
+          SVN_ERR(svn_auth_save_credentials(state, scratch_pool));
+
+          svn_failures &= ~server_creds->accepted_failures;
         }
+
+      if (svn_failures)
+        conn->server_cert_failures |= svn_failures;
+
+      return APR_SUCCESS;
     }
 
   svn_auth_set_parameter(conn->session->wc_callbacks->auth_baton,
@@ -348,13 +417,27 @@ ssl_server_cert(void *baton, int failure
   if (creds)
     {
       server_creds = creds;
+      svn_failures &= ~server_creds->accepted_failures;
       SVN_ERR(svn_auth_save_credentials(state, scratch_pool));
     }
 
+  while (svn_failures && creds)
+    {
+      SVN_ERR(svn_auth_next_credentials(&creds, state, scratch_pool));
+
+      if (creds)
+        {
+          server_creds = creds;
+          svn_failures &= ~server_creds->accepted_failures;
+          SVN_ERR(svn_auth_save_credentials(state, scratch_pool));
+        }
+    }
+
   svn_auth_set_parameter(conn->session->wc_callbacks->auth_baton,
                          SVN_AUTH_PARAM_SSL_SERVER_CERT_INFO, NULL);
 
-  if (!server_creds)
+  /* Are there non accepted failures left? */
+  if (svn_failures)
     {
       svn_stringbuf_t *errmsg;
       int reasons = 0;

Modified: subversion/branches/log-addressing/subversion/libsvn_ra_serf/util_error.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_ra_serf/util_error.c?rev=1536950&r1=1536949&r2=1536950&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_ra_serf/util_error.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_ra_serf/util_error.c Wed Oct 30 01:33:37 2013
@@ -88,7 +88,8 @@ svn_ra_serf__wrap_err(apr_status_t statu
         }
       if (err_msg)
         {
-          err->message = apr_pstrcat(err->pool, msg, ": ", err_msg, NULL);
+          err->message = apr_pstrcat(err->pool, msg, ": ", err_msg,
+                                     SVN_VA_NULL);
         }
       else
         {

Modified: subversion/branches/log-addressing/subversion/libsvn_ra_svn/client.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_ra_svn/client.c?rev=1536950&r1=1536949&r2=1536950&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_ra_svn/client.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_ra_svn/client.c Wed Oct 30 01:33:37 2013
@@ -678,7 +678,7 @@ static svn_error_t *open_session(svn_ra_
                                                &client_string, pool));
   if (client_string)
     sess->useragent = apr_pstrcat(pool, SVN_RA_SVN__DEFAULT_USERAGENT " ",
-                                  client_string, (char *)NULL);
+                                  client_string, SVN_VA_NULL);
   else
     sess->useragent = SVN_RA_SVN__DEFAULT_USERAGENT;
 
@@ -1340,7 +1340,14 @@ static svn_error_t *ra_svn_get_dir(svn_r
       SVN_ERR(svn_ra_svn__parse_tuple(elt->u.list, pool, "cwnbr(?c)(?c)",
                                       &name, &kind, &size, &has_props,
                                       &crev, &cdate, &cauthor));
-      name = svn_relpath_canonicalize(name, pool);
+
+      /* Nothing to sanitize here.  Any multi-segment path is simply
+         illegal in the hash returned by svn_ra_get_dir2. */
+      if (strchr(name, '/'))
+        return svn_error_createf(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
+                                 _("Invalid directory entry name '%s'"),
+                                 name);
+
       dirent = svn_dirent_create(pool);
       dirent->kind = svn_node_kind_from_word(kind);
       dirent->size = size;/* FIXME: svn_filesize_t */

Modified: subversion/branches/log-addressing/subversion/libsvn_ra_svn/cyrus_auth.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_ra_svn/cyrus_auth.c?rev=1536950&r1=1536949&r2=1536950&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_ra_svn/cyrus_auth.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_ra_svn/cyrus_auth.c Wed Oct 30 01:33:37 2013
@@ -488,7 +488,7 @@ static svn_error_t *try_auth(svn_ra_svn_
                                               pmech - mechstring);
               const char *tail = pmech + strlen(mech);
 
-              mechstring = apr_pstrcat(pool, head, tail, (char *)NULL);
+              mechstring = apr_pstrcat(pool, head, tail, SVN_VA_NULL);
               again = TRUE;
             }
         }
@@ -807,10 +807,10 @@ svn_error_t *svn_ra_svn__get_addresses(c
       /* Format the IP address and port number like this: a.b.c.d;port */
       *local_addrport = apr_pstrcat(pool, local_addr, ";",
                                     apr_itoa(pool, (int)local_sa->port),
-                                    (char *)NULL);
+                                    SVN_VA_NULL);
       *remote_addrport = apr_pstrcat(pool, remote_addr, ";",
                                      apr_itoa(pool, (int)remote_sa->port),
-                                     (char *)NULL);
+                                     SVN_VA_NULL);
     }
   return SVN_NO_ERROR;
 }
@@ -849,7 +849,7 @@ svn_ra_svn__do_cyrus_auth(svn_ra_svn__se
           mechstring = apr_pstrcat(pool,
                                    mechstring,
                                    i == 0 ? "" : " ",
-                                   elt->u.word, (char *)NULL);
+                                   elt->u.word, SVN_VA_NULL);
         }
     }
 

Modified: subversion/branches/log-addressing/subversion/libsvn_ra_svn/deprecated.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_ra_svn/deprecated.c?rev=1536950&r1=1536949&r2=1536950&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_ra_svn/deprecated.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_ra_svn/deprecated.c Wed Oct 30 01:33:37 2013
@@ -232,3 +232,27 @@ svn_ra_svn_write_cmd_failure(svn_ra_svn_
 {
   return svn_error_trace(svn_ra_svn__write_cmd_failure(conn, pool, err));
 }
+
+/* From marshal.c */
+svn_ra_svn_conn_t *
+svn_ra_svn_create_conn2(apr_socket_t *sock,
+                        apr_file_t *in_file,
+                        apr_file_t *out_file,
+                        int compression_level,
+                        apr_pool_t *pool)
+{
+  return svn_ra_svn_create_conn3(sock, in_file, out_file,
+                                 compression_level, 0, 0, pool);
+}
+
+/* backward-compatible implementation using the default compression level */
+svn_ra_svn_conn_t *
+svn_ra_svn_create_conn(apr_socket_t *sock,
+                       apr_file_t *in_file,
+                       apr_file_t *out_file,
+                       apr_pool_t *pool)
+{
+  return svn_ra_svn_create_conn3(sock, in_file, out_file,
+                                 SVN_DELTA_COMPRESSION_LEVEL_DEFAULT, 0, 0,
+                                 pool);
+}

Modified: subversion/branches/log-addressing/subversion/libsvn_ra_svn/marshal.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_ra_svn/marshal.c?rev=1536950&r1=1536949&r2=1536950&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_ra_svn/marshal.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_ra_svn/marshal.c Wed Oct 30 01:33:37 2013
@@ -119,6 +119,16 @@ svn_ra_svn_conn_t *svn_ra_svn_create_con
             && apr_sockaddr_ip_get(&conn->remote_ip, sa) == APR_SUCCESS))
         conn->remote_ip = NULL;
       svn_ra_svn__stream_timeout(conn->stream, get_timeout(conn));
+
+      /* We are using large r/w buffers already.
+       * So, once we decide to actually send data, we want it to go over
+       * the wire a.s.a.p..  So disable Nagle's algorithm.
+       *
+       * We ignore the result of this call since it safe to continue even
+       * if we keep delaying.  The only negative effect is increased
+       * latency (can be additional 5 .. 10ms depending on circumstances).
+       */
+      apr_socket_opt_set(sock, APR_TCP_NODELAY, 1);
     }
   else
     {
@@ -129,27 +139,6 @@ svn_ra_svn_conn_t *svn_ra_svn_create_con
   return conn;
 }
 
-svn_ra_svn_conn_t *svn_ra_svn_create_conn2(apr_socket_t *sock,
-                                           apr_file_t *in_file,
-                                           apr_file_t *out_file,
-                                           int compression_level,
-                                           apr_pool_t *pool)
-{
-  return svn_ra_svn_create_conn3(sock, in_file, out_file,
-                                 compression_level, 0, 0, pool);
-}
-
-/* backward-compatible implementation using the default compression level */
-svn_ra_svn_conn_t *svn_ra_svn_create_conn(apr_socket_t *sock,
-                                          apr_file_t *in_file,
-                                          apr_file_t *out_file,
-                                          apr_pool_t *pool)
-{
-  return svn_ra_svn_create_conn3(sock, in_file, out_file,
-                                 SVN_DELTA_COMPRESSION_LEVEL_DEFAULT, 0, 0,
-                                 pool);
-}
-
 svn_error_t *svn_ra_svn_set_capabilities(svn_ra_svn_conn_t *conn,
                                          const apr_array_header_t *list)
 {

Modified: subversion/branches/log-addressing/subversion/libsvn_repos/authz.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_repos/authz.c?rev=1536950&r1=1536949&r2=1536950&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_repos/authz.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_repos/authz.c Wed Oct 30 01:33:37 2013
@@ -36,6 +36,7 @@
 #include "svn_config.h"
 #include "svn_ctype.h"
 #include "private/svn_fspath.h"
+#include "private/svn_repos_private.h"
 #include "repos.h"
 
 
@@ -352,7 +353,7 @@ authz_get_path_access(svn_config_t *cfg,
   baton.user = user;
 
   /* Try to locate a repository-specific block first. */
-  qualified_path = apr_pstrcat(pool, repos_name, ":", path, (char *)NULL);
+  qualified_path = apr_pstrcat(pool, repos_name, ":", path, SVN_VA_NULL);
   svn_config_enumerate2(cfg, qualified_path,
                         authz_parse_line, &baton, pool);
 
@@ -395,7 +396,7 @@ authz_get_tree_access(svn_config_t *cfg,
   baton.required_access = required_access;
   baton.repos_path = path;
   baton.qualified_repos_path = apr_pstrcat(pool, repos_name,
-                                           ":", path, (char *)NULL);
+                                           ":", path, SVN_VA_NULL);
   /* Default to access granted if no rules say otherwise. */
   baton.access = TRUE;
 
@@ -454,7 +455,7 @@ authz_get_any_access(svn_config_t *cfg, 
   baton.access = FALSE; /* Deny access by default. */
   baton.repos_path = "/";
   baton.qualified_repos_path = apr_pstrcat(pool, repos_name,
-                                           ":/", (char *)NULL);
+                                           ":/", SVN_VA_NULL);
 
   /* We could have used svn_config_enumerate2 for "repos_name:/".
    * However, this requires access for root explicitly (which the user

Modified: subversion/branches/log-addressing/subversion/libsvn_repos/commit.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_repos/commit.c?rev=1536950&r1=1536949&r2=1536950&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_repos/commit.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_repos/commit.c Wed Oct 30 01:33:37 2013
@@ -1013,7 +1013,7 @@ ev2_check_authz(const struct ev2_baton *
     return SVN_NO_ERROR;
 
   if (relpath)
-    fspath = apr_pstrcat(scratch_pool, "/", relpath, NULL);
+    fspath = apr_pstrcat(scratch_pool, "/", relpath, SVN_VA_NULL);
   else
     fspath = NULL;
 

Modified: subversion/branches/log-addressing/subversion/libsvn_repos/config_pool.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_repos/config_pool.c?rev=1536950&r1=1536949&r2=1536950&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_repos/config_pool.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_repos/config_pool.c Wed Oct 30 01:33:37 2013
@@ -434,7 +434,7 @@ add_checksum(svn_repos__config_pool_t *c
 }
 
 /* Set *CFG to the configuration stored in URL@HEAD and cache it in 
- * CONFIG_POOL.
+ * CONFIG_POOL. ### Always returns a NULL CFG.
  * 
  * RESULT_POOL determines the lifetime of the returned reference and 
  * SCRATCH_POOL is being used for temporary allocations.
@@ -463,7 +463,6 @@ find_repos_config(svn_config_t **cfg,
 
   /* Search for a repository in the full path. */
   repos_root_dirent = svn_repos_find_root_path(dirent, scratch_pool);
-    return SVN_NO_ERROR;
 
   /* Attempt to open a repository at repos_root_dirent. */
   SVN_ERR(svn_repos_open2(&repos, repos_root_dirent, NULL, scratch_pool));

Modified: subversion/branches/log-addressing/subversion/libsvn_repos/dump.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_repos/dump.c?rev=1536950&r1=1536949&r2=1536950&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_repos/dump.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_repos/dump.c Wed Oct 30 01:33:37 2013
@@ -45,6 +45,269 @@
 /*----------------------------------------------------------------------*/
 
 
+/* To be able to check whether a path exists in the current revision
+   (as changes come in), we need to track the relevant tree changes.
+
+   In particular, we remember deletions, additions and copies including
+   their copy-from info.  Since the dump performs a pre-order tree walk,
+   we only need to store the data for the stack of parent folders.
+
+   The problem that we are trying to solve is that the dump receives
+   transforming operations whose validity depends on previous operations
+   in the same revision but cannot be checked against the final state
+   as stored in the repository as that is the state *after* we applied
+   the respective tree changes.
+
+   Note that the tracker functions don't perform any sanity or validity
+   checks.  Those higher-level tests have to be done in the calling code.
+   However, there is no way to corrupt the data structure using the
+   provided functions.
+ */
+
+/* Single entry in the path tracker.  Not all levels along the path
+   hierarchy do need to have an instance of this struct but only those
+   that got changed by a tree modification.
+
+   Please note that the path info in this struct is stored in re-usable
+   stringbuf objects such that we don't need to allocate more memory than
+   the longest path we encounter.
+ */
+typedef struct path_tracker_entry_t
+{
+  /* path in the current tree */
+  svn_stringbuf_t *path;
+
+  /* copy-from path (must be empty if COPYFROM_REV is SVN_INVALID_REVNUM) */
+  svn_stringbuf_t *copyfrom_path;
+
+  /* copy-from revision (SVN_INVALID_REVNUM for additions / replacements
+     that don't copy history, i.e. with no sub-tree) */
+  svn_revnum_t copyfrom_rev;
+
+  /* if FALSE, PATH has been deleted */
+  svn_boolean_t exists;
+} path_tracker_entry_t;
+
+/* Tracks all tree modifications above the current path.
+ */
+typedef struct path_tracker_t
+{
+  /* Container for all relevant tree changes in depth order.
+     May contain more entries than DEPTH to allow for reusing memory.
+     Only entries 0 .. DEPTH-1 are valid.
+   */
+  apr_array_header_t *stack;
+
+  /* Number of relevant entries in STACK.  May be 0 */
+  int depth;
+
+  /* Revision that we current track.  If DEPTH is 0, paths are exist in
+     REVISION exactly when they exist in REVISION-1.  This applies only
+     to the current state of our tree walk.
+   */
+  svn_revnum_t revision;
+
+  /* Allocate container entries here. */
+  apr_pool_t *pool;
+} path_tracker_t;
+
+/* Return a new path tracker object for REVISION, allocated in POOL.
+ */
+static path_tracker_t *
+tracker_create(svn_revnum_t revision,
+               apr_pool_t *pool)
+{
+  path_tracker_t *result = apr_pcalloc(pool, sizeof(*result));
+  result->stack = apr_array_make(pool, 16, sizeof(path_tracker_entry_t));
+  result->revision = revision;
+  result->pool = pool;
+
+  return result;
+}
+
+/* Remove all entries from TRACKER that are not relevant to PATH anymore.
+ * If ALLOW_EXACT_MATCH is FALSE, keep only entries that pertain to
+ * parent folders but not to PATH itself.
+ *
+ * This internal function implicitly updates the tracker state during the
+ * tree by removing "past" entries.  Other functions will add entries when
+ * we encounter a new tree change.
+ */
+static void
+tracker__trim(path_tracker_t *tracker,
+              const char *path,
+              svn_boolean_t allow_exact_match)
+{
+  /* remove everything that is unrelated to PATH.
+     Note that TRACKER->STACK is depth-ordered,
+     i.e. stack[N] is a (maybe indirect) parent of stack[N+1]
+     for N+1 < DEPTH.
+   */
+  for (; tracker->depth; --tracker->depth)
+    {
+      path_tracker_entry_t *parent = &APR_ARRAY_IDX(tracker->stack,
+                                                    tracker->depth - 1,
+                                                    path_tracker_entry_t);
+      const char *rel_path
+        = svn_dirent_skip_ancestor(parent->path->data, path);
+
+      /* always keep parents.  Keep exact matches when allowed. */
+      if (rel_path && (allow_exact_match || *rel_path != '\0'))
+        break;
+    }
+}
+
+/* Using TRACKER, check what path at what revision in the repository must
+   be checked to decide that whether PATH exists.  Return the info in
+   *ORIG_PATH and *ORIG_REV, respectively.
+
+   If the path is known to not exist, *ORIG_PATH will be NULL and *ORIG_REV
+   will be SVN_INVALID_REVNUM.  If *ORIG_REV is SVN_INVALID_REVNUM, PATH
+   has just been added in the revision currently being tracked.
+
+   Use POOL for allocations.  Note that *ORIG_PATH may be allocated in POOL,
+   a reference to internal data with the same lifetime as TRACKER or just
+   PATH.
+ */
+static void
+tracker_lookup(const char **orig_path,
+               svn_revnum_t *orig_rev,
+               path_tracker_t *tracker,
+               const char *path,
+               apr_pool_t *pool)
+{
+  tracker__trim(tracker, path, TRUE);
+  if (tracker->depth == 0)
+    {
+      /* no tree changes -> paths are the same as in the previous rev. */
+      *orig_path = path;
+      *orig_rev = tracker->revision - 1;
+    }
+  else
+    {
+      path_tracker_entry_t *parent = &APR_ARRAY_IDX(tracker->stack,
+                                                    tracker->depth - 1,
+                                                    path_tracker_entry_t);
+      if (parent->exists)
+        {
+          const char *rel_path
+            = svn_dirent_skip_ancestor(parent->path->data, path);
+
+          if (parent->copyfrom_rev != SVN_INVALID_REVNUM)
+            {
+              /* parent is a copy with history. Translate path. */
+              *orig_path = svn_dirent_join(parent->copyfrom_path->data,
+                                           rel_path, pool);
+              *orig_rev = parent->copyfrom_rev;
+            }
+          else if (*rel_path == '\0')
+            {
+              /* added in this revision with no history */
+              *orig_path = path;
+              *orig_rev = tracker->revision;
+            }
+          else
+            {
+              /* parent got added but not this path */
+              *orig_path = NULL;
+              *orig_rev = SVN_INVALID_REVNUM;
+            }
+        }
+      else
+        {
+          /* (maybe parent) path has been deleted */
+          *orig_path = NULL;
+          *orig_rev = SVN_INVALID_REVNUM;
+        }
+    }
+}
+
+/* Return a reference to the stack entry in TRACKER for PATH.  If no
+   suitable entry exists, add one.  Implicitly updates the tracked tree
+   location.
+
+   Only the PATH member of the result is being updated.  All other members
+   will have undefined values.
+ */
+static path_tracker_entry_t *
+tracker__add_entry(path_tracker_t *tracker,
+                   const char *path)
+{
+  path_tracker_entry_t *entry;
+  tracker__trim(tracker, path, FALSE);
+
+  if (tracker->depth == tracker->stack->nelts)
+    {
+      entry = apr_array_push(tracker->stack);
+      entry->path = svn_stringbuf_create_empty(tracker->pool);
+      entry->copyfrom_path = svn_stringbuf_create_empty(tracker->pool);
+    }
+  else
+    {
+      entry = &APR_ARRAY_IDX(tracker->stack, tracker->depth,
+                             path_tracker_entry_t);
+    }
+
+  svn_stringbuf_set(entry->path, path);
+  ++tracker->depth;
+
+  return entry;
+}
+
+/* Update the TRACKER with a copy from COPYFROM_PATH@COPYFROM_REV to
+   PATH in the tracked revision.
+ */
+static void
+tracker_path_copy(path_tracker_t *tracker,
+                  const char *path,
+                  const char *copyfrom_path,
+                  svn_revnum_t copyfrom_rev)
+{
+  path_tracker_entry_t *entry = tracker__add_entry(tracker, path);
+
+  svn_stringbuf_set(entry->copyfrom_path, copyfrom_path);
+  entry->copyfrom_rev = copyfrom_rev;
+  entry->exists = TRUE;
+}
+
+/* Update the TRACKER with a plain addition of PATH (without history).
+ */
+static void
+tracker_path_add(path_tracker_t *tracker,
+                 const char *path)
+{
+  path_tracker_entry_t *entry = tracker__add_entry(tracker, path);
+
+  svn_stringbuf_setempty(entry->copyfrom_path);
+  entry->copyfrom_rev = SVN_INVALID_REVNUM;
+  entry->exists = TRUE;
+}
+
+/* Update the TRACKER with a replacement of PATH with a plain addition
+   (without history).
+ */
+static void
+tracker_path_replace(path_tracker_t *tracker,
+                     const char *path)
+{
+  /* this will implicitly purge all previous sub-tree info from STACK.
+     Thus, no need to tack the deletion explicitly. */
+  tracker_path_add(tracker, path);
+}
+
+/* Update the TRACKER with a deletion of PATH.
+ */
+static void
+tracker_path_delete(path_tracker_t *tracker,
+                    const char *path)
+{
+  path_tracker_entry_t *entry = tracker__add_entry(tracker, path);
+
+  svn_stringbuf_setempty(entry->copyfrom_path);
+  entry->copyfrom_rev = SVN_INVALID_REVNUM;
+  entry->exists = FALSE;
+}
+
 
 /* Compute the delta between OLDROOT/OLDPATH and NEWROOT/NEWPATH and
    store it into a new temporary file *TEMPFILE.  OLDROOT may be NULL,
@@ -138,6 +401,10 @@ struct edit_baton
      respective node has already been verified as readable and being
      of the type stored as value in the cache. */
   svn_cache__t *verified_dirents_cache;
+
+  /* Structure allows us to verify the paths currently being dumped.
+     If NULL, validity checks are being skipped. */
+  path_tracker_t *path_tracker;
 };
 
 struct dir_baton
@@ -224,6 +491,95 @@ make_dir_baton(const char *path,
   return new_db;
 }
 
+static svn_error_t *
+fetch_kind_func(svn_node_kind_t *kind,
+                void *baton,
+                const char *path,
+                svn_revnum_t base_revision,
+                apr_pool_t *scratch_pool);
+
+/* Return an error when PATH in REVISION does not exist or is of a
+   different kind than EXPECTED_KIND.  If the latter is svn_node_unknown,
+   skip that check.  Use EB for context information.  If REVISION is the
+   current revision, use EB's path tracker to follow renames, deletions,
+   etc.
+
+   Use SCRATCH_POOL for temporary allocations.
+   No-op if EB's path tracker has not been initialized.
+ */
+static svn_error_t *
+node_must_exist(struct edit_baton *eb,
+                const char *path,
+                svn_revnum_t revision,
+                svn_node_kind_t expected_kind,
+                apr_pool_t *scratch_pool)
+{
+  svn_node_kind_t kind = svn_node_none;
+
+  /* in case the caller is trying something stupid ... */
+  if (eb->path_tracker == NULL)
+    return SVN_NO_ERROR;
+
+  /* paths pertaining to the revision currently being processed must
+     be translated / checked using our path tracker. */
+  if (revision == eb->path_tracker->revision)
+    tracker_lookup(&path, &revision, eb->path_tracker, path, scratch_pool);
+
+  /* determine the node type (default: no such node) */
+  if (path)
+    SVN_ERR(fetch_kind_func(&kind, eb, path, revision, scratch_pool));
+
+  /* check results */
+  if (kind == svn_node_none)
+    return svn_error_createf(SVN_ERR_FS_NOT_FOUND, NULL,
+                             _("Path '%s' not found in r%ld."),
+                             path, revision);
+
+  if (expected_kind != kind && expected_kind != svn_node_unknown)
+    return svn_error_createf(SVN_ERR_NODE_UNEXPECTED_KIND, NULL,
+                             _("Unexpected node kind %d for '%s' at r%ld. "
+                               "Expected kind was %d."),
+                             kind, path, revision, expected_kind);
+
+  return SVN_NO_ERROR;
+}
+
+/* Return an error when PATH exists in REVISION.  Use EB for context
+   information.  If REVISION is the current revision, use EB's path
+   tracker to follow renames, deletions, etc.
+
+   Use SCRATCH_POOL for temporary allocations.
+   No-op if EB's path tracker has not been initialized.
+ */
+static svn_error_t *
+node_must_not_exist(struct edit_baton *eb,
+                    const char *path,
+                    svn_revnum_t revision,
+                    apr_pool_t *scratch_pool)
+{
+  svn_node_kind_t kind = svn_node_none;
+
+  /* in case the caller is trying something stupid ... */
+  if (eb->path_tracker == NULL)
+    return SVN_NO_ERROR;
+
+  /* paths pertaining to the revision currently being processed must
+     be translated / checked using our path tracker. */
+  if (revision == eb->path_tracker->revision)
+    tracker_lookup(&path, &revision, eb->path_tracker, path, scratch_pool);
+
+  /* determine the node type (default: no such node) */
+  if (path)
+    SVN_ERR(fetch_kind_func(&kind, eb, path, revision, scratch_pool));
+
+  /* check results */
+  if (kind != svn_node_none)
+    return svn_error_createf(SVN_ERR_FS_ALREADY_EXISTS, NULL,
+                             _("Path '%s' exists in r%ld."),
+                             path, revision);
+
+  return SVN_NO_ERROR;
+}
 
 /* This helper is the main "meat" of the editor -- it does all the
    work of writing a node record.
@@ -311,6 +667,11 @@ dump_node(struct edit_baton *eb,
 
   if (action == svn_node_action_change)
     {
+      if (eb->path_tracker)
+        SVN_ERR_W(node_must_exist(eb, path, eb->current_rev, kind, pool),
+                  apr_psprintf(pool, _("Change invalid path '%s' in r%ld"),
+                               path, eb->current_rev));
+
       SVN_ERR(svn_stream_puts(eb->stream,
                               SVN_REPOS_DUMPFILE_NODE_ACTION ": change\n"));
 
@@ -329,8 +690,18 @@ dump_node(struct edit_baton *eb,
     }
   else if (action == svn_node_action_replace)
     {
+      if (eb->path_tracker)
+        SVN_ERR_W(node_must_exist(eb, path, eb->current_rev,
+                                  svn_node_unknown, pool),
+                  apr_psprintf(pool,
+                               _("Replacing non-existent path '%s' in r%ld"),
+                               path, eb->current_rev));
+
       if (! is_copy)
         {
+          if (eb->path_tracker)
+            tracker_path_replace(eb->path_tracker, path);
+
           /* a simple delete+add, implied by a single 'replace' action. */
           SVN_ERR(svn_stream_puts(eb->stream,
                                   SVN_REPOS_DUMPFILE_NODE_ACTION
@@ -343,6 +714,20 @@ dump_node(struct edit_baton *eb,
         }
       else
         {
+          if (eb->path_tracker)
+            {
+              SVN_ERR_W(node_must_exist(eb, compare_path, compare_rev,
+                                        kind, pool),
+                        apr_psprintf(pool,
+                                     _("Replacing path '%s' in r%ld "
+                                       "with invalid path"),
+                                     path, eb->current_rev));
+
+              /* we will call dump_node again with an addition further
+                 down the road */
+              tracker_path_delete(eb->path_tracker, path);
+            }
+
           /* more complex:  delete original, then add-with-history.  */
 
           /* the path & kind headers have already been printed;  just
@@ -363,6 +748,14 @@ dump_node(struct edit_baton *eb,
     }
   else if (action == svn_node_action_delete)
     {
+      if (eb->path_tracker)
+        {
+          SVN_ERR_W(node_must_exist(eb, path, eb->current_rev, kind, pool),
+                    apr_psprintf(pool, _("Deleting invalid path '%s' in r%ld"),
+                                 path, eb->current_rev));
+          tracker_path_delete(eb->path_tracker, path);
+        }
+
       SVN_ERR(svn_stream_puts(eb->stream,
                               SVN_REPOS_DUMPFILE_NODE_ACTION ": delete\n"));
 
@@ -373,11 +766,20 @@ dump_node(struct edit_baton *eb,
     }
   else if (action == svn_node_action_add)
     {
+      if (eb->path_tracker)
+        SVN_ERR_W(node_must_not_exist(eb, path, eb->current_rev, pool),
+                  apr_psprintf(pool,
+                               _("Adding already existing path '%s' in r%ld"),
+                               path, eb->current_rev));
+
       SVN_ERR(svn_stream_puts(eb->stream,
                               SVN_REPOS_DUMPFILE_NODE_ACTION ": add\n"));
 
       if (! is_copy)
         {
+          if (eb->path_tracker)
+            tracker_path_add(eb->path_tracker, path);
+
           /* Dump all contents for a simple 'add'. */
           if (kind == svn_node_file)
             must_dump_text = TRUE;
@@ -385,6 +787,18 @@ dump_node(struct edit_baton *eb,
         }
       else
         {
+          if (eb->path_tracker)
+            {
+              SVN_ERR_W(node_must_exist(eb, compare_path, compare_rev,
+                                        kind, pool),
+                        apr_psprintf(pool,
+                                     _("Copying from invalid path to "
+                                       "'%s' in r%ld"),
+                                     path, eb->current_rev));
+              tracker_path_copy(eb->path_tracker, path, compare_path,
+                                compare_rev);
+            }
+
           if (!eb->verify && cmp_rev < eb->oldest_dumped_rev
               && eb->notify_func)
             {
@@ -995,6 +1409,14 @@ get_dump_editor(const svn_delta_editor_t
   eb->found_old_mergeinfo = found_old_mergeinfo;
   eb->verified_dirents_cache = verified_dirents_cache;
 
+  /* In non-verification mode, we will allow anything to be dumped because
+     it might be an incremental dump with possible manual intervention.
+     Also, this might be the last resort when it comes to data recovery.
+
+     Else, make sure that all paths exists at their respective revisions.
+  */
+  eb->path_tracker = verify ? tracker_create(to_rev, pool) : NULL;
+
   /* Set up the editor. */
   dump_editor->open_root = open_root;
   dump_editor->delete_entry = delete_entry;
@@ -1313,7 +1735,7 @@ verify_directory_entry(void *baton, cons
      type defined in the DIRENT. */
   if (db->edit_baton->verified_dirents_cache)
     {
-      svn_node_kind_t kind;
+      svn_node_kind_t *kind;
       svn_boolean_t found;
       unparsed_id = svn_fs_unparse_id(dirent->id, pool);
 
@@ -1323,7 +1745,7 @@ verify_directory_entry(void *baton, cons
 
       if (found)
         {
-          if (kind == dirent->kind)
+          if (*kind == dirent->kind)
             return SVN_NO_ERROR;
           else
             {
@@ -1333,7 +1755,7 @@ verify_directory_entry(void *baton, cons
                   svn_error_createf(SVN_ERR_NODE_UNEXPECTED_KIND, NULL,
                                     _("Unexpected node kind %d for '%s'. "
                                       "Expected kind was %d."),
-                                    dirent->kind, path, kind);
+                                    dirent->kind, path, *kind);
             }
         }
     }
@@ -1494,7 +1916,7 @@ deserialize_node_kind(void **out,
                       apr_size_t data_len,
                       apr_pool_t *pool)
 {
-  *(svn_node_kind_t *)out = *(svn_node_kind_t *)data;
+  *out = data;
 
   return SVN_NO_ERROR;
 }

Modified: subversion/branches/log-addressing/subversion/libsvn_repos/hooks.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_repos/hooks.c?rev=1536950&r1=1536949&r2=1536950&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_repos/hooks.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_repos/hooks.c Wed Oct 30 01:33:37 2013
@@ -335,7 +335,7 @@ check_hook_cmd(const char *hook, svn_boo
   for (extn = check_extns; *extn; ++extn)
     {
       const char *const hook_path =
-        (**extn ? apr_pstrcat(pool, hook, *extn, (char *)NULL) : hook);
+        (**extn ? apr_pstrcat(pool, hook, *extn, SVN_VA_NULL) : hook);
 
       svn_node_kind_t kind;
       if (!(err = svn_io_check_resolved_path(hook_path, &kind, pool))

Modified: subversion/branches/log-addressing/subversion/libsvn_repos/log.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_repos/log.c?rev=1536950&r1=1536949&r2=1536950&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_repos/log.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_repos/log.c Wed Oct 30 01:33:37 2013
@@ -42,7 +42,6 @@
 #include "private/svn_mergeinfo_private.h"
 #include "private/svn_subr_private.h"
 
-
 
 svn_error_t *
 svn_repos_check_revision_access(svn_repos_revision_access_level_t *access_level,
@@ -69,8 +68,7 @@ svn_repos_check_revision_access(svn_repo
 
   /* Fetch the changes associated with REVISION. */
   SVN_ERR(svn_fs_revision_root(&rev_root, fs, revision, pool));
-  SVN_ERR(svn_fs_paths_changed3(&changes, rev_root,
-                                svn_move_behavior_explicit_moves, pool));
+  SVN_ERR(svn_fs_paths_changed2(&changes, rev_root, pool));
 
   /* No changed paths?  We're done. */
   if (apr_hash_count(changes) == 0)
@@ -155,6 +153,147 @@ svn_repos_check_revision_access(svn_repo
   return SVN_NO_ERROR;
 }
 
+/* Return TRUE, if CHANGE deleted the node previously found at its target
+   path. */
+static svn_boolean_t
+is_deletion(svn_log_changed_path2_t *change)
+{
+  /* We need a 'N' action here ... */
+  return change->action == 'E'
+      || change->action == 'R'
+      || change->action == 'D';
+}
+
+/* Change all moves in CHANGES to ADD.  Use POOL for temporary allocations.
+ */
+static void
+turn_moves_into_copies(apr_hash_t *changes,
+                       apr_pool_t *pool)
+{
+  apr_hash_index_t *hi;
+  for (hi = apr_hash_first(pool, changes); hi; hi = apr_hash_next(hi))
+    {
+      const char *key;
+      apr_ssize_t klen;
+      svn_log_changed_path2_t *change;
+      apr_hash_this(hi, (const void **)&key, &klen, (void**)&change);
+
+      switch (change->action)
+        {
+          case 'V':
+            change->action = 'A';
+            break;
+
+          case 'E':
+            change->action = 'R';
+            break;
+
+          default:
+            break;
+        }
+    }
+}
+
+/* Replace ADDs with MOVes, if they are unique, have a matching deletion
+ * and if the copy-from revision is REVISION-1.  Use POOL for temporary
+ * allocations.
+ */
+static void
+turn_unique_copies_into_moves(apr_hash_t *changes,
+                              svn_revnum_t revision,
+                              apr_pool_t *pool)
+{
+  apr_hash_index_t *hi;
+  apr_hash_t *unique_copy_sources;
+  const char **sources;
+  int i;
+
+  /* find all copy-from paths (ADD and MOV alike) */
+
+  svn_boolean_t any_deletion = FALSE;
+  apr_array_header_t *copy_sources
+    = apr_array_make(pool, apr_hash_count(changes), sizeof(const char*));
+
+  for (hi = apr_hash_first(pool, changes); hi; hi = apr_hash_next(hi))
+    {
+      svn_log_changed_path2_t *change;
+      apr_hash_this(hi, NULL, NULL, (void**)&change);
+
+      if (change->copyfrom_path && change->copyfrom_rev == revision-1)
+        APR_ARRAY_PUSH(copy_sources, const char *)
+          = change->copyfrom_path;
+
+      any_deletion |= is_deletion(change);
+    }
+
+  /* no suitable copy-from or no deletion -> no moves */
+
+  if (!copy_sources->nelts || !any_deletion)
+    return;
+
+  /* identify copy-from paths that have been mentioned exactly once */
+
+  sources = (const char **)copy_sources->elts;
+  qsort(sources, copy_sources->nelts, copy_sources->elt_size,
+        (int (*)(const void *, const void *))svn_sort_compare_paths);
+
+  unique_copy_sources = apr_hash_make(pool);
+  for (i = 0; i < copy_sources->nelts; ++i)
+    if (   (i == 0 || strcmp(sources[i-1], sources[i]))
+        && (i == copy_sources->nelts-1 || strcmp(sources[i+1], sources[i])))
+      {
+        apr_hash_set(unique_copy_sources, sources[i],
+                     APR_HASH_KEY_STRING, sources[i]);
+      }
+
+  /* no unique copy-from paths -> no moves */
+
+  if (!apr_hash_count(unique_copy_sources))
+    return;
+
+  /* Replace all additions, replacements with a unique copy-from path,
+     the correct copy-from rev and a matching deletion in this revision,
+     with moves and move-replacements, respectively. */
+
+  for (hi = apr_hash_first(pool, changes); hi; hi = apr_hash_next(hi))
+    {
+      const char *key;
+      apr_ssize_t klen;
+      svn_log_changed_path2_t *change, *copy_from_change;
+
+      apr_hash_this(hi, (const void **)&key, &klen, (void**)&change);
+      if (   change->copyfrom_rev != revision-1
+          || !change->copyfrom_path
+          || !apr_hash_get(unique_copy_sources, change->copyfrom_path,
+                           APR_HASH_KEY_STRING))
+        continue;
+
+      copy_from_change = apr_hash_get(changes, change->copyfrom_path,
+                                      APR_HASH_KEY_STRING);
+      if (!copy_from_change || !is_deletion(copy_from_change))
+        continue;
+
+      /* There is a deletion of the ADD's copy-from path in *REVISION*.
+         This can either be the same as in REVISION-1 (o.k.) or must have
+         been replaced by some other node.  However, that would imply that
+         it still got deleted as part of the replacement, i.e. both cases
+         are o.k. */
+
+      switch (change->action)
+        {
+          case 'A':
+            change->action = 'V';
+            break;
+
+          case 'R':
+            change->action = 'E';
+            break;
+
+          default:
+            break;
+        }
+    }
+}
 
 /* Store as keys in CHANGED the paths of all node in ROOT that show a
  * significant change.  "Significant" means that the text or
@@ -201,7 +340,7 @@ detect_changed(apr_hash_t **changed,
 
   *changed = svn_hash__make(pool);
   if (changes == NULL)
-    SVN_ERR(svn_fs_paths_changed3(&changes, root, move_behavior, pool));
+    SVN_ERR(svn_fs_paths_changed2(&changes, root, pool));
 
   if (apr_hash_count(changes) == 0)
     /* No paths changed in this revision?  Uh, sure, I guess the
@@ -368,6 +507,23 @@ detect_changed(apr_hash_t **changed,
     return svn_error_create(SVN_ERR_AUTHZ_UNREADABLE,
                             NULL, NULL);
 
+  /* at least some paths are readable.  Post-process them. */
+  switch(move_behavior)
+    {
+      case svn_move_behavior_no_moves:
+        turn_moves_into_copies(*changed, pool);
+        break;
+
+      case svn_move_behavior_auto_moves:
+        turn_unique_copies_into_moves(*changed,
+                                      svn_fs_revision_root_revision(root),
+                                      pool);
+        break;
+
+      default:
+        break;
+    }
+
   if (found_unreadable)
     /* At least one changed-path was unreadable. */
     return svn_error_create(SVN_ERR_AUTHZ_PARTIALLY_READABLE,
@@ -577,9 +733,7 @@ next_history_rev(const apr_array_header_
    catalogs describing how mergeinfo values on paths (which are the
    keys of those catalogs) were changed in REV.  If *PREFETCHED_CAHNGES
    already contains the changed paths for REV, use that.  Otherwise,
-   request that data and return it in *PREFETCHED_CHANGES.
-   MOVE_BEHAVIOR is a simple pass-through parameter that tells the FS
-   layer which changes to report as moves instead of additions. */
+   request that data and return it in *PREFETCHED_CHANGES. */
 /* ### TODO: This would make a *great*, useful public function,
    ### svn_repos_fs_mergeinfo_changed()!  -- cmpilato  */
 static svn_error_t *
@@ -588,7 +742,6 @@ fs_mergeinfo_changed(svn_mergeinfo_catal
                      apr_hash_t **prefetched_changes,
                      svn_fs_t *fs,
                      svn_revnum_t rev,
-                     svn_move_behavior_t move_behavior,
                      apr_pool_t *result_pool,
                      apr_pool_t *scratch_pool)
 
@@ -609,8 +762,7 @@ fs_mergeinfo_changed(svn_mergeinfo_catal
      narrow down our search. */
   SVN_ERR(svn_fs_revision_root(&root, fs, rev, scratch_pool));
   if (*prefetched_changes == NULL)
-    SVN_ERR(svn_fs_paths_changed3(prefetched_changes, root, move_behavior,
-                                  scratch_pool));
+    SVN_ERR(svn_fs_paths_changed2(prefetched_changes, root, scratch_pool));
 
   /* No changed paths?  We're done. */
   if (apr_hash_count(*prefetched_changes) == 0)
@@ -802,9 +954,7 @@ fs_mergeinfo_changed(svn_mergeinfo_catal
    *ADDED_MERGEINFO and deleted mergeinfo in *DELETED_MERGEINFO.
    If *PREFETCHED_CAHNGES already contains the changed paths for
    REV, use that.  Otherwise, request that data and return it in
-   *PREFETCHED_CHANGES.  MOVE_BEHAVIOR tells the FS layer which
-   changes to report as moves instead of additions.
-   Use POOL for all allocations. */
+   *PREFETCHED_CHANGES.  Use POOL for all allocations. */
 static svn_error_t *
 get_combined_mergeinfo_changes(svn_mergeinfo_t *added_mergeinfo,
                                svn_mergeinfo_t *deleted_mergeinfo,
@@ -812,7 +962,6 @@ get_combined_mergeinfo_changes(svn_merge
                                svn_fs_t *fs,
                                const apr_array_header_t *paths,
                                svn_revnum_t rev,
-                               svn_move_behavior_t move_behavior,
                                apr_pool_t *result_pool,
                                apr_pool_t *scratch_pool)
 {
@@ -842,7 +991,7 @@ get_combined_mergeinfo_changes(svn_merge
   err = fs_mergeinfo_changed(&deleted_mergeinfo_catalog,
                              &added_mergeinfo_catalog,
                              prefetched_changes,
-                             fs, rev, move_behavior,
+                             fs, rev,
                              scratch_pool, scratch_pool);
   if (err)
     {
@@ -2050,7 +2199,7 @@ do_logs(svn_fs_t *fs,
                                                      &deleted_mergeinfo,
                                                      &changes,
                                                      fs, cur_paths,
-                                                     current, move_behavior,
+                                                     current,
                                                      iterpool, iterpool));
               has_children = (apr_hash_count(added_mergeinfo) > 0
                               || apr_hash_count(deleted_mergeinfo) > 0);

Modified: subversion/branches/log-addressing/subversion/libsvn_repos/reporter.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_repos/reporter.c?rev=1536950&r1=1536949&r2=1536950&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_repos/reporter.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_repos/reporter.c Wed Oct 30 01:33:37 2013
@@ -842,7 +842,7 @@ add_file_smartly(report_baton_t *b,
          starting with '/', so make sure o_path always starts with a '/'
          too. */
       if (*o_path != '/')
-        o_path = apr_pstrcat(pool, "/", o_path, (char *)NULL);
+        o_path = apr_pstrcat(pool, "/", o_path, SVN_VA_NULL);
 
       SVN_ERR(svn_fs_closest_copy(&closest_copy_root, &closest_copy_path,
                                   b->t_root, o_path, pool));

Modified: subversion/branches/log-addressing/subversion/libsvn_repos/rev_hunt.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_repos/rev_hunt.c?rev=1536950&r1=1536949&r2=1536950&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_repos/rev_hunt.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_repos/rev_hunt.c Wed Oct 30 01:33:37 2013
@@ -661,7 +661,7 @@ svn_repos_trace_node_locations(svn_fs_t 
   /* Ensure that FS_PATH is absolute, because our path-math below will
      depend on that being the case.  */
   if (*fs_path != '/')
-    fs_path = apr_pstrcat(pool, "/", fs_path, (char *)NULL);
+    fs_path = apr_pstrcat(pool, "/", fs_path, SVN_VA_NULL);
 
   /* Another sanity check. */
   if (authz_read_func)
@@ -878,7 +878,7 @@ svn_repos_node_location_segments(svn_rep
   /* Ensure that PATH is absolute, because our path-math will depend
      on that being the case.  */
   if (*path != '/')
-    path = apr_pstrcat(pool, "/", path, (char *)NULL);
+    path = apr_pstrcat(pool, "/", path, SVN_VA_NULL);
 
   /* Auth check. */
   if (authz_read_func)
@@ -942,7 +942,7 @@ svn_repos_node_location_segments(svn_rep
 
           /* authz_read_func requires path to have a leading slash. */
           const char *abs_path = apr_pstrcat(subpool, "/", segment->path,
-                                             (char *)NULL);
+                                             SVN_VA_NULL);
 
           SVN_ERR(svn_fs_revision_root(&cur_rev_root, fs,
                                        segment->range_end, subpool));

Modified: subversion/branches/log-addressing/subversion/libsvn_subr/auth.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_subr/auth.c?rev=1536950&r1=1536949&r2=1536950&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_subr/auth.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_subr/auth.c Wed Oct 30 01:33:37 2013
@@ -35,6 +35,7 @@
 #include "svn_config.h"
 #include "svn_dso.h"
 #include "svn_version.h"
+#include "private/svn_auth_private.h"
 #include "private/svn_dep_compat.h"
 
 #include "auth.h"
@@ -194,7 +195,7 @@ make_cache_key(const char *cred_kind,
                const char *realmstring,
                apr_pool_t *pool)
 {
-  return apr_pstrcat(pool, cred_kind, ":", realmstring, (char *)NULL);
+  return apr_pstrcat(pool, cred_kind, ":", realmstring, SVN_VA_NULL);
 }
 
 svn_error_t *
@@ -542,6 +543,11 @@ svn_auth_get_platform_specific_provider(
         {
           svn_auth_get_windows_ssl_server_trust_provider(provider, pool);
         }
+      else if (strcmp(provider_name, "windows") == 0 &&
+               strcmp(provider_type, "ssl_server_authority") == 0)
+        {
+          svn_auth__get_windows_ssl_server_authority_provider(provider, pool);
+        }
 #endif
     }
 
@@ -652,5 +658,22 @@ svn_auth_get_platform_specific_client_pr
         }
     }
 
+  /* Windows has two providers without a store to allow easy access to
+     SSL servers. We enable these unconditionally.
+     (This behavior was moved here from svn_cmdline_create_auth_baton()) */
+  SVN_ERR(svn_auth_get_platform_specific_provider(&provider,
+                                                  "windows",
+                                                  "ssl_server_trust",
+                                                  pool));
+  SVN__MAYBE_ADD_PROVIDER(*providers, provider);
+
+  /* The windows ssl authority certificate CRYPTOAPI provider. */
+  SVN_ERR(svn_auth_get_platform_specific_provider(&provider,
+                                                  "windows",
+                                                  "ssl_server_authority",
+                                                  pool));
+
+  SVN__MAYBE_ADD_PROVIDER(*providers, provider);
+
   return SVN_NO_ERROR;
 }

Modified: subversion/branches/log-addressing/subversion/libsvn_subr/cache-memcache.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_subr/cache-memcache.c?rev=1536950&r1=1536949&r2=1536950&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_subr/cache-memcache.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_subr/cache-memcache.c Wed Oct 30 01:33:37 2013
@@ -99,7 +99,7 @@ build_key(const char **mc_key,
     }
 
   long_key = apr_pstrcat(pool, "SVN:", cache->prefix, ":", encoded_suffix,
-                         (char *)NULL);
+                         SVN_VA_NULL);
   long_key_len = strlen(long_key);
 
   /* We don't want to have a key that's too big.  If it was going to
@@ -120,7 +120,7 @@ build_key(const char **mc_key,
                              apr_pstrmemdup(pool, long_key,
                                             MEMCACHED_KEY_UNHASHED_LEN),
                              svn_checksum_to_cstring_display(checksum, pool),
-                             (char *)NULL);
+                             SVN_VA_NULL);
     }
 
   *mc_key = long_key;

Modified: subversion/branches/log-addressing/subversion/libsvn_subr/checksum.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_subr/checksum.c?rev=1536950&r1=1536949&r2=1536950&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_subr/checksum.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_subr/checksum.c Wed Oct 30 01:33:37 2013
@@ -324,7 +324,7 @@ svn_checksum_serialize(const svn_checksu
   return apr_pstrcat(result_pool,
                      ckind_str,
                      svn_checksum_to_cstring(checksum, scratch_pool),
-                     (char *)NULL);
+                     SVN_VA_NULL);
 }
 
 

Modified: subversion/branches/log-addressing/subversion/libsvn_subr/cmdline.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_subr/cmdline.c?rev=1536950&r1=1536949&r2=1536950&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_subr/cmdline.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_subr/cmdline.c Wed Oct 30 01:33:37 2013
@@ -34,6 +34,7 @@
 #else
 #include <crtdbg.h>
 #include <io.h>
+#include <conio.h>
 #endif
 
 #include <apr.h>                /* for STDIN_FILENO */
@@ -77,6 +78,14 @@ static const char *input_encoding = NULL
 
 /* The stdout encoding. If null, it's the same as the native encoding. */
 static const char *output_encoding = NULL;
+#elif defined(WIN32) && defined(_MSC_VER)
+/* For now limit this code to Visual C++, as the result is highly dependent
+   on the CRT implementation */
+#define USE_WIN32_CONSOLE_SHORTCUT
+
+/* When TRUE, stdout/stderr is directly connected to a console */
+static svn_boolean_t shortcut_stdout_to_console = FALSE;
+static svn_boolean_t shortcut_stderr_to_console = FALSE;
 #endif
 
 
@@ -254,6 +263,31 @@ svn_cmdline_init(const char *progname, F
       return EXIT_FAILURE;
     }
 
+#ifdef USE_WIN32_CONSOLE_SHORTCUT
+  if (_isatty(STDOUT_FILENO))
+    {
+      DWORD ignored;
+      HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE);
+
+       /* stdout is a char device handle, but is it the console? */
+       if (GetConsoleMode(stdout_handle, &ignored))
+        shortcut_stdout_to_console = TRUE;
+
+       /* Don't close stdout_handle */
+    }
+  if (_isatty(STDERR_FILENO))
+    {
+      DWORD ignored;
+      HANDLE stderr_handle = GetStdHandle(STD_ERROR_HANDLE);
+
+       /* stderr is a char device handle, but is it the console? */
+      if (GetConsoleMode(stderr_handle, &ignored))
+          shortcut_stderr_to_console = TRUE;
+
+      /* Don't close stderr_handle */
+    }
+#endif
+
   return EXIT_SUCCESS;
 }
 
@@ -347,6 +381,45 @@ svn_cmdline_fputs(const char *string, FI
   svn_error_t *err;
   const char *out;
 
+#ifdef USE_WIN32_CONSOLE_SHORTCUT
+  /* For legacy reasons the Visual C++ runtime converts output to the console
+     from the native 'ansi' encoding, to unicode, then back to 'ansi' and then
+     onwards to the console which is implemented as unicode.
+
+     For operations like 'svn status -v' this may cause about 70% of the total
+     processing time, with absolutely no gain.
+
+     For this specific scenario this shortcut exists. It has the nice side
+     effect of allowing full unicode output to the console.
+
+     Note that this shortcut is not used when the output is redirected, as in
+     that case the data is put on the pipe/file after the first conversion to
+     ansi. In this case the most expensive conversion is already avoided.
+   */
+  if ((stream == stdout && shortcut_stdout_to_console)
+      || (stream == stderr && shortcut_stderr_to_console))
+    {
+      WCHAR *result;
+
+      if (string[0] == '\0')
+        return SVN_NO_ERROR;
+
+      SVN_ERR(svn_cmdline_fflush(stream)); /* Flush existing output */
+
+      SVN_ERR(svn_utf__win32_utf8_to_utf16(&result, string, NULL, pool));
+
+      if (_cputws(result))
+        {
+          if (apr_get_os_error())
+          {
+            return svn_error_wrap_apr(apr_get_os_error(), _("Write error"));
+          }
+        }
+
+      return SVN_NO_ERROR;
+    }
+#endif
+
   err = svn_cmdline_cstring_from_utf8(&out, string, pool);
 
   if (err)
@@ -518,15 +591,6 @@ svn_cmdline_create_auth_baton(svn_auth_b
   svn_auth_get_username_provider(&provider, pool);
   APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider;
 
-  /* The server-cert, client-cert, and client-cert-password providers. */
-  SVN_ERR(svn_auth_get_platform_specific_provider(&provider,
-                                                  "windows",
-                                                  "ssl_server_trust",
-                                                  pool));
-
-  if (provider)
-    APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider;
-
   svn_auth_get_ssl_server_trust_file_provider(&provider, pool);
   APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider;
   svn_auth_get_ssl_client_cert_file_provider(&provider, pool);

Modified: subversion/branches/log-addressing/subversion/libsvn_subr/config.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_subr/config.c?rev=1536950&r1=1536949&r2=1536950&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_subr/config.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_subr/config.c Wed Oct 30 01:33:37 2013
@@ -39,6 +39,7 @@
 #include "config_impl.h"
 
 #include "private/svn_dep_compat.h"
+#include "private/svn_subr_private.h"
 
 
 
@@ -264,9 +265,9 @@ get_category_config(svn_config_t **cfg,
     {
 #ifdef WIN32
       sys_reg_path = apr_pstrcat(pool, SVN_REGISTRY_SYS_CONFIG_PATH,
-                                 category, NULL);
+                                 category, SVN_VA_NULL);
       usr_reg_path = apr_pstrcat(pool, SVN_REGISTRY_USR_CONFIG_PATH,
-                                 category, NULL);
+                                 category, SVN_VA_NULL);
 #endif /* WIN32 */
 
       err = svn_config__sys_config_path(&sys_cfg_path, category, pool);
@@ -652,6 +653,33 @@ svn_config_create_option(cfg_option_t **
   *opt = o;
 }
 
+svn_boolean_t
+svn_config__is_expanded(svn_config_t *cfg,
+                        const char *section,
+                        const char *option)
+{
+  cfg_option_t *opt;
+
+  if (cfg == NULL)
+    return FALSE;
+
+  /* does the option even exist? */
+  opt = find_option(cfg, section, option, NULL);
+  if (opt == NULL)
+    return FALSE;
+
+  /* already expanded? */
+  if (opt->expanded)
+    return TRUE;
+
+  /* needs expansion? */
+  if (opt->value && strchr(opt->value, '%'))
+    return FALSE;
+
+  /* no expansion necessary */
+  return TRUE;
+}
+
 
 void
 svn_config_get(svn_config_t *cfg, const char **valuep,
@@ -701,7 +729,9 @@ svn_config_set(svn_config_t *cfg,
    * Since we should never try to modify r/o data, trigger an assertion
    * in debug mode.
    */
-  assert(!cfg->read_only);
+#ifdef SVN_DEBUG
+  SVN_ERR_ASSERT_NO_RETURN(!cfg->read_only);
+#endif
   if (cfg->read_only)
     return;
 

Modified: subversion/branches/log-addressing/subversion/libsvn_subr/config_file.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_subr/config_file.c?rev=1536950&r1=1536949&r2=1536950&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_subr/config_file.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_subr/config_file.c Wed Oct 30 01:33:37 2013
@@ -395,7 +395,8 @@ svn_config__sys_config_path(const char *
     const char *folder;
     SVN_ERR(svn_config__win_config_path(&folder, TRUE, pool));
     *path_p = svn_dirent_join_many(pool, folder,
-                                   SVN_CONFIG__SUBDIRECTORY, fname, NULL);
+                                   SVN_CONFIG__SUBDIRECTORY, fname,
+                                   SVN_VA_NULL);
   }
 
 #elif defined(__HAIKU__)
@@ -408,11 +409,13 @@ svn_config__sys_config_path(const char *
       return SVN_NO_ERROR;
 
     *path_p = svn_dirent_join_many(pool, folder,
-                                   SVN_CONFIG__SYS_DIRECTORY, fname, NULL);
+                                   SVN_CONFIG__SYS_DIRECTORY, fname,
+                                   SVN_VA_NULL);
   }
 #else  /* ! WIN32 && !__HAIKU__ */
 
-  *path_p = svn_dirent_join_many(pool, SVN_CONFIG__SYS_DIRECTORY, fname, NULL);
+  *path_p = svn_dirent_join_many(pool, SVN_CONFIG__SYS_DIRECTORY, fname,
+                                 SVN_VA_NULL);
 
 #endif /* WIN32 */
 
@@ -460,6 +463,12 @@ svn_config__set_read_only(svn_config_t *
   cfg->read_only = TRUE;
 }
 
+svn_boolean_t
+svn_config__is_read_only(svn_config_t *cfg)
+{
+  return cfg->read_only;
+}
+
 
 
 svn_error_t *
@@ -1303,7 +1312,7 @@ svn_config_get_user_config_path(const ch
 
   if (config_dir)
     {
-      *path = svn_dirent_join_many(pool, config_dir, fname, NULL);
+      *path = svn_dirent_join_many(pool, config_dir, fname, SVN_VA_NULL);
       return SVN_NO_ERROR;
     }
 
@@ -1312,7 +1321,7 @@ svn_config_get_user_config_path(const ch
     const char *folder;
     SVN_ERR(svn_config__win_config_path(&folder, FALSE, pool));
     *path = svn_dirent_join_many(pool, folder,
-                                 SVN_CONFIG__SUBDIRECTORY, fname, NULL);
+                                 SVN_CONFIG__SUBDIRECTORY, fname, SVN_VA_NULL);
   }
 
 #elif defined(__HAIKU__)
@@ -1325,7 +1334,8 @@ svn_config_get_user_config_path(const ch
       return SVN_NO_ERROR;
 
     *path = svn_dirent_join_many(pool, folder,
-                                 SVN_CONFIG__USR_DIRECTORY, fname, NULL);
+                                 SVN_CONFIG__USR_DIRECTORY, fname,
+                                 SVN_VA_NULL);
   }
 #else  /* ! WIN32 && !__HAIKU__ */
 
@@ -1335,7 +1345,7 @@ svn_config_get_user_config_path(const ch
       return SVN_NO_ERROR;
     *path = svn_dirent_join_many(pool,
                                svn_dirent_canonicalize(homedir, pool),
-                               SVN_CONFIG__USR_DIRECTORY, fname, NULL);
+                               SVN_CONFIG__USR_DIRECTORY, fname, SVN_VA_NULL);
   }
 #endif /* WIN32 */
 

Modified: subversion/branches/log-addressing/subversion/libsvn_subr/config_win.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_subr/config_win.c?rev=1536950&r1=1536949&r2=1536950&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_subr/config_win.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_subr/config_win.c Wed Oct 30 01:33:37 2013
@@ -44,10 +44,11 @@
 #include "svn_path.h"
 #include "svn_pools.h"
 #include "svn_utf.h"
+#include "private/svn_utf_private.h"
 
 svn_error_t *
 svn_config__win_config_path(const char **folder, int system_path,
-                            apr_pool_t *pool)
+                            apr_pool_t *result_pool)
 {
   /* ### Adding CSIDL_FLAG_CREATE here, because those folders really
      must exist.  I'm not too sure about the SHGFP_TYPE_CURRENT
@@ -56,8 +57,6 @@ svn_config__win_config_path(const char *
                      | CSIDL_FLAG_CREATE);
 
   WCHAR folder_ucs2[MAX_PATH];
-  int inwords, outbytes, outlength;
-  char *folder_utf8;
 
   if (S_OK != SHGetFolderPathW(NULL, csidl, NULL, SHGFP_TYPE_CURRENT,
                                folder_ucs2))
@@ -66,26 +65,8 @@ svn_config__win_config_path(const char *
                            ? "Can't determine the system config path"
                            : "Can't determine the user's config path"));
 
-  /* ### When mapping from UCS-2 to UTF-8, we need at most 3 bytes
-         per wide char, plus extra space for the nul terminator. */
-  inwords = lstrlenW(folder_ucs2);
-  outbytes = outlength = 3 * (inwords + 1);
-
-  folder_utf8 = apr_palloc(pool, outlength);
-
-  outbytes = WideCharToMultiByte(CP_UTF8, 0, folder_ucs2, inwords,
-                                 folder_utf8, outbytes, NULL, NULL);
-
-  if (outbytes == 0)
-    return svn_error_wrap_apr(apr_get_os_error(),
-                              "Can't convert config path to UTF-8");
-
-  /* Note that WideCharToMultiByte does _not_ terminate the
-     outgoing buffer. */
-  folder_utf8[outbytes] = '\0';
-  *folder = folder_utf8;
-
-  return SVN_NO_ERROR;
+  return svn_error_trace(svn_utf__win32_utf16_to_utf8(folder, folder_ucs2,
+                                                      NULL, result_pool));
 }
 
 
@@ -97,6 +78,8 @@ svn_config__win_config_path(const char *
 #define SVN_REG_DEFAULT_NAME_SIZE  2048
 #define SVN_REG_DEFAULT_VALUE_SIZE 8192
 
+/* ### This function should be converted to use the unicode functions
+   ### instead of the ansi functions */
 static svn_error_t *
 parse_section(svn_config_t *cfg, HKEY hkey, const char *section,
               svn_stringbuf_t *option, svn_stringbuf_t *value)

Modified: subversion/branches/log-addressing/subversion/libsvn_subr/dirent_uri.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_subr/dirent_uri.c?rev=1536950&r1=1536949&r2=1536950&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_subr/dirent_uri.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_subr/dirent_uri.c Wed Oct 30 01:33:37 2013
@@ -2398,7 +2398,7 @@ svn_uri_get_dirent_from_file_url(const c
                                      "no path"), url);
 
         /* We still know that the path starts with a slash. */
-        *dirent = apr_pstrcat(pool, "//", hostname, dup_path, NULL);
+        *dirent = apr_pstrcat(pool, "//", hostname, dup_path, SVN_VA_NULL);
       }
     else
       *dirent = dup_path;
@@ -2431,18 +2431,18 @@ svn_uri_get_file_url_from_dirent(const c
   if (dirent[0] == '/' && dirent[1] == '\0')
     dirent = NULL; /* "file://" is the canonical form of "file:///" */
 
-  *url = apr_pstrcat(pool, "file://", dirent, (char *)NULL);
+  *url = apr_pstrcat(pool, "file://", dirent, SVN_VA_NULL);
 #else
   if (dirent[0] == '/')
     {
       /* Handle UNC paths //server/share -> file://server/share */
       assert(dirent[1] == '/'); /* Expect UNC, not non-absolute */
 
-      *url = apr_pstrcat(pool, "file:", dirent, NULL);
+      *url = apr_pstrcat(pool, "file:", dirent, SVN_VA_NULL);
     }
   else
     {
-      char *uri = apr_pstrcat(pool, "file:///", dirent, NULL);
+      char *uri = apr_pstrcat(pool, "file:///", dirent, SVN_VA_NULL);
       apr_size_t len = 8 /* strlen("file:///") */ + strlen(dirent);
 
       /* "C:/" is a canonical dirent on Windows,
@@ -2476,7 +2476,7 @@ svn_fspath__canonicalize(const char *fsp
     return "/";
 
   return apr_pstrcat(pool, "/", svn_relpath_canonicalize(fspath, pool),
-                     (char *)NULL);
+                     SVN_VA_NULL);
 }
 
 
@@ -2509,7 +2509,7 @@ svn_fspath__dirname(const char *fspath,
     return apr_pstrdup(pool, fspath);
   else
     return apr_pstrcat(pool, "/", svn_relpath_dirname(fspath + 1, pool),
-                       (char *)NULL);
+                       SVN_VA_NULL);
 }
 
 
@@ -2553,9 +2553,9 @@ svn_fspath__join(const char *fspath,
   if (relpath[0] == '\0')
     result = apr_pstrdup(result_pool, fspath);
   else if (fspath[1] == '\0')
-    result = apr_pstrcat(result_pool, "/", relpath, (char *)NULL);
+    result = apr_pstrcat(result_pool, "/", relpath, SVN_VA_NULL);
   else
-    result = apr_pstrcat(result_pool, fspath, "/", relpath, (char *)NULL);
+    result = apr_pstrcat(result_pool, fspath, "/", relpath, SVN_VA_NULL);
 
   assert(svn_fspath__is_canonical(result));
   return result;
@@ -2574,7 +2574,7 @@ svn_fspath__get_longest_ancestor(const c
                        svn_relpath_get_longest_ancestor(fspath1 + 1,
                                                         fspath2 + 1,
                                                         result_pool),
-                       (char *)NULL);
+                       SVN_VA_NULL);
 
   assert(svn_fspath__is_canonical(result));
   return result;

Modified: subversion/branches/log-addressing/subversion/libsvn_subr/error.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_subr/error.c?rev=1536950&r1=1536949&r2=1536950&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_subr/error.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_subr/error.c Wed Oct 30 01:33:37 2013
@@ -202,7 +202,8 @@ svn_error_wrap_apr(apr_status_t status,
       va_end(ap);
       if (msg_apr)
         {
-          err->message = apr_pstrcat(err->pool, msg, ": ", msg_apr, NULL);
+          err->message = apr_pstrcat(err->pool, msg, ": ", msg_apr,
+                                     SVN_VA_NULL);
         }
       else
         {

Modified: subversion/branches/log-addressing/subversion/libsvn_subr/file.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_subr/file.c?rev=1536950&r1=1536949&r2=1536950&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_subr/file.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_subr/file.c Wed Oct 30 01:33:37 2013
@@ -184,7 +184,7 @@ reclaim_shared_handle(shared_handle_pool
                 shared_handle_t *) = NULL;
 
   /* implicitly closes the file */
-  apr_pool_clear(result->pool);
+  svn_pool_clear(result->pool);
 
   return result;
 }
@@ -331,7 +331,7 @@ close_handle(shared_handle_pool_t *handl
              shared_handle_t *handle)
 {
   /* implicitly closes the file */
-  apr_pool_clear(handle->pool);
+  svn_pool_clear(handle->pool);
 
   handle_pool->last_open = handle->previous;
   handle->next = handle_pool->first_unused;

Modified: subversion/branches/log-addressing/subversion/libsvn_subr/io.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_subr/io.c?rev=1536950&r1=1536949&r2=1536950&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_subr/io.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_subr/io.c Wed Oct 30 01:33:37 2013
@@ -47,10 +47,6 @@
 #include <apr_portable.h>
 #include <apr_md5.h>
 
-#ifdef WIN32
-#include <arch/win32/apr_arch_file_io.h>
-#endif
-
 #if APR_HAVE_FCNTL_H
 #include <fcntl.h>
 #endif
@@ -70,6 +66,8 @@
 
 #include "private/svn_atomic.h"
 #include "private/svn_io_private.h"
+#include "private/svn_utf_private.h"
+#include "private/svn_dep_compat.h"
 
 #define SVN_SLEEP_ENV_VAR "SVN_I_LOVE_CORRUPTED_WORKING_COPIES_SO_DISABLE_SLEEP_FOR_TIMESTAMPS"
 
@@ -150,7 +148,7 @@ static volatile svn_atomic_t win_dynamic
 /* Pointer to GetFinalPathNameByHandleW function from kernel32.dll. */
 typedef DWORD (WINAPI *GETFINALPATHNAMEBYHANDLE)(
                HANDLE hFile,
-               apr_wchar_t *lpszFilePath,
+               WCHAR *lpszFilePath,
                DWORD cchFilePath,
                DWORD dwFlags);
 
@@ -1693,27 +1691,13 @@ io_set_file_perms(const char *path,
 #endif /* !WIN32 && !__OS2__ */
 
 #ifdef WIN32
-#if APR_HAS_UNICODE_FS
-/* copy of the apr function utf8_to_unicode_path since apr doesn't export this one */
-static apr_status_t io_utf8_to_unicode_path(apr_wchar_t* retstr, apr_size_t retlen,
-                                            const char* srcstr)
-{
-    /* TODO: The computations could preconvert the string to determine
-     * the true size of the retstr, but that's a memory over speed
-     * tradeoff that isn't appropriate this early in development.
-     *
-     * Allocate the maximum string length based on leading 4
-     * characters of \\?\ (allowing nearly unlimited path lengths)
-     * plus the trailing null, then transform /'s into \\'s since
-     * the \\?\ form doesn't allow '/' path separators.
-     *
-     * Note that the \\?\ form only works for local drive paths, and
-     * \\?\UNC\ is needed UNC paths.
-     */
-    apr_size_t srcremains = strlen(srcstr) + 1;
-    apr_wchar_t *t = retstr;
-    apr_status_t rv;
-
+/* This is semantically the same as the APR utf8_to_unicode_path
+   function, but reimplemented here because APR does not export it. */
+static svn_error_t*
+io_utf8_to_unicode_path(const WCHAR **result,
+                        const char *source,
+                        apr_pool_t *result_pool)
+{
     /* This is correct, we don't twist the filename if it will
      * definitely be shorter than 248 characters.  It merits some
      * performance testing to see if this has any effect, but there
@@ -1728,132 +1712,119 @@ static apr_status_t io_utf8_to_unicode_p
      * Note that a utf-8 name can never result in more wide chars
      * than the original number of utf-8 narrow chars.
      */
-    if (srcremains > 248) {
-        if (srcstr[1] == ':' && (srcstr[2] == '/' || srcstr[2] == '\\')) {
-            wcscpy (retstr, L"\\\\?\\");
-            retlen -= 4;
-            t += 4;
-        }
-        else if ((srcstr[0] == '/' || srcstr[0] == '\\')
-              && (srcstr[1] == '/' || srcstr[1] == '\\')
-              && (srcstr[2] != '?')) {
-            /* Skip the slashes */
-            srcstr += 2;
-            srcremains -= 2;
-            wcscpy (retstr, L"\\\\?\\UNC\\");
-            retlen -= 8;
-            t += 8;
+    const WCHAR *prefix = NULL;
+    const int srclen = strlen(source);
+    WCHAR *buffer;
+
+    if (srclen > 248)
+    {
+        if (svn_ctype_isalpha(source[0]) && source[1] == ':'
+            && (source[2] == '/' || source[2] == '\\'))
+        {
+            /* This is an ordinary absolute path. */
+            prefix = L"\\\\?\\";
+        }
+        else if ((source[0] == '/' || source[0] == '\\')
+                 && (source[1] == '/' || source[1] == '\\')
+                 && source[2] != '?')
+        {
+            /* This is a UNC path */
+            source += 2;        /* Skip the leading slashes */
+            prefix = L"\\\\?\\UNC\\";
         }
     }
 
-    if (rv = apr_conv_utf8_to_ucs2(srcstr, &srcremains, t, &retlen)) {
-        return (rv == APR_INCOMPLETE) ? APR_EINVAL : rv;
-    }
-    if (srcremains) {
-        return APR_ENAMETOOLONG;
-    }
-    for (; *t; ++t)
-        if (*t == L'/')
-            *t = L'\\';
-    return APR_SUCCESS;
-}
-
-/* copy of the apr function unicode_to_utf8_path since apr doesn't export this
- * one */
-static apr_status_t io_unicode_to_utf8_path(char* retstr, apr_size_t retlen,
-                                            const apr_wchar_t* srcstr)
-{
+    SVN_ERR(svn_utf__win32_utf8_to_utf16(&(const WCHAR*)buffer, source,
+                                         prefix, result_pool));
+
+    /* Convert slashes to backslashes because the \\?\ path format
+       does not allow backslashes as path separators. */
+    *result = buffer;
+    for (; *buffer; ++buffer)
+    {
+        if (*buffer == '/')
+            *buffer = '\\';
+    }
+    return SVN_NO_ERROR;
+}
+
+/* This is semantically the same as the APR unicode_to_utf8_path
+   function, but reimplemented here because APR does not export it. */
+static svn_error_t *
+io_unicode_to_utf8_path(const char **result,
+                        const WCHAR *source,
+                        apr_pool_t *result_pool)
+{
+    const char *utf8_buffer;
+    char *buffer;
+
+    SVN_ERR(svn_utf__win32_utf16_to_utf8(&utf8_buffer, source,
+                                         NULL, result_pool));
+    if (!*utf8_buffer)
+      {
+        *result = utf8_buffer;
+        return SVN_NO_ERROR;
+      }
+
+    /* We know that the non-empty buffer returned from the UTF-16 to
+       UTF-8 conversion function is in fact writable. */
+    buffer = (char*)utf8_buffer;
+
     /* Skip the leading 4 characters if the path begins \\?\, or substitute
      * // for the \\?\UNC\ path prefix, allocating the maximum string
      * length based on the remaining string, plus the trailing null.
      * then transform \\'s back into /'s since the \\?\ form never
      * allows '/' path seperators, and APR always uses '/'s.
      */
-    apr_size_t srcremains = wcslen(srcstr) + 1;
-    apr_status_t rv;
-    char *t = retstr;
-    if (srcstr[0] == L'\\' && srcstr[1] == L'\\' && 
-        srcstr[2] == L'?'  && srcstr[3] == L'\\') {
-        if (srcstr[4] == L'U' && srcstr[5] == L'N' && 
-            srcstr[6] == L'C' && srcstr[7] == L'\\') {
-            srcremains -= 8;
-            srcstr += 8;
-            retstr[0] = '\\';
-            retstr[1] = '\\';
-            retlen -= 2;
-            t += 2;
-        }
-        else {
-            srcremains -= 4;
-            srcstr += 4;
-        }
-    }
-        
-    if ((rv = apr_conv_ucs2_to_utf8(srcstr, &srcremains, t, &retlen))) {
-        return rv;
-    }
-    if (srcremains) {
-        return APR_ENAMETOOLONG;
-    }
-    return APR_SUCCESS;
+    if (0 == strncmp(buffer, "\\\\?\\", 4))
+    {
+        buffer += 4;
+        if (0 == strncmp(buffer, "UNC\\", 4))
+        {
+            buffer += 2;
+            *buffer = '/';
+        }
+    }
+
+    *result = buffer;
+    for (; *buffer; ++buffer)
+    {
+        if (*buffer == '\\')
+            *buffer = '/';
+    }
+    return SVN_NO_ERROR;
 }
-#endif
 
-static apr_status_t io_win_file_attrs_set(const char *fname,
-                                          DWORD attributes,
-                                          DWORD attr_mask,
-                                          apr_pool_t *pool)
+static svn_error_t *
+io_win_file_attrs_set(const char *fname,
+                      DWORD attributes,
+                      DWORD attr_mask,
+                      apr_pool_t *pool)
 {
     /* this is an implementation of apr_file_attrs_set() but one
        that uses the proper Windows attributes instead of the apr
        attributes. This way, we can apply any Windows file and
        folder attributes even if apr doesn't implement them */
     DWORD flags;
-    apr_status_t rv;
-#if APR_HAS_UNICODE_FS
-    apr_wchar_t wfname[APR_PATH_MAX];
-#endif
+    const WCHAR *wfname;
 
-#if APR_HAS_UNICODE_FS
-    IF_WIN_OS_IS_UNICODE
-    {
-        if (rv = io_utf8_to_unicode_path(wfname,
-                                         sizeof(wfname) / sizeof(wfname[0]),
-                                         fname))
-            return rv;
-        flags = GetFileAttributesW(wfname);
-    }
-#endif
-#if APR_HAS_ANSI_FS
-    ELSE_WIN_OS_IS_ANSI
-    {
-        flags = GetFileAttributesA(fname);
-    }
-#endif
+    SVN_ERR(io_utf8_to_unicode_path(&wfname, fname, pool));
 
+    flags = GetFileAttributesW(wfname);
     if (flags == 0xFFFFFFFF)
-        return apr_get_os_error();
+        return svn_error_wrap_apr(apr_get_os_error(),
+                                  _("Can't get attributes of file '%s'"),
+                                  svn_dirent_local_style(fname, pool));
 
     flags &= ~attr_mask;
     flags |= (attributes & attr_mask);
 
-#if APR_HAS_UNICODE_FS
-    IF_WIN_OS_IS_UNICODE
-    {
-        rv = SetFileAttributesW(wfname, flags);
-    }
-#endif
-#if APR_HAS_ANSI_FS
-    ELSE_WIN_OS_IS_ANSI
-    {
-        rv = SetFileAttributesA(fname, flags);
-    }
-#endif
-
-    if (rv == 0)
-        return apr_get_os_error();
+    if (!SetFileAttributesW(wfname, flags))
+        return svn_error_wrap_apr(apr_get_os_error(),
+                                  _("Can't set attributes of file '%s'"),
+                                  svn_dirent_local_style(fname, pool));
 
-    return APR_SUCCESS;
+    return SVN_NO_ERROR;;
 }
 
 static svn_error_t *win_init_dynamic_imports(void *baton, apr_pool_t *pool)
@@ -1869,7 +1840,6 @@ static svn_error_t * io_win_read_link(sv
                                       const char *path,
                                       apr_pool_t *pool)
 {
-#if APR_HAS_UNICODE_FS
     SVN_ERR(svn_atomic__init_once(&win_dynamic_imports_state,
                                   win_init_dynamic_imports, NULL, pool));
 
@@ -1879,8 +1849,8 @@ static svn_error_t * io_win_read_link(sv
         apr_status_t status;
         apr_file_t *file;
         apr_os_file_t filehand;
-        apr_wchar_t wdest[APR_PATH_MAX];
-        char buf[APR_PATH_MAX];
+        WCHAR wdest[APR_PATH_MAX];
+        const char *data;
 
         /* reserve one char for terminating zero. */
         DWORD wdest_len = sizeof(wdest)/sizeof(wdest[0]) - 1;
@@ -1914,18 +1884,20 @@ static svn_error_t * io_win_read_link(sv
 
         /* GetFinaPathNameByHandleW doesn't add terminating NUL. */
         wdest[rv] = 0;
+        SVN_ERR(io_unicode_to_utf8_path(&data, wdest, pool));
 
-        status = io_unicode_to_utf8_path(buf, sizeof(buf), wdest);
-        if (status)
-          return svn_error_wrap_apr(status,
-                                    _("Can't read contents of link"));
-
-        *dest = svn_string_create(buf, pool);
+        /* The result is already in the correct pool, so avoid copying
+           it to create the string. */
+        *dest = svn_string_create_empty(pool);
+        if (*data)
+          {
+            (*dest)->data = data;
+            (*dest)->len = strlen(data);
+          }
 
         return SVN_NO_ERROR;
       }
     else
-#endif
       {
         return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
                                 _("Symbolic links are not supported on this "
@@ -1933,7 +1905,7 @@ static svn_error_t * io_win_read_link(sv
       }
 }
 
-#endif
+#endif /* WIN32 */
 
 svn_error_t *
 svn_io_set_file_read_write_carefully(const char *path,
@@ -3199,7 +3171,8 @@ svn_io_run_diff3_3(int *exitcode,
         svn_config_get(cfg, &diff_cmd, SVN_CONFIG_SECTION_HELPERS,
                        SVN_CONFIG_OPTION_DIFF_CMD, SVN_CLIENT_DIFF);
         SVN_ERR(cstring_to_utf8(&diff_utf8, diff_cmd, pool));
-        args[i++] = apr_pstrcat(pool, "--diff-program=", diff_utf8, NULL);
+        args[i++] = apr_pstrcat(pool, "--diff-program=", diff_utf8,
+                                SVN_VA_NULL);
 #ifndef NDEBUG
         ++nargs;
 #endif
@@ -4081,22 +4054,26 @@ dir_make(const char *path, apr_fileperms
                                   APR_FILE_ATTR_HIDDEN,
                                   APR_FILE_ATTR_HIDDEN,
                                   pool);
-#else
-    /* on Windows, use our wrapper so we can also set the
-       FILE_ATTRIBUTE_NOT_CONTENT_INDEXED attribute */
-    status = io_win_file_attrs_set(path_apr,
-                                   FILE_ATTRIBUTE_HIDDEN |
-                                   FILE_ATTRIBUTE_NOT_CONTENT_INDEXED,
-                                   FILE_ATTRIBUTE_HIDDEN |
-                                   FILE_ATTRIBUTE_NOT_CONTENT_INDEXED,
-                                   pool);
-
-#endif
       if (status)
         return svn_error_wrap_apr(status, _("Can't hide directory '%s'"),
                                   svn_dirent_local_style(path, pool));
+#else
+    /* on Windows, use our wrapper so we can also set the
+       FILE_ATTRIBUTE_NOT_CONTENT_INDEXED attribute */
+      svn_error_t *err =
+          io_win_file_attrs_set(path_apr,
+                                FILE_ATTRIBUTE_HIDDEN |
+                                FILE_ATTRIBUTE_NOT_CONTENT_INDEXED,
+                                FILE_ATTRIBUTE_HIDDEN |
+                                FILE_ATTRIBUTE_NOT_CONTENT_INDEXED,
+                                pool);
+      if (err)
+        return svn_error_createf(err->apr_err, err,
+                                 _("Can't hide directory '%s'"),
+                                 svn_dirent_local_style(path, pool));
+#endif /* WIN32 */
     }
-#endif
+#endif /* APR_FILE_ATTR_HIDDEN */
 
 /* Windows does not implement sgid. Skip here because retrieving
    the file permissions via APR_FINFO_PROT | APR_FINFO_OWNER is documented

Modified: subversion/branches/log-addressing/subversion/libsvn_subr/log.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_subr/log.c?rev=1536950&r1=1536949&r2=1536950&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_subr/log.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_subr/log.c Wed Oct 30 01:33:37 2013
@@ -45,7 +45,7 @@ log_depth(svn_depth_t depth, apr_pool_t 
 {
   if (depth == svn_depth_unknown)
     return "";
-  return apr_pstrcat(pool, " depth=", svn_depth_to_word(depth), (char *)NULL);
+  return apr_pstrcat(pool, " depth=", svn_depth_to_word(depth), SVN_VA_NULL);
 }
 
 static const char *