You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by ju...@apache.org on 2022/01/14 14:01:51 UTC

svn commit: r1897034 [19/37] - in /subversion/branches/multi-wc-format: ./ build/ build/ac-macros/ build/generator/ build/generator/swig/ build/generator/templates/ contrib/client-side/ contrib/client-side/svn_load_dirs/ contrib/hook-scripts/ contrib/s...

Modified: subversion/branches/multi-wc-format/subversion/libsvn_delta/compat.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_delta/compat.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_delta/compat.c (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_delta/compat.c Fri Jan 14 14:01:45 2022
@@ -108,7 +108,7 @@ svn_compat_wrap_file_rev_handler(svn_fil
  * deletion has side effects (unlike deleting a non-existent regular property
  * would).  To solve this, we introduce *another* function into the API, not
  * a part of the Ev2 callbacks, but a companion which is used to register
- * the unlock of a path.  See ev2_change_file_prop() for implemenation
+ * the unlock of a path.  See ev2_change_file_prop() for implementation
  * details.
  */
 
@@ -467,7 +467,7 @@ run_ev2_actions(struct ev2_edit_baton *e
 
   iterpool = svn_pool_create(scratch_pool);
 
-  /* Possibly pick up where we left off. Ocassionally, we do some of these
+  /* Possibly pick up where we left off. Occasionally, we do some of these
      as part of close_edit() and then some more as part of abort_edit()  */
   for (; eb->paths_processed < eb->path_order->nelts; ++eb->paths_processed)
     {
@@ -877,7 +877,7 @@ ev2_change_file_prop(void *file_baton,
 
   if (!strcmp(name, SVN_PROP_ENTRY_LOCK_TOKEN) && value == NULL)
     {
-      /* We special case the lock token propery deletion, which is the
+      /* We special case the lock token property deletion, which is the
          server's way of telling the client to unlock the path. */
 
       /* ### this duplicates much of apply_propedit(). fix in future.  */
@@ -1577,6 +1577,8 @@ drive_ev1_props(const struct editor_bato
 /* Conforms to svn_delta_path_driver_cb_func_t  */
 static svn_error_t *
 apply_change(void **dir_baton,
+             const svn_delta_editor_t *deditor,
+             void *dedit_baton,
              void *parent_baton,
              void *callback_baton,
              const char *ev1_relpath,
@@ -1614,10 +1616,10 @@ apply_change(void **dir_baton,
 
   if (change->action == RESTRUCTURE_DELETE)
     {
-      SVN_ERR(eb->deditor->delete_entry(ev1_relpath, change->deleting,
-                                        parent_baton, scratch_pool));
+      SVN_ERR(deditor->delete_entry(ev1_relpath, change->deleting,
+                                    parent_baton, scratch_pool));
 
-      /* No futher action possible for this node.  */
+      /* No further action possible for this node.  */
       return SVN_NO_ERROR;
     }
 
@@ -1627,11 +1629,11 @@ apply_change(void **dir_baton,
   if (change->action == RESTRUCTURE_ADD_ABSENT)
     {
       if (change->kind == svn_node_dir)
-        SVN_ERR(eb->deditor->absent_directory(ev1_relpath, parent_baton,
-                                              scratch_pool));
+        SVN_ERR(deditor->absent_directory(ev1_relpath, parent_baton,
+                                          scratch_pool));
       else
-        SVN_ERR(eb->deditor->absent_file(ev1_relpath, parent_baton,
-                                         scratch_pool));
+        SVN_ERR(deditor->absent_file(ev1_relpath, parent_baton,
+                                     scratch_pool));
 
       /* No further action possible for this node.  */
       return SVN_NO_ERROR;
@@ -1645,8 +1647,8 @@ apply_change(void **dir_baton,
 
       /* Do we have an old node to delete first?  */
       if (SVN_IS_VALID_REVNUM(change->deleting))
-        SVN_ERR(eb->deditor->delete_entry(ev1_relpath, change->deleting,
-                                          parent_baton, scratch_pool));
+        SVN_ERR(deditor->delete_entry(ev1_relpath, change->deleting,
+                                      parent_baton, scratch_pool));
 
       /* Are we copying the node from somewhere?  */
       if (change->copyfrom_path)
@@ -1669,24 +1671,24 @@ apply_change(void **dir_baton,
         }
 
       if (change->kind == svn_node_dir)
-        SVN_ERR(eb->deditor->add_directory(ev1_relpath, parent_baton,
-                                           copyfrom_url, copyfrom_rev,
-                                           result_pool, dir_baton));
+        SVN_ERR(deditor->add_directory(ev1_relpath, parent_baton,
+                                       copyfrom_url, copyfrom_rev,
+                                       result_pool, dir_baton));
       else
-        SVN_ERR(eb->deditor->add_file(ev1_relpath, parent_baton,
-                                      copyfrom_url, copyfrom_rev,
-                                      result_pool, &file_baton));
+        SVN_ERR(deditor->add_file(ev1_relpath, parent_baton,
+                                  copyfrom_url, copyfrom_rev,
+                                  result_pool, &file_baton));
     }
   else
     {
       if (change->kind == svn_node_dir)
-        SVN_ERR(eb->deditor->open_directory(ev1_relpath, parent_baton,
-                                            change->changing,
-                                            result_pool, dir_baton));
+        SVN_ERR(deditor->open_directory(ev1_relpath, parent_baton,
+                                        change->changing,
+                                        result_pool, dir_baton));
       else
-        SVN_ERR(eb->deditor->open_file(ev1_relpath, parent_baton,
-                                       change->changing,
-                                       result_pool, &file_baton));
+        SVN_ERR(deditor->open_file(ev1_relpath, parent_baton,
+                                   change->changing,
+                                   result_pool, &file_baton));
     }
 
   /* Apply any properties in CHANGE to the node.  */
@@ -1703,8 +1705,8 @@ apply_change(void **dir_baton,
 
       /* ### would be nice to have a BASE_CHECKSUM, but hey: this is the
          ### shim code...  */
-      SVN_ERR(eb->deditor->apply_textdelta(file_baton, NULL, scratch_pool,
-                                           &handler, &handler_baton));
+      SVN_ERR(deditor->apply_textdelta(file_baton, NULL, scratch_pool,
+                                       &handler, &handler_baton));
       SVN_ERR(svn_stream_open_readonly(&contents, change->contents_abspath,
                                        scratch_pool, scratch_pool));
       /* ### it would be nice to send a true txdelta here, but whatever.  */
@@ -1718,7 +1720,7 @@ apply_change(void **dir_baton,
       const char *digest = svn_checksum_to_cstring(change->checksum,
                                                    scratch_pool);
 
-      SVN_ERR(eb->deditor->close_file(file_baton, digest, scratch_pool));
+      SVN_ERR(deditor->close_file(file_baton, digest, scratch_pool));
     }
 
   return SVN_NO_ERROR;
@@ -1747,7 +1749,7 @@ drive_changes(const struct editor_baton
 
   /* Get a sorted list of Ev1-relative paths.  */
   paths = get_sorted_paths(eb->changes, eb->base_relpath, scratch_pool);
-  SVN_ERR(svn_delta_path_driver2(eb->deditor, eb->dedit_baton, paths,
+  SVN_ERR(svn_delta_path_driver3(eb->deditor, eb->dedit_baton, paths,
                                  FALSE, apply_change, (void *)eb,
                                  scratch_pool));
 

Modified: subversion/branches/multi-wc-format/subversion/libsvn_delta/compose_delta.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_delta/compose_delta.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_delta/compose_delta.c (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_delta/compose_delta.c Fri Jan 14 14:01:45 2022
@@ -128,7 +128,7 @@ free_block(void *ptr, alloc_block_t **fr
 
 
 /* ==================================================================== */
-/* Mapping offsets in the target streem to txdelta ops. */
+/* Mapping offsets in the target stream to txdelta ops. */
 
 typedef struct offset_index_t
 {

Modified: subversion/branches/multi-wc-format/subversion/libsvn_delta/deprecated.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_delta/deprecated.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_delta/deprecated.c (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_delta/deprecated.c Fri Jan 14 14:01:45 2022
@@ -30,6 +30,79 @@
 #include "svn_sorts.h"
 
 
+struct path_driver_2_to_3_baton_t
+{
+  svn_delta_path_driver_cb_func_t callback_func;
+  void *callback_baton;
+  svn_boolean_t slash_prefix;
+};
+
+/* Convert from a newer to older callback
+ */
+static svn_error_t *
+path_driver_2_to_3_func(void **dir_baton,
+                        const svn_delta_editor_t *editor,
+                        void *edit_baton,
+                        void *parent_baton,
+                        void *callback_baton,
+                        const char *path,
+                        apr_pool_t *pool)
+{
+  struct path_driver_2_to_3_baton_t *b = callback_baton;
+
+  if (b->slash_prefix)
+    path = apr_pstrcat(pool, "/", path, SVN_VA_NULL);
+
+  /* Just drop the 'editor' parameters */
+  SVN_ERR(b->callback_func(dir_baton, parent_baton,
+                           b->callback_baton,
+                           path, pool));
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_delta_path_driver2(const svn_delta_editor_t *editor,
+                       void *edit_baton,
+                       const apr_array_header_t *paths,
+                       svn_boolean_t sort_paths,
+                       svn_delta_path_driver_cb_func_t callback_func,
+                       void *callback_baton,
+                       apr_pool_t *pool)
+{
+  struct path_driver_2_to_3_baton_t b;
+  int i;
+
+  b.callback_func = callback_func;
+  b.callback_baton = callback_baton;
+  b.slash_prefix = FALSE;
+
+  /* Remove any '/' prefix from incoming paths. Arrange to add a '/'
+     prefix to all paths for the callback, if any incoming path had one. */
+  for (i = 0; i < paths->nelts; i++)
+    {
+      const char *path = APR_ARRAY_IDX(paths, i, const char *);
+
+      if (path[0] == '/')
+        {
+          /* Re-allocate the array and note that we found a '/' prefix. */
+          if (!b.slash_prefix)
+            {
+              paths = apr_array_copy(pool, paths);
+              b.slash_prefix = TRUE;
+            }
+
+          /* Modify each array element that had a '/' prefix */
+          APR_ARRAY_IDX(paths, i, const char *) = path + 1;
+        }
+    }
+
+  SVN_ERR(svn_delta_path_driver3(editor, edit_baton,
+                                 paths, sort_paths,
+                                 path_driver_2_to_3_func, &b,
+                                 pool));
+  return SVN_NO_ERROR;
+}
+
 svn_error_t *
 svn_delta_path_driver(const svn_delta_editor_t *editor,
                       void *edit_baton,

Modified: subversion/branches/multi-wc-format/subversion/libsvn_delta/path_driver.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_delta/path_driver.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_delta/path_driver.c (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_delta/path_driver.c Fri Jan 14 14:01:45 2022
@@ -31,7 +31,6 @@
 #include "svn_dirent_uri.h"
 #include "svn_path.h"
 #include "svn_sorts.h"
-#include "private/svn_fspath.h"
 #include "private/svn_sorts_private.h"
 
 
@@ -45,6 +44,22 @@ typedef struct dir_stack_t
 } dir_stack_t;
 
 
+/* Push onto dir_stack a new item allocated in POOL and containing
+ * DIR_BATON and POOL.
+ */
+static void
+push_dir_stack_item(apr_array_header_t *db_stack,
+                    void *dir_baton,
+                    apr_pool_t *pool)
+{
+  dir_stack_t *item = apr_pcalloc(pool, sizeof(*item));
+
+  item->dir_baton = dir_baton;
+  item->pool = pool;
+  APR_ARRAY_PUSH(db_stack, dir_stack_t *) = item;
+}
+
+
 /* Call EDITOR's open_directory() function with the PATH argument, then
  * add the resulting dir baton to the dir baton stack.
  */
@@ -72,10 +87,7 @@ open_dir(apr_array_header_t *db_stack,
                                  &db));
 
   /* Now add the dir baton to the stack. */
-  item = apr_pcalloc(subpool, sizeof(*item));
-  item->dir_baton = db;
-  item->pool = subpool;
-  APR_ARRAY_PUSH(db_stack, dir_stack_t *) = item;
+  push_dir_stack_item(db_stack, db, subpool);
 
   return SVN_NO_ERROR;
 }
@@ -131,168 +143,215 @@ count_components(const char *path)
 
 /*** Public interfaces ***/
 svn_error_t *
-svn_delta_path_driver2(const svn_delta_editor_t *editor,
+svn_delta_path_driver3(const svn_delta_editor_t *editor,
                        void *edit_baton,
-                       const apr_array_header_t *paths,
+                       const apr_array_header_t *relpaths,
                        svn_boolean_t sort_paths,
-                       svn_delta_path_driver_cb_func_t callback_func,
+                       svn_delta_path_driver_cb_func2_t callback_func,
                        void *callback_baton,
                        apr_pool_t *pool)
 {
-  apr_array_header_t *db_stack = apr_array_make(pool, 4, sizeof(void *));
-  const char *last_path = NULL;
-  int i = 0;
-  void *parent_db = NULL, *db = NULL;
-  const char *path;
+  svn_delta_path_driver_state_t *state;
+  int i;
   apr_pool_t *subpool, *iterpool;
-  dir_stack_t *item;
 
   /* Do nothing if there are no paths. */
-  if (! paths->nelts)
+  if (! relpaths->nelts)
     return SVN_NO_ERROR;
 
   subpool = svn_pool_create(pool);
   iterpool = svn_pool_create(pool);
 
   /* sort paths if necessary */
-  if (sort_paths && paths->nelts > 1)
+  if (sort_paths && relpaths->nelts > 1)
     {
-      apr_array_header_t *sorted = apr_array_copy(subpool, paths);
+      apr_array_header_t *sorted = apr_array_copy(subpool, relpaths);
       svn_sort__array(sorted, svn_sort_compare_paths);
-      paths = sorted;
+      relpaths = sorted;
     }
 
-  item = apr_pcalloc(subpool, sizeof(*item));
-
-  /* If the root of the edit is also a target path, we want to call
-     the callback function to let the user open the root directory and
-     do what needs to be done.  Otherwise, we'll do the open_root()
-     ourselves. */
-  path = APR_ARRAY_IDX(paths, 0, const char *);
-  if (svn_path_is_empty(path))
-    {
-      SVN_ERR(callback_func(&db, NULL, callback_baton, path, subpool));
-      last_path = path;
-      i++;
-    }
-  else
-    {
-      SVN_ERR(editor->open_root(edit_baton, SVN_INVALID_REVNUM, subpool, &db));
-    }
-  item->pool = subpool;
-  item->dir_baton = db;
-  APR_ARRAY_PUSH(db_stack, void *) = item;
+  SVN_ERR(svn_delta_path_driver_start(&state,
+                                      editor, edit_baton,
+                                      callback_func, callback_baton,
+                                      pool));
 
   /* Now, loop over the commit items, traversing the URL tree and
      driving the editor. */
-  for (; i < paths->nelts; i++)
+  for (i = 0; i < relpaths->nelts; i++)
     {
-      const char *pdir;
-      const char *common = "";
-      size_t common_len;
+      const char *relpath;
 
       /* Clear the iteration pool. */
       svn_pool_clear(iterpool);
 
       /* Get the next path. */
-      path = APR_ARRAY_IDX(paths, i, const char *);
+      relpath = APR_ARRAY_IDX(relpaths, i, const char *);
 
-      /*** Step A - Find the common ancestor of the last path and the
-           current one.  For the first iteration, this is just the
-           empty string. ***/
-      if (i > 0)
-        common = (last_path[0] == '/')
-          ? svn_fspath__get_longest_ancestor(last_path, path, iterpool)
-          : svn_relpath_get_longest_ancestor(last_path, path, iterpool);
-      common_len = strlen(common);
-
-      /*** Step B - Close any directories between the last path and
-           the new common ancestor, if any need to be closed.
-           Sometimes there is nothing to do here (like, for the first
-           iteration, or when the last path was an ancestor of the
-           current one). ***/
-      if ((i > 0) && (strlen(last_path) > common_len))
-        {
-          const char *rel = last_path + (common_len ? (common_len + 1) : 0);
-          int count = count_components(rel);
-          while (count--)
-            {
-              SVN_ERR(pop_stack(db_stack, editor));
-            }
-        }
+      SVN_ERR(svn_delta_path_driver_step(state, relpath, iterpool));
+    }
 
-      /*** Step C - Open any directories between the common ancestor
-           and the parent of the current path. ***/
-      if (*path == '/')
-        pdir = svn_fspath__dirname(path, iterpool);
-      else
-        pdir = svn_relpath_dirname(path, iterpool);
+  /* Destroy the iteration subpool. */
+  svn_pool_destroy(iterpool);
 
-      if (strlen(pdir) > common_len)
-        {
-          const char *piece = pdir + common_len + 1;
+  SVN_ERR(svn_delta_path_driver_finish(state, pool));
 
-          while (1)
-            {
-              const char *rel = pdir;
-
-              /* Find the first separator. */
-              piece = strchr(piece, '/');
-
-              /* Calculate REL as the portion of PDIR up to (but not
-                 including) the location to which PIECE is pointing. */
-              if (piece)
-                rel = apr_pstrmemdup(iterpool, pdir, piece - pdir);
-
-              /* Open the subdirectory. */
-              SVN_ERR(open_dir(db_stack, editor, rel, pool));
-
-              /* If we found a '/', advance our PIECE pointer to
-                 character just after that '/'.  Otherwise, we're
-                 done.  */
-              if (piece)
-                piece++;
-              else
-                break;
-            }
-        }
+  return SVN_NO_ERROR;
+}
 
-      /*** Step D - Tell our caller to handle the current path. ***/
-      item = APR_ARRAY_IDX(db_stack, db_stack->nelts - 1, void *);
-      parent_db = item->dir_baton;
-      subpool = svn_pool_create(pool);
-      SVN_ERR(callback_func(&db, parent_db, callback_baton, path, subpool));
-      if (db)
+struct svn_delta_path_driver_state_t
+{
+  const svn_delta_editor_t *editor;
+  void *edit_baton;
+  svn_delta_path_driver_cb_func2_t callback_func;
+  void *callback_baton;
+  apr_array_header_t *db_stack;
+  const char *last_path;
+  apr_pool_t *pool;  /* at least the lifetime of the entire drive */
+};
+
+svn_error_t *
+svn_delta_path_driver_start(svn_delta_path_driver_state_t **state_p,
+                            const svn_delta_editor_t *editor,
+                            void *edit_baton,
+                            svn_delta_path_driver_cb_func2_t callback_func,
+                            void *callback_baton,
+                            apr_pool_t *pool)
+{
+  svn_delta_path_driver_state_t *state = apr_pcalloc(pool, sizeof(*state));
+
+  state->editor = editor;
+  state->edit_baton = edit_baton;
+  state->callback_func = callback_func;
+  state->callback_baton = callback_baton;
+  state->db_stack = apr_array_make(pool, 4, sizeof(void *));
+  state->last_path = NULL;
+  state->pool = pool;
+
+  *state_p = state;
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_delta_path_driver_step(svn_delta_path_driver_state_t *state,
+                           const char *relpath,
+                           apr_pool_t *scratch_pool)
+{
+  const char *pdir;
+  const char *common = "";
+  size_t common_len;
+  apr_pool_t *subpool;
+  dir_stack_t *item;
+  void *parent_db, *db;
+
+  SVN_ERR_ASSERT(svn_relpath_is_canonical(relpath));
+
+  /* If the first target path is not the root of the edit, we must first
+     call open_root() ourselves. (If the first target path is the root of
+     the edit, then we expect the user's callback to do so.) */
+  if (!state->last_path && !svn_path_is_empty(relpath))
+    {
+      subpool = svn_pool_create(state->pool);
+      SVN_ERR(state->editor->open_root(state->edit_baton, SVN_INVALID_REVNUM,
+                                       subpool, &db));
+      push_dir_stack_item(state->db_stack, db, subpool);
+    }
+
+  /*** Step A - Find the common ancestor of the last path and the
+       current one.  For the first iteration, this is just the
+       empty string. ***/
+  if (state->last_path)
+    common = svn_relpath_get_longest_ancestor(state->last_path, relpath,
+                                              scratch_pool);
+  common_len = strlen(common);
+
+  /*** Step B - Close any directories between the last path and
+       the new common ancestor, if any need to be closed.
+       Sometimes there is nothing to do here (like, for the first
+       iteration, or when the last path was an ancestor of the
+       current one). ***/
+  if ((state->last_path) && (strlen(state->last_path) > common_len))
+    {
+      const char *rel = state->last_path + (common_len ? (common_len + 1) : 0);
+      int count = count_components(rel);
+      while (count--)
         {
-          item = apr_pcalloc(subpool, sizeof(*item));
-          item->dir_baton = db;
-          item->pool = subpool;
-          APR_ARRAY_PUSH(db_stack, void *) = item;
+          SVN_ERR(pop_stack(state->db_stack, state->editor));
         }
-      else
+    }
+
+  /*** Step C - Open any directories between the common ancestor
+       and the parent of the current path. ***/
+  pdir = svn_relpath_dirname(relpath, scratch_pool);
+
+  if (strlen(pdir) > common_len)
+    {
+      const char *piece = pdir + common_len + 1;
+
+      while (1)
         {
-          svn_pool_destroy(subpool);
+          const char *rel = pdir;
+
+          /* Find the first separator. */
+          piece = strchr(piece, '/');
+
+          /* Calculate REL as the portion of PDIR up to (but not
+             including) the location to which PIECE is pointing. */
+          if (piece)
+            rel = apr_pstrmemdup(scratch_pool, pdir, piece - pdir);
+
+          /* Open the subdirectory. */
+          SVN_ERR(open_dir(state->db_stack, state->editor, rel, state->pool));
+
+          /* If we found a '/', advance our PIECE pointer to
+             character just after that '/'.  Otherwise, we're
+             done.  */
+          if (piece)
+            piece++;
+          else
+            break;
         }
+    }
 
-      /*** Step E - Save our state for the next iteration.  If our
-           caller opened or added PATH as a directory, that becomes
-           our LAST_PATH.  Otherwise, we use PATH's parent
-           directory. ***/
-
-      /* NOTE:  The variable LAST_PATH needs to outlive the loop. */
-      if (db)
-        last_path = path; /* lives in a pool outside our control. */
-      else
-        last_path = apr_pstrdup(pool, pdir); /* duping into POOL. */
+  /*** Step D - Tell our caller to handle the current path. ***/
+  if (state->db_stack->nelts)
+    {
+      item = APR_ARRAY_IDX(state->db_stack, state->db_stack->nelts - 1, void *);
+      parent_db = item->dir_baton;
+    }
+  else
+    parent_db = NULL;
+  db = NULL;  /* predictable behaviour for callbacks that don't set it */
+  subpool = svn_pool_create(state->pool);
+  SVN_ERR(state->callback_func(&db,
+                               state->editor, state->edit_baton, parent_db,
+                               state->callback_baton,
+                               relpath, subpool));
+  if (db)
+    {
+      push_dir_stack_item(state->db_stack, db, subpool);
+    }
+  else
+    {
+      svn_pool_destroy(subpool);
     }
 
-  /* Destroy the iteration subpool. */
-  svn_pool_destroy(iterpool);
+  /*** Step E - Save our state for the next iteration.  If our
+       caller opened or added PATH as a directory, that becomes
+       our LAST_PATH.  Otherwise, we use PATH's parent
+       directory. ***/
+  state->last_path = apr_pstrdup(state->pool, db ? relpath : pdir);
+
+  return SVN_NO_ERROR;
+}
 
+svn_error_t *
+svn_delta_path_driver_finish(svn_delta_path_driver_state_t *state,
+                             apr_pool_t *scratch_pool)
+{
   /* Close down any remaining open directory batons. */
-  while (db_stack->nelts)
+  while (state->db_stack->nelts)
     {
-      SVN_ERR(pop_stack(db_stack, editor));
+      SVN_ERR(pop_stack(state->db_stack, state->editor));
     }
 
   return SVN_NO_ERROR;

Modified: subversion/branches/multi-wc-format/subversion/libsvn_delta/svndiff.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_delta/svndiff.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_delta/svndiff.c (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_delta/svndiff.c Fri Jan 14 14:01:45 2022
@@ -396,7 +396,7 @@ struct decode_baton
 };
 
 
-/* Wrapper aroung svn__deencode_uint taking a file size as *VAL. */
+/* Wrapper around svn__deencode_uint taking a file size as *VAL. */
 static const unsigned char *
 decode_file_offset(svn_filesize_t *val,
                    const unsigned char *p,

Modified: subversion/branches/multi-wc-format/subversion/libsvn_delta/xdelta.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_delta/xdelta.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_delta/xdelta.c (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_delta/xdelta.c Fri Jan 14 14:01:45 2022
@@ -124,7 +124,7 @@ struct blocks
      This value has an upper bound proportionate to the text delta
      window size, so unless we dramatically increase the window size,
      it's safe to make this a 32-bit value.  In any case, it has to be
-     hte same width as the block position index, (struct
+     the same width as the block position index, (struct
      block).pos. */
   apr_uint32_t max;
 

Modified: subversion/branches/multi-wc-format/subversion/libsvn_diff/deprecated.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_diff/deprecated.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_diff/deprecated.c (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_diff/deprecated.c Fri Jan 14 14:01:45 2022
@@ -409,7 +409,7 @@ svn_diff_mem_string_output_merge2(svn_st
                                                            conflict_latest,
                                                            conflict_separator,
                                                            style,
-                                                           /* no cancelation */
+                                                           /* no cancellation */
                                                            NULL, NULL,
                                                            pool));
 }

Modified: subversion/branches/multi-wc-format/subversion/libsvn_diff/diff_file.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_diff/diff_file.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_diff/diff_file.c (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_diff/diff_file.c Fri Jan 14 14:01:45 2022
@@ -1095,7 +1095,7 @@ token_compare(void *baton, void *token1,
           if (length[i] == 0)
             {
               /* Error if raw_length is 0, that's an unexpected change
-               * of the file that can happen when ingoring whitespace
+               * of the file that can happen when ignoring whitespace
                * and that can lead to an infinite loop. */
               if (raw_length[i] == 0)
                 return svn_error_createf(SVN_ERR_DIFF_DATASOURCE_MODIFIED,
@@ -1253,7 +1253,7 @@ svn_diff_file_options_parse(svn_diff_fil
   apr_array_cat(argv, args);
   APR_ARRAY_PUSH(argv, const char *) = NULL;
 
-  apr_getopt_init(&os, pool, 
+  apr_getopt_init(&os, pool,
                   argv->nelts - 1 /* Exclude trailing NULL */,
                   (const char *const *) argv->elts);
 

Modified: subversion/branches/multi-wc-format/subversion/libsvn_diff/parse-diff.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_diff/parse-diff.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_diff/parse-diff.c (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_diff/parse-diff.c Fri Jan 14 14:01:45 2022
@@ -215,7 +215,7 @@ svn_diff_hunk__create_adds_single_line(s
                                        apr_pool_t *result_pool,
                                        apr_pool_t *scratch_pool)
 {
-  SVN_ERR(add_or_delete_single_line(hunk_out, line, patch, 
+  SVN_ERR(add_or_delete_single_line(hunk_out, line, patch,
                                     (!patch->reverse),
                                     result_pool, scratch_pool));
   return SVN_NO_ERROR;
@@ -1235,7 +1235,7 @@ parse_next_hunk(svn_diff_hunk_t **hunk,
           c = line->data[0];
           if (c == ' '
               || ((original_lines > 0 && modified_lines > 0)
-                  && ( 
+                  && (
                /* Tolerate chopped leading spaces on empty lines. */
                       (! eof && line->len == 0)
                /* Maybe tolerate chopped leading spaces on non-empty lines. */
@@ -2085,7 +2085,7 @@ parse_binary_patch(svn_patch_t *patch, a
           else if (in_src)
             {
               patch->binary_patch = bpatch; /* SUCCESS! */
-              break; 
+              break;
             }
           else
             {

Modified: subversion/branches/multi-wc-format/subversion/libsvn_fs/fs-loader.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_fs/fs-loader.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_fs/fs-loader.c (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_fs/fs-loader.c Fri Jan 14 14:01:45 2022
@@ -438,7 +438,7 @@ svn_fs_initialize(apr_pool_t *pool)
 static void
 default_warning_func(void *baton, svn_error_t *err)
 {
-  /* The one unforgiveable sin is to fail silently.  Dumping to stderr
+  /* The one unforgivable sin is to fail silently.  Dumping to stderr
      or /dev/tty is not acceptable default behavior for server
      processes, since those may both be equivalent to /dev/null.
 
@@ -2221,3 +2221,42 @@ svn_fs_info_dup(const void *info_void,
     return apr_pmemdup(result_pool, info, sizeof(*info));
 }
 
+svn_error_t *
+svn_fs_ioctl(svn_fs_t *fs,
+             svn_fs_ioctl_code_t ctlcode,
+             void *input,
+             void **output_p,
+             svn_cancel_func_t cancel_func,
+             void *cancel_baton,
+             apr_pool_t *result_pool,
+             apr_pool_t *scratch_pool)
+{
+  void *output;
+
+  if (fs)
+    {
+      if (!fs->vtable->ioctl)
+        return svn_error_create(SVN_ERR_FS_UNRECOGNIZED_IOCTL_CODE, NULL, NULL);
+
+      SVN_ERR(fs->vtable->ioctl(fs, ctlcode, input, &output,
+                                cancel_func, cancel_baton,
+                                result_pool, scratch_pool));
+    }
+  else
+    {
+      fs_library_vtable_t *vtable;
+
+      SVN_ERR(get_library_vtable(&vtable, ctlcode.fs_type, scratch_pool));
+
+      if (!vtable->ioctl)
+        return svn_error_create(SVN_ERR_FS_UNRECOGNIZED_IOCTL_CODE, NULL, NULL);
+
+      SVN_ERR(vtable->ioctl(ctlcode, input, &output,
+                            cancel_func, cancel_baton,
+                            result_pool, scratch_pool));
+    }
+
+  if (output_p)
+    *output_p = output;
+  return SVN_NO_ERROR;
+}

Modified: subversion/branches/multi-wc-format/subversion/libsvn_fs/fs-loader.h
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_fs/fs-loader.h?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_fs/fs-loader.h (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_fs/fs-loader.h Fri Jan 14 14:01:45 2022
@@ -159,6 +159,13 @@ typedef struct fs_library_vtable_t
   /* For svn_fs_info_fsfs_dup(). */
   void *(*info_fsap_dup)(const void *fsap_info,
                          apr_pool_t *result_pool);
+
+  svn_error_t *(*ioctl)(svn_fs_ioctl_code_t ctlcode,
+                        void *input, void **output_p,
+                        svn_cancel_func_t cancel_func,
+                        void *cancel_baton,
+                        apr_pool_t *result_pool,
+                        apr_pool_t *scratch_pool);
 } fs_library_vtable_t;
 
 /* This is the type of symbol an FS module defines to fetch the
@@ -200,12 +207,12 @@ typedef struct fs_vtable_t
   svn_error_t *(*revision_prop)(svn_string_t **value_p, svn_fs_t *fs,
                                 svn_revnum_t rev, const char *propname,
                                 svn_boolean_t refresh,
-                                apr_pool_t *result_pool, 
+                                apr_pool_t *result_pool,
                                 apr_pool_t *scratch_pool);
   svn_error_t *(*revision_proplist)(apr_hash_t **table_p, svn_fs_t *fs,
                                     svn_revnum_t rev,
                                     svn_boolean_t refresh,
-                                    apr_pool_t *result_pool, 
+                                    apr_pool_t *result_pool,
                                     apr_pool_t *scratch_pool);
   svn_error_t *(*change_rev_prop)(svn_fs_t *fs, svn_revnum_t rev,
                                   const char *name,
@@ -266,6 +273,12 @@ typedef struct fs_vtable_t
   svn_error_t *(*bdb_set_errcall)(svn_fs_t *fs,
                                   void (*handler)(const char *errpfx,
                                                   char *msg));
+  svn_error_t *(*ioctl)(svn_fs_t *fs, svn_fs_ioctl_code_t ctlcode,
+                        void *input, void **output_p,
+                        svn_cancel_func_t cancel_func,
+                        void *cancel_baton,
+                        apr_pool_t *result_pool,
+                        apr_pool_t *scratch_pool);
 } fs_vtable_t;
 
 

Modified: subversion/branches/multi-wc-format/subversion/libsvn_fs_base/bdb/locks-table.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_fs_base/bdb/locks-table.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_fs_base/bdb/locks-table.c (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_fs_base/bdb/locks-table.c Fri Jan 14 14:01:45 2022
@@ -261,7 +261,7 @@ svn_fs_bdb__locks_get(svn_fs_t *fs,
   lookup_len = strlen(lookup_path);
 
   /* As long as the prefix of the returned KEY matches LOOKUP_PATH we
-     know it is either LOOKUP_PATH or a decendant thereof.  */
+     know it is either LOOKUP_PATH or a descendant thereof.  */
   while ((! db_err)
          && lookup_len < key.size
          && strncmp(lookup_path, key.data, lookup_len) == 0)

Modified: subversion/branches/multi-wc-format/subversion/libsvn_fs_base/fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_fs_base/fs.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_fs_base/fs.c (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_fs_base/fs.c Fri Jan 14 14:01:45 2022
@@ -574,6 +574,7 @@ static fs_vtable_t fs_vtable = {
   base_bdb_verify_root,
   base_bdb_freeze,
   base_bdb_set_errcall,
+  NULL /* ioctl */
 };
 
 /* Where the format number is stored. */
@@ -906,7 +907,7 @@ bdb_recover(const char *path, svn_boolea
      will simply join it instead, and will then be running with
      incorrectly sized (and probably terribly small) caches.  */
 
-  /* Note that since we're using a private environment, we shoudl
+  /* Note that since we're using a private environment, we should
      /not/ initialize locking. We want the environment files to go
      away. */
 
@@ -1077,7 +1078,7 @@ base_bdb_logfiles(apr_array_header_t **l
 /* Copying a live Berkeley DB-base filesystem.  */
 
 /**
- * Delete all unused log files from DBD enviroment at @a live_path that exist
+ * Delete all unused log files from DBD environment at @a live_path that exist
  * in @a backup_path.
  */
 static svn_error_t *
@@ -1515,7 +1516,8 @@ static fs_library_vtable_t library_vtabl
   base_bdb_logfiles,
   svn_fs_base__id_parse,
   base_set_svn_fs_open,
-  NULL /* info_fsap_dup */
+  NULL /* info_fsap_dup */,
+  NULL /* ioctl */
 };
 
 svn_error_t *

Modified: subversion/branches/multi-wc-format/subversion/libsvn_fs_base/key-gen.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_fs_base/key-gen.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_fs_base/key-gen.c (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_fs_base/key-gen.c Fri Jan 14 14:01:45 2022
@@ -50,7 +50,7 @@ svn_fs_base__next_key(const char *this,
    * from being propagated further. */
   SVN_ERR_ASSERT_NO_RETURN(olen != 0 && (olen == 1 || this[0] != '0'));
 
-  i = olen - 1; /* initial index: we work backwords */
+  i = olen - 1; /* initial index: we work backwards */
   while (1729)
     {
       c = this[i];

Modified: subversion/branches/multi-wc-format/subversion/libsvn_fs_base/notes/fs-history
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_fs_base/notes/fs-history?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_fs_base/notes/fs-history (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_fs_base/notes/fs-history Fri Jan 14 14:01:45 2022
@@ -128,7 +128,7 @@ node-revision ID consists of the same no
 that was cloned (since this is just another point along the historical
 lineage of this versioned resource), a copy ID (which will be
 discussed later), and the txn ID in which this modification is
-occuring.
+occurring.
 
 There are some cool things we can read between the lines above.  Since
 the only time a node-revision comes into existence is when it is brand

Modified: subversion/branches/multi-wc-format/subversion/libsvn_fs_base/reps-strings.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_fs_base/reps-strings.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_fs_base/reps-strings.c (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_fs_base/reps-strings.c Fri Jan 14 14:01:45 2022
@@ -1,4 +1,4 @@
-/* reps-strings.c : intepreting representations with respect to strings
+/* reps-strings.c : interpreting representations with respect to strings
  *
  * ====================================================================
  *    Licensed to the Apache Software Foundation (ASF) under one

Modified: subversion/branches/multi-wc-format/subversion/libsvn_fs_base/tree.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_fs_base/tree.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_fs_base/tree.c (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_fs_base/tree.c Fri Jan 14 14:01:45 2022
@@ -1627,7 +1627,7 @@ base_dir_optimal_order(apr_array_header_
                        apr_pool_t *result_pool,
                        apr_pool_t *scratch_pool)
 {
-  /* 1:1 copy of entries with no differnce in ordering */
+  /* 1:1 copy of entries with no difference in ordering */
   apr_hash_index_t *hi;
   apr_array_header_t *result
     = apr_array_make(result_pool, apr_hash_count(entries),
@@ -3936,7 +3936,7 @@ txn_body_fulltext_finalize_edits(void *b
                     trail->pool);
 }
 
-/* Write function for the publically returned stream. */
+/* Write function for the publicly returned stream. */
 static svn_error_t *
 text_stream_writer(void *baton,
                    const char *data,
@@ -3948,7 +3948,7 @@ text_stream_writer(void *baton,
   return svn_stream_write(tb->file_stream, data, len);
 }
 
-/* Close function for the publically returned stream. */
+/* Close function for the publicly returned stream. */
 static svn_error_t *
 text_stream_closer(void *baton)
 {

Modified: subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/cached_data.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/cached_data.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/cached_data.c (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/cached_data.c Fri Jan 14 14:01:45 2022
@@ -1224,7 +1224,7 @@ struct rep_read_baton
   /* Used for temporary allocations during the read. */
   apr_pool_t *pool;
 
-  /* Pool used to store file handles and other data that is persistant
+  /* Pool used to store file handles and other data that is persistent
      for the entire stream read. */
   apr_pool_t *filehandle_pool;
 };
@@ -1775,7 +1775,7 @@ get_combined_window(svn_stringbuf_t **re
   return SVN_NO_ERROR;
 }
 
-/* Returns whether or not the expanded fulltext of the file is cachable
+/* Returns whether or not the expanded fulltext of the file is cacheable
  * based on its size SIZE.  The decision depends on the cache used by FFD.
  */
 static svn_boolean_t
@@ -2337,7 +2337,7 @@ svn_fs_fs__get_contents_from_file(svn_st
                              rb->filehandle_pool));
 
       /* Insert the access to REP as the first element of the delta chain. */
-      svn_sort__array_insert(rb->rs_list, &rs, 0);
+      SVN_ERR(svn_sort__array_insert2(rb->rs_list, &rs, 0));
     }
 
   /* Now, the baton is complete and we can assemble the stream around it. */
@@ -2699,7 +2699,7 @@ read_dir_entries(apr_array_header_t **en
 }
 
 /* For directory NODEREV in FS, return the *FILESIZE of its in-txn
- * representation.  If the directory representation is comitted data,
+ * representation.  If the directory representation is committed data,
  * set *FILESIZE to SVN_INVALID_FILESIZE. Use SCRATCH_POOL for temporaries.
  */
 static svn_error_t *
@@ -3345,7 +3345,7 @@ cache_windows(svn_fs_t *fs,
           /* update relative offset in representation */
           rs->current += window_len;
 
-          /* Construct the cachable raw window object. */
+          /* Construct the cacheable raw window object. */
           window.end_offset = rs->current;
           window.window.len = window_len;
           window.window.data = buf;

Modified: subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/dump-index.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/dump-index.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/dump-index.c (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/dump-index.c Fri Jan 14 14:01:45 2022
@@ -21,8 +21,8 @@
  */
 
 #include "svn_pools.h"
-#include "private/svn_fs_fs_private.h"
 
+#include "fs_fs.h"
 #include "index.h"
 #include "rev_file.h"
 #include "util.h"

Modified: subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/fs.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/fs.c (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/fs.c Fri Jan 14 14:01:45 2022
@@ -47,6 +47,7 @@
 #include "verify.h"
 #include "svn_private_config.h"
 #include "private/svn_fs_util.h"
+#include "private/svn_fs_fs_private.h"
 
 #include "../libsvn_fs/fs-loader.h"
 
@@ -254,6 +255,83 @@ fs_set_uuid(svn_fs_t *fs,
 }
 
 
+static svn_error_t *
+fs_ioctl(svn_fs_t *fs, svn_fs_ioctl_code_t ctlcode,
+         void *input_void, void **output_p,
+         svn_cancel_func_t cancel_func,
+         void *cancel_baton,
+         apr_pool_t *result_pool,
+         apr_pool_t *scratch_pool)
+{
+  if (strcmp(ctlcode.fs_type, SVN_FS_TYPE_FSFS) == 0)
+    {
+      if (ctlcode.code == SVN_FS_FS__IOCTL_GET_STATS.code)
+        {
+          svn_fs_fs__ioctl_get_stats_input_t *input = input_void;
+          svn_fs_fs__ioctl_get_stats_output_t *output;
+
+          output = apr_pcalloc(result_pool, sizeof(*output));
+          SVN_ERR(svn_fs_fs__get_stats(&output->stats, fs,
+                                       input->progress_func,
+                                       input->progress_baton,
+                                       cancel_func, cancel_baton,
+                                       result_pool, scratch_pool));
+          *output_p = output;
+          return SVN_NO_ERROR;
+        }
+      else if (ctlcode.code == SVN_FS_FS__IOCTL_DUMP_INDEX.code)
+        {
+          svn_fs_fs__ioctl_dump_index_input_t *input = input_void;
+
+          SVN_ERR(svn_fs_fs__dump_index(fs, input->revision,
+                                        input->callback_func,
+                                        input->callback_baton,
+                                        cancel_func, cancel_baton,
+                                        scratch_pool));
+          *output_p = NULL;
+          return SVN_NO_ERROR;
+        }
+      else if (ctlcode.code == SVN_FS_FS__IOCTL_LOAD_INDEX.code)
+        {
+          svn_fs_fs__ioctl_load_index_input_t *input = input_void;
+
+          SVN_ERR(svn_fs_fs__load_index(fs, input->revision, input->entries,
+                                        scratch_pool));
+          *output_p = NULL;
+          return SVN_NO_ERROR;
+        }
+      else if (ctlcode.code == SVN_FS_FS__IOCTL_REVISION_SIZE.code)
+        {
+          svn_fs_fs__ioctl_revision_size_input_t *input = input_void;
+          svn_fs_fs__ioctl_revision_size_output_t *output
+            = apr_pcalloc(result_pool, sizeof(*output));
+
+          SVN_ERR(svn_fs_fs__revision_size(&output->rev_size,
+                                           fs, input->revision,
+                                           scratch_pool));
+          *output_p = output;
+          return SVN_NO_ERROR;
+        }
+      else if (ctlcode.code == SVN_FS_FS__IOCTL_BUILD_REP_CACHE.code)
+        {
+          svn_fs_fs__ioctl_build_rep_cache_input_t *input = input_void;
+
+          SVN_ERR(svn_fs_fs__build_rep_cache(fs,
+                                             input->start_rev,
+                                             input->end_rev,
+                                             input->progress_func,
+                                             input->progress_baton,
+                                             cancel_func,
+                                             cancel_baton,
+                                             scratch_pool));
+
+          *output_p = NULL;
+          return SVN_NO_ERROR;
+        }
+    }
+
+  return svn_error_create(SVN_ERR_FS_UNRECOGNIZED_IOCTL_CODE, NULL, NULL);
+}
 
 /* The vtable associated with a specific open filesystem. */
 static fs_vtable_t fs_vtable = {
@@ -279,7 +357,8 @@ static fs_vtable_t fs_vtable = {
   fs_info,
   svn_fs_fs__verify_root,
   fs_freeze,
-  fs_set_errcall
+  fs_set_errcall,
+  fs_ioctl
 };
 
 
@@ -602,7 +681,8 @@ static fs_library_vtable_t library_vtabl
   fs_logfiles,
   NULL /* parse_id */,
   fs_set_svn_fs_open,
-  fs_info_dup
+  fs_info_dup,
+  NULL /* ioctl */
 };
 
 svn_error_t *

Modified: subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/fs_fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/fs_fs.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/fs_fs.c (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/fs_fs.c Fri Jan 14 14:01:45 2022
@@ -37,6 +37,7 @@
 #include "cached_data.h"
 #include "id.h"
 #include "index.h"
+#include "low_level.h"
 #include "rep-cache.h"
 #include "revprops.h"
 #include "transaction.h"
@@ -2343,3 +2344,181 @@ svn_fs_fs__info_config_files(apr_array_h
                                                          result_pool);
   return SVN_NO_ERROR;
 }
+
+/* If no SHA1 checksum is stored in REP->SHA1_DIGEST yet, compute the
+ * SHA1 checksum and fill it in. Use POOL for temporary allocations. */
+static svn_error_t *
+ensure_representation_sha1(svn_fs_t *fs,
+                           representation_t *rep,
+                           apr_pool_t *pool)
+{
+  if (!rep->has_sha1)
+    {
+      svn_stream_t *contents;
+      svn_checksum_t *checksum;
+
+      SVN_ERR(svn_fs_fs__get_contents(&contents, fs, rep, FALSE, pool));
+      SVN_ERR(svn_stream_contents_checksum(&checksum, contents,
+                                           svn_checksum_sha1, pool, pool));
+
+      memcpy(rep->sha1_digest, checksum->digest, APR_SHA1_DIGESTSIZE);
+      rep->has_sha1 = TRUE;
+    }
+
+  return SVN_NO_ERROR;
+}
+
+/* Recursively index (in the rep-cache) the filesystem node with the
+ * given ID, located in revision REV and its matching REV_FILE (if the
+ * node ID cannot be found in this revision, do nothing).
+ * Compute the SHA1 checksum of the node's representation and add
+ * a corresponding entry to the repository's rep-cache.
+ * If the node represents a directory this function will recurse and
+ * index all children of this directory as well. */
+static svn_error_t *
+reindex_node(svn_fs_t *fs,
+             const svn_fs_id_t *id,
+             svn_revnum_t rev,
+             svn_fs_fs__revision_file_t *rev_file,
+             svn_cancel_func_t cancel_func,
+             void *cancel_baton,
+             apr_pool_t *pool)
+{
+  node_revision_t *noderev;
+  apr_off_t offset;
+
+  if (svn_fs_fs__id_rev(id) != rev)
+    {
+      return SVN_NO_ERROR;
+    }
+
+  if (cancel_func)
+    SVN_ERR(cancel_func(cancel_baton));
+
+  SVN_ERR(svn_fs_fs__item_offset(&offset, fs, rev_file, rev, NULL,
+                                 svn_fs_fs__id_item(id), pool));
+
+  SVN_ERR(svn_io_file_seek(rev_file->file, APR_SET, &offset, pool));
+  SVN_ERR(svn_fs_fs__read_noderev(&noderev, rev_file->stream,
+                                  pool, pool));
+
+  /* Make sure EXPANDED_SIZE has the correct value for every rep. */
+  SVN_ERR(svn_fs_fs__fixup_expanded_size(fs, noderev->data_rep, pool));
+  SVN_ERR(svn_fs_fs__fixup_expanded_size(fs, noderev->prop_rep, pool));
+
+  /* First reindex sub-directory to match write_final_rev() behavior. */
+  if (noderev->kind == svn_node_dir)
+    {
+      apr_array_header_t *entries;
+
+      SVN_ERR(svn_fs_fs__rep_contents_dir(&entries, fs, noderev, pool, pool));
+
+      if (entries->nelts > 0)
+        {
+          int i;
+          apr_pool_t *iterpool;
+
+          iterpool = svn_pool_create(pool);
+          for (i = 0; i < entries->nelts; i++)
+            {
+              const svn_fs_dirent_t *dirent;
+
+              svn_pool_clear(iterpool);
+
+              dirent = APR_ARRAY_IDX(entries, i, svn_fs_dirent_t *);
+
+              SVN_ERR(reindex_node(fs, dirent->id, rev, rev_file,
+                                   cancel_func, cancel_baton, iterpool));
+            }
+          svn_pool_destroy(iterpool);
+        }
+    }
+
+  if (noderev->data_rep && noderev->data_rep->revision == rev &&
+      noderev->kind == svn_node_file)
+    {
+      SVN_ERR(ensure_representation_sha1(fs, noderev->data_rep, pool));
+      SVN_ERR(svn_fs_fs__set_rep_reference(fs, noderev->data_rep, pool));
+    }
+
+  if (noderev->prop_rep && noderev->prop_rep->revision == rev)
+    {
+      SVN_ERR(ensure_representation_sha1(fs, noderev->prop_rep, pool));
+      SVN_ERR(svn_fs_fs__set_rep_reference(fs, noderev->prop_rep, pool));
+    }
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_fs_fs__build_rep_cache(svn_fs_t *fs,
+                           svn_revnum_t start_rev,
+                           svn_revnum_t end_rev,
+                           svn_fs_progress_notify_func_t progress_func,
+                           void *progress_baton,
+                           svn_cancel_func_t cancel_func,
+                           void *cancel_baton,
+                           apr_pool_t *pool)
+{
+  fs_fs_data_t *ffd = fs->fsap_data;
+  apr_pool_t *iterpool;
+  svn_revnum_t rev;
+
+  if (ffd->format < SVN_FS_FS__MIN_REP_SHARING_FORMAT)
+    {
+      return svn_error_createf(SVN_ERR_FS_REP_SHARING_NOT_SUPPORTED, NULL,
+                               _("FSFS format (%d) too old for rep-sharing; "
+                                 "please upgrade the filesystem."),
+                               ffd->format);
+    }
+
+  if (!ffd->rep_sharing_allowed)
+    {
+      return svn_error_create(SVN_ERR_FS_REP_SHARING_NOT_ALLOWED, NULL,
+                              _("Filesystem does not allow rep-sharing."));
+    }
+
+  /* Do not build rep-cache for revision zero to match
+   * svn_fs_fs__create() behavior. */
+  if (start_rev == SVN_INVALID_REVNUM)
+    start_rev = 1;
+
+  if (end_rev == SVN_INVALID_REVNUM)
+    SVN_ERR(svn_fs_fs__youngest_rev(&end_rev, fs, pool));
+
+  /* Do nothing for empty FS. */
+  if (start_rev > end_rev)
+    {
+      return SVN_NO_ERROR;
+    }
+
+  if (!ffd->rep_cache_db)
+    SVN_ERR(svn_fs_fs__open_rep_cache(fs, pool));
+
+  iterpool = svn_pool_create(pool);
+  for (rev = start_rev; rev <= end_rev; rev++)
+    {
+      svn_fs_id_t *root_id;
+      svn_fs_fs__revision_file_t *file;
+      svn_error_t *err;
+
+      svn_pool_clear(iterpool);
+
+      if (progress_func)
+        progress_func(rev, progress_baton, iterpool);
+
+      SVN_ERR(svn_fs_fs__open_pack_or_rev_file(&file, fs, rev,
+                                               iterpool, iterpool));
+      SVN_ERR(svn_fs_fs__rev_get_root(&root_id, fs, rev, iterpool, iterpool));
+
+      SVN_ERR(svn_sqlite__begin_transaction(ffd->rep_cache_db));
+      err = reindex_node(fs, root_id, rev, file, cancel_func, cancel_baton, iterpool);
+      SVN_ERR(svn_sqlite__finish_transaction(ffd->rep_cache_db, err));
+
+      SVN_ERR(svn_fs_fs__close_revision_file(file));
+    }
+
+  svn_pool_destroy(iterpool);
+
+  return SVN_NO_ERROR;
+}

Modified: subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/fs_fs.h
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/fs_fs.h?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/fs_fs.h (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/fs_fs.h Fri Jan 14 14:01:45 2022
@@ -304,4 +304,75 @@ svn_fs_fs__initialize_txn_caches(svn_fs_
 void
 svn_fs_fs__reset_txn_caches(svn_fs_t *fs);
 
+/* Scan all contents of the repository FS and return statistics in *STATS,
+ * allocated in RESULT_POOL.  Report progress through PROGRESS_FUNC with
+ * PROGRESS_BATON, if PROGRESS_FUNC is not NULL.
+ * Use SCRATCH_POOL for temporary allocations.
+ */
+svn_error_t *
+svn_fs_fs__get_stats(svn_fs_fs__stats_t **stats,
+                     svn_fs_t *fs,
+                     svn_fs_progress_notify_func_t progress_func,
+                     void *progress_baton,
+                     svn_cancel_func_t cancel_func,
+                     void *cancel_baton,
+                     apr_pool_t *result_pool,
+                     apr_pool_t *scratch_pool);
+
+/* Read the P2L index for the rev / pack file containing REVISION in FS.
+ * For each index entry, invoke CALLBACK_FUNC with CALLBACK_BATON.
+ * If not NULL, call CANCEL_FUNC with CANCEL_BATON from time to time.
+ * Use SCRATCH_POOL for temporary allocations.
+ */
+svn_error_t *
+svn_fs_fs__dump_index(svn_fs_t *fs,
+                      svn_revnum_t revision,
+                      svn_fs_fs__dump_index_func_t callback_func,
+                      void *callback_baton,
+                      svn_cancel_func_t cancel_func,
+                      void *cancel_baton,
+                      apr_pool_t *scratch_pool);
+
+
+/* Rewrite the respective index information of the rev / pack file in FS
+ * containing REVISION and use the svn_fs_fs__p2l_entry_t * array ENTRIES
+ * as the new index contents.  Allocate temporaries from SCRATCH_POOL.
+ *
+ * Note that this becomes a no-op if ENTRIES is empty.  You may use a zero-
+ * sized empty entry instead.
+ */
+svn_error_t *
+svn_fs_fs__load_index(svn_fs_t *fs,
+                      svn_revnum_t revision,
+                      apr_array_header_t *entries,
+                      apr_pool_t *scratch_pool);
+
+/* Set *REV_SIZE to the total size of objects belonging to revision REVISION
+ * in FS. The size includes revision properties and excludes indexes.
+ */
+svn_error_t *
+svn_fs_fs__revision_size(apr_off_t *rev_size,
+                         svn_fs_t *fs,
+                         svn_revnum_t revision,
+                         apr_pool_t *scratch_pool);
+
+/* Add missing entries to the rep-cache on the filesystem FS. Process data
+ * in revisions START_REV through END_REV inclusive. If START_REV is
+ * SVN_INVALID_REVNUM, start at revision 1; if END_REV is SVN_INVALID_REVNUM,
+ * end at the head revision. If the rep-cache does not exist, then create it.
+ *
+ * Indicate progress via the optional PROGRESS_FUNC callback using
+ * PROGRESS_BATON. The optional CANCEL_FUNC will periodically be called with
+ * CANCEL_BATON to allow cancellation. Use POOL for temporary allocations.
+ */
+svn_error_t *
+svn_fs_fs__build_rep_cache(svn_fs_t *fs,
+                           svn_revnum_t start_rev,
+                           svn_revnum_t end_rev,
+                           svn_fs_progress_notify_func_t progress_func,
+                           void *progress_baton,
+                           svn_cancel_func_t cancel_func,
+                           void *cancel_baton,
+                           apr_pool_t *pool);
+
 #endif

Modified: subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/hotcopy.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/hotcopy.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/hotcopy.c (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/hotcopy.c Fri Jan 14 14:01:45 2022
@@ -922,7 +922,7 @@ hotcopy_body(void *baton, apr_pool_t *po
     SVN_ERR(cancel_func(cancel_baton));
 
   /* Split the logic for new and old FS formats. The latter is much simpler
-   * due to the absense of sharding and packing. However, it requires special
+   * due to the absence of sharding and packing. However, it requires special
    * care when updating the 'current' file (which contains not just the
    * revision number, but also the next-ID counters). */
   if (src_ffd->format >= SVN_FS_FS__MIN_NO_GLOBAL_IDS_FORMAT)

Modified: subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/index.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/index.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/index.c (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/index.c Fri Jan 14 14:01:45 2022
@@ -827,7 +827,7 @@ svn_fs_fs__l2p_index_append(svn_checksum
                                               &eof, local_pool));
 
       /* handle new revision */
-      if ((entry > 0 && proto_entry.offset == 0) || eof)
+      if (eof || (entry > 0 && proto_entry.offset == 0))
         {
           /* dump entries, grouped into pages */
 
@@ -2522,8 +2522,8 @@ get_p2l_page(apr_array_header_t **entrie
  * MIN_OFFSET.  Set *END to TRUE if the caller should stop refeching.
  *
  * *BATON will be updated with the selected page's info and SCRATCH_POOL
- * will be used for temporary allocations.  If the data is alread in the
- * cache, descrease *LEAKING_BUCKET and increase it otherwise.  With that
+ * will be used for temporary allocations.  If the data is already in the
+ * cache, decrease *LEAKING_BUCKET and increase it otherwise.  With that
  * pattern we will still read all pages from the block even if some of
  * them survived in the cached.
  */
@@ -2681,7 +2681,7 @@ append_p2l_entries(apr_array_header_t *e
     }
 }
 
-/* Auxilliary struct passed to p2l_entries_func selecting the relevant
+/* Auxiliary struct passed to p2l_entries_func selecting the relevant
  * data range. */
 typedef struct p2l_entries_baton_t
 {

Modified: subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/load-index.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/load-index.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/load-index.c (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/load-index.c Fri Jan 14 14:01:45 2022
@@ -22,9 +22,9 @@
 
 #include "svn_pools.h"
 
-#include "private/svn_fs_fs_private.h"
 #include "private/svn_sorts_private.h"
 
+#include "fs_fs.h"
 #include "index.h"
 #include "util.h"
 #include "transaction.h"

Modified: subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/low_level.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/low_level.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/low_level.c (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/low_level.c Fri Jan 14 14:01:45 2022
@@ -248,16 +248,16 @@ svn_fs_fs__parse_footer(apr_off_t *l2p_o
                             rev));
   *p2l_offset = (apr_off_t)val;
 
-  /* The P2L indes follows the L2P index */
+  /* The P2L index follows the L2P index */
   if (*p2l_offset <= *l2p_offset)
     return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
                              "P2L offset %s must be larger than L2P offset %s"
                              " in r%ld footer",
                              apr_psprintf(result_pool,
-                                          "%" APR_UINT64_T_HEX_FMT,
+                                          "0x%" APR_UINT64_T_HEX_FMT,
                                           (apr_uint64_t)*p2l_offset),
                              apr_psprintf(result_pool,
-                                          "%" APR_UINT64_T_HEX_FMT,
+                                          "0x%" APR_UINT64_T_HEX_FMT,
                                           (apr_uint64_t)*l2p_offset),
                              rev);
 
@@ -506,7 +506,7 @@ svn_fs_fs__read_changes(apr_array_header
       SVN_ERR(read_change(&change, stream, result_pool, iterpool));
       if (!change)
         break;
- 
+
       APR_ARRAY_PUSH(*changes, change_t*) = change;
     }
   svn_pool_destroy(iterpool);

Modified: subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/pack.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/pack.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/pack.c (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/pack.c Fri Jan 14 14:01:45 2022
@@ -315,12 +315,12 @@ initialize_pack_context(pack_context_t *
   context->file_props = apr_array_make(pool, max_items,
                                        sizeof(svn_fs_fs__p2l_entry_t *));
   SVN_ERR(svn_io_open_unique_file3(&context->file_props_file, NULL, temp_dir,
-                                   svn_io_file_del_on_close, 
+                                   svn_io_file_del_on_close,
                                    context->info_pool, pool));
   context->dir_props = apr_array_make(pool, max_items,
                                       sizeof(svn_fs_fs__p2l_entry_t *));
   SVN_ERR(svn_io_open_unique_file3(&context->dir_props_file, NULL, temp_dir,
-                                   svn_io_file_del_on_close, 
+                                   svn_io_file_del_on_close,
                                    context->info_pool, pool));
 
   /* noderev and representation item bucket */
@@ -1701,7 +1701,7 @@ svn_fs_fs__get_packed_offset(apr_off_t *
   return svn_cache__set(ffd->packed_offset_cache, &shard, manifest, pool);
 }
 
-/* Packing logic for physical addresssing mode:
+/* Packing logic for physical addressing mode:
  * Simply concatenate all revision contents.
  *
  * Pack the revision shard starting at SHARD_REV containing exactly

Modified: subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/rep-cache-db.sql
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/rep-cache-db.sql?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/rep-cache-db.sql (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/rep-cache-db.sql Fri Jan 14 14:01:45 2022
@@ -61,7 +61,7 @@ WHERE hash = ?1
 
 -- STMT_SET_REP
 /* Works for both V1 and V2 schemas. */
-INSERT OR FAIL INTO rep_cache (hash, revision, offset, size, expanded_size)
+INSERT OR IGNORE INTO rep_cache (hash, revision, offset, size, expanded_size)
 VALUES (?1, ?2, ?3, ?4, ?5)
 
 -- STMT_GET_REPS_FOR_RANGE

Modified: subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/rep-cache.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/rep-cache.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/rep-cache.c (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/rep-cache.c Fri Jan 14 14:01:45 2022
@@ -328,7 +328,6 @@ svn_fs_fs__set_rep_reference(svn_fs_t *f
 {
   fs_fs_data_t *ffd = fs->fsap_data;
   svn_sqlite__stmt_t *stmt;
-  svn_error_t *err;
   svn_checksum_t checksum;
   checksum.kind = svn_checksum_sha1;
   checksum.digest = rep->sha1_digest;
@@ -351,28 +350,7 @@ svn_fs_fs__set_rep_reference(svn_fs_t *f
                             (apr_int64_t) rep->size,
                             (apr_int64_t) rep->expanded_size));
 
-  err = svn_sqlite__insert(NULL, stmt);
-  if (err)
-    {
-      representation_t *old_rep;
-
-      if (err->apr_err != SVN_ERR_SQLITE_CONSTRAINT)
-        return svn_error_trace(err);
-
-      svn_error_clear(err);
-
-      /* Constraint failed so the mapping for SHA1_CHECKSUM->REP
-         should exist.  If so that's cool -- just do nothing.  If not,
-         that's a red flag!  */
-      SVN_ERR(svn_fs_fs__get_rep_reference(&old_rep, fs, &checksum, pool));
-
-      if (!old_rep)
-        {
-          /* Something really odd at this point, we failed to insert the
-             checksum AND failed to read an existing checksum.  Do we need
-             to flag this? */
-        }
-    }
+  SVN_ERR(svn_sqlite__insert(NULL, stmt));
 
   return SVN_NO_ERROR;
 }

Modified: subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/revprops.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/revprops.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/revprops.c (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/revprops.c Fri Jan 14 14:01:45 2022
@@ -261,7 +261,7 @@ cache_revprops(svn_boolean_t *is_cached,
 }
 
 /* Read the non-packed revprops for revision REV in FS, put them into the
- * revprop cache if PROPULATE_CACHE is set and return them in *PROPERTIES. 
+ * revprop cache if PROPULATE_CACHE is set and return them in *PROPERTIES.
  *
  * If the data could not be read due to an otherwise recoverable error,
  * leave *PROPERTIES unchanged. No error will be returned in that case.
@@ -671,6 +671,64 @@ read_pack_revprop(packed_revprops_t **re
 
   return SVN_NO_ERROR;
 }
+
+svn_error_t *
+svn_fs_fs__get_revision_props_size(apr_off_t *props_size_p,
+                                   svn_fs_t *fs,
+                                   svn_revnum_t rev,
+                                   apr_pool_t *scratch_pool)
+{
+  fs_fs_data_t *ffd = fs->fsap_data;
+
+  /* should they be available at all? */
+  SVN_ERR(svn_fs_fs__ensure_revision_exists(rev, fs, scratch_pool));
+
+  /* if REV had not been packed when we began, try reading it from the
+   * non-packed shard.  If that fails, we will fall through to packed
+   * shard reads. */
+  if (!svn_fs_fs__is_packed_revprop(fs, rev))
+    {
+      const char *path = svn_fs_fs__path_revprops(fs, rev, scratch_pool);
+      svn_error_t *err;
+      apr_file_t *file;
+      svn_filesize_t file_size;
+
+      err = svn_io_file_open(&file, path, APR_FOPEN_READ, APR_OS_DEFAULT,
+                             scratch_pool);
+      if (!err)
+        err = svn_io_file_size_get(&file_size, file, scratch_pool);
+      if (!err)
+        {
+          *props_size_p = (apr_off_t)file_size;
+          return SVN_NO_ERROR;
+        }
+      else if (!APR_STATUS_IS_ENOENT(err->apr_err)
+               || ffd->format < SVN_FS_FS__MIN_PACKED_REVPROP_FORMAT)
+        {
+          return svn_error_trace(err);
+        }
+
+      /* fall through: maybe the revision got packed while we were looking */
+      svn_error_clear(err);
+    }
+
+  /* Try reading packed revprops.  If that fails, REV is most
+   * likely invalid (or its revprops highly contested). */
+  {
+    packed_revprops_t *revprops;
+
+    /* ### This is inefficient -- reading all the revprops in a pack. We
+       should just read the index. */
+    SVN_ERR(read_pack_revprop(&revprops, fs, rev,
+                              TRUE /*read_all*/, FALSE /*populate_cache*/,
+                              scratch_pool));
+    *props_size_p = (apr_off_t)APR_ARRAY_IDX(revprops->sizes,
+                                             rev - revprops->start_revision,
+                                             apr_size_t);
+  }
+
+  return SVN_NO_ERROR;
+}
 
 /* Read the revprops for revision REV in FS and return them in *PROPERTIES_P.
  *

Modified: subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/revprops.h
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/revprops.h?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/revprops.h (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/revprops.h Fri Jan 14 14:01:45 2022
@@ -62,6 +62,15 @@ svn_fs_fs__upgrade_cleanup_pack_revprops
 void
 svn_fs_fs__reset_revprop_cache(svn_fs_t *fs);
 
+/* Set *PROPS_SIZE_P to the size in bytes on disk of the revprops for
+ * revision REV in FS. The size excludes indexes.
+ */
+svn_error_t *
+svn_fs_fs__get_revision_props_size(apr_off_t *props_size_p,
+                                   svn_fs_t *fs,
+                                   svn_revnum_t rev,
+                                   apr_pool_t *scratch_pool);
+
 /* Read the revprops for revision REV in FS and return them in *PROPERTIES_P.
  * If REFRESH is set, clear the revprop cache before accessing the data.
  *

Modified: subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/stats.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/stats.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/stats.c (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/stats.c Fri Jan 14 14:01:45 2022
@@ -28,7 +28,6 @@
 #include "private/svn_cache.h"
 #include "private/svn_sorts_private.h"
 #include "private/svn_string_private.h"
-#include "private/svn_fs_fs_private.h"
 
 #include "index.h"
 #include "pack.h"
@@ -37,6 +36,7 @@
 #include "fs_fs.h"
 #include "cached_data.h"
 #include "low_level.h"
+#include "revprops.h"
 
 #include "../libsvn_fs/fs-loader.h"
 
@@ -488,7 +488,7 @@ parse_representation(rep_stats_t **repre
             }
         }
 
-      svn_sort__array_insert(revision_info->representations, &result, idx);
+      SVN_ERR(svn_sort__array_insert2(revision_info->representations, &result, idx));
     }
 
   *representation = result;
@@ -1397,3 +1397,96 @@ svn_fs_fs__get_stats(svn_fs_fs__stats_t
 
   return SVN_NO_ERROR;
 }
+
+/* Baton for rev_size_index_entry_cb. */
+struct rev_size_baton_t {
+  svn_revnum_t revision;
+  apr_off_t rev_size;
+};
+
+/* Implements svn_fs_fs__dump_index_func_t, summing object sizes for
+ * revision BATON->revision into BATON->rev_size.
+ */
+static svn_error_t *
+rev_size_index_entry_cb(const svn_fs_fs__p2l_entry_t *entry,
+                        void *baton,
+                        apr_pool_t *scratch_pool)
+{
+  struct rev_size_baton_t *b = baton;
+
+  if (entry->item.revision == b->revision)
+    b->rev_size += entry->size;
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_fs_fs__revision_size(apr_off_t *rev_size,
+                         svn_fs_t *fs,
+                         svn_revnum_t revision,
+                         apr_pool_t *scratch_pool)
+{
+  /* Get the size of the revision (excluding rev-props) */
+  if (svn_fs_fs__use_log_addressing(fs))
+    {
+      /* This works for a packed or a non-packed revision.
+         We could provide an optimized case for a non-packed revision
+         using svn_fs_fs__p2l_get_max_offset(). */
+      struct rev_size_baton_t b = { 0, 0 };
+
+      b.revision = revision;
+      SVN_ERR(svn_fs_fs__dump_index(fs, revision,
+                                    rev_size_index_entry_cb, &b,
+                                    NULL, NULL, scratch_pool));
+      *rev_size = b.rev_size;
+    }
+  else
+    {
+      svn_fs_fs__revision_file_t *rev_file;
+      svn_revnum_t min_unpacked_rev;
+
+      SVN_ERR(svn_fs_fs__open_pack_or_rev_file(&rev_file, fs, revision,
+                                               scratch_pool, scratch_pool));
+      SVN_ERR(svn_fs_fs__min_unpacked_rev(&min_unpacked_rev, fs,
+                                          scratch_pool));
+      if (revision < min_unpacked_rev)
+        {
+          int shard_size = svn_fs_fs__shard_size(fs);
+          apr_off_t start_offset, end_offset;
+
+          SVN_ERR(svn_fs_fs__get_packed_offset(&start_offset, fs, revision,
+                                               scratch_pool));
+          if (((revision + 1) % shard_size) == 0)
+            {
+              svn_filesize_t file_size;
+
+              SVN_ERR(svn_io_file_size_get(&file_size, rev_file->file, scratch_pool));
+              end_offset = (apr_off_t)file_size;
+            }
+          else
+            {
+              SVN_ERR(svn_fs_fs__get_packed_offset(&end_offset, fs,
+                                                   revision + 1, scratch_pool));
+            }
+          *rev_size = (end_offset - start_offset);
+        }
+      else
+        {
+          svn_filesize_t file_size;
+
+          SVN_ERR(svn_io_file_size_get(&file_size, rev_file->file, scratch_pool));
+          *rev_size = (apr_off_t)file_size;
+        }
+
+      SVN_ERR(svn_fs_fs__close_revision_file(rev_file));
+    }
+
+  /* Add the size of the rev-props */
+  {
+    apr_off_t size;
+
+    SVN_ERR(svn_fs_fs__get_revision_props_size(&size, fs, revision, scratch_pool));
+    *rev_size += size;
+  }
+
+  return SVN_NO_ERROR;
+}

Modified: subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/structure
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/structure?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/structure (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/structure Fri Jan 14 14:01:45 2022
@@ -118,7 +118,7 @@ representation checksum and location map
 hash text as the primary key, mapped to the representation revision, offset,
 size and expanded size.  This file is only consulted during writes and never
 during reads.  Consequently, it is not required, and may be removed at an
-abritrary time, with the subsequent loss of rep-sharing capabilities for
+arbitrary time, with the subsequent loss of rep-sharing capabilities for
 revisions written thereafter.
 
 Filesystem formats

Modified: subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/temp_serializer.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/temp_serializer.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/temp_serializer.c (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/temp_serializer.c Fri Jan 14 14:01:45 2022
@@ -38,7 +38,7 @@
 #include "cached_data.h"
 
 /* Utility to encode a signed NUMBER into a variable-length sequence of
- * 8-bit chars in KEY_BUFFER and return the last writen position.
+ * 8-bit chars in KEY_BUFFER and return the last written position.
  *
  * Numbers will be stored in 7 bits / byte and using byte values above
  * 32 (' ') to make them combinable with other string by simply separating
@@ -1013,13 +1013,13 @@ slowly_replace_dir_entry(void **data,
         APR_ARRAY_IDX(entries, idx, svn_fs_dirent_t *)
           = replace_baton->new_entry;
       else
-        svn_sort__array_insert(entries, &replace_baton->new_entry, idx);
+        SVN_ERR(svn_sort__array_insert2(entries, &replace_baton->new_entry, idx));
     }
   else
     {
       /* Remove the old ENTRY. */
       if (entry)
-        svn_sort__array_delete(entries, idx, 1);
+        SVN_ERR(svn_sort__array_delete2(entries, idx, 1));
     }
 
   return svn_fs_fs__serialize_dir_entries(data, data_len, dir, pool);

Modified: subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/transaction.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/transaction.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/transaction.c (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/transaction.c Fri Jan 14 14:01:45 2022
@@ -587,7 +587,7 @@ unparse_dir_entry(svn_fs_dirent_t *diren
                       : sizeof(SVN_FS_FS__KIND_DIR);
   apr_size_t value_len = type_len + id_str->len;
 
-  /* A buffer with sufficient space for 
+  /* A buffer with sufficient space for
    * - both string lines
    * - 4 newlines
    * - 2 lines K/V lines containing a number each
@@ -3713,7 +3713,7 @@ promote_cached_directories(svn_fs_t *fs,
 
       /* Currently, the entry for KEY - if it still exists - is marked
        * as "stale" and would not be used.  Mark it as current for in-
-       * revison data. */
+       * revision data. */
       SVN_ERR(svn_cache__set_partial(ffd->dir_cache, key,
                                      svn_fs_fs__reset_txn_filesize, NULL,
                                      iterpool));

Modified: subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/tree.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/tree.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/tree.c (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/tree.c Fri Jan 14 14:01:45 2022
@@ -920,6 +920,25 @@ try_match_last_node(dag_node_t **node_p,
   return SVN_NO_ERROR;
 }
 
+/* Helper for open_path() that constructs and returns an appropriate
+   SVN_ERR_FS_NOT_DIRECTORY error. */
+static svn_error_t *
+err_not_directory(svn_fs_root_t *root,
+                  const char *path,
+                  apr_pool_t *scratch_pool)
+{
+  const char *msg;
+
+  msg = root->is_txn_root
+      ? apr_psprintf(scratch_pool,
+                     _("Failure opening '%s' in transaction '%s'"),
+                     path, root->txn)
+      : apr_psprintf(scratch_pool,
+                     _("Failure opening '%s' in revision %ld"),
+                     path, root->rev);
+
+  return svn_error_quick_wrap(SVN_FS__ERR_NOT_DIRECTORY(root->fs, path), msg);
+}
 
 /* Open the node identified by PATH in ROOT, allocating in POOL.  Set
    *PARENT_PATH_P to a path from the node up to ROOT.  The resulting
@@ -1016,12 +1035,26 @@ open_path(parent_path_t **parent_path_p,
           SVN_ERR(dag_node_cache_get(&here, root, directory, pool));
 
           /* Did the shortcut work? */
-          if (here)
+          if (here && svn_fs_fs__dag_node_kind(here) == svn_node_dir)
             {
               apr_size_t dirname_len = strlen(directory);
               path_so_far->len = dirname_len;
               rest = path + dirname_len + 1;
             }
+          else if (here)
+            {
+              /* The parent node is not a directory.  We are looking for some
+                 sub-path, so that sub-path will not exist.  That will be o.k.
+                 if we are just here to check for the path's existence, but
+                 should result in an error otherwise. */
+              if (flags & open_path_allow_null)
+                {
+                  *parent_path_p = NULL;
+                  return SVN_NO_ERROR;
+                }
+              else
+                return svn_error_trace(err_not_directory(root, directory, pool));
+            }
         }
     }
 
@@ -1144,8 +1177,6 @@ open_path(parent_path_t **parent_path_p,
       /* The path isn't finished yet; we'd better be in a directory.  */
       if (svn_fs_fs__dag_node_kind(child) != svn_node_dir)
         {
-          const char *msg;
-
           /* Since this is not a directory and we are looking for some
              sub-path, that sub-path will not exist.  That will be o.k.,
              if we are just here to check for the path's existence. */
@@ -1156,14 +1187,8 @@ open_path(parent_path_t **parent_path_p,
             }
 
           /* It's really a problem ... */
-          msg = root->is_txn_root
-              ? apr_psprintf(iterpool,
-                             _("Failure opening '%s' in transaction '%s'"),
-                             path, root->txn)
-              : apr_psprintf(iterpool,
-                             _("Failure opening '%s' in revision %ld"),
-                             path, root->rev);
-          SVN_ERR_W(SVN_FS__ERR_NOT_DIRECTORY(fs, path_so_far->data), msg);
+          return svn_error_trace(
+                   err_not_directory(root, path_so_far->data, iterpool));
         }
 
       rest = next;
@@ -3123,7 +3148,7 @@ struct text_baton_t
  * svn_fs_apply_text()      ==> ... ==> txn_body_fulltext_finalize_edits()
  */
 
-/* Write function for the publically returned stream. */
+/* Write function for the publicly returned stream. */
 static svn_error_t *
 text_stream_writer(void *baton,
                    const char *data,
@@ -3135,7 +3160,7 @@ text_stream_writer(void *baton,
   return svn_stream_write(tb->file_stream, data, len);
 }
 
-/* Close function for the publically returned stream. */
+/* Close function for the publicly returned stream. */
 static svn_error_t *
 text_stream_closer(void *baton)
 {
@@ -4619,7 +4644,7 @@ make_txn_root(svn_fs_root_t **root_p,
                                       svn_fs_fs__dag_deserialize,
                                       APR_HASH_KEY_STRING,
                                       32, 20, FALSE,
-                                      apr_pstrcat(pool, txn, ":TXN",
+                                      apr_pstrcat(pool, root->txn, ":TXN",
                                                   SVN_VA_NULL),
                                       root->pool));
 

Modified: subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/util.h
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/util.h?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/util.h (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_fs_fs/util.h Fri Jan 14 14:01:45 2022
@@ -316,7 +316,7 @@ svn_error_t *
 svn_fs_fs__update_min_unpacked_rev(svn_fs_t *fs,
                                    apr_pool_t *pool);
 
-/* Atomically update the 'min-unpacked-rev' file in FS to hold the specifed
+/* Atomically update the 'min-unpacked-rev' file in FS to hold the specified
  * REVNUM.  Perform temporary allocations in SCRATCH_POOL.
  */
 svn_error_t *
@@ -336,7 +336,7 @@ svn_fs_fs__read_current(svn_revnum_t *re
                         svn_fs_t *fs,
                         apr_pool_t *pool);
 
-/* Atomically update the 'current' file to hold the specifed REV,
+/* Atomically update the 'current' file to hold the specified REV,
    NEXT_NODE_ID, and NEXT_COPY_ID.  (The two next-ID parameters are
    ignored and may be 0 if the FS format does not use them.)
    Perform temporary allocations in POOL. */