Index: subversion/include/svn_repos.h
===================================================================
--- subversion/include/svn_repos.h	(revision 9955)
+++ subversion/include/svn_repos.h	(arbetskopia)
@@ -537,6 +537,24 @@
                    svn_boolean_t cross_copies,
                    apr_pool_t *pool);
 
+/** Set @a *locations to be a mapping of the revisions to the paths of
+ * the file @a fs_path present at the repository in revision
+ * @a peg_revision, where the revisions are taken out of the array
+ * @a location_revisions.
+ *
+ * @a location_revisions is an array of svn_revnum_t's and @a *locations
+ * maps svn_revnum_t's to const char *.
+ *
+ * @a pool is used for all allocations.
+ */
+svn_error_t *
+svn_repos_trace_node_locations (svn_fs_t *fs,
+                                apr_hash_t **locations,
+                                const char *fs_path,
+                                svn_revnum_t peg_revision,
+                                apr_array_header_t *location_revisions,
+                                apr_pool_t *pool);
+
 /* ### other queries we can do someday --
 
      * fetch the last revision created by <user>
Index: subversion/libsvn_repos/rev_hunt.c
===================================================================
--- subversion/libsvn_repos/rev_hunt.c	(revision 9955)
+++ subversion/libsvn_repos/rev_hunt.c	(arbetskopia)
@@ -27,7 +27,9 @@
 #include "svn_time.h"
 #include "repos.h"
 
+#include <assert.h>
 
+
 
 /* Note:  this binary search assumes that the datestamp properties on
    each revision are in chronological order.  That is if revision A >
@@ -251,4 +253,157 @@
   return SVN_NO_ERROR;
 }
 
-                             
+/* Compare revision numbers for sorting in decreasing order. */
+static int
+compare_revnums (const void *p_a, const void *p_b)
+{
+  svn_revnum_t a, b;
+  a = *(svn_revnum_t *)p_a;
+  b = *(svn_revnum_t *)p_b;
+
+  return (a < b) ? 1 : (a > b) ? -1 : 0;
+}
+
+/* The purpose of this function is to discover if fs_path@future_rev
+ * is derived from fs_path@peg_rev.  The return is placed in *is_ancestor. */
+
+static svn_error_t *
+check_ancestry_of_peg_path (svn_boolean_t *is_ancestor,
+                            svn_fs_t *fs,
+                            const char *fs_path,
+                            svn_revnum_t peg_revision,
+                            svn_revnum_t future_revision,
+                            apr_pool_t *pool)
+{
+  svn_fs_root_t *root;
+  svn_fs_history_t *history;
+  const char *path;
+  svn_revnum_t revision;
+  apr_pool_t *lastpool, *currpool;
+
+  lastpool = svn_pool_create (pool);
+  currpool = svn_pool_create (pool);
+
+  SVN_ERR (svn_fs_revision_root (&root, fs, future_revision, pool));
+
+  SVN_ERR (svn_fs_node_history (&history, root, fs_path, lastpool));
+
+  while (1)
+    {
+      apr_pool_t *tmppool;
+
+      SVN_ERR (svn_fs_history_prev (&history, history, TRUE, currpool));
+
+      if (!history)
+        break;
+
+      SVN_ERR (svn_fs_history_location (&path, &revision, history, currpool));
+
+      if (revision <= peg_revision)
+        break;
+
+      /* Clear old pool and flip. */
+      svn_pool_clear (lastpool);
+      tmppool = lastpool;
+      lastpool = currpool;
+      currpool = tmppool;
+    }
+
+  if (! history)
+    *is_ancestor = FALSE;
+  else
+    *is_ancestor = (strcmp(path, fs_path) == 0);
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_repos_trace_node_locations (svn_fs_t *fs,
+                                apr_hash_t **locations,
+                                const char *fs_path,
+                                svn_revnum_t peg_revision,
+                                apr_array_header_t *location_revisions_orig,
+                                apr_pool_t *pool)
+{
+  apr_array_header_t *location_revisions;
+  svn_revnum_t *revision_ptr, *revision_ptr_end;
+  svn_fs_root_t *root;
+  svn_fs_history_t *history;
+  const char *path;
+  svn_revnum_t revision;
+  svn_boolean_t is_ancestor;
+  apr_pool_t *lastpool, *currpool;
+
+  /* Sanity check. */
+  assert (location_revisions_orig->elt_size == sizeof(svn_revnum_t));
+
+  *locations = apr_hash_make (pool);
+
+  /* We flip between two pools in the second loop below. */
+  lastpool = svn_pool_create(pool);
+  currpool = svn_pool_create (pool);
+
+  /* First - let's sort the array of the revisions from the greatest revision
+   * downward, so it will be easier to search on. */
+  location_revisions = apr_array_copy (pool, location_revisions_orig);
+  qsort (location_revisions->elts, location_revisions->nelts,
+         sizeof (*revision_ptr), compare_revnums);
+
+  revision_ptr = (svn_revnum_t *)location_revisions->elts;
+  revision_ptr_end = revision_ptr + location_revisions->nelts;
+
+  /* Ignore revisions R that are younger than the peg_revisions where
+     path@peg_revision is not an ancestor of path@R. */
+  is_ancestor = FALSE;
+  while (revision_ptr < revision_ptr_end && *revision_ptr > peg_revision)
+    {
+      svn_pool_clear (currpool);
+      SVN_ERR (check_ancestry_of_peg_path (&is_ancestor, fs, fs_path,
+                                           peg_revision, *revision_ptr,
+                                           currpool));
+      if (is_ancestor)
+        break;
+      ++revision_ptr;
+    }
+
+  SVN_ERR (svn_fs_revision_root (&root, fs,
+                                 (is_ancestor ?
+                                  (*revision_ptr) :
+                                  peg_revision), pool));
+
+  SVN_ERR (svn_fs_node_history (&history, root, fs_path, lastpool));
+
+  while (revision_ptr < revision_ptr_end)
+    {
+      apr_pool_t *tmppool;
+
+      SVN_ERR (svn_fs_history_prev (&history, history, TRUE, currpool));
+      if (!history)
+        break;
+
+      SVN_ERR (svn_fs_history_location (&path, &revision, history, currpool));
+
+      /* Assign the current path to all younger revisions until we reach
+         the current one. */
+      while ((revision_ptr < revision_ptr_end) && (*revision_ptr >= revision))
+        {
+          /* *revision_ptr is allocated out of pool, so we can point
+             to in the hash table. */
+          apr_hash_set (*locations, revision_ptr, sizeof (*revision_ptr),
+                        apr_pstrdup (pool, path));
+          revision_ptr++;
+        }
+
+      /* Clear last pool and switch. */
+      svn_pool_clear (lastpool);
+      tmppool = lastpool;
+      lastpool = currpool;
+      currpool = tmppool;
+    }
+
+  svn_pool_destroy (lastpool);
+  svn_pool_destroy (currpool);
+
+  return SVN_NO_ERROR;
+}
+
Index: subversion/tests/libsvn_repos/repos-test.c
===================================================================
--- subversion/tests/libsvn_repos/repos-test.c	(revision 9955)
+++ subversion/tests/libsvn_repos/repos-test.c	(arbetskopia)
@@ -697,7 +697,101 @@
   return SVN_NO_ERROR;
 }
 
+
 
+struct locations_info
+{
+  svn_revnum_t rev;
+  const char *path;
+};
+
+/* Check that LOCATIONS contain everything in INFO and nothing more. */
+static svn_error_t *
+check_locations_info (apr_hash_t *locations, const struct locations_info *info)
+{
+  int i;
+  for (i = 0; info->rev != 0; ++i, ++info)
+    {
+      const char *p = apr_hash_get(locations, &info->rev, sizeof
+                                   (svn_revnum_t));
+      if (!p)
+        return svn_error_createf (SVN_ERR_TEST_FAILED, NULL,
+                                  "Missing path for revision %ld", info->rev);
+      if (strcmp (p, info->path) != 0)
+        return svn_error_createf (SVN_ERR_TEST_FAILED, NULL,
+                                  "Pth mismatch for rev %ld", info->rev);
+    }
+
+  if (apr_hash_count (locations) > i)
+    return svn_error_create (SVN_ERR_TEST_FAILED, NULL,
+                             "Returned locations contain too many elements.");
+  
+  return SVN_NO_ERROR;
+}
+
+/* Check that all locations in INFO exist in REPOS for PATH and PEG_REVISION.
+ */
+static svn_error_t *
+check_locations (svn_fs_t *fs, struct locations_info *info,
+                 const char *path, svn_revnum_t peg_revision,
+                 apr_pool_t *pool)
+{
+  apr_array_header_t *a = apr_array_make (pool, 0, sizeof (svn_revnum_t));
+  apr_hash_t *h;
+  struct locations_info *iter;
+
+  for (iter = info; iter->rev != 0; ++iter)
+    *(svn_revnum_t *) apr_array_push (a) = iter->rev;
+
+  SVN_ERR (svn_repos_trace_node_locations (fs, &h, path, peg_revision, a, pool));
+  SVN_ERR (check_locations_info (h, info));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+node_locations (const char **msg, svn_boolean_t msg_only, apr_pool_t *pool)
+{
+  apr_pool_t *subpool = svn_pool_create (pool);
+  svn_repos_t *repos;
+  svn_fs_t *fs;
+  svn_fs_txn_t *txn;
+  svn_fs_root_t *txn_root, *root;
+  svn_revnum_t youngest_rev;
+
+  *msg = "test svn_repos_node_locations";
+  if (msg_only)
+    return SVN_NO_ERROR;
+
+  /* Create the repository with a Greek tree. */
+  SVN_ERR (svn_test__create_repos (&repos, "test-repo-node-locations", pool));
+  fs = svn_repos_fs (repos);
+  SVN_ERR (svn_fs_begin_txn (&txn, fs, 0, subpool));
+  SVN_ERR (svn_fs_txn_root (&txn_root, txn, subpool));
+  SVN_ERR (svn_test__create_greek_tree (txn_root, subpool));
+  SVN_ERR (svn_repos_fs_commit_txn (NULL, repos, &youngest_rev, txn, subpool));
+  svn_pool_clear (subpool);
+
+  /* Move a file. Rev 2. */
+  SVN_ERR (svn_fs_revision_root (&root, fs, youngest_rev, subpool));
+  SVN_ERR (svn_fs_begin_txn (&txn, fs, 0, subpool));
+  SVN_ERR (svn_fs_txn_root (&txn_root, txn, subpool));
+  SVN_ERR (svn_fs_copy (root, "/A/mu", txn_root, "/mu.new", subpool));
+  SVN_ERR (svn_repos_fs_commit_txn (NULL, repos, &youngest_rev, txn, subpool));
+  {
+    struct locations_info info[] =
+      {
+        { 1, "/A/mu" },
+        { 2, "/mu.new" }
+      };
+    SVN_ERR (check_locations (fs, info, "/mu.new", 2, pool));
+  }
+  svn_pool_clear (subpool);
+  
+  return SVN_NO_ERROR;
+}
+
+
 
 /* The test table.  */
 
@@ -707,5 +801,6 @@
     SVN_TEST_PASS (dir_deltas),
     SVN_TEST_PASS (node_tree_delete_under_copy),
     SVN_TEST_PASS (revisions_changed),
+    SVN_TEST_PASS (node_locations),
     SVN_TEST_NULL
   };
