Modified: subversion/branches/ra-git/subversion/libsvn_repos/replay.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_repos/replay.c?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_repos/replay.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_repos/replay.c Tue Oct 11 
09:11:50 2016
@@ -198,7 +198,7 @@ add_subdir(svn_fs_root_t *source_root,
 
   for (hi = apr_hash_first(pool, dirents); hi; hi = apr_hash_next(hi))
     {
-      svn_fs_path_change2_t *change;
+      svn_fs_path_change3_t *change;
       svn_boolean_t readable = TRUE;
       svn_fs_dirent_t *dent = apr_hash_this_val(hi);
       const char *copyfrom_path = NULL;
@@ -412,7 +412,7 @@ fill_copyfrom(svn_fs_root_t **copyfrom_r
               svn_revnum_t *copyfrom_rev,
               svn_boolean_t *src_readable,
               svn_fs_root_t *root,
-              svn_fs_path_change2_t *change,
+              svn_fs_path_change3_t *change,
               svn_repos_authz_func_t authz_read_func,
               void *authz_read_baton,
               const char *path,
@@ -463,7 +463,7 @@ path_driver_cb_func(void **dir_baton,
   const svn_delta_editor_t *editor = cb->editor;
   void *edit_baton = cb->edit_baton;
   svn_fs_root_t *root = cb->root;
-  svn_fs_path_change2_t *change;
+  svn_fs_path_change3_t *change;
   svn_boolean_t do_add = FALSE, do_delete = FALSE;
   void *file_baton = NULL;
   svn_revnum_t copyfrom_rev;
@@ -843,6 +843,80 @@ fetch_props_func(apr_hash_t **props,
 
 
 
+/* Retrieve the path changes under ROOT, filter them with AUTHZ_READ_FUNC
+   and AUTHZ_READ_BATON and return those that intersect with BASE_RELPATH.
+
+   The svn_fs_path_change3_t* will be returned in *CHANGED_PATHS, keyed by
+   their path.  The paths themselves are additionally returned in *PATHS.
+
+   Allocate the returned data in RESULT_POOL and use SCRATCH_POOL for
+   temporary allocations.
+ */
+static svn_error_t *
+get_relevant_changes(apr_hash_t **changed_paths,
+                     apr_array_header_t **paths,
+                     svn_fs_root_t *root,
+                     const char *base_relpath,
+                     svn_repos_authz_func_t authz_read_func,
+                     void *authz_read_baton,
+                     apr_pool_t *result_pool,
+                     apr_pool_t *scratch_pool)
+{
+  svn_fs_path_change_iterator_t *iterator;
+  svn_fs_path_change3_t *change;
+  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+
+  /* Fetch the paths changed under ROOT. */
+  SVN_ERR(svn_fs_paths_changed3(&iterator, root, scratch_pool, scratch_pool));
+  SVN_ERR(svn_fs_path_change_get(&change, iterator));
+
+  /* Make an array from the keys of our CHANGED_PATHS hash, and copy
+     the values into a new hash whose keys have no leading slashes. */
+  *paths = apr_array_make(result_pool, 16, sizeof(const char *));
+  *changed_paths = apr_hash_make(result_pool);
+  while (change)
+    {
+      const char *path = change->path.data;
+      apr_ssize_t keylen = change->path.len;
+      svn_boolean_t allowed = TRUE;
+
+      svn_pool_clear(iterpool);
+      if (authz_read_func)
+        SVN_ERR(authz_read_func(&allowed, root, path, authz_read_baton,
+                                iterpool));
+
+      if (allowed)
+        {
+          if (path[0] == '/')
+            {
+              path++;
+              keylen--;
+            }
+
+          /* If the base_path doesn't match the top directory of this path
+             we don't want anything to do with it... 
+             ...unless this was a change to one of the parent directories of
+             base_path. */
+          if (   svn_relpath_skip_ancestor(base_relpath, path)
+              || svn_relpath_skip_ancestor(path, base_relpath))
+            {
+              change = svn_fs_path_change3_dup(change, result_pool);
+              path = change->path.data;
+              if (path[0] == '/')
+                path++;
+
+              APR_ARRAY_PUSH(*paths, const char *) = path;
+              apr_hash_set(*changed_paths, path, keylen, change);
+            }
+        }
+
+      SVN_ERR(svn_fs_path_change_get(&change, iterator));
+    }
+
+  svn_pool_destroy(iterpool);
+  return SVN_NO_ERROR;
+}
+
 svn_error_t *
 svn_repos_replay2(svn_fs_root_t *root,
                   const char *base_path,
@@ -855,9 +929,7 @@ svn_repos_replay2(svn_fs_root_t *root,
                   apr_pool_t *pool)
 {
 #ifndef USE_EV2_IMPL
-  apr_hash_t *fs_changes;
   apr_hash_t *changed_paths;
-  apr_hash_index_t *hi;
   apr_array_header_t *paths;
   struct path_driver_cb_baton cb_baton;
 
@@ -869,54 +941,15 @@ svn_repos_replay2(svn_fs_root_t *root,
       return SVN_NO_ERROR;
     }
 
-  /* Fetch the paths changed under ROOT. */
-  SVN_ERR(svn_fs_paths_changed2(&fs_changes, root, pool));
-
   if (! base_path)
     base_path = "";
   else if (base_path[0] == '/')
     ++base_path;
 
-  /* Make an array from the keys of our CHANGED_PATHS hash, and copy
-     the values into a new hash whose keys have no leading slashes. */
-  paths = apr_array_make(pool, apr_hash_count(fs_changes),
-                         sizeof(const char *));
-  changed_paths = apr_hash_make(pool);
-  for (hi = apr_hash_first(pool, fs_changes); hi; hi = apr_hash_next(hi))
-    {
-      const char *path = apr_hash_this_key(hi);
-      apr_ssize_t keylen = apr_hash_this_key_len(hi);
-      svn_fs_path_change2_t *change = apr_hash_this_val(hi);
-      svn_boolean_t allowed = TRUE;
-
-      if (authz_read_func)
-        SVN_ERR(authz_read_func(&allowed, root, path, authz_read_baton,
-                                pool));
-
-      if (allowed)
-        {
-          if (path[0] == '/')
-            {
-              path++;
-              keylen--;
-            }
-
-          /* If the base_path doesn't match the top directory of this path
-             we don't want anything to do with it... */
-          if (svn_relpath_skip_ancestor(base_path, path) != NULL)
-            {
-              APR_ARRAY_PUSH(paths, const char *) = path;
-              apr_hash_set(changed_paths, path, keylen, change);
-            }
-          /* ...unless this was a change to one of the parent directories of
-             base_path. */
-          else if (svn_relpath_skip_ancestor(path, base_path) != NULL)
-            {
-              APR_ARRAY_PUSH(paths, const char *) = path;
-              apr_hash_set(changed_paths, path, keylen, change);
-            }
-        }
-    }
+  /* Fetch the paths changed under ROOT. */
+  SVN_ERR(get_relevant_changes(&changed_paths, &paths, root, base_path,
+                               authz_read_func, authz_read_baton,
+                               pool, pool));
 
   /* If we were not given a low water mark, assume that everything is there,
      all the way back to revision 0. */
@@ -1062,7 +1095,7 @@ add_subdir_ev2(svn_fs_root_t *source_roo
 
   for (hi = apr_hash_first(scratch_pool, dirents); hi; hi = apr_hash_next(hi))
     {
-      svn_fs_path_change2_t *change;
+      svn_fs_path_change3_t *change;
       svn_boolean_t readable = TRUE;
       svn_fs_dirent_t *dent = apr_hash_this_val(hi);
       const char *copyfrom_path = NULL;
@@ -1190,7 +1223,7 @@ replay_node(svn_fs_root_t *root,
             apr_pool_t *result_pool,
             apr_pool_t *scratch_pool)
 {
-  svn_fs_path_change2_t *change;
+  svn_fs_path_change3_t *change;
   svn_boolean_t do_add = FALSE;
   svn_boolean_t do_delete = FALSE;
   svn_revnum_t copyfrom_rev;
@@ -1485,9 +1518,7 @@ svn_repos__replay_ev2(svn_fs_root_t *roo
                       void *authz_read_baton,
                       apr_pool_t *scratch_pool)
 {
-  apr_hash_t *fs_changes;
   apr_hash_t *changed_paths;
-  apr_hash_index_t *hi;
   apr_array_header_t *paths;
   apr_array_header_t *copies;
   apr_pool_t *iterpool;
@@ -1505,49 +1536,10 @@ svn_repos__replay_ev2(svn_fs_root_t *roo
     }
 
   /* Fetch the paths changed under ROOT. */
-  SVN_ERR(svn_fs_paths_changed2(&fs_changes, root, scratch_pool));
-
-  /* Make an array from the keys of our CHANGED_PATHS hash, and copy
-     the values into a new hash whose keys have no leading slashes. */
-  paths = apr_array_make(scratch_pool, apr_hash_count(fs_changes),
-                         sizeof(const char *));
-  changed_paths = apr_hash_make(scratch_pool);
-  for (hi = apr_hash_first(scratch_pool, fs_changes); hi;
-        hi = apr_hash_next(hi))
-    {
-      const char *path = apr_hash_this_key(hi);
-      apr_ssize_t keylen = apr_hash_this_key_len(hi);
-      svn_fs_path_change2_t *change = apr_hash_this_val(hi);
-      svn_boolean_t allowed = TRUE;
-
-      if (authz_read_func)
-        SVN_ERR(authz_read_func(&allowed, root, path, authz_read_baton,
-                                scratch_pool));
-
-      if (allowed)
-        {
-          if (path[0] == '/')
-            {
-              path++;
-              keylen--;
-            }
-
-          /* If the base_path doesn't match the top directory of this path
-             we don't want anything to do with it... */
-          if (svn_relpath_skip_ancestor(base_repos_relpath, path) != NULL)
-            {
-              APR_ARRAY_PUSH(paths, const char *) = path;
-              apr_hash_set(changed_paths, path, keylen, change);
-            }
-          /* ...unless this was a change to one of the parent directories of
-             base_path. */
-          else if (svn_relpath_skip_ancestor(path, base_repos_relpath) != NULL)
-            {
-              APR_ARRAY_PUSH(paths, const char *) = path;
-              apr_hash_set(changed_paths, path, keylen, change);
-            }
-        }
-    }
+  SVN_ERR(get_relevant_changes(&changed_paths, &paths, root,
+                               base_repos_relpath,
+                               authz_read_func, authz_read_baton,
+                               scratch_pool, scratch_pool));
 
   /* If we were not given a low water mark, assume that everything is there,
      all the way back to revision 0. */

Modified: subversion/branches/ra-git/subversion/libsvn_repos/reporter.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_repos/reporter.c?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_repos/reporter.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_repos/reporter.c Tue Oct 11 
09:11:50 2016
@@ -522,19 +522,13 @@ delta_proplists(report_baton_t *b, svn_r
 {
   svn_fs_root_t *s_root;
   apr_hash_t *s_props = NULL, *t_props;
-  apr_array_header_t *prop_diffs;
-  int i;
   svn_revnum_t crev;
-  revision_info_t *revision_info;
-  svn_boolean_t changed;
-  const svn_prop_t *pc;
-  svn_lock_t *lock;
-  apr_hash_index_t *hi;
 
   /* Fetch the created-rev and send entry props. */
   SVN_ERR(svn_fs_node_created_rev(&crev, b->t_root, t_path, pool));
   if (SVN_IS_VALID_REVNUM(crev))
     {
+      revision_info_t *revision_info;
       /* convert committed-rev to  string */
       char buf[SVN_INT64_BUFFER_SIZE];
       svn_string_t cr_str;
@@ -565,6 +559,7 @@ delta_proplists(report_baton_t *b, svn_r
   /* Update lock properties. */
   if (lock_token)
     {
+      svn_lock_t *lock;
       SVN_ERR(svn_fs_get_lock(&lock, b->repos->fs, t_path, pool));
 
       /* Delete a defunct lock. */
@@ -575,6 +570,7 @@ delta_proplists(report_baton_t *b, svn_r
 
   if (s_path)
     {
+      svn_boolean_t changed;
       SVN_ERR(get_source_root(b, &s_root, s_rev));
 
       /* Is this deltification worth our time? */
@@ -592,16 +588,20 @@ delta_proplists(report_baton_t *b, svn_r
 
   if (s_props && apr_hash_count(s_props))
     {
+      apr_array_header_t *prop_diffs;
+      int i;
+
       /* Now transmit the differences. */
       SVN_ERR(svn_prop_diffs(&prop_diffs, t_props, s_props, pool));
       for (i = 0; i < prop_diffs->nelts; i++)
         {
-          pc = &APR_ARRAY_IDX(prop_diffs, i, svn_prop_t);
+          const svn_prop_t *pc = &APR_ARRAY_IDX(prop_diffs, i, svn_prop_t);
           SVN_ERR(change_fn(b, object, pc->name, pc->value, pool));
         }
     }
   else if (apr_hash_count(t_props))
     {
+      apr_hash_index_t *hi;
       /* So source, i.e. all new.  Transmit all target props. */
       for (hi = apr_hash_first(pool, t_props); hi; hi = apr_hash_next(hi))
         {
@@ -671,7 +671,6 @@ delta_files(report_baton_t *b, void *fil
             const char *s_path, const char *t_path, const char *lock_token,
             apr_pool_t *pool)
 {
-  svn_boolean_t changed;
   svn_fs_root_t *s_root = NULL;
   svn_txdelta_stream_t *dstream = NULL;
   svn_checksum_t *s_checksum;
@@ -685,14 +684,15 @@ delta_files(report_baton_t *b, void *fil
 
   if (s_path)
     {
+      svn_boolean_t changed;
       SVN_ERR(get_source_root(b, &s_root, s_rev));
 
       /* We're not interested in the theoretical difference between "has
          contents which have not changed with respect to" and "has the same
          actual contents as" when sending text-deltas.  If we know the
          delta is an empty one, we avoiding sending it in either case. */
-      SVN_ERR(svn_repos__compare_files(&changed, b->t_root, t_path,
-                                       s_root, s_path, pool));
+      SVN_ERR(svn_fs_contents_different(&changed, b->t_root, t_path,
+                                        s_root, s_path, pool));
 
       if (!changed)
         return SVN_NO_ERROR;
@@ -918,7 +918,7 @@ update_entry(report_baton_t *b, svn_revn
              const char *e_path, path_info_t *info, svn_depth_t wc_depth,
              svn_depth_t requested_depth, apr_pool_t *pool)
 {
-  svn_fs_root_t *s_root;
+  svn_fs_root_t *s_root = NULL;
   svn_boolean_t allowed, related;
   void *new_baton;
   svn_checksum_t *checksum;
@@ -961,7 +961,26 @@ update_entry(report_baton_t *b, svn_revn
   if (s_entry && t_entry && s_entry->kind == t_entry->kind)
     {
       int distance = svn_fs_compare_ids(s_entry->id, t_entry->id);
-      if (distance == 0 && !any_path_info(b, e_path)
+      svn_boolean_t changed = TRUE;
+
+      /* Check related files for content changes to avoid reporting
+       * unchanged copies of files to the client as an open_file() call
+       * and change_file_prop()/apply_textdelta() calls with no-op changes.
+       * The client will otherwise raise unnecessary tree conflicts. */
+      if (!b->ignore_ancestry && t_entry->kind == svn_node_file &&
+          distance == 1)
+        {
+          if (s_root == NULL)
+            SVN_ERR(get_source_root(b, &s_root, s_rev));
+
+          SVN_ERR(svn_fs_props_different(&changed, s_root, s_path,
+                                         b->t_root, t_path, pool));
+          if (!changed)
+            SVN_ERR(svn_fs_contents_different(&changed, s_root, s_path,
+                                              b->t_root, t_path, pool));
+        }
+
+      if ((distance == 0 || !changed) && !any_path_info(b, e_path)
           && (requested_depth <= wc_depth || t_entry->kind == svn_node_file))
         {
           if (!info)

Modified: subversion/branches/ra-git/subversion/libsvn_repos/repos.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_repos/repos.c?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_repos/repos.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_repos/repos.c Tue Oct 11 
09:11:50 2016
@@ -712,7 +712,7 @@ create_hooks(svn_repos_t *repos, apr_poo
 "# Because the locks have already been created and cannot be undone,"        NL
 "# the exit code of the hook program is ignored.  The hook program"          NL
 "# can use the 'svnlook' utility to examine the paths in the repository"     NL
-"# but since the hook is invoked asyncronously the newly-created locks"      NL
+"# but since the hook is invoked asynchronously the newly-created locks"     NL
 "# may no longer be present."                                                
NL;
   script =
 "REPOS=\"$1\""                                                               NL
@@ -848,11 +848,16 @@ create_conf(svn_repos_t *repos, apr_pool
 "### 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
-"### The groups-db option controls the location of the groups file."         NL
-"### Unless you specify a path starting with a /, the file's location is"    NL
-"### relative to the directory containing this file.  The specified path"    NL
-"### may be a repository relative URL (^/) or an absolute file:// URL to a"  NL
-"### text file in a Subversion repository."                                  NL
+"### The groups-db option controls the location of the file with the"        NL
+"### group definitions and allows maintaining groups separately from the"    NL
+"### authorization rules.  The groups-db file is of the same format as the"  NL
+"### authz-db file and should contain a single [groups] section with the"    NL
+"### group definitions.  If the option is enabled, the authz-db file cannot" NL
+"### contain a [groups] section.  Unless you specify a path starting with"   NL
+"### a /, the file's location is relative to the directory containing this"  NL
+"### file.  The specified path may be a repository relative URL (^/) or an"  NL
+"### absolute file:// URL to a text file in a Subversion repository."        NL
+"### This option is not being used by default."                              NL
 "# groups-db = " SVN_REPOS__CONF_GROUPS                                      NL
 "### This option specifies the authentication realm of the repository."      NL
 "### If two repositories have the same authentication realm, they should"    NL

Modified: subversion/branches/ra-git/subversion/libsvn_repos/repos.h
URL: 
http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_repos/repos.h?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_repos/repos.h (original)
+++ subversion/branches/ra-git/subversion/libsvn_repos/repos.h Tue Oct 11 
09:11:50 2016
@@ -390,17 +390,6 @@ svn_repos__authz_validate(svn_authz_t *a
 
 /*** Utility Functions ***/
 
-/* Set *CHANGED_P to TRUE if ROOT1/PATH1 and ROOT2/PATH2 have
-   different contents, FALSE if they have the same contents.
-   Use POOL for temporary allocation. */
-svn_error_t *
-svn_repos__compare_files(svn_boolean_t *changed_p,
-                         svn_fs_root_t *root1,
-                         const char *path1,
-                         svn_fs_root_t *root2,
-                         const char *path2,
-                         apr_pool_t *pool);
-
 /* Set *PREV_PATH and *PREV_REV to the path and revision which
    represent the location at which PATH in FS was located immediately
    prior to REVISION iff there was a copy operation (to PATH or one of

Modified: subversion/branches/ra-git/subversion/libsvn_repos/rev_hunt.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_repos/rev_hunt.c?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_repos/rev_hunt.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_repos/rev_hunt.c Tue Oct 11 
09:11:50 2016
@@ -1012,26 +1012,39 @@ get_merged_mergeinfo(apr_hash_t **merged
   apr_hash_t *curr_mergeinfo, *prev_mergeinfo, *deleted, *changed;
   svn_error_t *err;
   svn_fs_root_t *root, *prev_root;
-  apr_hash_t *changed_paths;
-  const char *path = old_path_rev->path;
+  const char *start_path = old_path_rev->path;
+  const char *path = NULL;
+
+  svn_fs_path_change_iterator_t *iterator;
+  svn_fs_path_change3_t *change;
 
   /* Getting/parsing/diffing svn:mergeinfo is expensive, so only do it
      if there is a property change. */
   SVN_ERR(svn_fs_revision_root(&root, repos->fs, old_path_rev->revnum,
                                scratch_pool));
-  SVN_ERR(svn_fs_paths_changed2(&changed_paths, root, scratch_pool));
-  while (1)
+  SVN_ERR(svn_fs_paths_changed3(&iterator, root, scratch_pool, scratch_pool));
+  SVN_ERR(svn_fs_path_change_get(&change, iterator));
+
+  /* Find the changed PATH closest to START_PATH which may have a mergeinfo
+   * change. */
+  while (change)
     {
-      svn_fs_path_change2_t *changed_path = svn_hash_gets(changed_paths, path);
-      if (changed_path && changed_path->prop_mod
-          && changed_path->mergeinfo_mod != svn_tristate_false)
-        break;
-      if (svn_fspath__is_root(path, strlen(path)))
+      if (   change->prop_mod
+          && change->mergeinfo_mod != svn_tristate_false
+          && svn_fspath__skip_ancestor(change->path.data, start_path))
         {
-          *merged_mergeinfo = NULL;
-          return SVN_NO_ERROR;
+          if (!path || svn_fspath__skip_ancestor(path, change->path.data))
+            path = apr_pstrmemdup(scratch_pool, change->path.data,
+                                  change->path.len);
         }
-      path = svn_fspath__dirname(path, scratch_pool);
+
+      SVN_ERR(svn_fs_path_change_get(&change, iterator));
+    }
+
+  if (path == NULL)
+    {
+      *merged_mergeinfo = NULL;
+      return SVN_NO_ERROR;
     }
 
   /* First, find the mergeinfo difference for old_path_rev->revnum, and

Modified: subversion/branches/ra-git/subversion/libsvn_subr/cache-membuffer.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_subr/cache-membuffer.c?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_subr/cache-membuffer.c 
(original)
+++ subversion/branches/ra-git/subversion/libsvn_subr/cache-membuffer.c Tue Oct 
11 09:11:50 2016
@@ -147,6 +147,10 @@
 #endif
 
 /* For more efficient copy operations, let's align all data items properly.
+ * Since we can't portably align pointers, this is rather the item size
+ * granularity which ensures *relative* alignment within the cache - still
+ * giving us decent copy speeds on most machines.
+ *
  * Must be a power of 2.
  */
 #define ITEM_ALIGNMENT 16
@@ -354,7 +358,7 @@ prefix_pool_get_internal(apr_uint32_t *p
 
   bytes_needed = prefix_len + 1 + OVERHEAD;
   assert(prefix_pool->bytes_max >= prefix_pool->bytes_used);
-  if (prefix_pool->bytes_max - prefix_pool->bytes_used > bytes_needed)
+  if (prefix_pool->bytes_max - prefix_pool->bytes_used < bytes_needed)
     {
       *prefix_idx = NO_INDEX;
       return SVN_NO_ERROR;
@@ -814,10 +818,6 @@ struct svn_membuffer_t
  */
 #define ALIGN_VALUE(value) (((value) + ITEM_ALIGNMENT-1) & -ITEM_ALIGNMENT)
 
-/* Align POINTER value to the next ITEM_ALIGNMENT boundary.
- */
-#define ALIGN_POINTER(pointer) 
((void*)ALIGN_VALUE((apr_size_t)(char*)(pointer)))
-
 /* If locking is supported for CACHE, acquire a read lock for it.
  */
 static svn_error_t *
@@ -1827,28 +1827,6 @@ ensure_data_insertable_l1(svn_membuffer_
    * right answer. */
 }
 
-/* Mimic apr_pcalloc in APR_POOL_DEBUG mode, i.e. handle failed allocations
- * (e.g. OOM) properly: Allocate at least SIZE bytes from POOL and zero
- * the content of the allocated memory if ZERO has been set. Return NULL
- * upon failed allocations.
- *
- * Also, satisfy our buffer alignment needs for performance reasons.
- */
-static void* secure_aligned_alloc(apr_pool_t *pool,
-                                  apr_size_t size,
-                                  svn_boolean_t zero)
-{
-  void* memory = apr_palloc(pool, size + ITEM_ALIGNMENT);
-  if (memory != NULL)
-    {
-      memory = ALIGN_POINTER(memory);
-      if (zero)
-        memset(memory, 0, size);
-    }
-
-  return memory;
-}
-
 svn_error_t *
 svn_cache__membuffer_cache_create(svn_membuffer_t **cache,
                                   apr_size_t total_size,
@@ -2017,10 +1995,11 @@ svn_cache__membuffer_cache_create(svn_me
       c[seg].l2.last = NO_INDEX;
       c[seg].l2.next = NO_INDEX;
       c[seg].l2.start_offset = c[seg].l1.size;
-      c[seg].l2.size = data_size - c[seg].l1.size;
+      c[seg].l2.size = ALIGN_VALUE(data_size) - c[seg].l1.size;
       c[seg].l2.current_data = c[seg].l2.start_offset;
 
-      c[seg].data = secure_aligned_alloc(pool, (apr_size_t)data_size, FALSE);
+      /* This cast is safe because DATA_SIZE <= MAX_SEGMENT_SIZE. */
+      c[seg].data = apr_palloc(pool, (apr_size_t)ALIGN_VALUE(data_size));
       c[seg].data_used = 0;
       c[seg].max_entry_size = max_entry_size;
 
@@ -2219,18 +2198,13 @@ membuffer_cache_set_internal(svn_membuff
   /* first, look for a previous entry for the given key */
   entry_t *entry = find_entry(cache, group_index, to_find, FALSE);
 
-  /* Quick size check to make sure arithmetics will work further down
-   * the road. */
-  if (   cache->max_entry_size >= item_size
-      && cache->max_entry_size - item_size >= to_find->entry_key.key_len)
-    {
-      size = item_size + to_find->entry_key.key_len;
-    }
-  else
-    {
-      /* The combination of serialized ITEM and KEY does not fit, so the
-       * the insertion attempt will fail and simply remove any old entry
-       * if that exists. */
+  /* Quick check make sure arithmetics will work further down the road. */
+  size = item_size + to_find->entry_key.key_len;
+  if (size < item_size)
+    {
+      /* Arithmetic overflow, so combination of serialized ITEM and KEY
+       * cannot not fit into the cache.  Setting BUFFER to NULL will cause
+       * the removal of any entry if that exists without writing new data. */
       buffer = NULL;
     }
 
@@ -2414,7 +2388,7 @@ membuffer_cache_get_internal(svn_membuff
     }
 
   size = ALIGN_VALUE(entry->size) - entry->key.key_len;
-  *buffer = ALIGN_POINTER(apr_palloc(result_pool, size + ITEM_ALIGNMENT-1));
+  *buffer = apr_palloc(result_pool, size);
   memcpy(*buffer, cache->data + entry->offset + entry->key.key_len, size);
 
 #ifdef SVN_DEBUG_CACHE_MEMBUFFER

Modified: subversion/branches/ra-git/subversion/libsvn_subr/checksum.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_subr/checksum.c?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_subr/checksum.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_subr/checksum.c Tue Oct 11 
09:11:50 2016
@@ -86,6 +86,7 @@ static const char *ckind_str[] = {
   "$sha1$",
   "$fnv1$",
   "$fnvm$",
+  /* ### svn_checksum_deserialize() assumes all these have the same strlen() */
 };
 
 /* Returns the digest size of it's argument. */

Modified: subversion/branches/ra-git/subversion/libsvn_subr/cmdline.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_subr/cmdline.c?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_subr/cmdline.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_subr/cmdline.c Tue Oct 11 
09:11:50 2016
@@ -42,6 +42,7 @@
 #include <apr_general.h>        /* for apr_initialize/apr_terminate */
 #include <apr_strings.h>        /* for apr_snprintf */
 #include <apr_pools.h>
+#include <apr_signal.h>
 
 #include "svn_cmdline.h"
 #include "svn_ctype.h"
@@ -821,7 +822,7 @@ most_similar(const char *needle_cstr,
              apr_size_t haystack_len,
              apr_pool_t *scratch_pool)
 {
-  const char *max_similar;
+  const char *max_similar = NULL;
   apr_size_t max_score = 0;
   apr_size_t i;
   svn_membuf_t membuf;
@@ -846,10 +847,7 @@ most_similar(const char *needle_cstr,
         }
     }
 
-  if (max_score)
-    return max_similar;
-  else
-    return NULL;
+  return max_similar;
 }
 
 /* Verify that NEEDLE is in HAYSTACK, which contains HAYSTACK_LEN elements. */
@@ -1209,11 +1207,7 @@ svn_cmdline__be_interactive(svn_boolean_
    * 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
+      return svn_cmdline__stdin_is_a_terminal();
     }
   else if (force_interactive)
     return TRUE;
@@ -1606,3 +1600,99 @@ svn_cmdline__parse_trust_options(
 
   return SVN_NO_ERROR;
 }
+
+/* Flags to see if we've been cancelled by the client or not. */
+static volatile sig_atomic_t cancelled = FALSE;
+static volatile sig_atomic_t signum_cancelled = 0;
+
+/* The signals we handle. */
+static int signal_map [] = {
+  SIGINT
+#ifdef SIGBREAK
+  /* SIGBREAK is a Win32 specific signal generated by ctrl-break. */
+  , SIGBREAK
+#endif
+#ifdef SIGHUP
+  , SIGHUP
+#endif
+#ifdef SIGTERM
+  , SIGTERM
+#endif
+};
+
+/* A signal handler to support cancellation. */
+static void
+signal_handler(int signum)
+{
+  int i;
+
+  apr_signal(signum, SIG_IGN);
+  cancelled = TRUE;
+  for (i = 0; i < sizeof(signal_map)/sizeof(signal_map[0]); ++i)
+    if (signal_map[i] == signum)
+      {
+        signum_cancelled = i + 1;
+        break;
+      }
+}
+
+/* An svn_cancel_func_t callback. */
+static svn_error_t *
+check_cancel(void *baton)
+{
+  /* Cancel baton should be always NULL in command line client. */
+  SVN_ERR_ASSERT(baton == NULL);
+  if (cancelled)
+    return svn_error_create(SVN_ERR_CANCELLED, NULL, _("Caught signal"));
+  else
+    return SVN_NO_ERROR;
+}
+
+svn_cancel_func_t
+svn_cmdline__setup_cancellation_handler(void)
+{
+  int i;
+
+  for (i = 0; i < sizeof(signal_map)/sizeof(signal_map[0]); ++i)
+    apr_signal(signal_map[i], signal_handler);
+
+#ifdef SIGPIPE
+  /* Disable SIGPIPE generation for the platforms that have it. */
+  apr_signal(SIGPIPE, SIG_IGN);
+#endif
+
+#ifdef SIGXFSZ
+  /* Disable SIGXFSZ generation for the platforms that have it, otherwise
+   * working with large files when compiled against an APR that doesn't have
+   * large file support will crash the program, which is uncool. */
+  apr_signal(SIGXFSZ, SIG_IGN);
+#endif
+
+  return check_cancel;
+}
+
+void
+svn_cmdline__disable_cancellation_handler(void)
+{
+  int i;
+
+  for (i = 0; i < sizeof(signal_map)/sizeof(signal_map[0]); ++i)
+    apr_signal(signal_map[i], SIG_DFL);
+}
+
+void
+svn_cmdline__cancellation_exit(void)
+{
+  int signum = 0;
+
+  if (cancelled && signum_cancelled)
+    signum = signal_map[signum_cancelled - 1];
+  if (signum)
+    {
+#ifndef WIN32
+      apr_signal(signum, SIG_DFL);
+      /* No APR support for getpid() so cannot use apr_proc_kill(). */
+      kill(getpid(), signum);
+#endif
+    }
+}

Modified: subversion/branches/ra-git/subversion/libsvn_subr/deprecated.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_subr/deprecated.c?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_subr/deprecated.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_subr/deprecated.c Tue Oct 11 
09:11:50 2016
@@ -1521,7 +1521,11 @@ void
 svn_auth_get_keychain_simple_provider(svn_auth_provider_object_t **provider,
                                       apr_pool_t *pool)
 {
+#ifdef SVN_HAVE_KEYCHAIN_SERVICES
   svn_auth__get_keychain_simple_provider(provider, pool);
+#else
+  svn_auth__get_dummmy_simple_provider(provider, pool);
+#endif
 }
 
 void
@@ -1529,7 +1533,13 @@ svn_auth_get_keychain_ssl_client_cert_pw
   (svn_auth_provider_object_t **provider,
    apr_pool_t *pool)
 {
+#ifdef SVN_HAVE_KEYCHAIN_SERVICES
   svn_auth__get_keychain_ssl_client_cert_pw_provider(provider, pool);
+#else
+  /* Not really the right type of dummy provider, but doesn't throw NULL
+     errors as just returning NULL would */
+  svn_auth__get_dummmy_simple_provider(provider, pool);
+#endif
 }
 #endif /* DARWIN */
 

Modified: subversion/branches/ra-git/subversion/libsvn_subr/eol.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_subr/eol.c?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_subr/eol.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_subr/eol.c Tue Oct 11 09:11:50 
2016
@@ -33,43 +33,32 @@
 char *
 svn_eol__find_eol_start(char *buf, apr_size_t len)
 {
-#if !SVN_UNALIGNED_ACCESS_IS_OK
-
-  /* On some systems, we need to make sure that BUF is properly aligned
-   * for chunky data access. This overhead is still justified because
-   * only lines tend to be tens of chars long.
-   */
-  for (; (len > 0) && ((apr_uintptr_t)buf) & (sizeof(apr_uintptr_t)-1)
-       ; ++buf, --len)
-  {
-    if (*buf == '\n' || *buf == '\r')
-      return buf;
-  }
-
-#endif
+#if SVN_UNALIGNED_ACCESS_IS_OK
 
   /* Scan the input one machine word at a time. */
   for (; len > sizeof(apr_uintptr_t)
        ; buf += sizeof(apr_uintptr_t), len -= sizeof(apr_uintptr_t))
-  {
-    /* This is a variant of the well-known strlen test: */
-    apr_uintptr_t chunk = *(const apr_uintptr_t *)buf;
-
-    /* A byte in SVN__R_TEST is \0, iff it was \r in *BUF.
-     * Similarly, SVN__N_TEST is an indicator for \n. */
-    apr_uintptr_t r_test = chunk ^ SVN__R_MASK;
-    apr_uintptr_t n_test = chunk ^ SVN__N_MASK;
-
-    /* A byte in SVN__R_TEST can only be < 0x80, iff it has been \0 before
-     * (i.e. \r in *BUF). Ditto for SVN__N_TEST. */
-    r_test |= (r_test & SVN__LOWER_7BITS_SET) + SVN__LOWER_7BITS_SET;
-    n_test |= (n_test & SVN__LOWER_7BITS_SET) + SVN__LOWER_7BITS_SET;
-
-    /* Check whether at least one of the words contains a byte <0x80
-     * (if one is detected, there was a \r or \n in CHUNK). */
-    if ((r_test & n_test & SVN__BIT_7_SET) != SVN__BIT_7_SET)
-      break;
-  }
+    {
+      /* This is a variant of the well-known strlen test: */
+      apr_uintptr_t chunk = *(const apr_uintptr_t *)buf;
+
+      /* A byte in SVN__R_TEST is \0, iff it was \r in *BUF.
+       * Similarly, SVN__N_TEST is an indicator for \n. */
+      apr_uintptr_t r_test = chunk ^ SVN__R_MASK;
+      apr_uintptr_t n_test = chunk ^ SVN__N_MASK;
+
+      /* A byte in SVN__R_TEST can only be < 0x80, iff it has been \0 before
+       * (i.e. \r in *BUF). Ditto for SVN__N_TEST. */
+      r_test |= (r_test & SVN__LOWER_7BITS_SET) + SVN__LOWER_7BITS_SET;
+      n_test |= (n_test & SVN__LOWER_7BITS_SET) + SVN__LOWER_7BITS_SET;
+
+      /* Check whether at least one of the words contains a byte <0x80
+       * (if one is detected, there was a \r or \n in CHUNK). */
+      if ((r_test & n_test & SVN__BIT_7_SET) != SVN__BIT_7_SET)
+        break;
+    }
+
+#endif
 
   /* The remaining odd bytes will be examined the naive way: */
   for (; len > 0; ++buf, --len)

Modified: subversion/branches/ra-git/subversion/libsvn_subr/gpg_agent.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_subr/gpg_agent.c?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_subr/gpg_agent.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_subr/gpg_agent.c Tue Oct 11 
09:11:50 2016
@@ -103,6 +103,40 @@ escape_blanks(char *str)
   return str;
 }
 
+#define is_hex(c) (((c) >= '0' && (c) <= '9') || ((c) >= 'A' && (c) <= 'F'))
+#define hex_to_int(c) ((c) < '9' ? (c) - '0' : (c) - 'A' + 10)
+ 
+/* Modify STR in-place.  '%', CR and LF are always percent escaped,
+   other characters may be percent escaped, always using uppercase
+   hex, see https://www.gnupg.org/documentation/manuals/assuan.pdf */
+static char *
+unescape_assuan(char *str)
+{
+  char *s = str;
+
+  while (s[0])
+    {
+      if (s[0] == '%' && is_hex(s[1]) && is_hex(s[2]))
+        {
+          char *s2 = s;
+          char val = hex_to_int(s[1]) * 16 + hex_to_int(s[2]);
+
+          s2[0] = val;
+          ++s2;
+
+          while (s2[2])
+            {
+              s2[0] = s2[2];
+              ++s2;
+            }
+          s2[0] = '\0';
+        }
+      ++s;
+    }
+
+  return str;
+}
+
 /* Generate the string CACHE_ID_P based on the REALMSTRING allocated in
  * RESULT_POOL using SCRATCH_POOL for temporary allocations.  This is similar
  * to other password caching mechanisms. */
@@ -378,7 +412,7 @@ password_get_gpg_agent(svn_boolean_t *do
                        apr_pool_t *pool)
 {
   int sd;
-  const char *p = NULL;
+  char *p = NULL;
   char *ep = NULL;
   char *buffer;
   const char *request = NULL;
@@ -451,7 +485,7 @@ password_get_gpg_agent(svn_boolean_t *do
   if (ep != NULL)
     *ep = '\0';
 
-  *password = p;
+  *password = unescape_assuan(p);
 
   *done = TRUE;
   return SVN_NO_ERROR;

Modified: subversion/branches/ra-git/subversion/libsvn_subr/io.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_subr/io.c?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_subr/io.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_subr/io.c Tue Oct 11 09:11:50 
2016
@@ -1478,18 +1478,14 @@ svn_io_file_checksum2(svn_checksum_t **c
                       apr_pool_t *pool)
 {
   svn_stream_t *file_stream;
-  svn_stream_t *checksum_stream;
   apr_file_t* f;
 
   SVN_ERR(svn_io_file_open(&f, file, APR_READ, APR_OS_DEFAULT, pool));
   file_stream = svn_stream_from_aprfile2(f, FALSE, pool);
-  checksum_stream = svn_stream_checksummed2(file_stream, checksum, NULL, kind,
-                                            TRUE, pool);
+  SVN_ERR(svn_stream_contents_checksum(checksum, file_stream, kind,
+                                       pool, pool));
 
-  /* Because the checksummed stream will force the reading (and
-     checksumming) of all the file's bytes, we can just close the stream
-     and let its magic work. */
-  return svn_stream_close(checksum_stream);
+  return SVN_NO_ERROR;
 }
 
 
@@ -1568,8 +1564,14 @@ get_default_file_perms(apr_fileperms_t *
 
         Using svn_io_open_uniquely_named() here because other tempfile
         creation functions tweak the permission bits of files they create.
+
+        Note that APR pool structures are allocated as the first item
+        in their first memory page (with e.g. 4kB granularity), i.e. the
+        lower bits tend to be identical between pool instances.  That is
+        particularly true for the MMAPed allocator.
       */
       randomish = ((apr_uint32_t)(apr_uintptr_t)scratch_pool
+                   + (apr_uint32_t)((apr_uintptr_t)scratch_pool / 4096)
                    + (apr_uint32_t)apr_time_now());
       fname_base = apr_psprintf(scratch_pool, "svn-%08x", randomish);
 
@@ -1888,7 +1890,7 @@ io_win_file_attrs_set(const char *fname,
 
 static svn_error_t *win_init_dynamic_imports(void *baton, apr_pool_t *pool)
 {
-  HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
+  HMODULE kernel32 = GetModuleHandleW(L"kernel32.dll");
 
   if (kernel32)
     {
@@ -2649,9 +2651,6 @@ svn_io_remove_file2(const char *path,
          allow us to delete when path is read-only */
       SVN_ERR(svn_io_set_file_read_write(path, ignore_enoent, scratch_pool));
       apr_err = apr_file_remove(path_apr, scratch_pool);
-
-      if (!apr_err)
-        return SVN_NO_ERROR;
     }
 
   /* Check to make sure we aren't trying to delete a directory */
@@ -4065,6 +4064,26 @@ svn_io_write_atomic2(const char *final_p
 svn_error_t *
 svn_io_file_trunc(apr_file_t *file, apr_off_t offset, apr_pool_t *pool)
 {
+  /* Workaround for yet another APR issue with trunc.
+
+     If the APR file internally is in read mode, the current buffer pointer
+     will not be clipped to the valid data range. get_file_offset may then
+     return an invalid position *after* new data was written to it.
+
+     To prevent this, write 1 dummy byte just after the OFFSET at which we
+     will trunc it.  That will force the APR file into write mode
+     internally and the flush() work-around below becomes affective. */
+  apr_off_t position = 0;
+
+  /* A frequent usage is OFFSET==0, in which case we don't need to preserve
+     any file content or file pointer. */
+  if (offset)
+    {
+      SVN_ERR(svn_io_file_seek(file, APR_CUR, &position, pool));
+      SVN_ERR(svn_io_file_seek(file, APR_SET, &offset, pool));
+    }
+  SVN_ERR(svn_io_file_putc(0, file, pool));
+
   /* This is a work-around. APR would flush the write buffer
      _after_ truncating the file causing now invalid buffered
      data to be written behind OFFSET. */
@@ -4073,10 +4092,17 @@ svn_io_file_trunc(apr_file_t *file, apr_
                                      N_("Can't flush stream"),
                                      pool));
 
-  return do_io_file_wrapper_cleanup(file, apr_file_trunc(file, offset),
-                                    N_("Can't truncate file '%s'"),
-                                    N_("Can't truncate stream"),
-                                    pool);
+  SVN_ERR(do_io_file_wrapper_cleanup(file, apr_file_trunc(file, offset),
+                                     N_("Can't truncate file '%s'"),
+                                     N_("Can't truncate stream"),
+                                     pool));
+
+  /* Restore original file pointer, if necessary.
+     It's currently at OFFSET. */
+  if (position < offset)
+    SVN_ERR(svn_io_file_seek(file, APR_SET, &position, pool));
+
+  return SVN_NO_ERROR;
 }
 
 

Modified: subversion/branches/ra-git/subversion/libsvn_subr/packed_data.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_subr/packed_data.c?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_subr/packed_data.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_subr/packed_data.c Tue Oct 11 
09:11:50 2016
@@ -676,6 +676,12 @@ svn_packed__byte_count(svn_packed__byte_
   return stream->packed->len;
 }
 
+apr_size_t
+svn_packed__byte_block_count(svn_packed__byte_stream_t *stream)
+{
+  return svn_packed__int_count(stream->lengths_stream);
+}
+
 /* Read one 7b/8b encoded value from *P and return it in *RESULT.  Returns
  * the first position after the parsed data.
  *

Modified: subversion/branches/ra-git/subversion/libsvn_subr/path.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_subr/path.c?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_subr/path.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_subr/path.c Tue Oct 11 
09:11:50 2016
@@ -506,7 +506,7 @@ get_path_ancestor_length(const char *pat
   else
     if (last_dirsep == 0 && path1[0] == '/' && path2[0] == '/')
       return 1;
-    return last_dirsep;
+  return last_dirsep;
 }
 
 

Modified: subversion/branches/ra-git/subversion/libsvn_subr/pool.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_subr/pool.c?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_subr/pool.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_subr/pool.c Tue Oct 11 
09:11:50 2016
@@ -54,6 +54,13 @@ abort_on_pool_failure(int retcode)
   /* Don't translate this string! It requires memory allocation to do so!
      And we don't have any of it... */
   printf("libsvn: Out of memory - terminating application.\n");
+
+#ifdef WIN32
+  /* Provide a way to distinguish the out-of-memory error from abort(). */
+  if (retcode == APR_ENOMEM)
+    RaiseException(STATUS_NO_MEMORY, EXCEPTION_NONCONTINUABLE, 0, NULL);
+#endif
+
   abort();
   return 0; /* not reached */
 }

Modified: subversion/branches/ra-git/subversion/libsvn_subr/prefix_string.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_subr/prefix_string.c?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_subr/prefix_string.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_subr/prefix_string.c Tue Oct 
11 09:11:50 2016
@@ -49,7 +49,12 @@ struct svn_prefix_string__t
   /* mandatory prefix */
   node_t *prefix;
 
-  /* 0 ..7 chars to add the the prefix. NUL-terminated. */
+  /* 0 ..7 chars to add the the prefix.
+   *
+   * NUL-terminated, if this is indeed a tree leaf.  We use the same struct
+   * within node_t for inner tree nodes, too.  There, DATA[7] is not NUL,
+   * meaning DATA may or may not be NUL terminated.  The actual length is
+   * provided by the node_t.length field (minus parent node length). */
   char data[8];
 };
 
@@ -94,6 +99,12 @@ struct svn_prefix_tree__t
 static svn_boolean_t
 is_leaf(node_t *node)
 {
+  /* If this NOT a leaf node and this node has ...
+   *    ... 8 chars, data[7] will not be NUL because we only support
+   *        NUL-*terminated* strings.
+   *    ... less than 8 chars, this will be set to 0xff
+   *        (any other non-NUL would do as well but this is not valid UTF8
+   *         making it easy to recognize during debugging etc.) */
   return node->key.data[7] == 0;
 }
 
@@ -154,7 +165,7 @@ svn_prefix_tree__create(apr_pool_t *pool
   tree->pool = pool;
 
   tree->root = apr_pcalloc(pool, sizeof(*tree->root));
-  tree->root->key.data[7] = '\xff';
+  tree->root->key.data[7] = '\xff'; /* This is not a leaf. See is_leaf(). */
 
   return tree;
 }
@@ -188,6 +199,7 @@ svn_prefix_string__create(svn_prefix_tre
           || node->sub_nodes[idx]->key.data[0] != s[node->length])
         break;
 
+      /* Yes, it matches - at least the first character does. */
       sub_node = node->sub_nodes[idx];
 
       /* fully matching sub-node? */
@@ -198,6 +210,11 @@ svn_prefix_string__create(svn_prefix_tre
         }
       else
         {
+          /* The string formed by the path from the root down to
+           * SUB_NODE differs from S.
+           *
+           * Is it a prefix?  In that case, the chars added by SUB_NODE
+           * must fully match the respective chars in S. */
           apr_size_t sub_node_len = sub_node->length - node->length;
           if (strncmp(sub_node->key.data, s + node->length,
                       sub_node_len) == 0)
@@ -207,14 +224,24 @@ svn_prefix_string__create(svn_prefix_tre
             }
         }
 
-      /* partial match -> split */
+      /* partial match -> split
+       *
+       * At this point, S may either be a prefix to the string represented
+       * by SUB_NODE, or they may diverge at some offset with
+       * SUB_NODE->KEY.DATA .
+       *
+       * MATCH starts with 1 here b/c we already know that at least one
+       * char matches.  Also, the loop will terminate because the strings
+       * differ before SUB_NODE->KEY.DATA - either at the NUL terminator
+       * of S or some char before that.
+       */
       while (sub_node->key.data[match] == s[node->length + match])
         ++match;
 
       new_node = apr_pcalloc(tree->pool, sizeof(*new_node));
       new_node->key = sub_node->key;
       new_node->length = node->length + match;
-      new_node->key.data[7] = '\xff';
+      new_node->key.data[7] = '\xff';  /* This is not a leaf. See is_leaf(). */
       new_node->sub_node_count = 1;
       new_node->sub_nodes = apr_palloc(tree->pool, sizeof(node_t *));
       new_node->sub_nodes[0] = sub_node;

Modified: subversion/branches/ra-git/subversion/libsvn_subr/prompt.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_subr/prompt.c?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_subr/prompt.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_subr/prompt.c Tue Oct 11 
09:11:50 2016
@@ -814,6 +814,8 @@ plaintext_prompt_helper(svn_boolean_t *m
   const char *config_path = NULL;
   terminal_handle_t *terminal;
 
+  *may_save_plaintext = FALSE; /* de facto API promise */
+
   if (pb)
     SVN_ERR(svn_config_get_user_config_path(&config_path, pb->config_dir,
                                             SVN_CONFIG_CATEGORY_SERVERS, 
pool));
@@ -826,18 +828,7 @@ plaintext_prompt_helper(svn_boolean_t *m
 
   do
     {
-      svn_error_t *err = prompt(&answer, prompt_string, FALSE, pb, pool);
-      if (err)
-        {
-          if (err->apr_err == SVN_ERR_CANCELLED)
-            {
-              svn_error_clear(err);
-              *may_save_plaintext = FALSE;
-              return SVN_NO_ERROR;
-            }
-          else
-            return err;
-        }
+      SVN_ERR(prompt(&answer, prompt_string, FALSE, pb, pool));
       if (apr_strnatcasecmp(answer, _("yes")) == 0 ||
           apr_strnatcasecmp(answer, _("y")) == 0)
         {

Modified: subversion/branches/ra-git/subversion/libsvn_subr/sqlite.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_subr/sqlite.c?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_subr/sqlite.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_subr/sqlite.c Tue Oct 11 
09:11:50 2016
@@ -213,13 +213,6 @@ struct svn_sqlite__value_t
                              sqlite_err__temp, msg);             \
 } while (0)
 
-#define SVN_ERR_CLOSE(x, db) do                                       \
-{                                                                     \
-  svn_error_t *svn__err = (x);                                        \
-  if (svn__err)                                                       \
-    return svn_error_compose_create(svn__err, svn_sqlite__close(db)); \
-} while (0)
-
 
 /* Time (in milliseconds) to wait for sqlite locks before giving up. */
 #define BUSY_TIMEOUT 10000
@@ -1141,7 +1134,7 @@ svn_sqlite__open(svn_sqlite__db_t **db,
   sqlite3_profile((*db)->db3, sqlite_profiler, (*db)->db3);
 #endif
 
-  SVN_ERR_CLOSE(exec_sql(*db,
+  SVN_SQLITE__ERR_CLOSE(exec_sql(*db,
               /* The default behavior of the LIKE operator is to ignore case
                  for ASCII characters. Hence, by default 'a' LIKE 'A' is true.
                  The case_sensitive_like pragma installs a new application-
@@ -1180,8 +1173,8 @@ svn_sqlite__open(svn_sqlite__db_t **db,
   /* When running in debug mode, enable the checking of foreign key
      constraints.  This has possible performance implications, so we don't
      bother to do it for production...for now. */
-  SVN_ERR_CLOSE(exec_sql(*db, "PRAGMA foreign_keys=ON;"),
-                *db);
+  SVN_SQLITE__ERR_CLOSE(exec_sql(*db, "PRAGMA foreign_keys=ON;"),
+                        *db);
 #endif
 
 #ifdef SVN_SQLITE_REVERSE_UNORDERED_SELECTS
@@ -1189,8 +1182,8 @@ svn_sqlite__open(svn_sqlite__db_t **db,
      clause to emit their results in the reverse order of what they normally
      would.  This can help detecting invalid assumptions about the result
      order.*/
-  SVN_ERR_CLOSE(exec_sql(*db, "PRAGMA reverse_unordered_selects=ON;"),
-                *db);
+  SVN_SQLITE__ERR_CLOSE(exec_sql(*db, "PRAGMA reverse_unordered_selects=ON;"),
+                        *db);
 #endif
 
   /* Store temporary tables in RAM instead of in temporary files, but don't
@@ -1261,6 +1254,54 @@ reset_all_statements(svn_sqlite__db_t *d
   return err;
 }
 
+static svn_error_t *
+rollback_transaction(svn_sqlite__db_t *db,
+                     svn_error_t *error_to_wrap)
+{
+  svn_sqlite__stmt_t *stmt;
+  svn_error_t *err;
+
+  err = get_internal_statement(&stmt, db, STMT_INTERNAL_ROLLBACK_TRANSACTION);
+  if (!err)
+    {
+      err = svn_error_trace(svn_sqlite__step_done(stmt));
+
+      if (err && err->apr_err == SVN_ERR_SQLITE_BUSY)
+        {
+          /* ### Houston, we have a problem!
+
+             We are trying to rollback but we can't because some
+             statements are still busy. This leaves the database
+             unusable for future transactions as the current transaction
+             is still open.
+
+             As we are returning the actual error as the most relevant
+             error in the chain, our caller might assume that it can
+             retry/compensate on this error (e.g. SVN_WC_LOCKED), while
+             in fact the SQLite database is unusable until the statements
+             started within this transaction are reset and the transaction
+             aborted.
+
+             We try to compensate by resetting all prepared but unreset
+             statements; but we leave the busy error in the chain anyway to
+             help diagnosing the original error and help in finding where
+             a reset statement is missing. */
+          err = svn_error_trace(reset_all_statements(db, err));
+          err = svn_error_compose_create(
+                      svn_error_trace(svn_sqlite__step_done(stmt)),
+                      err);
+        }
+    }
+
+  if (err)
+    {
+      /* Rollback failed, use a specific error code. */
+      err = svn_error_create(SVN_ERR_SQLITE_ROLLBACK_FAILED, err, NULL);
+    }
+
+  return svn_error_compose_create(error_to_wrap, err);
+}
+
 svn_error_t *
 svn_sqlite__begin_transaction(svn_sqlite__db_t *db)
 {
@@ -1303,46 +1344,37 @@ svn_sqlite__finish_transaction(svn_sqlit
   /* Commit or rollback the sqlite transaction. */
   if (err)
     {
-      svn_error_t *err2;
-
-      err2 = get_internal_statement(&stmt, db,
-                                    STMT_INTERNAL_ROLLBACK_TRANSACTION);
-      if (!err2)
-        err2 = svn_error_trace(svn_sqlite__step_done(stmt));
-
-      if (err2 && err2->apr_err == SVN_ERR_SQLITE_BUSY)
-        {
-          /* ### Houston, we have a problem!
-
-             We are trying to rollback but we can't because some
-             statements are still busy. This leaves the database
-             unusable for future transactions as the current transaction
-             is still open.
-
-             As we are returning the actual error as the most relevant
-             error in the chain, our caller might assume that it can
-             retry/compensate on this error (e.g. SVN_WC_LOCKED), while
-             in fact the SQLite database is unusable until the statements
-             started within this transaction are reset and the transaction
-             aborted.
-
-             We try to compensate by resetting all prepared but unreset
-             statements; but we leave the busy error in the chain anyway to
-             help diagnosing the original error and help in finding where
-             a reset statement is missing. */
-
-          err2 = svn_error_trace(reset_all_statements(db, err2));
-          err2 = svn_error_compose_create(
-                      svn_error_trace(svn_sqlite__step_done(stmt)),
-                      err2);
-
-        }
-
-      return svn_error_compose_create(err, err2);
+      return svn_error_trace(rollback_transaction(db, err));
+    }
+  else
+    {
+      err = get_internal_statement(&stmt, db,
+                                   STMT_INTERNAL_COMMIT_TRANSACTION);
+      if (!err)
+        err = svn_error_trace(svn_sqlite__step_done(stmt));
+
+      /* Need to rollback if the commit fails as well, because otherwise the
+         db connection will be left in an unusable state.
+
+         One important case to keep in mind is trying to COMMIT with concurrent
+         readers. In case the commit fails, because someone else is holding a
+         shared lock, sqlite keeps the transaction, and *also* keeps the file
+         locks on the database. While the first part only prevents from using
+         this connection, the second part prevents everyone else from accessing
+         the database while the connection is open.
+
+         See https://www.sqlite.org/lang_transaction.html
+
+         COMMIT might also result in an SQLITE_BUSY return code if an another
+         thread or process has a shared lock on the database that prevented
+         the database from being updated. When COMMIT fails in this way, the
+         transaction remains active and the COMMIT can be retried later after
+         the reader has had a chance to clear. */
+      if (err)
+        return svn_error_trace(rollback_transaction(db, err));
     }
 
-  SVN_ERR(get_internal_statement(&stmt, db, STMT_INTERNAL_COMMIT_TRANSACTION));
-  return svn_error_trace(svn_sqlite__step_done(stmt));
+  return SVN_NO_ERROR;
 }
 
 svn_error_t *
@@ -1359,20 +1391,22 @@ svn_sqlite__finish_savepoint(svn_sqlite_
                                     STMT_INTERNAL_ROLLBACK_TO_SAVEPOINT_SVN);
 
       if (!err2)
-        err2 = svn_error_trace(svn_sqlite__step_done(stmt));
-
-      if (err2 && err2->apr_err == SVN_ERR_SQLITE_BUSY)
         {
-          /* Ok, we have a major problem. Some statement is still open, which
-             makes it impossible to release this savepoint.
+          err2 = svn_error_trace(svn_sqlite__step_done(stmt));
 
-             ### See huge comment in svn_sqlite__finish_transaction for
-                 further details */
+          if (err2 && err2->apr_err == SVN_ERR_SQLITE_BUSY)
+            {
+              /* Ok, we have a major problem. Some statement is still open,
+                 which makes it impossible to release this savepoint.
 
-          err2 = svn_error_trace(reset_all_statements(db, err2));
-          err2 = svn_error_compose_create(
-                      svn_error_trace(svn_sqlite__step_done(stmt)),
-                      err2);
+                 ### See huge comment in rollback_transaction() for
+                     further details */
+
+              err2 = svn_error_trace(reset_all_statements(db, err2));
+              err2 = svn_error_compose_create(
+                          svn_error_trace(svn_sqlite__step_done(stmt)),
+                          err2);
+            }
         }
 
       err = svn_error_compose_create(err, err2);
@@ -1388,6 +1422,8 @@ svn_sqlite__finish_savepoint(svn_sqlite_
   SVN_ERR(get_internal_statement(&stmt, db,
                                  STMT_INTERNAL_RELEASE_SAVEPOINT_SVN));
 
+  /* ### Releasing a savepoint can fail and leave the db connection
+         unusable; see svn_sqlite__finish_transaction(). */
   return svn_error_trace(svn_sqlite__step_done(stmt));
 }
 

Modified: subversion/branches/ra-git/subversion/libsvn_subr/stream.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_subr/stream.c?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_subr/stream.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_subr/stream.c Tue Oct 11 
09:11:50 2016
@@ -61,7 +61,7 @@ struct svn_stream_t {
   svn_stream_mark_fn_t mark_fn;
   svn_stream_seek_fn_t seek_fn;
   svn_stream_data_available_fn_t data_available_fn;
-  svn_stream__is_buffered_fn_t is_buffered_fn;
+  svn_stream_readline_fn_t readline_fn;
   apr_file_t *file; /* Maybe NULL */
 };
 
@@ -139,10 +139,10 @@ svn_stream_set_data_available(svn_stream
 }
 
 void
-svn_stream__set_is_buffered(svn_stream_t *stream,
-                            svn_stream__is_buffered_fn_t is_buffered_fn)
+svn_stream_set_readline(svn_stream_t *stream,
+                        svn_stream_readline_fn_t readline_fn)
 {
-  stream->is_buffered_fn = is_buffered_fn;
+  stream->readline_fn = readline_fn;
 }
 
 /* Standard implementation for svn_stream_read_full() based on
@@ -265,15 +265,6 @@ svn_stream_data_available(svn_stream_t *
                                                    data_available));
 }
 
-svn_boolean_t
-svn_stream__is_buffered(svn_stream_t *stream)
-{
-  if (stream->is_buffered_fn == NULL)
-    return FALSE;
-
-  return stream->is_buffered_fn(stream->baton);
-}
-
 svn_error_t *
 svn_stream_close(svn_stream_t *stream)
 {
@@ -328,11 +319,9 @@ svn_stream_printf_from_utf8(svn_stream_t
   return svn_error_trace(svn_stream_puts(stream, translated));
 }
 
-/* Guts of svn_stream_readline().
+/* Default implementation for svn_stream_readline().
  * Returns the line read from STREAM in *STRINGBUF, and indicates
- * end-of-file in *EOF.  If DETECT_EOL is TRUE, the end-of-line indicator
- * is detected automatically and returned in *EOL.
- * If DETECT_EOL is FALSE, *EOL must point to the desired end-of-line
+ * end-of-file in *EOF.  EOL must point to the desired end-of-line
  * indicator.  STRINGBUF is allocated in POOL. */
 static svn_error_t *
 stream_readline_bytewise(svn_stringbuf_t **stringbuf,
@@ -381,161 +370,27 @@ stream_readline_bytewise(svn_stringbuf_t
   return SVN_NO_ERROR;
 }
 
-static svn_error_t *
-stream_readline_chunky(svn_stringbuf_t **stringbuf,
-                       svn_boolean_t *eof,
-                       const char *eol,
-                       svn_stream_t *stream,
-                       apr_pool_t *pool)
+svn_error_t *
+svn_stream_readline(svn_stream_t *stream,
+                    svn_stringbuf_t **stringbuf,
+                    const char *eol,
+                    svn_boolean_t *eof,
+                    apr_pool_t *pool)
 {
-  /* Read larger chunks of data at once into this buffer and scan
-   * that for EOL. A good chunk size should be about 80 chars since
-   * most text lines will be shorter. However, don't use a much
-   * larger value because filling the buffer from the stream takes
-   * time as well.
-   */
-  char buffer[SVN__LINE_CHUNK_SIZE+1];
-
-  /* variables */
-  svn_stream_mark_t *mark;
-  apr_size_t numbytes;
-  const char *eol_pos;
-  apr_size_t total_parsed = 0;
-
-  /* invariant for this call */
-  const size_t eol_len = strlen(eol);
-
-  /* Remember the line start so this plus the line length will be
-   * the position to move to at the end of this function.
-   */
-  SVN_ERR(svn_stream_mark(stream, &mark, pool));
-
-  /* Read the first chunk. */
-  numbytes = SVN__LINE_CHUNK_SIZE;
-  SVN_ERR(svn_stream_read_full(stream, buffer, &numbytes));
-  buffer[numbytes] = '\0';
-
-  /* Look for the EOL in this first chunk. If we find it, we are done here.
-   */
-  eol_pos = strstr(buffer, eol);
-  if (eol_pos != NULL)
-    {
-      *stringbuf = svn_stringbuf_ncreate(buffer, eol_pos - buffer, pool);
-      total_parsed = eol_pos - buffer + eol_len;
-    }
-  else if (numbytes < SVN__LINE_CHUNK_SIZE)
-    {
-      /* We hit EOF but not EOL.
-       */
-      *stringbuf = svn_stringbuf_ncreate(buffer, numbytes, pool);
-      *eof = TRUE;
-      return SVN_NO_ERROR;
-     }
-  else
+  if (stream->readline_fn)
     {
-      /* A larger buffer for the string is needed. */
-      svn_stringbuf_t *str;
-      str = svn_stringbuf_create_ensure(2*SVN__LINE_CHUNK_SIZE, pool);
-      svn_stringbuf_appendbytes(str, buffer, numbytes);
-      *stringbuf = str;
-
-      /* Loop reading chunks until an EOL was found. If we hit EOF, fall
-       * back to the standard implementation. */
-      do
-      {
-        /* Append the next chunk to the string read so far.
-         */
-        svn_stringbuf_ensure(str, str->len + SVN__LINE_CHUNK_SIZE);
-        numbytes = SVN__LINE_CHUNK_SIZE;
-        SVN_ERR(svn_stream_read_full(stream, str->data + str->len, &numbytes));
-        str->len += numbytes;
-        str->data[str->len] = '\0';
-
-        /* Look for the EOL in the new data plus the last part of the
-         * previous chunk because the EOL may span over the boundary
-         * between both chunks.
-         */
-        eol_pos = strstr(str->data + str->len - numbytes - (eol_len-1), eol);
-
-        if ((numbytes < SVN__LINE_CHUNK_SIZE) && (eol_pos == NULL))
-        {
-          /* We hit EOF instead of EOL. */
-          *eof = TRUE;
-          return SVN_NO_ERROR;
-        }
-      }
-      while (eol_pos == NULL);
-
-      /* Number of bytes we actually consumed (i.e. line + EOF).
-       * We need to "return" the rest to the stream by moving its
-       * read pointer.
-       */
-      total_parsed = eol_pos - str->data + eol_len;
-
-      /* Terminate the string at the EOL postion and return it. */
-      str->len = eol_pos - str->data;
-      str->data[str->len] = 0;
-    }
-
-  /* Move the stream read pointer to the first position behind the EOL.
-   */
-  SVN_ERR(svn_stream_seek(stream, mark));
-  return svn_error_trace(svn_stream_skip(stream, total_parsed));
-}
-
-/* Guts of svn_stream_readline().
- * Returns the line read from STREAM in *STRINGBUF, and indicates
- * end-of-file in *EOF.  EOL must point to the desired end-of-line
- * indicator.  STRINGBUF is allocated in POOL. */
-static svn_error_t *
-stream_readline(svn_stringbuf_t **stringbuf,
-                svn_boolean_t *eof,
-                const char *eol,
-                svn_stream_t *stream,
-                apr_pool_t *pool)
-{
-  *eof = FALSE;
-
-  /* Often, we operate on APR file or string-based streams and know what
-   * EOL we are looking for. Optimize that common case.
-   */
-  if (svn_stream_supports_mark(stream) &&
-      svn_stream__is_buffered(stream))
-    {
-      /* We can efficiently read chunks speculatively and reposition the
-       * stream pointer to the end of the line once we found that.
-       */
-      SVN_ERR(stream_readline_chunky(stringbuf,
-                                     eof,
-                                     eol,
-                                     stream,
-                                     pool));
+      /* Use the specific implementation when it's available. */
+      SVN_ERR(stream->readline_fn(stream->baton, stringbuf, eol, eof, pool));
     }
   else
     {
-      /* Use the standard byte-byte implementation.
-       */
-      SVN_ERR(stream_readline_bytewise(stringbuf,
-                                       eof,
-                                       eol,
-                                       stream,
-                                       pool));
+      /* Use the default implementation. */
+      SVN_ERR(stream_readline_bytewise(stringbuf, eof, eol, stream, pool));
     }
 
   return SVN_NO_ERROR;
 }
 
-svn_error_t *
-svn_stream_readline(svn_stream_t *stream,
-                    svn_stringbuf_t **stringbuf,
-                    const char *eol,
-                    svn_boolean_t *eof,
-                    apr_pool_t *pool)
-{
-  return svn_error_trace(stream_readline(stringbuf, eof, eol, stream,
-                                         pool));
-}
-
 svn_error_t *svn_stream_copy3(svn_stream_t *from, svn_stream_t *to,
                               svn_cancel_func_t cancel_func,
                               void *cancel_baton,
@@ -664,11 +519,6 @@ seek_handler_empty(void *baton, const sv
   return SVN_NO_ERROR;
 }
 
-static svn_boolean_t
-is_buffered_handler_empty(void *baton)
-{
-  return FALSE;
-}
 
 
 svn_stream_t *
@@ -681,7 +531,6 @@ svn_stream_empty(apr_pool_t *pool)
   svn_stream_set_write(stream, write_handler_empty);
   svn_stream_set_mark(stream, mark_handler_empty);
   svn_stream_set_seek(stream, seek_handler_empty);
-  svn_stream__set_is_buffered(stream, is_buffered_handler_empty);
   return stream;
 }
 
@@ -788,10 +637,15 @@ data_available_disown(void *baton, svn_b
   return svn_error_trace(svn_stream_data_available(baton, data_available));
 }
 
-static svn_boolean_t
-is_buffered_handler_disown(void *baton)
+static svn_error_t *
+readline_handler_disown(void *baton,
+                        svn_stringbuf_t **stringbuf,
+                        const char *eol,
+                        svn_boolean_t *eof,
+                        apr_pool_t *pool)
 {
-  return svn_stream__is_buffered(baton);
+  return svn_error_trace(svn_stream_readline(baton, stringbuf, eol,
+                                             eof, pool));
 }
 
 svn_stream_t *
@@ -805,7 +659,7 @@ svn_stream_disown(svn_stream_t *stream,
   svn_stream_set_mark(s, mark_handler_disown);
   svn_stream_set_seek(s, seek_handler_disown);
   svn_stream_set_data_available(s, data_available_disown);
-  svn_stream__set_is_buffered(s, is_buffered_handler_disown);
+  svn_stream_set_readline(s, readline_handler_disown);
 
   return s;
 }
@@ -997,11 +851,146 @@ data_available_handler_apr(void *baton,
 #endif
 }
 
-static svn_boolean_t
-is_buffered_handler_apr(void *baton)
+static svn_error_t *
+readline_apr_lf(apr_file_t *file,
+                svn_stringbuf_t **stringbuf,
+                svn_boolean_t *eof,
+                apr_pool_t *pool)
+{
+  svn_stringbuf_t *buf;
+
+  buf = svn_stringbuf_create_ensure(SVN__LINE_CHUNK_SIZE, pool);
+  while (1)
+  {
+    apr_status_t status;
+
+    status = apr_file_gets(buf->data + buf->len,
+                           (int) (buf->blocksize - buf->len),
+                           file);
+    buf->len += strlen(buf->data + buf->len);
+
+    if (APR_STATUS_IS_EOF(status))
+      {
+        /* apr_file_gets() keeps the newline; strip it if necessary. */
+        if (buf->len > 0 && buf->data[buf->len - 1] == '\n')
+          svn_stringbuf_chop(buf, 1);
+
+        *eof = TRUE;
+        *stringbuf = buf;
+        return SVN_NO_ERROR;
+      }
+    else if (status != APR_SUCCESS)
+      {
+        const char *fname;
+        svn_error_t *err = svn_io_file_name_get(&fname, file, pool);
+        if (err)
+          fname = NULL;
+        svn_error_clear(err);
+
+        if (fname)
+          return svn_error_wrap_apr(status,
+                                    _("Can't read a line from file '%s'"),
+                                    svn_dirent_local_style(fname, pool));
+        else
+          return svn_error_wrap_apr(status,
+                                    _("Can't read a line from stream"));
+      }
+
+    /* Do we have the EOL?  If yes, strip it and return. */
+    if (buf->len > 0 && buf->data[buf->len - 1] == '\n')
+      {
+        svn_stringbuf_chop(buf, 1);
+        *eof = FALSE;
+        *stringbuf = buf;
+        return SVN_NO_ERROR;
+      }
+
+    /* Otherwise, prepare to read the next chunk. */
+    svn_stringbuf_ensure(buf, buf->blocksize + SVN__LINE_CHUNK_SIZE);
+  }
+}
+
+static svn_error_t *
+readline_apr_generic(apr_file_t *file,
+                     svn_stringbuf_t **stringbuf,
+                     const char *eol,
+                     svn_boolean_t *eof,
+                     apr_pool_t *pool)
+{
+  apr_size_t eol_len = strlen(eol);
+  apr_off_t offset;
+  svn_stringbuf_t *buf;
+
+  SVN_ERR(svn_io_file_get_offset(&offset, file, pool));
+
+  buf = svn_stringbuf_create_ensure(SVN__LINE_CHUNK_SIZE, pool);
+  while (1)
+    {
+      apr_size_t bytes_read;
+      svn_boolean_t hit_eof;
+      const char *search_start;
+      const char *eol_pos;
+
+      /* We look for the EOL in the new data plus the last part of the
+         previous chunk because the EOL may span over the boundary
+         between both chunks. */
+      if (buf->len < eol_len)
+        search_start = buf->data;
+      else
+        search_start = buf->data + buf->len - eol_len;
+
+      SVN_ERR(svn_io_file_read_full2(file, buf->data + buf->len,
+                                     buf->blocksize - buf->len - 1,
+                                     &bytes_read, &hit_eof, pool));
+      buf->len += bytes_read;
+      buf->data[buf->len] = '\0';
+
+      /* Do we have the EOL now? */
+      eol_pos = strstr(search_start, eol);
+      if (eol_pos)
+        {
+          svn_stringbuf_chop(buf, buf->data + buf->len - eol_pos);
+          /* Seek to the first position behind the EOL. */
+          offset += (buf->len + eol_len);
+          SVN_ERR(svn_io_file_seek(file, APR_SET, &offset, pool));
+
+          *eof = FALSE;
+          *stringbuf = buf;
+          return SVN_NO_ERROR;
+        }
+      else if (eol_pos == NULL && hit_eof)
+        {
+          *eof = TRUE;
+          *stringbuf = buf;
+          return SVN_NO_ERROR;
+        }
+
+      /* Prepare to read the next chunk. */
+      svn_stringbuf_ensure(buf, buf->blocksize + SVN__LINE_CHUNK_SIZE);
+    }
+}
+
+static svn_error_t *
+readline_handler_apr(void *baton,
+                     svn_stringbuf_t **stringbuf,
+                     const char *eol,
+                     svn_boolean_t *eof,
+                     apr_pool_t *pool)
 {
   struct baton_apr *btn = baton;
-  return (apr_file_flags_get(btn->file) & APR_BUFFERED) != 0;
+
+  if (eol[0] == '\n' && eol[1] == '\0')
+    {
+      /* Optimize the common case when we're looking for an LF ("\n")
+         end-of-line sequence by using apr_file_gets(). */
+      return svn_error_trace(readline_apr_lf(btn->file, stringbuf,
+                                             eof, pool));
+    }
+  else
+    {
+      return svn_error_trace(readline_apr_generic(btn->file, stringbuf,
+                                                  eol, eof, pool));
+    }
 }
 
 svn_error_t *
@@ -1083,10 +1072,10 @@ make_stream_from_apr_file(apr_file_t *fi
       svn_stream_set_skip(stream, skip_handler_apr);
       svn_stream_set_mark(stream, mark_handler_apr);
       svn_stream_set_seek(stream, seek_handler_apr);
+      svn_stream_set_readline(stream, readline_handler_apr);
     }
 
   svn_stream_set_data_available(stream, data_available_handler_apr);
-  svn_stream__set_is_buffered(stream, is_buffered_handler_apr);
   stream->file = file;
 
   if (! disown)
@@ -1478,6 +1467,51 @@ svn_stream_checksummed2(svn_stream_t *st
   return s;
 }
 
+/* Helper for svn_stream_contents_checksum() to compute checksum of
+ * KIND of STREAM. This function doesn't close source stream. */
+static svn_error_t *
+compute_stream_checksum(svn_checksum_t **checksum,
+                        svn_stream_t *stream,
+                        svn_checksum_kind_t kind,
+                        apr_pool_t *result_pool,
+                        apr_pool_t *scratch_pool)
+{
+  svn_checksum_ctx_t *ctx = svn_checksum_ctx_create(kind, scratch_pool);
+  char *buf = apr_palloc(scratch_pool, SVN__STREAM_CHUNK_SIZE);
+
+  while (1)
+    {
+      apr_size_t len = SVN__STREAM_CHUNK_SIZE;
+
+      SVN_ERR(svn_stream_read_full(stream, buf, &len));
+
+      if (len > 0)
+        SVN_ERR(svn_checksum_update(ctx, buf, len));
+
+      if (len != SVN__STREAM_CHUNK_SIZE)
+          break;
+    }
+  SVN_ERR(svn_checksum_final(checksum, ctx, result_pool));
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_stream_contents_checksum(svn_checksum_t **checksum,
+                             svn_stream_t *stream,
+                             svn_checksum_kind_t kind,
+                             apr_pool_t *result_pool,
+                             apr_pool_t *scratch_pool)
+{
+  svn_error_t *err;
+
+  err = compute_stream_checksum(checksum, stream, kind,
+                                result_pool, scratch_pool);
+
+  /* Close source stream in all cases. */
+  return svn_error_compose_create(err, svn_stream_close(stream));
+}
+
 /* Miscellaneous stream functions. */
 
 /*
@@ -1606,10 +1640,35 @@ data_available_handler_stringbuf(void *b
   return SVN_NO_ERROR;
 }
 
-static svn_boolean_t
-is_buffered_handler_stringbuf(void *baton)
+static svn_error_t *
+readline_handler_stringbuf(void *baton,
+                           svn_stringbuf_t **stringbuf,
+                           const char *eol,
+                           svn_boolean_t *eof,
+                           apr_pool_t *pool)
 {
-  return TRUE;
+  struct stringbuf_stream_baton *btn = baton;
+  const char *pos = btn->str->data + btn->amt_read;
+  const char *eol_pos;
+
+  eol_pos = strstr(pos, eol);
+  if (eol_pos)
+    {
+      apr_size_t eol_len = strlen(eol);
+
+      *eof = FALSE;
+      *stringbuf = svn_stringbuf_ncreate(pos, eol_pos - pos, pool);
+      btn->amt_read += (eol_pos - pos + eol_len);
+    }
+  else
+    {
+      *eof = TRUE;
+      *stringbuf = svn_stringbuf_ncreate(pos, btn->str->len - btn->amt_read,
+                                         pool);
+      btn->amt_read = btn->str->len;
+    }
+
+  return SVN_NO_ERROR;
 }
 
 svn_stream_t *
@@ -1632,7 +1691,7 @@ svn_stream_from_stringbuf(svn_stringbuf_
   svn_stream_set_mark(stream, mark_handler_stringbuf);
   svn_stream_set_seek(stream, seek_handler_stringbuf);
   svn_stream_set_data_available(stream, data_available_handler_stringbuf);
-  svn_stream__set_is_buffered(stream, is_buffered_handler_stringbuf);
+  svn_stream_set_readline(stream, readline_handler_stringbuf);
   return stream;
 }
 
@@ -1711,10 +1770,35 @@ data_available_handler_string(void *bato
   return SVN_NO_ERROR;
 }
 
-static svn_boolean_t
-is_buffered_handler_string(void *baton)
+static svn_error_t *
+readline_handler_string(void *baton,
+                        svn_stringbuf_t **stringbuf,
+                        const char *eol,
+                        svn_boolean_t *eof,
+                        apr_pool_t *pool)
 {
-  return TRUE;
+  struct string_stream_baton *btn = baton;
+  const char *pos = btn->str->data + btn->amt_read;
+  const char *eol_pos;
+
+  eol_pos = strstr(pos, eol);
+  if (eol_pos)
+    {
+      apr_size_t eol_len = strlen(eol);
+
+      *eof = FALSE;
+      *stringbuf = svn_stringbuf_ncreate(pos, eol_pos - pos, pool);
+      btn->amt_read += (eol_pos - pos + eol_len);
+    }
+  else
+    {
+      *eof = TRUE;
+      *stringbuf = svn_stringbuf_ncreate(pos, btn->str->len - btn->amt_read,
+                                         pool);
+      btn->amt_read = btn->str->len;
+    }
+
+  return SVN_NO_ERROR;
 }
 
 svn_stream_t *
@@ -1736,7 +1820,7 @@ svn_stream_from_string(const svn_string_
   svn_stream_set_seek(stream, seek_handler_string);
   svn_stream_set_skip(stream, skip_handler_string);
   svn_stream_set_data_available(stream, data_available_handler_string);
-  svn_stream__set_is_buffered(stream, is_buffered_handler_string);
+  svn_stream_set_readline(stream, readline_handler_string);
   return stream;
 }
 
@@ -1985,17 +2069,19 @@ data_available_handler_lazyopen(void *ba
                                                    data_available));
 }
 
-/* Implements svn_stream__is_buffered_fn_t */
-static svn_boolean_t
-is_buffered_lazyopen(void *baton)
+/* Implements svn_stream_readline_fn_t */
+static svn_error_t *
+readline_handler_lazyopen(void *baton,
+                          svn_stringbuf_t **stringbuf,
+                          const char *eol,
+                          svn_boolean_t *eof,
+                          apr_pool_t *pool)
 {
   lazyopen_baton_t *b = baton;
 
-  /* No lazy open as we cannot handle an open error. */
-  if (!b->real_stream)
-    return FALSE;
-
-  return svn_stream__is_buffered(b->real_stream);
+  SVN_ERR(lazyopen_if_unopened(b));
+  return svn_error_trace(svn_stream_readline(b->real_stream, stringbuf,
+                                             eol, eof, pool));
 }
 
 svn_stream_t *
@@ -2022,7 +2108,7 @@ svn_stream_lazyopen_create(svn_stream_la
   svn_stream_set_mark(stream, mark_handler_lazyopen);
   svn_stream_set_seek(stream, seek_handler_lazyopen);
   svn_stream_set_data_available(stream, data_available_handler_lazyopen);
-  svn_stream__set_is_buffered(stream, is_buffered_lazyopen);
+  svn_stream_set_readline(stream, readline_handler_lazyopen);
 
   return stream;
 }

Modified: subversion/branches/ra-git/subversion/libsvn_subr/string.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_subr/string.c?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_subr/string.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_subr/string.c Tue Oct 11 
09:11:50 2016
@@ -479,7 +479,7 @@ svn_stringbuf_set(svn_stringbuf_t *str,
 {
   apr_size_t amt = strlen(value);
 
-  svn_stringbuf_ensure(str, amt);
+  membuf_ensure((void**) &str->data, &str->blocksize, amt + 1, str->pool);
   memcpy(str->data, value, amt + 1);
   str->len = amt;
 }

Modified: subversion/branches/ra-git/subversion/libsvn_subr/subst.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_subr/subst.c?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_subr/subst.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_subr/subst.c Tue Oct 11 
09:11:50 2016
@@ -1431,14 +1431,6 @@ translated_stream_seek(void *baton, cons
   return SVN_NO_ERROR;
 }
 
-/* Implements svn_stream__is_buffered_fn_t. */
-static svn_boolean_t
-translated_stream_is_buffered(void *baton)
-{
-  struct translated_stream_baton *b = baton;
-  return svn_stream__is_buffered(b->stream);
-}
-
 svn_error_t *
 svn_subst_read_specialfile(svn_stream_t **stream,
                            const char *path,
@@ -1546,9 +1538,11 @@ stream_translated(svn_stream_t *stream,
                        translated_stream_read);
   svn_stream_set_write(s, translated_stream_write);
   svn_stream_set_close(s, translated_stream_close);
-  svn_stream_set_mark(s, translated_stream_mark);
-  svn_stream_set_seek(s, translated_stream_seek);
-  svn_stream__set_is_buffered(s, translated_stream_is_buffered);
+  if (svn_stream_supports_mark(stream))
+    {
+      svn_stream_set_mark(s, translated_stream_mark);
+      svn_stream_set_seek(s, translated_stream_seek);
+    }
 
   return s;
 }

Modified: subversion/branches/ra-git/subversion/libsvn_subr/sysinfo.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_subr/sysinfo.c?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_subr/sysinfo.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_subr/sysinfo.c Tue Oct 11 
09:11:50 2016
@@ -666,7 +666,7 @@ system_info(SYSTEM_INFO *sysinfo,
             SYSTEM_INFO *local_sysinfo)
 {
   FNGETNATIVESYSTEMINFO GetNativeSystemInfo_ = (FNGETNATIVESYSTEMINFO)
-    GetProcAddress(GetModuleHandleA("kernel32.dll"), "GetNativeSystemInfo");
+    GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "GetNativeSystemInfo");
 
   memset(sysinfo, 0, sizeof *sysinfo);
   if (local_sysinfo)
@@ -875,12 +875,12 @@ enum_loaded_modules(apr_pool_t *pool)
   DWORD size;
   FNENUMPROCESSMODULES EnumProcessModules_;
 
-  psapi_dll = GetModuleHandleA("psapi.dll");
+  psapi_dll = GetModuleHandleW(L"psapi.dll");
 
   if (!psapi_dll)
     {
       /* Load and never unload, just like static linking */
-      psapi_dll = LoadLibraryA("psapi.dll");
+      psapi_dll = LoadLibraryW(L"psapi.dll");
     }
 
   if (!psapi_dll)
@@ -1143,6 +1143,8 @@ release_name_from_version(const char *os
     case  8: return "Mountain Lion";
     case  9: return "Mavericks";
     case 10: return "Yosemite";
+    case 11: return "El Capitan";
+    case 12: return "Sierra";
     }
 
   return NULL;

Modified: subversion/branches/ra-git/subversion/libsvn_subr/utf8proc.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_subr/utf8proc.c?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_subr/utf8proc.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_subr/utf8proc.c Tue Oct 11 
09:11:50 2016
@@ -126,15 +126,30 @@ decompose_normalized(apr_size_t *result_
  * STRING. Upon return, BUFFER->data points at a NUL-terminated string
  * of UTF-8 characters.
  *
+ * If CASEFOLD is non-zero, perform Unicode case folding, e.g., for
+ * case-insensitive string comparison. If STRIPMARK is non-zero, strip
+ * all diacritical marks (e.g., accents) from the string.
+ *
  * A returned error may indicate that STRING contains invalid UTF-8 or
  * invalid Unicode codepoints. Any error message comes from utf8proc.
  */
 static svn_error_t *
 normalize_cstring(apr_size_t *result_length,
                   const char *string, apr_size_t length,
+                  svn_boolean_t casefold,
+                  svn_boolean_t stripmark,
                   svn_membuf_t *buffer)
 {
-  ssize_t result = unicode_decomposition(0, string, length, buffer);
+  int flags = 0;
+  ssize_t result;
+
+  if (casefold)
+    flags |= UTF8PROC_CASEFOLD;
+
+  if (stripmark)
+    flags |= UTF8PROC_STRIPMARK;
+
+  result = unicode_decomposition(flags, string, length, buffer);
   if (result >= 0)
     {
       svn_membuf__resize(buffer, result * sizeof(apr_int32_t) + 1);
@@ -202,7 +217,21 @@ svn_utf__normalize(const char **result,
                    svn_membuf_t *buf)
 {
   apr_size_t result_length;
-  SVN_ERR(normalize_cstring(&result_length, str, len, buf));
+  SVN_ERR(normalize_cstring(&result_length, str, len, FALSE, FALSE, buf));
+  *result = (const char*)(buf->data);
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_utf__xfrm(const char **result,
+              const char *str, apr_size_t len,
+              svn_boolean_t case_insensitive,
+              svn_boolean_t accent_insensitive,
+              svn_membuf_t *buf)
+{
+  apr_size_t result_length;
+  SVN_ERR(normalize_cstring(&result_length, str, len,
+                            case_insensitive, accent_insensitive, buf));
   *result = (const char*)(buf->data);
   return SVN_NO_ERROR;
 }
@@ -359,7 +388,8 @@ svn_utf__is_normalized(const char *strin
   apr_size_t result_length;
   const apr_size_t length = strlen(string);
   svn_membuf__create(&buffer, length * sizeof(apr_int32_t), scratch_pool);
-  err = normalize_cstring(&result_length, string, length, &buffer);
+  err = normalize_cstring(&result_length, string, length,
+                          FALSE, FALSE, &buffer);
   if (err)
     {
       svn_error_clear(err);


Reply via email to