Index: subversion/include/svn_wc.h
===================================================================
--- subversion/include/svn_wc.h	(revision 10392)
+++ 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 10392)
+++ 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 10392)
+++ 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 10392)
+++ subversion/libsvn_client/externals.c	(working copy)
@@ -22,6 +22,7 @@
 
 /*** Includes. ***/
 
+#include <ne_uri.h>
 #include <assert.h>
 #include "svn_wc.h"
 #include "svn_pools.h"
@@ -32,6 +33,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 +163,85 @@
 }
 
 
+/* 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;
+
+  switch (external_item->url[0]) {
+  case '/' : /* host-local relative path */
+    /* fall through */
+  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;
+    }
+    assert(base_url);
+
+    {
+      /* compute the resulting URL */
+      ne_uri parsed;
+      char* saved_path;
+      char *new_uri;
+
+      if (ne_uri_parse(base_url, &parsed) != 0)
+	return svn_error_createf(SVN_ERR_BAD_URL, NULL,
+				 _("Invalid repository URL '%s' for '%s'"),
+				 base_url,
+				 ib->parent_dir);
+
+      saved_path = parsed.path;
+      parsed.path = svn_path_join (parsed.path, relative_url, subpool);
+      parsed.path =
+	(/*non-const*/ char*)svn_path_canonicalize (parsed.path, subpool);
+      new_uri = ne_uri_unparse(&parsed);
+      result_url = svn_path_join (new_uri, "", pool); /* do a strdup only */
+      free(new_uri);
+      parsed.path = saved_path;
+      ne_uri_free(&parsed);
+    }
+
+    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 +259,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 +517,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 +688,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);

