Index: subversion/include/svn_wc.h
===================================================================
--- subversion/include/svn_wc.h	(revision 10850)
+++ subversion/include/svn_wc.h	(working copy)
@@ -321,6 +321,35 @@
 
 
 /**
+ * @since New in 1.1.rel_ext_patch
+ *
+ * If @a externals_p is non-null, set @a *externals_p to an array of
+ * @a svn_wc_external_item_t * objects based on @a desc.
+ * The @a target_dir and @a url members of these objects 
+ * will be canonicalized or not according to the values
+ * of @a canonicalize_target_dir and @a canonicalize_url, respectively
+ *
+ * If the format of @a desc is invalid, don't touch @a *externals_p and
+ * return @c SVN_ERR_CLIENT_INVALID_EXTERNALS_DESCRIPTION.  Thus, if
+ * you just want to check the validity of an externals description,
+ * and don't care about the parsed result, pass null for @a externals_p.
+ *
+ * The format of @a desc is the same as for values of the directory
+ * property @c SVN_PROP_EXTERNALS, which see.
+ *
+ * Allocate the table, keys, and values in @a pool.
+ *
+ * Use @a parent_directory only in constructing error strings.
+ */
+svn_error_t *
+svn_wc_parse_externals_description3 (apr_array_header_t **externals_p,
+                                     const char *parent_directory,
+                                     const char *desc,
+                                     svn_boolean_t canonicalize_target_dir,
+                                     svn_boolean_t canonicalize_url,
+                                     apr_pool_t *pool);
+
+/**
  * @since New in 1.1.
  *
  * If @a externals_p is non-null, set @a *externals_p to an array of
@@ -336,6 +365,10 @@
  *
  * Allocate the table, keys, and values in @a pool.
  *
+ * This is equivalent to svn_wc_parse_externals_description3()
+ * with both the @a canonicalize_target_dir and @a canonicalize_url
+ * parameters set to @c TRUE.
+ *
  * Use @a parent_directory only in constructing error strings.
  */
 svn_error_t *
Index: subversion/libsvn_wc/props.c
===================================================================
--- subversion/libsvn_wc/props.c	(revision 10850)
+++ subversion/libsvn_wc/props.c	(working copy)
@@ -1447,9 +1447,11 @@
 /** Externals **/
 
 svn_error_t *
-svn_wc_parse_externals_description2 (apr_array_header_t **externals_p,
+svn_wc_parse_externals_description3 (apr_array_header_t **externals_p,
                                      const char *parent_directory,
                                      const char *desc,
+                                     svn_boolean_t canonicalize_target_dir,
+                                     svn_boolean_t canonicalize_url,
                                      apr_pool_t *pool)
 {
   apr_array_header_t *lines = svn_cstring_split (desc, "\n\r", TRUE, pool);
@@ -1540,8 +1542,9 @@
              SVN_PROP_EXTERNALS, parent_directory, line);
         }
 
-      item->target_dir = svn_path_canonicalize
-        (svn_path_internal_style (item->target_dir, pool), pool);
+      if (canonicalize_target_dir)
+        item->target_dir = svn_path_canonicalize
+          (svn_path_internal_style (item->target_dir, pool), pool);
       {
         if (item->target_dir[0] == '\0' || item->target_dir[0] == '/'
             || svn_path_is_backpath_present (item->target_dir))
@@ -1552,7 +1555,8 @@
              SVN_PROP_EXTERNALS, parent_directory);
       }
 
-      item->url = svn_path_canonicalize (item->url, pool);
+      if (canonicalize_url)
+        item->url = svn_path_canonicalize (item->url, pool);
 
       if (externals_p)
         APR_ARRAY_PUSH (*externals_p, svn_wc_external_item_t *) = item;
@@ -1563,6 +1567,20 @@
 
 
 svn_error_t *
+svn_wc_parse_externals_description2 (apr_array_header_t **externals_p,
+                                    const char *parent_directory,
+                                    const char *desc,
+                                    apr_pool_t *pool)
+{
+  SVN_ERR (svn_wc_parse_externals_description3 (externals_p,
+						parent_directory,
+						desc,
+						TRUE, TRUE,
+						pool));
+}
+
+
+svn_error_t *
 svn_wc_parse_externals_description (apr_hash_t **externals_p,
                                     const char *parent_directory,
                                     const char *desc,
Index: subversion/libsvn_subr/path.c
===================================================================
--- subversion/libsvn_subr/path.c	(revision 10850)
+++ subversion/libsvn_subr/path.c	(working copy)
@@ -1160,6 +1160,27 @@
         {
           /* Noop segment, so do nothing. */
         }
+      else if (canon_segments>0
+	       && seglen == 2 && src[0] == '.' && src[1] == '.')
+	{
+	  /* '..': remove last segment from 'dst' */
+	  char *new_dst = dst-1;
+	  assert(new_dst >= canon);
+	  assert(*new_dst == '/');
+	  --new_dst; /* remove the trailing '/' */
+
+	  while (new_dst >= canon && *new_dst!='/')
+	    --new_dst; /* remove up to the next '/' from the end */
+	  ++new_dst;
+
+	  if ((dst-1 - new_dst) == 2 &&
+	      new_dst[0] == '.' && new_dst[1] == '.') {
+	    /* another '..': keep both '../../' */
+	  } else {
+	    dst = new_dst; /* next component should start here */
+	    --canon_segments;
+	  }
+	}
       else
         {
           /* An actual segment, append it to the destination path */
Index: subversion/libsvn_client/externals.c
===================================================================
--- subversion/libsvn_client/externals.c	(revision 10850)
+++ subversion/libsvn_client/externals.c	(working copy)
@@ -32,6 +32,8 @@
 #include "svn_types.h"
 #include "svn_error.h"
 #include "svn_path.h"
+#include "svn_repos.h"
+#include "svn_private_config.h"
 #include "client.h"
 
 
@@ -160,6 +162,93 @@
 }
 
 
+/* If the URL for the @a external_item is relative
+ * (starting with '.' or '/'), resolve it and
+ * replace it with an absolute URL.
+ *
+ * The @a ib argument is used to determine the base URL to use (which
+ * is the repository URL of the directory containing this
+ * svn:externals property) as well as to provide the pool for memory
+ * management.
+ */
+static svn_error_t *
+resolve_relative_external(svn_wc_external_item_t *external_item,
+			  struct handle_external_item_change_baton *ib)
+{
+  apr_pool_t *pool = ib->pool;
+  const char *relative_url, *result_url;
+  svn_boolean_t host_local_p = FALSE;
+
+  switch (external_item->url[0]) {
+  case '/' : /* host-local relative path */
+    host_local_p = TRUE;
+    /* Cut off leading slash, because of svn_path_join.  UTF8 assumed. */
+    relative_url = external_item->url + 1;
+    break;
+  case '.': /* directory-local relative path */
+    relative_url = external_item->url;
+    break;
+
+  default: /* don't touch the URL in all other cases */
+    return SVN_NO_ERROR;
+  }
+  assert(relative_url);
+
+  { /* subpool's lifetime is within this block */
+    apr_pool_t *subpool = svn_pool_create (pool);
+    const char *base_url;
+
+    {
+      /* Get the path's corresponding repository URL */
+      const svn_wc_entry_t *entry;
+      svn_wc_adm_access_t *adm_access;
+      
+      SVN_ERR (svn_wc_adm_probe_open2 (&adm_access, NULL,
+				       ib->parent_dir, FALSE,
+				       0, /* non-recursive */
+				       subpool));
+      SVN_ERR (svn_wc_entry (&entry, ib->parent_dir,
+			     adm_access, FALSE, subpool));
+      base_url = entry->url;
+
+      if (host_local_p == TRUE)
+        {
+          /* Find the root of the repository */
+          svn_ra_plugin_t *ra_lib;
+          void *session;
+          svn_revnum_t rev;
+          const char *url;
+          svn_opt_revision_t revision = external_item->revision;
+
+          /* Get an RA plugin for this URL. */
+          SVN_ERR (svn_client__ra_lib_from_path (&ra_lib, &session, &rev,
+                                                 &url, base_url, &revision,
+                                                 ib->ctx, subpool));
+          /* Obtain repository root from ra session */
+          SVN_ERR (ra_lib->get_repos_root (session, &url, subpool));
+          base_url = url;
+        }
+    }
+    assert(base_url);
+
+    {
+      /* compute the resulting URL */
+      char *new_url;
+      new_url = svn_path_join (base_url, relative_url, subpool);
+      new_url =
+	(/*non-const*/ char*)svn_path_canonicalize (new_url, subpool);
+      result_url = svn_path_join (new_url, "", pool); /* do a strdup only */
+    }
+
+    svn_pool_destroy (subpool);
+  }
+
+  assert(result_url); /* note: result_url's content rests in 'pool'! */
+  external_item->url = result_url; /* effect the resolved URL */
+  return SVN_NO_ERROR;
+}
+
+
 /* This implements the 'svn_hash_diff_func_t' interface.
    BATON is of type 'struct handle_external_item_change_baton *'.  */
 static svn_error_t *
@@ -177,12 +266,18 @@
      attempting to retrieve the hash values anyway.  */
 
   if ((ib->old_desc) && (! ib->is_export))
-    old_item = apr_hash_get (ib->old_desc, key, klen);
+    {
+      old_item = apr_hash_get (ib->old_desc, key, klen);
+      SVN_ERR (resolve_relative_external(old_item, ib));
+    }
   else
     old_item = NULL;
 
   if (ib->new_desc)
-    new_item = apr_hash_get (ib->new_desc, key, klen);
+    {
+      new_item = apr_hash_get (ib->new_desc, key, klen);
+      SVN_ERR (resolve_relative_external(new_item, ib));
+    }
   else
     new_item = NULL;
 
@@ -429,14 +524,18 @@
   svn_wc_external_item_t *item;
 
   if ((old_desc_text = apr_hash_get (cb->externals_old, key, klen)))
-    SVN_ERR (svn_wc_parse_externals_description2 (&old_desc, (const char *) key,
-                                                  old_desc_text, cb->pool));
+    SVN_ERR (svn_wc_parse_externals_description3 (&old_desc, (const char *) key,
+                                                  old_desc_text,
+						  TRUE, FALSE,
+						  cb->pool));
   else
     old_desc = NULL;
 
   if ((new_desc_text = apr_hash_get (cb->externals_new, key, klen)))
-    SVN_ERR (svn_wc_parse_externals_description2 (&new_desc, (const char *) key,
-                                                  new_desc_text, cb->pool));
+    SVN_ERR (svn_wc_parse_externals_description3 (&new_desc, (const char *) key,
+                                                  new_desc_text,
+						  TRUE, FALSE,
+						  cb->pool));
   else
     new_desc = NULL;
 
@@ -596,8 +695,10 @@
 
       /* Parse the svn:externals property value.  This results in a
          hash mapping subdirectories to externals structures. */
-      SVN_ERR (svn_wc_parse_externals_description2 (&exts, path, 
-                                                    propval, subpool));
+      SVN_ERR (svn_wc_parse_externals_description3 (&exts, path, 
+                                                    propval,
+                                                    TRUE, FALSE,
+						    subpool));
 
       /* Make a sub-pool of SUBPOOL. */
       iterpool = svn_pool_create (subpool);

