Index: build.conf
===================================================================
--- build.conf	(revision 9246)
+++ build.conf	(working copy)
@@ -629,6 +629,15 @@
 # disabled for now, BROKEN.
 testing = skip
 
+[ra-get-past-location]
+type = exe
+path = subversion/tests/libsvn_ra_local
+sources = get-past-location.c
+install = fs-test
+libs = libsvn_ra libsvn_fs libsvn_delta libsvn_subr libsvn_client
+	aprutil apriconv apr neon
+# disabled for now, BROKEN.
+testing = skip
 
 ### Tests that don't use the C framework (rewrite?) ----------
 
Index: invoke-gdb.sh
===================================================================
--- invoke-gdb.sh	(revision 0)
+++ invoke-gdb.sh	(revision 0)
@@ -0,0 +1,3 @@
+#!/bin/sh
+cd subversion/tests/clients/cmdline
+gdb --command=cmds.gdb ../../libsvn_ra_local/.libs/ra-get-past-location
Index: subversion/include/svn_fs.h
===================================================================
--- subversion/include/svn_fs.h	(revision 9246)
+++ subversion/include/svn_fs.h	(working copy)
@@ -742,8 +742,18 @@
                                       svn_revnum_t *revision,
                                       svn_fs_history_t *history,
                                       apr_pool_t *pool);
-                                      
 
+/** Set @a *locations to the location at the repository @a location_revisions
+ * of the file @a fs_path present at the repository in revision @a 
+ * peg_revision.
+ */
+svn_error_t *svn_fs_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);
+
 /** Set @a *is_dir to @c TRUE iff @a path in @a root is a directory.
  * Do any necessary temporary allocation in @a pool.
  */
Index: subversion/include/svn_ra.h
===================================================================
--- subversion/include/svn_ra.h	(revision 9246)
+++ subversion/include/svn_ra.h	(working copy)
@@ -715,6 +715,20 @@
                                   const char **url,
                                   apr_pool_t *pool);
 
+  /** Set @a *locations to the location at the repository 
+   * @a locations_revisions of the file @a url present at the repository in 
+   * revision @a peg_revision. @a *locations will be a mapping from
+   * the revisions to their appropriate URLs.
+   * 
+   * Use @a pool for temporary allocations.
+   */  
+  svn_error_t *(*get_locations) (void *session_baton,
+                                 apr_hash_t **locations,
+                                 const char *url,
+                                 svn_revnum_t peg_revision,
+                                 apr_array_header_t *location_revisions,
+                                 apr_pool_t *pool);
+
 } svn_ra_plugin_t;
 
 
Index: subversion/libsvn_fs/tree.c
===================================================================
--- subversion/libsvn_fs/tree.c	(revision 9246)
+++ subversion/libsvn_fs/tree.c	(working copy)
@@ -4293,3 +4293,193 @@
   *revision = history->revision;
   return SVN_NO_ERROR;
 }
+
+/* 
+ * Makes sure that the revision numbers are sorted in decreasing order.
+ * */
+static int compare_revnum_t (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;
+
+  if (a < b)
+    {
+      return 1;
+    }
+  else if (a > b)
+    {
+      return (-1);
+    }
+  else
+    {
+      return 0;
+    }
+}
+
+/*
+ * The purpose of this function is to discover if fs_path@future_rev
+ * is derived from fs_path@peg_rev. The return is place 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_node_kind_t kind;
+  svn_fs_history_t *history, *new_history;
+  const char *path;
+  svn_revnum_t revision;
+  
+  SVN_ERR (svn_fs_revision_root (&root, fs, future_revision, pool));
+  SVN_ERR (svn_fs_check_path (&kind, root, fs_path, pool));
+  
+  if (kind == svn_node_none)
+    {
+      *is_ancestor = FALSE;
+      return SVN_NO_ERROR;
+    }
+
+  SVN_ERR (svn_fs_node_history (&history, root, fs_path, pool));
+  SVN_ERR (svn_fs_history_location (&path, &revision, history, pool));
+  
+  while (history && (revision > peg_revision))
+    {
+      SVN_ERR (svn_fs_history_prev (&new_history, history, TRUE, pool));
+      history = new_history;
+      if (history)
+        {
+          SVN_ERR (svn_fs_history_location (&path, &revision, history, pool));
+        }
+    }
+  if (! history)
+    {
+      *is_ancestor = FALSE;
+    }
+  else
+    {
+      *is_ancestor = (!strcmp(path, fs_path));
+    }
+    
+  return SVN_NO_ERROR;
+}
+                                         
+/** Set @a *past_fs_path to the location at the repository @a past_revision
+ * of the file @a fs_path present at the repository in revision @a 
+ * peg_revision.
+ */
+svn_error_t *svn_fs_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_node_kind_t kind;
+  svn_fs_history_t *history, *new_history;
+  const char *path;
+  svn_revnum_t revision;
+  svn_boolean_t is_ancestor;
+  apr_hash_t *locations_ret;
+  apr_pool_t *subpool;
+
+
+  /* We allocate a subpool for the temporary operations that will no longer
+   * be relevant after the termination of this function. Note which operations
+   * are done with pool and which with subpool 
+   * */
+  subpool = svn_pool_create(pool);
+  
+  /* TODO: What should be done if the elt_size of the array is not 
+   * sizeof(svn_revnum_t)? For the time being, I'm consistenly using
+   * sizeof(svn_renum_t) because its easier. */
+  
+  /* 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 (subpool, location_revisions_orig);
+  qsort (location_revisions->elts, 
+         location_revisions->nelts,
+         sizeof(*revision_ptr),
+         compare_revnum_t);
+  
+  revision_ptr = (svn_revnum_t *)location_revisions->elts;
+  revision_ptr_end = revision_ptr + location_revisions->nelts;
+
+  *locations = NULL;
+  locations_ret = apr_hash_make(pool);
+  
+  
+
+  /* Check if we have a greater revision number than the peg revision. In that
+   * case we should check the existence of the path in the future of this
+   * revision.
+   * */
+  is_ancestor = FALSE;
+  if ((*revision_ptr) > peg_revision)
+    {
+      for (;
+           ((*revision_ptr) > peg_revision) && 
+           (revision_ptr < revision_ptr_end);
+           revision_ptr++)
+        {
+          SVN_ERR (check_ancestry_of_peg_path (&is_ancestor, fs, fs_path,
+                                               peg_revision, *revision_ptr,
+                                               subpool));
+          if (is_ancestor)
+            {
+              break;
+            }
+        }
+    }
+
+    
+  SVN_ERR (svn_fs_revision_root (&root, fs, 
+                                 (is_ancestor ? 
+                                  (*revision_ptr) : 
+                                  peg_revision), 
+                                 subpool));
+  SVN_ERR (svn_fs_check_path (&kind, root, fs_path, subpool));
+  SVN_ERR (svn_fs_node_history (&history, root, fs_path, subpool));
+  SVN_ERR (svn_fs_history_location (&path, &revision, history, subpool));    
+    
+  while (history && (revision_ptr < revision_ptr_end))
+    {
+      while ((revision_ptr < revision_ptr_end) && (*revision_ptr >= revision))
+        {
+          const void * rev_copy;
+
+          /* We are duplicating revision_ptr because it is allocated out of
+           * the subpool that will be destroyed.
+           * */
+          rev_copy = apr_pmemdup (pool, revision_ptr, sizeof (*revision_ptr));
+          apr_hash_set (locations_ret, rev_copy,
+                        sizeof (*revision_ptr),
+                        apr_pstrdup (pool, path));
+          revision_ptr++;
+        }
+      if (revision_ptr == revision_ptr_end)
+        {
+          continue;
+        }
+      SVN_ERR (svn_fs_history_prev (&new_history, history, TRUE, subpool));
+      history = new_history;
+      if (history)
+        {
+          SVN_ERR (svn_fs_history_location (&path, &revision, history, pool));
+        }
+    }
+  
+  *locations = locations_ret;
+  apr_pool_destroy (subpool);
+
+  return SVN_NO_ERROR;      
+}
+
Index: subversion/libsvn_ra_local/ra_plugin.c
===================================================================
--- subversion/libsvn_ra_local/ra_plugin.c	(revision 9246)
+++ subversion/libsvn_ra_local/ra_plugin.c	(working copy)
@@ -840,8 +840,78 @@
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *
+svn_ra_local__get_locations (void *session_baton,
+                             apr_hash_t **locations,
+                             const char *url,
+                             svn_revnum_t peg_revision,
+                             apr_array_header_t *location_revisions,
+                             apr_pool_t *pool)
+{
+  svn_ra_local__session_baton_t *sbaton = session_baton;
+  int repos_url_len;
+  const char *repos_url;
+  const char *fs_path;
+  apr_hash_t *fs_locations;
+  apr_hash_t *url_locations;
+  apr_hash_index_t *iter;
+  apr_pool_t *subpool;
 
+  subpool = svn_pool_create(pool);
 
+  /* Check that the URL is contained within the repository */
+  url = svn_path_uri_decode(url, pool);
+  repos_url = sbaton->repos_url;
+  repos_url_len = strlen(repos_url);
+  if (strncmp(url, repos_url, repos_url_len) != 0)
+    return svn_error_createf (SVN_ERR_RA_ILLEGAL_URL, NULL,
+                              "'%s'\n"
+                              "is not the same repository as\n"
+                              "'%s'", url, repos_url);
+  fs_path = url + repos_url_len;
+
+  SVN_ERR (svn_fs_trace_node_locations (sbaton->fs, 
+                                        &fs_locations,
+                                        fs_path,
+                                        peg_revision,
+                                        location_revisions,
+                                        subpool));
+
+  /*
+   * Just to make sure we do not operate on a NULL hash. Shouldn't
+   * really happen if no error was thrown.
+   * */
+  if (! fs_locations)
+    {
+      *locations = NULL;
+      return SVN_NO_ERROR;
+    }
+
+  url_locations = apr_hash_make (pool);
+  iter = apr_hash_first (subpool, fs_locations);
+  while (iter)
+    {
+      svn_revnum_t * key;
+      apr_ssize_t key_len; /* Unused */
+      const char * past_fs_path;
+      const char * past_url;
+      apr_hash_this (iter, (const void**)&key, &key_len, (void **)&past_fs_path);
+      past_url = apr_psprintf (pool, "%s%s", repos_url, past_fs_path);
+      apr_hash_set (url_locations, 
+                    apr_pmemdup(pool, key, sizeof(*key)) , 
+                    sizeof(*key), 
+                    past_url);
+      iter = apr_hash_next (iter);
+    }
+  
+  *locations = url_locations;
+  
+  apr_pool_destroy(subpool);
+
+  return SVN_NO_ERROR;
+}
+
+
 /*----------------------------------------------------------------*/
 
 /** The ra_plugin **/
@@ -866,7 +936,8 @@
   svn_ra_local__get_log,
   svn_ra_local__do_check_path,
   svn_ra_local__get_uuid,
-  svn_ra_local__get_repos_root
+  svn_ra_local__get_repos_root,
+  svn_ra_local__get_locations
 };
 
 
Index: subversion/tests/libsvn_ra_local/get-past-location.c
===================================================================
--- subversion/tests/libsvn_ra_local/get-past-location.c	(revision 0)
+++ subversion/tests/libsvn_ra_local/get-past-location.c	(revision 0)
@@ -0,0 +1,237 @@
+#include <stdlib.h>
+
+#include "svn_ra.h"
+#include "svn_pools.h"
+#include "svn_config.h"
+
+/* Display a prompt and read a one-line response into the provided buffer,
+   removing a trailing newline if present. */
+static svn_error_t *
+prompt_and_read_line(const char *prompt,
+                     char *buffer,
+                     size_t max)
+{
+  int len;
+  printf("%s: ", prompt);
+  if (fgets(buffer, max, stdin) == NULL)
+    return svn_error_create(0, NULL, "error reading stdin");
+  len = strlen(buffer);
+  if (len > 0 && buffer[len-1] == '\n')
+    buffer[len-1] = 0;
+  return SVN_NO_ERROR;
+}
+
+
+/* A tiny callback function of type 'svn_auth_simple_prompt_func_t'. For
+   a much better example, see svn_cl__auth_simple_prompt in the official
+   svn cmdline client. */
+static svn_error_t *
+my_simple_prompt_callback (svn_auth_cred_simple_t **cred,
+                           void *baton,
+                           const char *realm,
+                           const char *username,
+                           svn_boolean_t may_save,
+                           apr_pool_t *pool)
+{
+  svn_auth_cred_simple_t *ret = apr_pcalloc (pool, sizeof (*ret));
+#if 0
+  char answerbuf[100];
+
+  if (realm)
+    {
+      printf ("Authentication realm: %s\n", realm);
+    }
+
+  if (username)
+    ret->username = apr_pstrdup (pool, username);
+  else
+    {
+      SVN_ERR (prompt_and_read_line("Username", answerbuf, sizeof(answerbuf)));
+      ret->username = apr_pstrdup (pool, answerbuf);
+    }
+
+  SVN_ERR (prompt_and_read_line("Password", answerbuf, sizeof(answerbuf)));
+  ret->password = apr_pstrdup (pool, answerbuf);
+#endif
+  ret->username = apr_pstrdup(pool, "jrandom");
+  ret->password = apr_pstrdup(pool, "rayjandom");
+  *cred = ret;
+  return SVN_NO_ERROR;
+}
+
+
+/* A tiny callback function of type 'svn_auth_username_prompt_func_t'. For
+   a much better example, see svn_cl__auth_username_prompt in the official
+   svn cmdline client. */
+static svn_error_t *
+my_username_prompt_callback (svn_auth_cred_username_t **cred,
+                             void *baton,
+                             const char *realm,
+                             svn_boolean_t may_save,
+                             apr_pool_t *pool)
+{
+  svn_auth_cred_username_t *ret = apr_pcalloc (pool, sizeof (*ret));
+#if 0  
+  char answerbuf[100];
+
+  if (realm)
+    {
+      printf ("Authentication realm: %s\n", realm);
+    }
+
+  SVN_ERR (prompt_and_read_line("Username", answerbuf, sizeof(answerbuf)));
+#endif
+  ret->username = apr_pstrdup(pool, "jrandom");
+#if 0  
+  ret->username = apr_pstrdup (pool, answerbuf);
+#endif
+  *cred = ret;
+  return SVN_NO_ERROR;
+}
+
+
+static svn_error_t * svn_main(apr_pool_t *pool, int argc, char *argv[])
+{
+  void *ra_baton;
+  svn_ra_plugin_t *plugin;
+  const char *repos_url, *file_url, *past_file_url;
+  svn_revnum_t peg_rev, past_rev;
+  void *session_baton;
+  svn_ra_callbacks_t my_ra_callbacks = { NULL, NULL, NULL, NULL, NULL, NULL };
+  void *callback_baton;
+  svn_error_t *error;
+  apr_hash_t *config;
+  int arg_idx, rev_idx;
+
+  /* TODO: check that I do not get past argc. Not very critical, because
+   * this is a test helper. 
+   * */
+  arg_idx = 1;
+  repos_url = argv[arg_idx++];
+  file_url = argv[arg_idx++];
+  peg_rev = atoi(argv[arg_idx++]);
+#if 0
+  past_rev = atoi(argv[4]);
+#endif
+
+  callback_baton = NULL;
+
+  SVN_ERR (svn_config_get_config (&(config), NULL, pool));
+
+    /* Make the client_ctx capable of authenticating users */
+    {
+      /* There are many different kinds of authentication back-end
+         "providers".  See svn_auth.h for a full overview. */
+      svn_auth_provider_object_t *provider;
+      apr_array_header_t *providers;
+
+      providers = apr_array_make (pool, 4, sizeof (svn_auth_provider_object_t *));
+
+      svn_client_get_simple_prompt_provider (&provider,
+                                             my_simple_prompt_callback,
+                                             NULL, /* baton */
+                                             2, /* retry limit */ pool);
+      APR_ARRAY_PUSH (providers, svn_auth_provider_object_t *) = provider;
+
+      svn_client_get_username_prompt_provider (&provider,
+                                               my_username_prompt_callback,
+                                               NULL, /* baton */
+                                               2, /* retry limit */ pool);
+      APR_ARRAY_PUSH (providers, svn_auth_provider_object_t *) = provider;
+
+      /* Register the auth-providers into the context's auth_baton. */
+      svn_auth_open (&(my_ra_callbacks.auth_baton), providers, pool);
+    }
+  
+  
+  /* Load all available RA implementations. */
+  SVN_ERR (svn_ra_init_ra_libs (&ra_baton, pool));
+
+  /* Get the plugin which handles "file:" URLs */
+  SVN_ERR (svn_ra_get_ra_library (&plugin, ra_baton, repos_url, pool));
+
+  SVN_ERR (plugin->open (&session_baton,
+                        repos_url,
+                        &my_ra_callbacks,
+                        callback_baton,
+                        config,
+                        pool));
+
+    {
+      apr_hash_t *old_locations;
+      apr_array_header_t *past_revs_array;
+      svn_boolean_t not_present;
+      int num_revs;
+
+      past_revs_array = apr_array_make (pool,
+                                        argc-arg_idx,
+                                        sizeof (past_rev));
+
+      num_revs = 0;
+      for(;arg_idx<argc;arg_idx++)
+        {
+          past_rev = atoi(argv[arg_idx]);
+          APR_ARRAY_PUSH( past_revs_array, svn_revnum_t) = past_rev;
+          num_revs++;
+        }
+      SVN_ERR (plugin->get_locations (session_baton,
+                                      &old_locations,
+                                      file_url,
+                                      peg_rev,
+                                      past_revs_array,
+                                      pool));
+
+      if (old_locations)
+        {
+          for(rev_idx = 0 ; rev_idx < num_revs ; rev_idx++)
+            {
+              const char *past_url;
+              past_rev = ((svn_revnum_t *)past_revs_array->elts)[rev_idx];
+              past_url = (const char *)apr_hash_get (old_locations, &past_rev,
+                                                     sizeof (past_rev));
+              
+              if (past_url)
+                {
+                  printf("%s\n", past_url);
+                }
+              else
+                {
+                  printf("%s", "notexist:\n");
+                }
+            }
+        }
+      else
+        {
+          for(rev_idx = 0 ; rev_idx<num_revs ; rev_idx++)
+            {
+              printf("%s", "notexist:\n");
+            }
+        }
+    }
+
+  return SVN_NO_ERROR;
+}
+
+int main(int argc, char *argv[])
+{
+  apr_pool_t *pool;
+  svn_error_t *error;
+
+  /* Initialize the app.  Send all error messages to 'stderr'.  */
+  if (svn_cmdline_init ("get_past_revision", stderr) != EXIT_SUCCESS)
+    return EXIT_FAILURE;
+  
+
+  pool = svn_pool_create(NULL);
+
+  error = svn_main(pool, argc, argv);
+
+  if (error)
+    {
+      svn_handle_error(error, stderr, 0);
+      return EXIT_FAILURE;
+    }
+
+  return EXIT_SUCCESS;
+}
+
Index: subversion/tests/clients/cmdline/cmds.gdb
===================================================================
--- subversion/tests/clients/cmdline/cmds.gdb	(revision 0)
+++ subversion/tests/clients/cmdline/cmds.gdb	(revision 0)
@@ -0,0 +1,6 @@
+set args "file:///home/shlomi/progs/svn/SVN-From-Repos/Peg-Revision/trunk/subversion/tests/clients/cmdline/repositories/past_loc_tests-1" "file:///home/shlomi/progs/svn/SVN-From-Repos/Peg-Revision/trunk/subversion/tests/clients/cmdline/repositories/past_loc_tests-1/mu.new" "2" "1"
+b main
+r
+b svn_fs_trace_node_locations
+c
+n
Index: subversion/tests/clients/cmdline/past_loc_tests.py
===================================================================
--- subversion/tests/clients/cmdline/past_loc_tests.py	(revision 0)
+++ subversion/tests/clients/cmdline/past_loc_tests.py	(revision 0)
@@ -0,0 +1,397 @@
+#!/usr/bin/env python
+#
+#  past_loc_tests.py:  testing the past location tracing function
+#
+#  Subversion is a tool for revision control. 
+#  See http://subversion.tigris.org for more information.
+#    
+# ====================================================================
+# Copyright (c) 2000-2004 CollabNet.  All rights reserved.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution.  The terms
+# are also available at http://subversion.tigris.org/license-1.html.
+# If newer versions of this license are posted there, you may use a
+# newer version instead, at your option.
+#
+######################################################################
+
+# General modules
+import stat, string, sys, os, shutil, re
+
+# Our testing module
+import svntest
+from svntest import SVNAnyOutput
+
+# (abbreviation)
+Skip = svntest.testcase.Skip
+XFail = svntest.testcase.XFail
+Item = svntest.wc.StateItem
+
+
+######################################################################
+# Utilities
+#
+
+
+def get_repos_rev(sbox):
+  wc_dir = sbox.wc_dir;
+  
+  out, err = svntest.actions.run_and_verify_svn("Getting Repository Revision", 
+                                                None, [], "up", wc_dir)
+
+  mo=re.match("At revision (\\d+)\\.", out[-1])
+  if mo: 
+    return int(mo.group(1))
+  else:
+    raise svntest.Failure
+
+def get_past_url(sbox, new_url, peg_revision, past_revision):
+  get_past_location_path = os.path.join("..", "..", "libsvn_ra_local",
+                                        "ra-get-past-location")
+
+  repos_url = svntest.main.current_repo_url
+
+  is_scalar = (1==0)
+
+  if (not isinstance(past_revision, list)):
+    past_revision = [past_revision]
+    is_scalar = (1==1)
+
+  args = [get_past_location_path, 0, 0, repos_url, new_url, 
+          peg_revision] + past_revision
+
+  out, err = svntest.main.run_command(*args)
+
+  if (len(out) == 0):
+    print "ra-get-past-location exited with error:"
+    for i in err:
+      print i
+    raise svntest.Failure
+  
+  ret = []
+  for url in out:
+    if (url[-1] == "\n"):
+      url = url[:-1]
+    ret = ret + [url]
+    
+  if (is_scalar):
+    return ret[0]
+  return ret
+
+
+######################################################################
+# Tests
+#
+#   Each test must return on success or raise on failure.
+
+
+def get_past_loc_for_move(sbox):
+  "get the past url for a moved file"
+
+  sbox.build()
+  wc_dir = sbox.wc_dir;
+  
+  starting_revision = get_repos_rev(sbox)
+
+  mu_path = os.path.join(wc_dir, 'A', 'mu')
+  new_mu_path = os.path.join(wc_dir, "mu.new")
+
+  svntest.actions.run_and_verify_svn(None, None, [], "mv", 
+                                     mu_path, new_mu_path)
+
+  svntest.actions.run_and_verify_svn(None, None, [], 'ci',
+                                     "-m", "Commiting Move",
+                                     wc_dir)
+
+  current_revision = starting_revision + 1
+
+  old_mu_url = svntest.main.current_repo_url + "/A/mu"
+  new_mu_url = svntest.main.current_repo_url + "/mu.new"
+
+  returned_old_mu_url = get_past_url(sbox, new_mu_url, current_revision,
+                                     starting_revision)
+
+  if (returned_old_mu_url != old_mu_url):
+    print "old_mu_url (\"" + old_mu_url + "\") is not " + \
+          "returned_old_mu_url (\"" + returned_old_mu_url + "\")"
+    raise svntest.Failure
+
+
+def get_past_loc_for_copy(sbox):
+  "get the past url for a copied file"
+
+  sbox.build()
+  wc_dir = sbox.wc_dir;
+  
+  starting_revision = get_repos_rev(sbox)
+
+  mu_path = os.path.join(wc_dir, 'A', 'mu')
+  new_mu_path = os.path.join(wc_dir, "mu.new")
+
+  svntest.actions.run_and_verify_svn(None, None, [], "cp", 
+                                     mu_path, new_mu_path)
+
+  svntest.actions.run_and_verify_svn(None, None, [], 'ci',
+                                     "-m", "Commiting Move",
+                                     wc_dir)
+
+  current_revision = starting_revision + 1
+
+  old_mu_url = svntest.main.current_repo_url + "/A/mu"
+  new_mu_url = svntest.main.current_repo_url + "/mu.new"
+
+  returned_old_mu_url = get_past_url(sbox, new_mu_url, current_revision,
+                                     starting_revision)
+
+  if (returned_old_mu_url != old_mu_url):
+    print "old_mu_url (\"" + old_mu_url + "\") is not " + \
+          "returned_old_mu_url (\"" + returned_old_mu_url + "\")"
+    raise svntest.Failure
+
+
+def get_past_loc_for_file_in_moved_dir(sbox):
+  "get the past url for file in moved dir"
+
+  sbox.build()
+  wc_dir = sbox.wc_dir;
+  
+  starting_revision = get_repos_rev(sbox)
+
+  b_path = os.path.join(wc_dir, 'A', 'B')
+  new_b_path = os.path.join(wc_dir, "B-mynew")
+
+  svntest.actions.run_and_verify_svn(None, None, [], "mv", 
+                                     b_path, new_b_path)
+
+  svntest.actions.run_and_verify_svn(None, None, [], 'ci',
+                                     "-m", "Commiting Move",
+                                     wc_dir)
+
+  current_revision = starting_revision + 1
+
+  old_alpha_url = svntest.main.current_repo_url + "/A/B/E/alpha"
+  new_alpha_url = svntest.main.current_repo_url + "/B-mynew/E/alpha"
+
+  returned_old_alpha_url = get_past_url(sbox, new_alpha_url, current_revision,
+                                        starting_revision)
+
+  if (returned_old_alpha_url != old_alpha_url):
+    print "old_mu_url (\"" + old_alpha_url + "\") is not " + \
+          "returned_old_mu_url (\"" + returned_old_alpha_url + "\")"
+    raise svntest.Failure
+
+
+def get_past_loc_for_file_in_copied_dir(sbox):
+  "get the past url for file in copied dir"
+
+  sbox.build()
+  wc_dir = sbox.wc_dir;
+  
+  starting_revision = get_repos_rev(sbox)
+
+  b_path = os.path.join(wc_dir, 'A', 'B')
+  new_b_path = os.path.join(wc_dir, "B-mynew")
+
+  svntest.actions.run_and_verify_svn(None, None, [], "cp", 
+                                     b_path, new_b_path)
+
+  svntest.actions.run_and_verify_svn(None, None, [], 'ci',
+                                     "-m", "Commiting Move",
+                                     wc_dir)
+
+  current_revision = starting_revision + 1
+
+  old_alpha_url = svntest.main.current_repo_url + "/A/B/E/alpha"
+  new_alpha_url = svntest.main.current_repo_url + "/B-mynew/E/alpha"
+
+  returned_old_alpha_url = get_past_url(sbox, new_alpha_url, current_revision,
+                                        starting_revision)
+
+  if (returned_old_alpha_url != old_alpha_url):
+    print "old_mu_url (\"" + old_alpha_url + "\") is not " + \
+          "returned_old_mu_url (\"" + returned_old_alpha_url + "\")"
+    raise svntest.Failure
+
+def non_existent_file(sbox):
+  "get the past URL of a then nonexistent file"
+
+  sbox.build()
+  wc_dir = sbox.wc_dir;
+  
+  starting_revision = get_repos_rev(sbox)
+
+  new_file_path = os.path.join(wc_dir, "new_file")
+
+  f = open(new_file_path, "w")
+  f.write("One Two Three Four\n");
+  f.close();
+
+  svntest.actions.run_and_verify_svn(None, None, [], "add", 
+                                     new_file_path)
+
+  svntest.actions.run_and_verify_svn(None, None, [], 'ci',
+                                     "-m", "Commiting Move",
+                                     wc_dir)
+
+  current_revision = starting_revision + 1
+
+  new_file_url = svntest.main.current_repo_url + "/new_file";
+
+  returned_old_new_file_url = get_past_url(sbox, 
+                                           new_file_url, current_revision,
+                                           starting_revision)
+
+  if (returned_old_new_file_url != "notexist:"):
+    print "URL is \"" + returned_old_new_file_url + "\" instead of notexist:"
+    raise svntest.Failure
+
+
+def future_rev(sbox):
+  "get location for a future rev"
+
+  sbox.build()
+  wc_dir = sbox.wc_dir;
+
+  urls = []
+  
+  starting_revision = get_repos_rev(sbox)
+
+  mu_path = os.path.join(wc_dir, 'A', 'mu')
+  mu_new_path = os.path.join(wc_dir, "mu.new")
+
+  mu_url = svntest.main.current_repo_url + "/A/mu"
+  urls = urls + [[starting_revision, mu_url]]
+
+  svntest.actions.run_and_verify_svn(None, None, [], "mv", 
+                                     mu_path, mu_new_path)
+
+  svntest.actions.run_and_verify_svn(None, None, [], 'ci',
+                                     "-m", "Commiting Move",
+                                     wc_dir)
+
+  mu_new_first_revision = starting_revision + 1
+
+  mu_new_url = svntest.main.current_repo_url + "/mu.new";
+  # Cancelled because this is the peg revision
+  # urls = urls + [[mu_new_first_revision, mu_new_url]];
+
+  mu_temp_path = os.path.join(wc_dir, "mu.temp")
+
+  svntest.actions.run_and_verify_svn(None, None, [], "mv", 
+                                     mu_new_path, mu_temp_path)
+
+  svntest.actions.run_and_verify_svn(None, None, [], 'ci',
+                                     "-m", "Commiting Move",
+                                     wc_dir)
+  
+  mu_temp_revision = mu_new_first_revision + 1
+
+  mu_temp_url = svntest.main.current_repo_url + "/mu.temp";
+
+  urls = urls + [[mu_temp_revision, mu_temp_url]];
+
+  svntest.actions.run_and_verify_svn(None, None, [], "mv", 
+                                     mu_temp_path, mu_new_path)
+
+  svntest.actions.run_and_verify_svn(None, None, [], 'ci',
+                                     "-m", "Commiting Move",
+                                     wc_dir)
+
+  mu_new_second_revision = mu_temp_revision + 1
+
+  urls = urls + [[mu_new_second_revision, mu_new_url]];
+
+  mu_inaccess_path = os.path.join(wc_dir, "mu-inaccess-path")
+  
+  svntest.actions.run_and_verify_svn(None, None, [], "mv", 
+                                     mu_new_path, mu_inaccess_path)
+
+  svntest.actions.run_and_verify_svn(None, None, [], 'ci',
+                                     "-m", "Commiting Move",
+                                     wc_dir)
+  
+  mu_inaccess_revision = mu_new_second_revision + 1
+
+  urls = urls + [[mu_inaccess_revision, "notexist:"]];
+
+  ret_urls = get_past_url(sbox, mu_new_url, mu_new_first_revision,
+                          map( (lambda x: x[0]), urls))
+
+  for i in range(0, len(urls)-1):
+    if (urls[i][1] != ret_urls[i]):
+      print "urls[" + str(i) + "] (\"" + urls[i][1] + "\") is not " + \
+            "ret_urls[" + str(i) + "] (\"" + ret_urls[i] + "\")"
+      raise svntest.Failure      
+
+#
+# Here we move the original file, and create a new file with its path. Then
+# we trace the future location of the moved file with the revision in the 
+# future. The get_locations() callbacks should detect they are not the
+# same file.
+#
+def future_false_file(sbox):
+  "get the future url for a future false file"
+
+  sbox.build()
+  wc_dir = sbox.wc_dir;
+  
+  starting_revision = get_repos_rev(sbox)
+
+  mu_path = os.path.join(wc_dir, 'A', 'mu')
+  new_mu_path = os.path.join(wc_dir, "mu.new")
+
+  svntest.actions.run_and_verify_svn(None, None, [], "mv", 
+                                     mu_path, new_mu_path)
+
+  svntest.actions.run_and_verify_svn(None, None, [], 'ci',
+                                     "-m", "Commiting Move",
+                                     wc_dir)
+
+  intermediate_revision = starting_revision + 1
+
+  f = open(mu_path, "w");
+  f.write("Hello Moi! This is your captain speaking.\n\n");
+  f.close();
+  
+  svntest.actions.run_and_verify_svn(None, None, [], "add", 
+                                     mu_path)
+  
+  svntest.actions.run_and_verify_svn(None, None, [], 'ci',
+                                     "-m", "Commiting Add of mu",
+                                     wc_dir)
+
+  current_revision = intermediate_revision + 1
+  
+  old_mu_url = svntest.main.current_repo_url + "/A/mu"
+  new_mu_url = svntest.main.current_repo_url + "/mu.new"
+
+  returned_url = get_past_url(sbox, old_mu_url, starting_revision,
+                              current_revision)
+
+  if (returned_url != "notexist:"):
+    print "returned_url (\"" + returned_url + "\") is not notexist:"
+    raise svntest.Failure
+
+
+########################################################################
+# Run the tests
+
+
+# list all tests here, starting with None:
+test_list = [ None,
+              get_past_loc_for_move,
+              get_past_loc_for_copy,
+              get_past_loc_for_file_in_moved_dir,
+              get_past_loc_for_file_in_copied_dir,
+              non_existent_file,
+              future_rev,
+              future_false_file,
+             ]
+
+if __name__ == '__main__':
+  svntest.main.run_tests(test_list)
+  # NOTREACHED
+
+
+### End of file.

Property changes on: subversion/tests/clients/cmdline/past_loc_tests.py
___________________________________________________________________
Name: svn:executable
   + *

Index: subversion/libsvn_ra_dav/ra_dav.h
===================================================================
--- subversion/libsvn_ra_dav/ra_dav.h	(revision 9246)
+++ subversion/libsvn_ra_dav/ra_dav.h	(working copy)
@@ -696,6 +696,16 @@
                              int okay_2,
                              apr_pool_t *pool);
 
+/*
+ * Handler for the trace_old_file_location ra_plugin_t callback. 
+ * */
+svn_error_t *
+svn_ra_dav__trace_old_file_location(void *session_baton,
+                                    const char *url,
+                                    svn_revnum_t peg_revision,
+                                    svn_revnum_t past_revision,
+                                    const char **past_url,
+                                    apr_pool_t *pool);
 
 #ifdef __cplusplus
 }
Index: subversion/libsvn_ra_dav/session.c
===================================================================
--- subversion/libsvn_ra_dav/session.c	(revision 9246)
+++ subversion/libsvn_ra_dav/session.c	(working copy)
@@ -849,6 +849,9 @@
   svn_ra_dav__do_check_path,
   svn_ra_dav__do_get_uuid,
   svn_ra_dav__get_repos_root
+#if 0
+  svn_ra_dav__trace_old_file_location
+#endif
 };
 
 
Index: subversion/libsvn_ra_dav/fetch.c
===================================================================
--- subversion/libsvn_ra_dav/fetch.c	(revision 9246)
+++ subversion/libsvn_ra_dav/fetch.c	(working copy)
@@ -1089,7 +1089,98 @@
   return SVN_NO_ERROR;
 }
 
+#if 0
+/* This implements the `svn_ra_dav__xml_validate_cb' prototype. */
+static int drev_validate_element(void *userdata, svn_ra_dav__xml_elmid parent,
+                                 svn_ra_dav__xml_elmid child)
+{
+  return SVN_RA_DAV__XML_VALID;
+}
 
+/* This implements the `svn_ra_dav__xml_startelm_cb' prototype. */
+static int drev_start_element(void *userdata, const svn_ra_dav__xml_elm_t *elm,
+                              const char **atts)
+{
+  return SVN_RA_DAV__XML_VALID;
+}
+
+/* This implements the `svn_ra_dav__xml_endelm_cb' prototype. */
+static int drev_end_element(void *userdata, const svn_ra_dav__xml_elm_t *elm,
+                            const char *cdata)
+{
+  if (elm->id == ELEM_version_name)
+    *((svn_revnum_t *) userdata) = SVN_STR_TO_REV(cdata);
+
+  return SVN_RA_DAV__XML_VALID;
+}
+
+struct trace_old_baton
+{
+  svn_ra_session_t * ras;
+  const char **past_url;
+  apr_pool_t *pool;
+};
+
+typedef struct trace_old_baton trace_old_baton_t;
+
+svn_error_t *svn_ra_dav__trace_old_file_location (void *session_baton,
+                                                  const char *url,
+                                                  svn_revnum_t peg_revision,
+                                                  svn_revnum_t past_revision,
+                                                  const char **past_url,
+                                                  apr_pool_t *pool)
+{
+  svn_ra_session_t *ras = session_baton;
+  const char *body;
+  svn_error_t *err;
+  int repos_url_len;
+  const char *repos_url;
+  trace_old_baton_t request_baton;
+
+  /* Check that the URL is contained within the repository */
+  url = svn_path_uri_decode(url, pool);
+  repos_url = ras->repos_url;
+  repos_url_len = strlen(repos_url);
+  if (strncmp(url, repos_url, repos_url_len) != 0)
+    return svn_error_createf (SVN_ERR_RA_ILLEGAL_URL, NULL,
+                              "'%s'\n"
+                              "is not the same repository as\n"
+                              "'%s'", url, repos_url);
+  
+
+  body = apr_psprintf(pool,
+                      "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+                      "<S:trace-old-node-url xmlns:S=\"" SVN_XML_NAMESPACE "\" "
+                      "xmlns:D=\"DAV:\">"
+                      "<D:source><D:href>%s</D:href></D:source>"
+                      "<S:peg-revision>%" SVN_REVNUM_T_FMT "</S:peg-revision>"
+                      "<S:past-revision>%" SVN_REVNUM_T_FMT "</S:past-revision>"
+                      "</S:trace-old-node-url>",
+                      url, peg_revision, past_revision);
+
+  request_baton.ras = ras;
+  request_baton.past_url = past_url;
+  request_baton.pool = pool;
+
+  *revision = SVN_INVALID_REVNUM;
+  SVN_ERR (svn_ra_dav__parsed_request_compat (ras->sess, "REPORT",
+                                              ras->root.path, body, NULL, NULL
+                                              told_report_elements,
+                                              told_validate_element,
+                                              told_start_element, 
+                                              told_end_element,
+                                              &request_baton, NULL, NULL, 
+                                              pool));
+
+  if (*revision == SVN_INVALID_REVNUM)
+    return svn_error_create(SVN_ERR_INCOMPLETE_DATA, NULL,
+                            "Invalid server response to dated-rev request");
+
+  return SVN_NO_ERROR;
+}
+
+#endif
+
 /* Populate the members of ne_propname structure *PROP for the
    Subversion property NAME.  */
 static void


