subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From br...@apache.org
Subject svn commit: r1416996 [8/13] - in /subversion/branches/wc-collate-path: ./ build/ build/ac-macros/ build/generator/ contrib/client-side/svnmerge/ contrib/server-side/svncutter/ notes/ subversion/bindings/cxxhl/ subversion/bindings/javahl/native/ subvers...
Date Tue, 04 Dec 2012 15:35:57 GMT
Modified: subversion/branches/wc-collate-path/subversion/libsvn_wc/wc_db.c
URL: http://svn.apache.org/viewvc/subversion/branches/wc-collate-path/subversion/libsvn_wc/wc_db.c?rev=1416996&r1=1416995&r2=1416996&view=diff
==============================================================================
--- subversion/branches/wc-collate-path/subversion/libsvn_wc/wc_db.c (original)
+++ subversion/branches/wc-collate-path/subversion/libsvn_wc/wc_db.c Tue Dec  4 15:35:13 2012
@@ -32,6 +32,7 @@
 #include "svn_dirent_uri.h"
 #include "svn_path.h"
 #include "svn_hash.h"
+#include "svn_sorts.h"
 #include "svn_wc.h"
 #include "svn_checksum.h"
 #include "svn_pools.h"
@@ -320,6 +321,7 @@ static svn_error_t *
 db_read_pristine_props(apr_hash_t **props,
                        svn_wc__db_wcroot_t *wcroot,
                        const char *local_relpath,
+                       svn_boolean_t deleted_ok,
                        apr_pool_t *result_pool,
                        apr_pool_t *scratch_pool);
 
@@ -381,7 +383,18 @@ wclock_owns_lock(svn_boolean_t *own_lock
                  svn_boolean_t exact,
                  apr_pool_t *scratch_pool);
 
+/* Baton for db_is_switched */
+struct db_is_switched_baton_t
+{
+  svn_boolean_t *is_switched;
+  svn_kind_t *kind;
+};
 
+static svn_error_t *
+db_is_switched(void *baton,
+               svn_wc__db_wcroot_t *wcroot,
+               const char *local_relpath,
+               apr_pool_t *scratch_pool);
  
 /* Return the absolute path, in local path style, of LOCAL_RELPATH
    in WCROOT.  */
@@ -1778,6 +1791,7 @@ svn_wc__db_base_add_file(svn_wc__db_t *d
                          svn_boolean_t delete_working,
                          svn_boolean_t update_actual_props,
                          apr_hash_t *new_actual_props,
+                         apr_array_header_t *new_iprops,
                          svn_boolean_t keep_recorded_info,
                          svn_boolean_t insert_base_deleted,
                          const svn_skel_t *conflict,
@@ -1821,6 +1835,7 @@ svn_wc__db_base_add_file(svn_wc__db_t *d
   ibb.checksum = checksum;
 
   ibb.dav_cache = dav_cache;
+  ibb.iprops = new_iprops;
 
   if (update_actual_props)
     {
@@ -1863,6 +1878,7 @@ svn_wc__db_base_add_symlink(svn_wc__db_t
                             svn_boolean_t delete_working,
                             svn_boolean_t update_actual_props,
                             apr_hash_t *new_actual_props,
+                            apr_array_header_t *new_iprops,
                             svn_boolean_t keep_recorded_info,
                             svn_boolean_t insert_base_deleted,
                             const svn_skel_t *conflict,
@@ -1905,6 +1921,7 @@ svn_wc__db_base_add_symlink(svn_wc__db_t
   ibb.target = target;
 
   ibb.dav_cache = dav_cache;
+  ibb.iprops = new_iprops;
 
   if (update_actual_props)
     {
@@ -2074,16 +2091,15 @@ db_base_remove(void *baton,
                                             wcroot, local_relpath,
                                             scratch_pool, scratch_pool));
 
-  /* ### This function should be turned into a helper of this function,
-         as this is the only valid caller */
   if (status == svn_wc__db_status_normal
       && rb->keep_as_working)
     {
-      SVN_ERR(svn_wc__db_temp_op_make_copy(rb->db,
-                                           svn_dirent_join(wcroot->abspath,
-                                                           local_relpath,
-                                                           scratch_pool),
-                                           scratch_pool));
+      SVN_ERR(svn_wc__db_op_make_copy(rb->db,
+                                      svn_dirent_join(wcroot->abspath,
+                                                      local_relpath,
+                                                      scratch_pool),
+                                      NULL, NULL,
+                                      scratch_pool));
       keep_working = TRUE;
     }
   else
@@ -2668,27 +2684,24 @@ svn_wc__db_base_clear_dav_cache_recursiv
 }
 
 
-
-/* Like svn_wc__db_base_get_info(), but taking WCROOT+LOCAL_RELPATH instead of
-   DB+LOCAL_ABSPATH and outputting REPOS_ID instead of URL+UUID. */
-static svn_error_t *
-depth_get_info(svn_wc__db_status_t *status,
-                svn_kind_t *kind,
-                svn_revnum_t *revision,
-                const char **repos_relpath,
-                apr_int64_t *repos_id,
-                svn_revnum_t *changed_rev,
-                apr_time_t *changed_date,
-                const char **changed_author,
-                svn_depth_t *depth,
-                const svn_checksum_t **checksum,
-                const char **target,
-                svn_boolean_t *had_props,
-                svn_wc__db_wcroot_t *wcroot,
-                const char *local_relpath,
-                int op_depth,
-                apr_pool_t *result_pool,
-                apr_pool_t *scratch_pool)
+svn_error_t *
+svn_wc__db_depth_get_info(svn_wc__db_status_t *status,
+                          svn_kind_t *kind,
+                          svn_revnum_t *revision,
+                          const char **repos_relpath,
+                          apr_int64_t *repos_id,
+                          svn_revnum_t *changed_rev,
+                          apr_time_t *changed_date,
+                          const char **changed_author,
+                          svn_depth_t *depth,
+                          const svn_checksum_t **checksum,
+                          const char **target,
+                          svn_boolean_t *had_props,
+                          svn_wc__db_wcroot_t *wcroot,
+                          const char *local_relpath,
+                          int op_depth,
+                          apr_pool_t *result_pool,
+                          apr_pool_t *scratch_pool)
 {
   svn_sqlite__stmt_t *stmt;
   svn_boolean_t have_row;
@@ -3640,7 +3653,7 @@ cross_db_copy(svn_wc__db_wcroot_t *src_w
                     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
                     src_wcroot, src_relpath, scratch_pool, scratch_pool));
 
-  SVN_ERR(db_read_pristine_props(&props, src_wcroot, src_relpath,
+  SVN_ERR(db_read_pristine_props(&props, src_wcroot, src_relpath, FALSE,
                                  scratch_pool, scratch_pool));
 
   blank_iwb(&iwb);
@@ -4176,11 +4189,11 @@ db_op_copy_shadowed_layer(svn_wc__db_wcr
 
   {
     svn_error_t *err;
-    err = depth_get_info(&status, &kind, &node_revision, &node_repos_relpath,
-                         &node_repos_id, NULL, NULL, NULL, NULL, NULL,
-                         NULL, NULL,
-                         src_wcroot, src_relpath, src_op_depth,
-                         scratch_pool, scratch_pool);
+    err = svn_wc__db_depth_get_info(&status, &kind, &node_revision,
+                                    &node_repos_relpath, &node_repos_id,
+                                    NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+                                    src_wcroot, src_relpath, src_op_depth,
+                                    scratch_pool, scratch_pool);
 
     if (err)
       {
@@ -4393,10 +4406,11 @@ op_copy_shadowed_layer_txn(void * baton,
   del_op_depth = relpath_depth(ocb->dst_relpath);
 
   /* Get some information from the parent */
-  SVN_ERR(depth_get_info(NULL, NULL, &revision, &repos_relpath, &repos_id,
-                         NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-                         ocb->src_wcroot, src_parent_relpath, src_op_depth,
-                         scratch_pool, scratch_pool));
+  SVN_ERR(svn_wc__db_depth_get_info(NULL, NULL, &revision, &repos_relpath,
+                                    &repos_id, NULL, NULL, NULL, NULL, NULL,
+                                    NULL, NULL, ocb->src_wcroot,
+                                    src_parent_relpath, src_op_depth,
+                                    scratch_pool, scratch_pool));
 
   if (repos_relpath == NULL)
     {
@@ -5088,7 +5102,7 @@ set_props_txn(void *baton,
   /* Check if the props are modified. If no changes, then wipe out the
      ACTUAL props.  PRISTINE_PROPS==NULL means that any
      ACTUAL props are okay as provided, so go ahead and set them.  */
-  SVN_ERR(db_read_pristine_props(&pristine_props, wcroot, local_relpath,
+  SVN_ERR(db_read_pristine_props(&pristine_props, wcroot, local_relpath, FALSE,
                                  scratch_pool, scratch_pool));
   if (spb->props && pristine_props)
     {
@@ -7666,7 +7680,7 @@ read_info(svn_wc__db_status_t *status,
           if (op_depth != 0)
             *lock = NULL;
           else
-            *lock = lock_from_columns(stmt_info, 16, 17, 18, 19, result_pool);
+            *lock = lock_from_columns(stmt_info, 17, 18, 19, 20, result_pool);
         }
 
       if (have_work)
@@ -8060,6 +8074,7 @@ read_children_info(void *baton,
           child->recorded_mod_time = svn_sqlite__column_int64(stmt, 13);
           child->recorded_size = get_recorded_size(stmt, 7);
           child->has_checksum = !svn_sqlite__column_is_null(stmt, 6);
+          child->copied = op_depth > 0 && !svn_sqlite__column_is_null(stmt, 2);
           child->had_props = SQLITE_PROPERTIES_AVAILABLE(stmt, 14);
 #ifdef HAVE_SYMLINK
           if (child->had_props)
@@ -8827,7 +8842,7 @@ db_read_props(void *baton,
     return SVN_NO_ERROR;
 
   /* No local changes. Return the pristine props for this node.  */
-  SVN_ERR(db_read_pristine_props(&rpb->props, wcroot, local_relpath,
+  SVN_ERR(db_read_pristine_props(&rpb->props, wcroot, local_relpath, FALSE,
                                  rpb->result_pool, scratch_pool));
   if (rpb->props == NULL)
     {
@@ -8875,6 +8890,7 @@ static svn_error_t *
 db_read_pristine_props(apr_hash_t **props,
                        svn_wc__db_wcroot_t *wcroot,
                        const char *local_relpath,
+                       svn_boolean_t deleted_ok,
                        apr_pool_t *result_pool,
                        apr_pool_t *scratch_pool)
 {
@@ -8902,9 +8918,8 @@ db_read_pristine_props(apr_hash_t **prop
   presence = svn_sqlite__column_token(stmt, 1, presence_map);
 
   /* For "base-deleted", it is obvious the pristine props are located
-     in the BASE table. Fall through to fetch them.
-     ### BH: Is this really the behavior we want here? */
-  if (presence == svn_wc__db_status_base_deleted)
+     below the current node. Fetch the NODE from the next record. */
+  if (presence == svn_wc__db_status_base_deleted && deleted_ok)
     {
       SVN_ERR(svn_sqlite__step(&have_row, stmt));
 
@@ -8930,8 +8945,13 @@ db_read_pristine_props(apr_hash_t **prop
       return SVN_NO_ERROR;
     }
 
-  *props = NULL;
-  return svn_error_trace(svn_sqlite__reset(stmt));
+  return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS,
+                           svn_sqlite__reset(stmt),
+                           _("The node '%s' has a status that"
+                             " has no properties."),
+                           path_for_error_message(wcroot,
+                                                  local_relpath,
+                                                  scratch_pool));
 }
 
 
@@ -8951,7 +8971,7 @@ svn_wc__db_read_pristine_props(apr_hash_
                               local_abspath, scratch_pool, scratch_pool));
   VERIFY_USABLE_WCROOT(wcroot);
 
-  SVN_ERR(db_read_pristine_props(props, wcroot, local_relpath,
+  SVN_ERR(db_read_pristine_props(props, wcroot, local_relpath, TRUE,
                                  result_pool, scratch_pool));
   return SVN_NO_ERROR;
 }
@@ -9016,6 +9036,45 @@ svn_wc__db_prop_retrieve_recursive(apr_h
   return svn_error_trace(svn_sqlite__reset(stmt));
 }
 
+/* Baton for db_read_cached_iprops */
+struct read_cached_iprops_baton_t
+{
+  apr_array_header_t *iprops;
+  apr_pool_t *result_pool;
+};
+
+/* Implements svn_wc__db_txn_callback_t for svn_wc__db_read_cached_iprops */
+static svn_error_t *
+db_read_cached_iprops(void *baton,
+                      svn_wc__db_wcroot_t *wcroot,
+                      const char *local_relpath,
+                      apr_pool_t *scratch_pool)
+{
+  struct read_cached_iprops_baton_t *rib = baton;
+  svn_sqlite__stmt_t *stmt;
+  svn_boolean_t have_row;
+
+  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_SELECT_IPROPS));
+  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
+  SVN_ERR(svn_sqlite__step(&have_row, stmt));
+
+  if (!have_row)
+    {
+      return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND,
+                               svn_sqlite__reset(stmt),
+                               _("The node '%s' was not found."),
+                               path_for_error_message(wcroot, local_relpath,
+                                                      scratch_pool));
+    }
+
+  SVN_ERR(svn_sqlite__column_iprops(&rib->iprops, stmt, 0,
+                                    rib->result_pool, scratch_pool));
+
+  SVN_ERR(svn_sqlite__reset(stmt));
+
+  return SVN_NO_ERROR;
+}
+
 svn_error_t *
 svn_wc__db_read_cached_iprops(apr_array_header_t **iprops,
                               svn_wc__db_t *db,
@@ -9025,91 +9084,269 @@ svn_wc__db_read_cached_iprops(apr_array_
 {
   svn_wc__db_wcroot_t *wcroot;
   const char *local_relpath;
-  svn_sqlite__stmt_t *stmt;
-  svn_boolean_t have_row;
-  const char *repos_root_url;
-  svn_revnum_t revision;
-  int op_depth;
-  const char *repos_relpath;
+  struct read_cached_iprops_baton_t rcib;
 
   SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
 
-  SVN_ERR(svn_wc__db_read_info(NULL, NULL,
-                               &revision, &repos_relpath, &repos_root_url,
-                               NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-                               NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-                               NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-                               NULL, db, local_abspath, result_pool,
-                               scratch_pool));
+  SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath,
+                                                db, local_abspath,
+                                                scratch_pool, scratch_pool));
+  VERIFY_USABLE_WCROOT(wcroot);
+
+  rcib.result_pool = result_pool;
+
+  /* Don't use with_txn yet, as we perform just a single transaction */
+  SVN_ERR(db_read_cached_iprops(&rcib, wcroot, local_relpath, scratch_pool));
 
-  if (repos_relpath && repos_relpath[0] == '\0')
+  if (rcib.iprops)
+    *iprops = rcib.iprops;
+  else
     {
-      /* LOCAL_ABSPATH reflects the root of the repository, so there is
-         no parents to inherit from. */
       *iprops = apr_array_make(result_pool, 0,
                                sizeof(svn_prop_inherited_item_t *));
     }
-  else
+
+  return SVN_NO_ERROR;
+}
+
+/* Remove all prop name value pairs from PROP_HASH where the property
+   name is not PROPNAME. */
+static void
+filter_unwanted_props(apr_hash_t *prop_hash,
+                      const char * propname,
+                      apr_pool_t *scratch_pool)
+{
+  apr_hash_index_t *hi;
+
+  for (hi = apr_hash_first(scratch_pool, prop_hash);
+       hi;
+       hi = apr_hash_next(hi))
     {
-      SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath,
-                                                    db, local_abspath,
-                                                    scratch_pool,
-                                                    scratch_pool));
-      VERIFY_USABLE_WCROOT(wcroot);
-      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
-                                        STMT_SELECT_IPROPS));
-      SVN_ERR(op_depth_of(&op_depth, wcroot, local_relpath));
-      SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
-      SVN_ERR(svn_sqlite__step(&have_row, stmt));
+      const char *ipropname = svn__apr_hash_index_key(hi);
 
-      if (!have_row)
+      if (strcmp(ipropname, propname) != 0)
+        apr_hash_set(prop_hash, ipropname, APR_HASH_KEY_STRING, NULL);
+    }
+  return;
+}
+
+/* Baton for db_read_inherited_props */
+struct read_inherited_props_baton_t
+{
+  apr_array_header_t *iprops;
+  const char *propname;
+  apr_pool_t *result_pool;
+};
+
+/* Implements svn_wc__db_txn_callback_t for svn_wc__db_read_inherited_props */
+static svn_error_t *
+db_read_inherited_props(void *baton,
+                        svn_wc__db_wcroot_t *wcroot,
+                        const char *local_relpath,
+                        apr_pool_t *scratch_pool)
+{
+  struct read_inherited_props_baton_t *ripb = baton;
+  int i;
+  apr_array_header_t *cached_iprops = NULL;
+  const char *parent_relpath = local_relpath;
+  svn_boolean_t is_wc_root = FALSE;
+  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+  apr_pool_t *result_pool = ripb->result_pool;
+
+  ripb->iprops = apr_array_make(ripb->result_pool, 1,
+                                sizeof(svn_prop_inherited_item_t *));
+
+  /* Walk up to the root of the WC looking for inherited properties.  When we
+     reach the WC root also check for cached inherited properties. */
+  while (TRUE)
+    {
+      apr_hash_t *actual_props;
+      svn_boolean_t is_switched;
+      struct db_is_switched_baton_t swb;
+
+      svn_pool_clear(iterpool);
+
+      swb.is_switched = &is_switched;
+      swb.kind = NULL;
+
+      if (*parent_relpath == '\0')
         {
-          /* No cached iprops. */
-          *iprops = NULL;
+          is_switched = FALSE;
+          is_wc_root = TRUE;
         }
       else
+        SVN_ERR(db_is_switched(&swb, wcroot, parent_relpath, scratch_pool));
+
+      if (is_switched || is_wc_root)
         {
-          SVN_ERR(svn_sqlite__column_iprops(iprops, stmt, 0, result_pool,
-                                            scratch_pool));
-         }
+          struct read_cached_iprops_baton_t rib;
+          is_wc_root = TRUE;
 
-      SVN_ERR(svn_sqlite__reset(stmt));
+          rib.result_pool = scratch_pool;
+
+          /* If the WC root is also the root of the repository then by
+             definition there are no inheritable properties to be had,
+             but checking for that is just as expensive as fetching them
+             anyway. */
+
+          /* Grab the cached inherited properties for the WC root. */
+          SVN_ERR(db_read_cached_iprops(&rib, wcroot, parent_relpath,
+                                       iterpool));
+
+          cached_iprops = rib.iprops;
+        }
+
+      /* If PARENT_ABSPATH is a true parent of LOCAL_ABSPATH, then
+         LOCAL_ABSPATH can inherit properties from it. */
+      if (strcmp(local_relpath, parent_relpath) != 0)
+        {
+          struct db_read_props_baton_t rpb;
+          rpb.result_pool = result_pool;
+
+          SVN_ERR(db_read_props(&rpb, wcroot, parent_relpath, iterpool));
+
+          actual_props = rpb.props;
+
+          if (actual_props)
+            {
+              /* If we only want PROPNAME filter out any other properties. */
+              if (ripb->propname)
+                filter_unwanted_props(actual_props, ripb->propname, iterpool);
+
+              if (apr_hash_count(actual_props))
+                {
+                  svn_prop_inherited_item_t *iprop_elt =
+                    apr_pcalloc(ripb->result_pool,
+                                sizeof(svn_prop_inherited_item_t));
+                  iprop_elt->path_or_url = svn_dirent_join(wcroot->abspath,
+                                                           parent_relpath,
+                                                           result_pool);
+
+                  iprop_elt->prop_hash = actual_props;
+                  /* Build the output array in depth-first order. */
+                  svn_sort__array_insert(&iprop_elt, ripb->iprops, 0);
+                }
+            }
+        }
+
+      /* Inheritance only goes as far as the nearest WC root. */
+      if (is_wc_root)
+        break;
+
+      /* Keep looking for the WC root. */
+      parent_relpath = svn_relpath_dirname(parent_relpath, scratch_pool);
     }
 
+  if (cached_iprops)
+    {
+      for (i = cached_iprops->nelts - 1; i >= 0; i--)
+        {
+          svn_prop_inherited_item_t *cached_iprop =
+            APR_ARRAY_IDX(cached_iprops, i, svn_prop_inherited_item_t *);
+
+          /* An empty property hash in the iprops cache means there are no
+             inherited properties. */
+          if (apr_hash_count(cached_iprop->prop_hash) == 0)
+            continue;
+
+          if (ripb->propname)
+            filter_unwanted_props(cached_iprop->prop_hash, ripb->propname,
+                                  scratch_pool);
+
+          /* If we didn't filter everything then keep this iprop. */
+          if (apr_hash_count(cached_iprop->prop_hash))
+            svn_sort__array_insert(&cached_iprop, ripb->iprops, 0);
+        }
+    }
+
+  svn_pool_destroy(iterpool);
   return SVN_NO_ERROR;
 }
 
-/* Recursive body of svn_wc__db_get_children_with_cached_iprops. */
-static svn_error_t *
-get_children_with_cached_iprops(apr_hash_t *iprop_paths,
-                                svn_depth_t depth,
-                                const char *local_abspath,
+svn_error_t *
+svn_wc__db_read_inherited_props(apr_array_header_t **iprops,
                                 svn_wc__db_t *db,
+                                const char *local_abspath,
+                                const char *propname,
                                 apr_pool_t *result_pool,
                                 apr_pool_t *scratch_pool)
 {
   svn_wc__db_wcroot_t *wcroot;
   const char *local_relpath;
-  svn_sqlite__stmt_t *stmt;
-  svn_boolean_t have_row;
+  struct read_inherited_props_baton_t ripb;
 
   SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
 
-  SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
-                                                local_abspath, scratch_pool,
-                                                scratch_pool));
+  SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath,
+                                                db, local_abspath,
+                                                scratch_pool, scratch_pool));
   VERIFY_USABLE_WCROOT(wcroot);
-  if (depth == svn_depth_empty
-      || depth == svn_depth_files
-      || depth == svn_depth_immediates)
+
+  ripb.iprops = NULL;
+  ripb.propname = propname;
+  ripb.result_pool = result_pool;
+
+  SVN_ERR(svn_wc__db_with_txn(wcroot, local_relpath, db_read_inherited_props,
+                              &ripb, scratch_pool));
+
+  *iprops = ripb.iprops;
+  return SVN_NO_ERROR;
+}
+
+/* Baton for get_children_with_cached_iprops */
+struct get_children_with_cached_baton_t
+{
+  svn_depth_t depth;
+  apr_hash_t *iprop_paths;
+  apr_pool_t *result_pool;
+};
+
+/* Implements svn_wc__db_txn_callback_t for
+   svn_wc__db_get_children_with_cached_iprops. */
+static svn_error_t *
+get_children_with_cached_iprops(void *baton,
+                                svn_wc__db_wcroot_t *wcroot,
+                                const char *local_relpath,
+                                apr_pool_t *scratch_pool)
+{
+  struct get_children_with_cached_baton_t *cwcb = baton;
+  svn_sqlite__stmt_t *stmt;
+  svn_boolean_t have_row;
+  apr_hash_t *iprop_paths = cwcb->iprop_paths;
+  apr_pool_t *result_pool = cwcb->result_pool;
+
+  /* First check if LOCAL_RELPATH itself has iprops */
+  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+                                    STMT_SELECT_IPROPS_NODE));
+  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
+  SVN_ERR(svn_sqlite__step(&have_row, stmt));
+
+  if (have_row)
+   {
+      const char *relpath_with_cache = svn_sqlite__column_text(stmt, 0,
+                                                               NULL);
+      const char *abspath_with_cache = svn_dirent_join(wcroot->abspath,
+                                                       relpath_with_cache,
+                                                       result_pool);
+      apr_hash_set(iprop_paths, abspath_with_cache, APR_HASH_KEY_STRING,
+                   svn_sqlite__column_text(stmt, 1, result_pool));
+    }
+  SVN_ERR(svn_sqlite__reset(stmt));
+
+  if (cwcb->depth == svn_depth_empty)
+    return SVN_NO_ERROR;
+
+  /* Now fetch information for children or all descendants */
+  if (cwcb->depth == svn_depth_files
+      || cwcb->depth == svn_depth_immediates)
     {
       SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
-                                        STMT_SELECT_INODES));  
+                                        STMT_SELECT_IPROPS_CHILDREN));
     }
   else /* Default to svn_depth_infinity. */
     {
       SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
-                                        STMT_SELECT_INODES_RECURSIVE));
+                                        STMT_SELECT_IPROPS_RECURSIVE));
     }
 
   SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
@@ -9123,46 +9360,50 @@ get_children_with_cached_iprops(apr_hash
                                                        relpath_with_cache,
                                                        result_pool);
       apr_hash_set(iprop_paths, abspath_with_cache, APR_HASH_KEY_STRING,
-                   abspath_with_cache);
+                   svn_sqlite__column_text(stmt, 1, result_pool));
       SVN_ERR(svn_sqlite__step(&have_row, stmt));
     }
 
   SVN_ERR(svn_sqlite__reset(stmt));
 
-  if (depth == svn_depth_files || depth == svn_depth_immediates)
+  /* For depth files we should filter non files */
+  if (cwcb->depth == svn_depth_files)
     {
-      const apr_array_header_t *rel_children;
-      int i;
+      apr_hash_index_t *hi;
       apr_pool_t *iterpool = svn_pool_create(scratch_pool);
 
-      SVN_ERR(svn_wc__db_read_children_of_working_node(&rel_children,
-                                                       db, local_abspath,
-                                                       scratch_pool,
-                                                       scratch_pool));
-      for (i = 0; i < rel_children->nelts; i++)
+      for (hi = apr_hash_first(scratch_pool, iprop_paths);
+           hi;
+           hi = apr_hash_next(hi))
         {
-          const char *child_abspath;
+          const char *child_abspath = svn__apr_hash_index_key(hi);
+          const char *child_relpath;
+          svn_kind_t child_kind;
 
           svn_pool_clear(iterpool);
-          child_abspath = svn_dirent_join(
-            local_abspath, APR_ARRAY_IDX(rel_children, i, const char *),
-            iterpool);
 
-          if (depth == svn_depth_files)
-            {
-              svn_kind_t child_kind;
+          child_relpath = svn_dirent_is_child(local_relpath, child_abspath,
+                                              NULL);
 
-              SVN_ERR(svn_wc__db_read_kind(&child_kind, db, child_abspath,
-                                           FALSE, FALSE, iterpool));
-              if (child_kind != svn_kind_file)
-                continue;
+          if (! child_relpath)
+            {
+              continue; /* local_relpath itself */
             }
 
-          SVN_ERR(get_children_with_cached_iprops(iprop_paths,
-                                                  svn_depth_empty,
-                                                  child_abspath, db,
-                                                  result_pool,
-                                                  iterpool));
+          SVN_ERR(svn_wc__db_base_get_info_internal(NULL, &child_kind, NULL,
+                                                    NULL, NULL, NULL, NULL,
+                                                    NULL, NULL, NULL, NULL,
+                                                    NULL, NULL, NULL,
+                                                    wcroot, child_relpath,
+                                                    scratch_pool,
+                                                    scratch_pool));
+
+          /* Filter if not a file */
+          if (child_kind != svn_kind_file)
+            {
+              apr_hash_set(iprop_paths, child_abspath, APR_HASH_KEY_STRING,
+                           NULL);
+            }
         }
 
       svn_pool_destroy(iterpool);
@@ -9179,10 +9420,26 @@ svn_wc__db_get_children_with_cached_ipro
                                            apr_pool_t *result_pool,
                                            apr_pool_t *scratch_pool)
 {
-  *iprop_paths = apr_hash_make(result_pool);
-  SVN_ERR(get_children_with_cached_iprops(*iprop_paths, depth,
-                                          local_abspath, db, result_pool,
-                                          scratch_pool));
+  svn_wc__db_wcroot_t *wcroot;
+  const char *local_relpath;
+  struct get_children_with_cached_baton_t cwcb;
+
+  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
+
+  SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
+                                                local_abspath, scratch_pool,
+                                                scratch_pool));
+  VERIFY_USABLE_WCROOT(wcroot);
+
+  cwcb.iprop_paths = apr_hash_make(result_pool);
+  cwcb.depth = depth;
+  cwcb.result_pool = result_pool;
+
+  SVN_ERR(svn_wc__db_with_txn(wcroot, local_relpath,
+                              get_children_with_cached_iprops, &cwcb,
+                              scratch_pool));
+
+  *iprop_paths = cwcb.iprop_paths;
   return SVN_NO_ERROR;
 }
 
@@ -9688,6 +9945,7 @@ commit_node(void *baton,
   svn_sqlite__stmt_t *stmt_act;
   svn_boolean_t have_act;
   svn_string_t prop_blob = { 0 };
+  svn_string_t inherited_prop_blob = { 0 };
   const char *changelist = NULL;
   const char *parent_relpath;
   svn_wc__db_status_t new_presence;
@@ -9757,6 +10015,10 @@ commit_node(void *baton,
     prop_blob.data = svn_sqlite__column_blob(stmt_info, 14, &prop_blob.len,
                                              scratch_pool);
 
+  inherited_prop_blob.data = svn_sqlite__column_blob(stmt_info, 16,
+                                                     &inherited_prop_blob.len,
+                                                     scratch_pool);
+
   if (cb->keep_changelist && have_act)
     changelist = svn_sqlite__column_text(stmt_act, 0, scratch_pool);
 
@@ -9843,6 +10105,11 @@ commit_node(void *baton,
                                     scratch_pool));
   SVN_ERR(svn_sqlite__bind_properties(stmt, 15, cb->new_dav_cache,
                                       scratch_pool));
+  if (inherited_prop_blob.data != NULL)
+    {
+      SVN_ERR(svn_sqlite__bind_blob(stmt, 17, inherited_prop_blob.data,
+                                    inherited_prop_blob.len));
+    }
 
   SVN_ERR(svn_sqlite__step_done(stmt));
 
@@ -12477,6 +12744,118 @@ svn_wc__db_is_wcroot(svn_boolean_t *is_r
    return SVN_NO_ERROR;
 }
 
+/* This implements svn_wc__db_txn_callback_t for svn_wc_db__is_switched */
+static svn_error_t *
+db_is_switched(void *baton,
+               svn_wc__db_wcroot_t *wcroot,
+               const char *local_relpath,
+               apr_pool_t *scratch_pool)
+{
+  struct db_is_switched_baton_t *isb = baton;
+  svn_wc__db_status_t status;
+  apr_int64_t repos_id;
+  const char *repos_relpath;
+  const char *name;
+  const char *parent_local_relpath;
+  apr_int64_t parent_repos_id;
+  const char *parent_repos_relpath;
+
+  SVN_ERR_ASSERT(*local_relpath != '\0'); /* Handled in wrapper */
+
+  SVN_ERR(read_info(&status, isb->kind, NULL, &repos_relpath, &repos_id, NULL,
+                    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+                    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+                    wcroot, local_relpath, scratch_pool, scratch_pool));
+
+  if (status == svn_wc__db_status_server_excluded
+      || status == svn_wc__db_status_excluded
+      || status == svn_wc__db_status_not_present)
+    {
+      return svn_error_createf(
+                    SVN_ERR_WC_PATH_NOT_FOUND, NULL,
+                    _("The node '%s' was not found."),
+                    path_for_error_message(wcroot, local_relpath,
+                                           scratch_pool));
+    }
+  else if (! repos_relpath)
+    {
+      /* Node is shadowed; easy out */
+      if (isb->is_switched)
+        *isb->is_switched = FALSE;
+
+      return SVN_NO_ERROR;
+    }
+
+  if (! isb->is_switched)
+    return SVN_NO_ERROR;
+
+  svn_relpath_split(&parent_local_relpath, &name, local_relpath, scratch_pool);
+
+  SVN_ERR(svn_wc__db_base_get_info_internal(NULL, NULL, NULL,
+                                            &parent_repos_relpath,
+                                            &parent_repos_id, NULL, NULL, NULL,
+                                            NULL, NULL, NULL, NULL, NULL, NULL,
+                                            wcroot, parent_local_relpath,
+                                            scratch_pool, scratch_pool));
+
+  if (repos_id != parent_repos_id)
+    *isb->is_switched = TRUE;
+  else
+    {
+      const char *expected_relpath;
+
+      expected_relpath = svn_relpath_join(parent_repos_relpath, name,
+                                          scratch_pool);
+
+      *isb->is_switched = (strcmp(expected_relpath, repos_relpath) != 0);
+    }
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_wc__db_is_switched(svn_boolean_t *is_wcroot,
+                       svn_boolean_t *is_switched,
+                       svn_kind_t *kind,
+                       svn_wc__db_t *db,
+                       const char *local_abspath,
+                       apr_pool_t *scratch_pool)
+{
+  svn_wc__db_wcroot_t *wcroot;
+  const char *local_relpath;
+  struct db_is_switched_baton_t isb;
+
+  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
+
+  SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
+                              local_abspath, scratch_pool, scratch_pool));
+  VERIFY_USABLE_WCROOT(wcroot);
+
+  if (is_switched)
+    *is_switched = FALSE;
+
+  if (*local_relpath == '\0')
+    {
+      /* Easy out */
+      if (is_wcroot)
+        *is_wcroot = TRUE;
+      
+      if (kind)
+        *kind = svn_kind_dir;
+      return SVN_NO_ERROR;
+    }
+
+  if (is_wcroot)
+    *is_wcroot = FALSE;
+
+  isb.is_switched = is_switched;
+  isb.kind = kind;
+
+  return svn_error_trace(svn_wc__db_with_txn(wcroot, local_relpath,
+                                             db_is_switched, &isb,
+                                             scratch_pool));
+}
+
 
 svn_error_t *
 svn_wc__db_temp_wcroot_tempdir(const char **temp_dir_abspath,
@@ -13087,6 +13466,8 @@ svn_wc__db_temp_op_start_directory_updat
 struct make_copy_baton_t
 {
   int op_depth;
+  const svn_skel_t *conflicts;
+  const svn_skel_t *work_items;
 };
 
 
@@ -13135,6 +13516,7 @@ make_copy_txn(void *baton,
   svn_boolean_t add_working_base_deleted = FALSE;
   svn_boolean_t remove_working = FALSE;
   const apr_array_header_t *children;
+  struct make_copy_baton_t cbt;
   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
   int i;
 
@@ -13199,18 +13581,20 @@ make_copy_txn(void *baton,
   SVN_ERR(gather_repo_children(&children, wcroot, local_relpath,
                                0, scratch_pool, iterpool));
 
+  cbt.op_depth = mcb->op_depth;
+  cbt.conflicts = NULL;
+  cbt.work_items = NULL;
+
   for (i = 0; i < children->nelts; i++)
     {
       const char *name = APR_ARRAY_IDX(children, i, const char *);
-      struct make_copy_baton_t cbt;
+      
       const char *copy_relpath;
 
       svn_pool_clear(iterpool);
 
       copy_relpath = svn_relpath_join(local_relpath, name, iterpool);
 
-      cbt.op_depth = mcb->op_depth;
-
       SVN_ERR(make_copy_txn(&cbt, wcroot, copy_relpath, iterpool));
     }
 
@@ -13218,6 +13602,11 @@ make_copy_txn(void *baton,
                                                 iterpool),
                                                 svn_depth_empty, iterpool));
 
+  if (mcb->conflicts)
+    SVN_ERR(mark_conflict(wcroot, local_relpath, mcb->conflicts, iterpool));
+
+  SVN_ERR(add_work_items(wcroot->sdb, mcb->work_items, iterpool));
+
   svn_pool_destroy(iterpool);
 
   return SVN_NO_ERROR;
@@ -13225,9 +13614,11 @@ make_copy_txn(void *baton,
 
 
 svn_error_t *
-svn_wc__db_temp_op_make_copy(svn_wc__db_t *db,
-                             const char *local_abspath,
-                             apr_pool_t *scratch_pool)
+svn_wc__db_op_make_copy(svn_wc__db_t *db,
+                        const char *local_abspath,
+                        const svn_skel_t *conflicts,
+                        const svn_skel_t *work_items,
+                        apr_pool_t *scratch_pool)
 {
   svn_wc__db_wcroot_t *wcroot;
   const char *local_relpath;
@@ -13260,6 +13651,8 @@ svn_wc__db_temp_op_make_copy(svn_wc__db_
   SVN_ERR(catch_copy_of_server_excluded(wcroot, local_relpath, scratch_pool));
 
   mcb.op_depth = relpath_depth(local_relpath);
+  mcb.conflicts = conflicts;
+  mcb.work_items = work_items;
 
   SVN_ERR(svn_wc__db_with_txn(wcroot, local_relpath, make_copy_txn, &mcb,
                               scratch_pool));

Modified: subversion/branches/wc-collate-path/subversion/libsvn_wc/wc_db.h
URL: http://svn.apache.org/viewvc/subversion/branches/wc-collate-path/subversion/libsvn_wc/wc_db.h?rev=1416996&r1=1416995&r2=1416996&view=diff
==============================================================================
--- subversion/branches/wc-collate-path/subversion/libsvn_wc/wc_db.h (original)
+++ subversion/branches/wc-collate-path/subversion/libsvn_wc/wc_db.h Tue Dec  4 15:35:13 2012
@@ -134,7 +134,8 @@ typedef enum svn_wc__db_status_t {
     svn_wc__db_status_normal,
 
     /* The node has been added (potentially obscuring a delete or move of
-       the BASE node; see HAVE_BASE param). The text will be marked as
+       the BASE node; see HAVE_BASE param [### What param? This is an enum
+       not a function.] ). The text will be marked as
        modified, and if properties exist, they will be marked as modified.
 
        In many cases svn_wc__db_status_added means any of added, moved-here
@@ -511,6 +512,7 @@ svn_wc__db_base_add_file(svn_wc__db_t *d
                          svn_boolean_t delete_working,
                          svn_boolean_t update_actual_props,
                          apr_hash_t *new_actual_props,
+                         apr_array_header_t *new_iprops,
                          svn_boolean_t keep_recorded_info,
                          svn_boolean_t insert_base_deleted,
                          const svn_skel_t *conflict,
@@ -593,6 +595,7 @@ svn_wc__db_base_add_symlink(svn_wc__db_t
                             svn_boolean_t delete_working,
                             svn_boolean_t update_actual_props,
                             apr_hash_t *new_actual_props,
+                            apr_array_header_t *new_iprops,
                             svn_boolean_t keep_recorded_info,
                             svn_boolean_t insert_base_deleted,
                             const svn_skel_t *conflict,
@@ -1918,6 +1921,7 @@ struct svn_wc__db_info_t {
   svn_boolean_t op_root;
 
   svn_boolean_t has_checksum;
+  svn_boolean_t copied;
   svn_boolean_t had_props;
   svn_boolean_t props_mod;
 
@@ -2090,6 +2094,26 @@ svn_wc__db_read_pristine_props(apr_hash_
                                apr_pool_t *result_pool,
                                apr_pool_t *scratch_pool);
 
+
+/**
+ * Set @a *inherited_props to a depth-first ordered array of
+ * #svn_prop_inherited_item_t * structures representing the properties
+ * inherited by @a local_abspath from the ACTUAL tree above
+ * @a local_abspath (looking through to the WORKING or BASE tree as
+ * required), up to and including the root of the working copy and
+ * any cached inherited properties inherited by the root.
+ *
+ * Allocate @a *inherited_props in @a result_pool.  Use @a scratch_pool
+ * for temporary allocations.
+ */
+svn_error_t *
+svn_wc__db_read_inherited_props(apr_array_header_t **iprops,
+                                svn_wc__db_t *db,
+                                const char *local_abspath,
+                                const char *propname,
+                                apr_pool_t *result_pool,
+                                apr_pool_t *scratch_pool);
+
 /* Read a BASE node's inherited property information.
 
    Set *IPROPS to to a depth-first ordered array of
@@ -2112,9 +2136,11 @@ svn_wc__db_read_cached_iprops(apr_array_
 /* Find BASE nodes with cached inherited properties.
 
    Set *IPROPS_PATHS to a hash mapping const char * absolute working copy
-   paths to the same for each path in the working copy at or below
-   LOCAL_ABSPATH, limited by DEPTH, that has cached inherited properties
-   for the BASE node of the path.  Allocate *IPROP_PATHS in RESULT_POOL.
+   paths to the repos_relpath of the path for each path in the working copy
+   at or below LOCAL_ABSPATH, limited by DEPTH, that has cached inherited
+   properties for the BASE node of the path.
+
+   Allocate *IPROP_PATHS in RESULT_POOL.
    Use SCRATCH_POOL for temporary allocations. */
 svn_error_t *
 svn_wc__db_get_children_with_cached_iprops(apr_hash_t **iprop_paths,
@@ -2286,6 +2312,21 @@ svn_wc__db_is_wcroot(svn_boolean_t *is_r
                      const char *local_abspath,
                      apr_pool_t *scratch_pool);
 
+/* Checks if LOCAL_ABSPATH is a working copy root, switched and a directory.
+   With these answers we can answer all 'is anchor' questions that we need for
+   the different ra operations with just a single sqlite transaction and
+   filestat.
+
+   All output arguments can be null to specify that the result is not
+   interesting to the caller
+ */
+svn_error_t *
+svn_wc__db_is_switched(svn_boolean_t *is_wcroot,
+                       svn_boolean_t *is_switched,
+                       svn_kind_t *kind,
+                       svn_wc__db_t *db,
+                       const char *local_abspath,
+                       apr_pool_t *scratch_pool);
 
 
 /* @} */
@@ -3027,9 +3068,11 @@ svn_wc__db_temp_op_end_directory_update(
    leaving any subtree additions and copies as-is.  This allows the
    base node tree to be removed. */
 svn_error_t *
-svn_wc__db_temp_op_make_copy(svn_wc__db_t *db,
-                             const char *local_abspath,
-                             apr_pool_t *scratch_pool);
+svn_wc__db_op_make_copy(svn_wc__db_t *db,
+                        const char *local_abspath,
+                        const svn_skel_t *conflicts,
+                        const svn_skel_t *work_items,
+                        apr_pool_t *scratch_pool);
 
 /* Close the wc root LOCAL_ABSPATH and remove any per-directory
    handles associated with it. */
@@ -3204,8 +3247,8 @@ svn_wc__db_follow_moved_to(apr_array_hea
  * need to run as part of marking the conflict resolved. */
 svn_error_t *
 svn_wc__db_update_moved_away_conflict_victim(svn_skel_t **work_items,
-                                             const char *victim_abspath,
                                              svn_wc__db_t *db,
+                                             const char *victim_abspath,
                                              svn_wc_notify_func2_t notify_func,
                                              void *notify_baton,
                                              svn_cancel_func_t cancel_func,

Modified: subversion/branches/wc-collate-path/subversion/libsvn_wc/wc_db_private.h
URL: http://svn.apache.org/viewvc/subversion/branches/wc-collate-path/subversion/libsvn_wc/wc_db_private.h?rev=1416996&r1=1416995&r2=1416996&view=diff
==============================================================================
--- subversion/branches/wc-collate-path/subversion/libsvn_wc/wc_db_private.h (original)
+++ subversion/branches/wc-collate-path/subversion/libsvn_wc/wc_db_private.h Tue Dec  4 15:35:13 2012
@@ -260,6 +260,27 @@ svn_wc__db_base_get_info_internal(svn_wc
                                   apr_pool_t *result_pool,
                                   apr_pool_t *scratch_pool);
 
+/* Similar to svn_wc__db_base_get_info(), but taking WCROOT+LOCAL_RELPATH 
+ * instead of DB+LOCAL_ABSPATH, an explicit op-depth of the node to get
+ * information about, and outputting REPOS_ID instead of URL+UUID. */
+svn_error_t *
+svn_wc__db_depth_get_info(svn_wc__db_status_t *status,
+                          svn_kind_t *kind,
+                          svn_revnum_t *revision,
+                          const char **repos_relpath,
+                          apr_int64_t *repos_id,
+                          svn_revnum_t *changed_rev,
+                          apr_time_t *changed_date,
+                          const char **changed_author,
+                          svn_depth_t *depth,
+                          const svn_checksum_t **checksum,
+                          const char **target,
+                          svn_boolean_t *had_props,
+                          svn_wc__db_wcroot_t *wcroot,
+                          const char *local_relpath,
+                          int op_depth,
+                          apr_pool_t *result_pool,
+                          apr_pool_t *scratch_pool);
 
 /* Like svn_wc__db_read_conflict(), but with WCROOT+LOCAL_RELPATH instead of
    DB+LOCAL_ABSPATH, and outputting relpaths instead of abspaths. */

Modified: subversion/branches/wc-collate-path/subversion/libsvn_wc/wc_db_update_move.c
URL: http://svn.apache.org/viewvc/subversion/branches/wc-collate-path/subversion/libsvn_wc/wc_db_update_move.c?rev=1416996&r1=1416995&r2=1416996&view=diff
==============================================================================
--- subversion/branches/wc-collate-path/subversion/libsvn_wc/wc_db_update_move.c (original)
+++ subversion/branches/wc-collate-path/subversion/libsvn_wc/wc_db_update_move.c Tue Dec  4 15:35:13 2012
@@ -47,19 +47,23 @@
 
 #include "wc.h"
 #include "wc_db_private.h"
+#include "wc-queries.h"
 #include "conflicts.h"
 #include "workqueue.h"
 
 /*
  * Receiver code.
+ *
+ * The receiver is an editor that, when driven with a certain change, will
+ * merge the edits into the 'actual' layer of a moved subtree.
  */
 
 struct tc_editor_baton {
-  const char *src_relpath;
-  const char *dst_relpath;
+  svn_skel_t **work_items;
   svn_wc__db_t *db;
   svn_wc__db_wcroot_t *wcroot;
-  svn_skel_t **work_items;
+  const char *move_root_src_relpath;
+  const char *move_root_dst_relpath;
   svn_wc_conflict_version_t *old_version;
   svn_wc_conflict_version_t *new_version;
   svn_wc_notify_func2_t notify_func;
@@ -122,130 +126,209 @@ tc_editor_alter_directory(void *baton,
   return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL, NULL);
 }
 
+
+/* Check whether the node at LOCAL_RELPATH in the working copy at WCROOT
+ * is shadowed by some node at a higher op depth than EXPECTED_OP_DEPTH. */
+static svn_error_t *
+check_shadowed_node(svn_boolean_t *is_shadowed,
+                    int expected_op_depth,
+                    const char *local_relpath,
+                    svn_wc__db_wcroot_t *wcroot)
+{
+  svn_sqlite__stmt_t *stmt;
+  svn_boolean_t have_row;
+
+  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+                                    STMT_SELECT_WORKING_NODE));
+  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
+  SVN_ERR(svn_sqlite__step(&have_row, stmt));
+
+  while (have_row)
+    {
+      int op_depth = svn_sqlite__column_int(stmt, 0);
+
+      if (op_depth > expected_op_depth)
+        {
+          *is_shadowed = TRUE;
+          SVN_ERR(svn_sqlite__reset(stmt));
+
+          return SVN_NO_ERROR;
+        }
+
+      SVN_ERR(svn_sqlite__step(&have_row, stmt));
+    }
+
+  *is_shadowed = FALSE;
+  SVN_ERR(svn_sqlite__reset(stmt));
+
+  return SVN_NO_ERROR;
+}
+
+/* Update text and prop contents of the working file at DST_RELPATH
+ * in the working copy at WCROOT, from OLD_VERSION to NEW_VERSION,
+ * based on pristine contents identified by MOVE_SRC_CHECKSUM and
+ * MOVE_DST_CHECKSUM. MOVE_DST_REPOS_RELPATH is the repository path 
+ * the node at DST_RELPATH would be committed to.
+ * Use working copy database DB.
+ * Use NOTIFY_FUNC and NOTIFY_BATON for notifications.
+ * Add any required work items to *WORK_ITEMS, allocated in RESULT_POOL.
+ * Use SCRATCH_POOL for temporary allocations. */
+static svn_error_t *
+update_working_file(svn_skel_t **work_items,
+                    const char *dst_relpath,
+                    const char *move_dst_repos_relpath,
+                    const svn_checksum_t *move_src_checksum,
+                    const svn_checksum_t *move_dst_checksum,
+                    svn_wc_conflict_version_t *old_version,
+                    svn_wc_conflict_version_t *new_version,
+                    svn_wc__db_wcroot_t *wcroot,
+                    svn_wc__db_t *db,
+                    svn_wc_notify_func2_t notify_func,
+                    void *notify_baton,
+                    apr_pool_t *result_pool,
+                    apr_pool_t *scratch_pool)
+{
+  const char *moved_to_abspath = svn_dirent_join(wcroot->abspath,
+                                                 dst_relpath,
+                                                 scratch_pool);
+  const char *pre_update_pristine_abspath;
+  const char *post_update_pristine_abspath;
+  svn_skel_t *conflict_skel;
+  enum svn_wc_merge_outcome_t merge_outcome;
+  svn_wc_notify_state_t content_state;
+  svn_wc_notify_t *notify;
+
+  /*
+   * Run a 3-way merge to update the file, using the pre-update
+   * pristine text as the merge base, the post-update pristine
+   * text as the merge-left version, and the current content of the
+   * moved-here working file as the merge-right version.
+   */
+  SVN_ERR(svn_wc__db_pristine_get_path(&pre_update_pristine_abspath,
+                                       db, wcroot->abspath,
+                                       move_dst_checksum,
+                                       scratch_pool, scratch_pool));
+  SVN_ERR(svn_wc__db_pristine_get_path(&post_update_pristine_abspath,
+                                       db, wcroot->abspath,
+                                       move_src_checksum,
+                                       scratch_pool, scratch_pool));
+  SVN_ERR(svn_wc__internal_merge(work_items, &conflict_skel,
+                                 &merge_outcome, db,
+                                 pre_update_pristine_abspath,
+                                 post_update_pristine_abspath,
+                                 moved_to_abspath,
+                                 moved_to_abspath,
+                                 NULL, NULL, NULL, /* diff labels */
+                                 NULL, /* actual props */
+                                 FALSE, /* dry-run */
+                                 NULL, /* diff3-cmd */
+                                 NULL, /* merge options */
+                                 NULL, /* prop_diff */
+                                 NULL, NULL, /* cancel_func + baton */
+                                 result_pool, scratch_pool));
+
+  if (merge_outcome == svn_wc_merge_conflict)
+    {
+      svn_skel_t *work_item;
+      svn_wc_conflict_version_t *original_version;
+
+      if (conflict_skel)
+        {
+          original_version = svn_wc_conflict_version_dup(old_version,
+                                                         scratch_pool);
+          original_version->path_in_repos = move_dst_repos_relpath;
+          original_version->node_kind = svn_node_file;
+          SVN_ERR(svn_wc__conflict_skel_set_op_update(conflict_skel,
+                                                      original_version,
+                                                      scratch_pool,
+                                                      scratch_pool));
+          SVN_ERR(svn_wc__conflict_create_markers(&work_item, db,
+                                                  moved_to_abspath,
+                                                  conflict_skel,
+                                                  scratch_pool,
+                                                  scratch_pool));
+          *work_items = svn_wc__wq_merge(*work_items, work_item, result_pool);
+        }
+      content_state = svn_wc_notify_state_conflicted;
+    }
+  else
+    {
+      svn_boolean_t is_locally_modified;
+
+      SVN_ERR(svn_wc__internal_file_modified_p(&is_locally_modified,
+                                               db, moved_to_abspath,
+                                               FALSE /* exact_comparison */,
+                                               scratch_pool));
+      if (is_locally_modified)
+        content_state = svn_wc_notify_state_merged;
+      else
+        content_state = svn_wc_notify_state_changed;
+    }
+
+  notify = svn_wc_create_notify(moved_to_abspath,
+                                svn_wc_notify_update_update,
+                                scratch_pool);
+  notify->kind = svn_node_file;
+  notify->content_state = content_state;
+  notify->prop_state = svn_wc_notify_state_unknown; /* ### TODO */
+  notify->old_revision = old_version->peg_rev;
+  notify->revision = new_version->peg_rev;
+  notify_func(notify_baton, notify, scratch_pool);
+
+  return SVN_NO_ERROR;
+}
+
+
 static svn_error_t *
 tc_editor_alter_file(void *baton,
                      const char *dst_relpath,
-                     svn_revnum_t expected_moved_here_revision,
+                     svn_revnum_t expected_move_dst_revision,
                      apr_hash_t *props,
-                     const svn_checksum_t *moved_away_checksum,
+                     const svn_checksum_t *move_src_checksum,
                      svn_stream_t *post_update_contents,
                      apr_pool_t *scratch_pool)
 {
   struct tc_editor_baton *b = baton;
-  const svn_checksum_t *moved_here_checksum;
-  const char *original_repos_relpath;
-  svn_revnum_t original_revision;
-  svn_kind_t kind;
+  const svn_checksum_t *move_dst_checksum;
+  const char *move_dst_repos_relpath;
+  svn_revnum_t move_dst_revision;
+  svn_kind_t move_dst_kind;
 
   /* Get kind, revision, and checksum of the moved-here node. */
-  /* 
-   * ### Currently doesn't work right if the moved-away node has been replaced.
-   * ### Need to read info from the move op-root's op-depth, not WORKING, to
-   * ### properly update shadowed nodes within multi-layer move destinations.
-   */
-  SVN_ERR(svn_wc__db_read_info_internal(NULL, &kind, NULL, NULL, NULL, NULL,
-                                        NULL, NULL, NULL, &moved_here_checksum,
-                                        NULL, &original_repos_relpath, NULL,
-                                        &original_revision, NULL, NULL, NULL,
-                                        NULL, NULL, NULL, NULL, NULL, NULL,
-                                        NULL, NULL, b->wcroot, dst_relpath,
-                                        scratch_pool, scratch_pool));
-  SVN_ERR_ASSERT(original_revision == expected_moved_here_revision);
-
-  /* ### check original revision against moved-here op-root revision? */
-  if (kind != svn_kind_file)
-    return SVN_NO_ERROR;
-
-  /* ### what if checksum kind differs?*/
-  if (!svn_checksum_match(moved_away_checksum, moved_here_checksum))
+  SVN_ERR(svn_wc__db_depth_get_info(NULL, &move_dst_kind, &move_dst_revision,
+                                    &move_dst_repos_relpath, NULL, NULL, NULL,
+                                    NULL, NULL, &move_dst_checksum, NULL,
+                                    NULL, b->wcroot, dst_relpath,
+                                    relpath_depth(b->move_root_dst_relpath),
+                                    scratch_pool, scratch_pool));
+  SVN_ERR_ASSERT(move_dst_revision == expected_move_dst_revision);
+  SVN_ERR_ASSERT(move_dst_kind == svn_kind_file);
+
+  /* ### TODO update revision etc. in NODES table */
+
+  /* Update file and prop contents if the update has changed them. */
+  if (!svn_checksum_match(move_src_checksum, move_dst_checksum)
+      /* ### || props have changed */)
     {
-      const char *moved_to_abspath = svn_dirent_join(b->wcroot->abspath,
-                                                     dst_relpath,
-                                                     scratch_pool);
-      const char *pre_update_pristine_abspath;
-      const char *post_update_pristine_abspath;
-      svn_skel_t *conflict_skel;
-      enum svn_wc_merge_outcome_t merge_outcome;
-      svn_wc_notify_state_t content_state;
-      svn_wc_notify_t *notify;
-
-      /*
-       * Run a 3-way merge to update the file, using the pre-update
-       * pristine text as the merge base, the post-update pristine
-       * text as the merge-left version, and the current content of the
-       * moved-here working file as the merge-right version.
-       */
-      SVN_ERR(svn_wc__db_pristine_get_path(&pre_update_pristine_abspath,
-                                           b->db, moved_to_abspath,
-                                           moved_here_checksum,
-                                           scratch_pool, scratch_pool));
-      SVN_ERR(svn_wc__db_pristine_get_path(&post_update_pristine_abspath,
-                                           b->db, moved_to_abspath,
-                                           moved_away_checksum,
-                                           scratch_pool, scratch_pool));
-      SVN_ERR(svn_wc__internal_merge(b->work_items, &conflict_skel,
-                                     &merge_outcome, b->db,
-                                     pre_update_pristine_abspath,
-                                     post_update_pristine_abspath,
-                                     moved_to_abspath,
-                                     moved_to_abspath,
-                                     NULL, NULL, NULL, /* diff labels */
-                                     NULL, /* actual props */
-                                     FALSE, /* dry-run */
-                                     NULL, /* diff3-cmd */
-                                     NULL, /* merge options */
-                                     NULL, /* prop_diff */
-                                     NULL, NULL, /* cancel_func + baton */
-                                     b->result_pool, scratch_pool));
+      svn_boolean_t is_shadowed;
 
-      if (merge_outcome == svn_wc_merge_conflict)
+      /* If the node is shadowed by a higher layer, we need to flag a 
+       * tree conflict and must not touch the working file. */
+      SVN_ERR(check_shadowed_node(&is_shadowed,
+                                  relpath_depth(b->move_root_dst_relpath),
+                                  dst_relpath, b->wcroot));
+      if (is_shadowed)
         {
-          svn_skel_t *work_item;
-          svn_wc_conflict_version_t *original_version;
-
-          if (conflict_skel)
-            {
-              original_version = svn_wc_conflict_version_dup(b->old_version,
-                                                             scratch_pool);
-              original_version->path_in_repos = original_repos_relpath;
-              original_version->node_kind = svn_node_file;
-              SVN_ERR(svn_wc__conflict_skel_set_op_update(conflict_skel,
-                                                          original_version,
-                                                          scratch_pool,
-                                                          scratch_pool));
-              SVN_ERR(svn_wc__conflict_create_markers(&work_item, b->db,
-                                                      moved_to_abspath,
-                                                      conflict_skel,
-                                                      scratch_pool,
-                                                      scratch_pool));
-              *b->work_items = svn_wc__wq_merge(*b->work_items, work_item,
-                                                b->result_pool);
-            }
-          content_state = svn_wc_notify_state_conflicted;
+          /* ### TODO flag tree conflict */
         }
       else
-        {
-          svn_boolean_t is_locally_modified;
-
-          SVN_ERR(svn_wc__internal_file_modified_p(&is_locally_modified,
-                                                   b->db, moved_to_abspath,
-                                                   FALSE /* exact_comparison */,
-                                                   scratch_pool));
-          if (is_locally_modified)
-            content_state = svn_wc_notify_state_merged;
-          else
-            content_state = svn_wc_notify_state_changed;
-        }
-
-      notify = svn_wc_create_notify(moved_to_abspath,
-                                    svn_wc_notify_update_update,
-                                    scratch_pool);
-      notify->kind = svn_node_file;
-      notify->content_state = content_state;
-      notify->prop_state = svn_wc_notify_state_unknown; /* ### TODO */
-      notify->old_revision = b->old_version->peg_rev;
-      notify->revision = b->new_version->peg_rev;
-      b->notify_func(b->notify_baton, notify, scratch_pool);
+        SVN_ERR(update_working_file(b->work_items, dst_relpath,
+                                    move_dst_repos_relpath,
+                                    move_src_checksum, move_dst_checksum,
+                                    b->old_version, b->new_version,
+                                    b->wcroot, b->db,
+                                    b->notify_func, b->notify_baton,
+                                    b->result_pool, scratch_pool));
     }
 
   return SVN_NO_ERROR;
@@ -310,7 +393,7 @@ tc_editor_complete(void *baton,
   svn_wc_notify_t *notify;
 
   notify = svn_wc_create_notify(svn_dirent_join(b->wcroot->abspath,
-                                                b->dst_relpath,
+                                                b->move_root_dst_relpath,
                                                 scratch_pool),
                                 svn_wc_notify_update_completed,
                                 scratch_pool);
@@ -330,6 +413,13 @@ tc_editor_abort(void *baton,
   return SVN_NO_ERROR;
 }
 
+/* An editor.
+ *
+ * This editor will merge the edits into the 'actual' tree at
+ * MOVE_ROOT_DST_RELPATH (in struct tc_editor_baton),
+ * perhaps raising conflicts if necessary.
+ *
+ */
 static const svn_editor_cb_many_t editor_ops = {
   tc_editor_add_directory,
   tc_editor_add_file,
@@ -349,16 +439,33 @@ static const svn_editor_cb_many_t editor
 
 /*
  * Driver code.
+ *
+ * The scenario is that a subtree has been locally moved, and then the base
+ * layer on the source side of the move has received an update to a new
+ * state.  The destination subtree has not yet been updated, and still
+ * matches the pre-update state of the source subtree.
+ *
+ * The edit driver drives the receiver with the difference between the
+ * pre-update state (as found now at the move-destination) and the
+ * post-update state (found now at the move-source).
+ *
+ * We currently assume that both the pre-update and post-update states are
+ * single-revision.
  */
 
+/* Set *OPERATION, *LOCAL_CHANGE, *INCOMING_CHANGE, *OLD_VERSION, *NEW_VERSION
+ * to reflect the tree conflict on the victim SRC_ABSPATH in DB.
+ *
+ * If SRC_ABSPATH is not a tree-conflict victim, return an error.
+ */
 static svn_error_t *
 get_tc_info(svn_wc_operation_t *operation,
             svn_wc_conflict_reason_t *local_change,
             svn_wc_conflict_action_t *incoming_change,
             svn_wc_conflict_version_t **old_version,
             svn_wc_conflict_version_t **new_version,
-            const char *src_abspath,
             svn_wc__db_t *db,
+            const char *src_abspath,
             apr_pool_t *result_pool,
             apr_pool_t *scratch_pool)
 {
@@ -404,7 +511,7 @@ get_tc_info(svn_wc_operation_t *operatio
           svn_revnum_t revision;
           svn_node_kind_t node_kind;
 
-          /* Construct b->new_version from BASE info. */
+          /* Construct new_version from BASE info. */
           SVN_ERR(svn_wc__db_base_get_info(NULL, &kind, &revision,
                                            &repos_relpath, &repos_root_url,
                                            &repos_uuid, NULL, NULL, NULL,
@@ -430,47 +537,51 @@ get_tc_info(svn_wc_operation_t *operatio
   return SVN_NO_ERROR;
 }
 
+/* ### Drive TC_EDITOR so as to ...
+ */
 static svn_error_t *
 update_moved_away_file(svn_editor_t *tc_editor,
                        const char *src_relpath,
                        const char *dst_relpath,
-                       const char *move_dst_op_root_relpath,
-                       svn_revnum_t move_dst_op_root_revision,
+                       const char *move_root_dst_relpath,
+                       svn_revnum_t move_root_dst_revision,
                        svn_wc__db_t *db,
                        svn_wc__db_wcroot_t *wcroot,
                        apr_pool_t *scratch_pool)
 {
   svn_kind_t kind;
   svn_stream_t *post_update_contents;
-  const svn_checksum_t *moved_away_checksum;
+  const svn_checksum_t *move_src_checksum;
                     
   /* Read post-update contents from the updated moved-away file and tell
    * the editor to merge them into the moved-here file. */
   SVN_ERR(svn_wc__db_read_pristine_info(NULL, &kind, NULL, NULL, NULL, NULL,
-                                        &moved_away_checksum, NULL, NULL, db,
+                                        &move_src_checksum, NULL, NULL, db,
                                         svn_dirent_join(wcroot->abspath,
                                                         src_relpath,
                                                         scratch_pool),
                                         scratch_pool, scratch_pool));
   SVN_ERR(svn_wc__db_pristine_read(&post_update_contents, NULL, db,
-                                   wcroot->abspath, moved_away_checksum,
+                                   wcroot->abspath, move_src_checksum,
                                    scratch_pool, scratch_pool));
   SVN_ERR(svn_editor_alter_file(tc_editor, dst_relpath,
-                                move_dst_op_root_revision,
+                                move_root_dst_revision,
                                 NULL, /* ### TODO props */
-                                moved_away_checksum,
+                                move_src_checksum,
                                 post_update_contents));
   SVN_ERR(svn_stream_close(post_update_contents));
 
   return SVN_NO_ERROR;
 }
 
+/* ### Drive TC_EDITOR so as to ...
+ */
 static svn_error_t *
 update_moved_away_dir(svn_editor_t *tc_editor,
                       const char *src_relpath,
                       const char *dst_relpath,
-                      const char *move_dst_op_root_relpath,
-                      svn_revnum_t move_dst_op_root_revision,
+                      const char *move_root_dst_relpath,
+                      svn_revnum_t move_root_dst_revision,
                       svn_wc__db_t *db,
                       svn_wc__db_wcroot_t *wcroot,
                       apr_pool_t *scratch_pool)
@@ -484,12 +595,14 @@ update_moved_away_dir(svn_editor_t *tc_e
   return SVN_NO_ERROR;
 }
 
+/* ### Drive TC_EDITOR so as to ...
+ */
 static svn_error_t *
 update_moved_away_subtree(svn_editor_t *tc_editor,
                           const char *src_relpath,
                           const char *dst_relpath,
-                          const char *move_dst_op_root_relpath,
-                          svn_revnum_t move_dst_op_root_revision,
+                          const char *move_root_dst_relpath,
+                          svn_revnum_t move_root_dst_revision,
                           svn_wc__db_t *db,
                           svn_wc__db_wcroot_t *wcroot,
                           apr_pool_t *scratch_pool)
@@ -499,8 +612,8 @@ update_moved_away_subtree(svn_editor_t *
   int i;
 
   SVN_ERR(update_moved_away_dir(tc_editor, src_relpath, dst_relpath,
-                                move_dst_op_root_relpath,
-                                move_dst_op_root_revision,
+                                move_root_dst_relpath,
+                                move_root_dst_revision,
                                 db, wcroot, scratch_pool));
 
   SVN_ERR(svn_wc__db_base_get_children(&children, db,
@@ -531,7 +644,7 @@ update_moved_away_subtree(svn_editor_t *
                                                 wcroot, child_src_relpath,
                                                 iterpool, iterpool));
       if (child_dst_op_root_relpath == NULL ||
-          strcmp(child_dst_op_root_relpath, move_dst_op_root_relpath) != 0)
+          strcmp(child_dst_op_root_relpath, move_root_dst_relpath) != 0)
         continue;
 
       SVN_ERR(svn_wc__db_base_get_info_internal(NULL, &child_kind,
@@ -544,14 +657,14 @@ update_moved_away_subtree(svn_editor_t *
       if (child_kind == svn_kind_file || child_kind == svn_kind_symlink)
         SVN_ERR(update_moved_away_file(tc_editor, child_src_relpath,
                                        child_dst_relpath,
-                                       move_dst_op_root_relpath,
-                                       move_dst_op_root_revision,
+                                       move_root_dst_relpath,
+                                       move_root_dst_revision,
                                        db, wcroot, iterpool));
       else if (child_kind == svn_kind_dir)
         SVN_ERR(update_moved_away_subtree(tc_editor, child_src_relpath,
                                           child_dst_relpath,
-                                          move_dst_op_root_relpath,
-                                          move_dst_op_root_revision,
+                                          move_root_dst_relpath,
+                                          move_root_dst_revision,
                                           db, wcroot, iterpool));
     }
   svn_pool_destroy(iterpool);
@@ -559,6 +672,17 @@ update_moved_away_subtree(svn_editor_t *
   return SVN_NO_ERROR;
 }
 
+/* Transfer changes from the move source to the move destination.
+ *
+ * Drive the editor TC_EDITOR with the difference between DST_RELPATH
+ * (at its own op-depth) and SRC_RELPATH (at op-depth zero).
+ *
+ * Then update the single op-depth layer in the move destination subtree
+ * rooted at DST_RELPATH to make it match the move source subtree
+ * rooted at SRC_RELPATH.
+ *
+ * ### And the other params?
+ */
 static svn_error_t *
 drive_tree_conflict_editor(svn_editor_t *tc_editor,
                            const char *src_relpath,
@@ -587,17 +711,9 @@ drive_tree_conflict_editor(svn_editor_t 
                                               src_relpath, scratch_pool),
                               scratch_pool));
 
-  /*
-   * Drive the TC editor to transfer incoming changes from the move source
-   * to the move destination.
-   *
-   * The pre-update tree is within dst at the op-depth of the move's op-root.
-   * The post-update base tree is within src at op-depth zero.
-   *
-   * We walk the move source (i.e. the post-update tree), comparing each node
+  /* We walk the move source (i.e. the post-update tree), comparing each node
    * with the equivalent node at the move destination and applying the update
-   * to nodes at the move destination.
-   */
+   * to nodes at the move destination. */
   if (old_version->node_kind == svn_node_file)
     SVN_ERR(update_moved_away_file(tc_editor, src_relpath, dst_relpath,
                                    dst_relpath, old_version->peg_rev,
@@ -614,13 +730,12 @@ drive_tree_conflict_editor(svn_editor_t 
 
 struct update_moved_away_conflict_victim_baton {
   svn_skel_t **work_items;
-  const char *victim_relpath;
+  svn_wc__db_t *db;
   svn_wc_operation_t operation;
   svn_wc_conflict_reason_t local_change;
   svn_wc_conflict_action_t incoming_change;
   svn_wc_conflict_version_t *old_version;
   svn_wc_conflict_version_t *new_version;
-  svn_wc__db_t *db;
   svn_wc_notify_func2_t notify_func;
   void *notify_baton;
   svn_cancel_func_t cancel_func;
@@ -628,7 +743,8 @@ struct update_moved_away_conflict_victim
   apr_pool_t *result_pool;
 };
 
-/* An implementation of svn_wc__db_txn_callback_t. */
+/* The body of svn_wc__db_update_moved_away_conflict_victim(), which see.
+ * An implementation of svn_wc__db_txn_callback_t. */
 static svn_error_t *
 update_moved_away_conflict_victim(void *baton,
                                   svn_wc__db_wcroot_t *wcroot,
@@ -643,18 +759,15 @@ update_moved_away_conflict_victim(void *
 
   /* Construct editor baton. */
   tc_editor_baton = apr_pcalloc(scratch_pool, sizeof(*tc_editor_baton));
-  tc_editor_baton->src_relpath = b->victim_relpath;
-  SVN_ERR(svn_wc__db_scan_deletion_internal(NULL,
-                                            &tc_editor_baton->dst_relpath,
-                                            NULL, NULL, wcroot,
-                                            tc_editor_baton->src_relpath,
-                                            scratch_pool, scratch_pool));
-  if (tc_editor_baton->dst_relpath == NULL)
+  tc_editor_baton->move_root_src_relpath = victim_relpath;
+  SVN_ERR(svn_wc__db_scan_deletion_internal(
+            NULL, &tc_editor_baton->move_root_dst_relpath, NULL, NULL,
+            wcroot, victim_relpath, scratch_pool, scratch_pool));
+  if (tc_editor_baton->move_root_dst_relpath == NULL)
     return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL,
                              _("The node '%s' has not been moved away"),
                              svn_dirent_local_style(
-                               svn_dirent_join(wcroot->abspath,
-                                               b->victim_relpath,
+                               svn_dirent_join(wcroot->abspath, victim_relpath,
                                                scratch_pool),
                                scratch_pool));
   tc_editor_baton->old_version= b->old_version;
@@ -674,8 +787,8 @@ update_moved_away_conflict_victim(void *
 
   /* ... and drive it. */
   SVN_ERR(drive_tree_conflict_editor(tc_editor,
-                                     tc_editor_baton->src_relpath,
-                                     tc_editor_baton->dst_relpath,
+                                     tc_editor_baton->move_root_src_relpath,
+                                     tc_editor_baton->move_root_dst_relpath,
                                      b->operation,
                                      b->local_change, b->incoming_change,
                                      tc_editor_baton->old_version,
@@ -690,8 +803,8 @@ update_moved_away_conflict_victim(void *
 
 svn_error_t *
 svn_wc__db_update_moved_away_conflict_victim(svn_skel_t **work_items,
-                                             const char *victim_abspath,
                                              svn_wc__db_t *db,
+                                             const char *victim_abspath,
                                              svn_wc_notify_func2_t notify_func,
                                              void *notify_baton,
                                              svn_cancel_func_t cancel_func,
@@ -702,15 +815,11 @@ svn_wc__db_update_moved_away_conflict_vi
   struct update_moved_away_conflict_victim_baton b;
   svn_wc__db_wcroot_t *wcroot;
   const char *local_relpath;
-  svn_wc_operation_t operation;
-  svn_wc_conflict_reason_t local_change;
-  svn_wc_conflict_action_t incoming_change;
-  svn_wc_conflict_version_t *old_version;
-  svn_wc_conflict_version_t *new_version;
 
-  SVN_ERR(get_tc_info(&operation, &local_change, &incoming_change,
-                      &old_version, &new_version,
-                      victim_abspath, db, scratch_pool, scratch_pool));
+  SVN_ERR(get_tc_info(&b.operation, &b.local_change, &b.incoming_change,
+                      &b.old_version, &b.new_version,
+                      db, victim_abspath,
+                      scratch_pool, scratch_pool));
 
   SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath,
                                                 db, victim_abspath,
@@ -718,12 +827,6 @@ svn_wc__db_update_moved_away_conflict_vi
   VERIFY_USABLE_WCROOT(wcroot);
 
   b.work_items = work_items;
-  b.victim_relpath = local_relpath;
-  b.operation = operation;
-  b.local_change = local_change;
-  b.incoming_change = incoming_change;
-  b.old_version = old_version;
-  b.new_version = new_version;
   b.db = db;
   b.notify_func = notify_func;
   b.notify_baton = notify_baton;

Modified: subversion/branches/wc-collate-path/subversion/libsvn_wc/wc_db_wcroot.c
URL: http://svn.apache.org/viewvc/subversion/branches/wc-collate-path/subversion/libsvn_wc/wc_db_wcroot.c?rev=1416996&r1=1416995&r2=1416996&view=diff
==============================================================================
--- subversion/branches/wc-collate-path/subversion/libsvn_wc/wc_db_wcroot.c (original)
+++ subversion/branches/wc-collate-path/subversion/libsvn_wc/wc_db_wcroot.c Tue Dec  4 15:35:13 2012
@@ -419,7 +419,7 @@ svn_wc__db_wcroot_parse_local_abspath(sv
   svn_wc__db_wcroot_t *probe_wcroot;
   svn_wc__db_wcroot_t *found_wcroot = NULL;
   const char *scan_abspath;
-  svn_sqlite__db_t *sdb;
+  svn_sqlite__db_t *sdb = NULL;
   svn_boolean_t moved_upwards = FALSE;
   svn_boolean_t always_check = FALSE;
   int wc_format = 0;
@@ -763,7 +763,8 @@ try_symlink_as_dir:
                                        scratch_pool));
               /* This handle was opened in this function but is not going
                  to be used further so close it. */
-              SVN_ERR(svn_sqlite__close(sdb));
+              if (sdb)
+                SVN_ERR(svn_sqlite__close(sdb));
               goto try_symlink_as_dir;
             }
         }

Modified: subversion/branches/wc-collate-path/subversion/mod_dav_svn/authz.c
URL: http://svn.apache.org/viewvc/subversion/branches/wc-collate-path/subversion/mod_dav_svn/authz.c?rev=1416996&r1=1416995&r2=1416996&view=diff
==============================================================================
--- subversion/branches/wc-collate-path/subversion/mod_dav_svn/authz.c (original)
+++ subversion/branches/wc-collate-path/subversion/mod_dav_svn/authz.c Tue Dec  4 15:35:13 2012
@@ -97,6 +97,55 @@ dav_svn__allow_read(request_rec *r,
 }
 
 
+svn_boolean_t
+dav_svn__allow_list_repos(request_rec *r,
+                          const char *repos_name,
+                          apr_pool_t *pool)
+{
+  const char *uri;
+  request_rec *subreq;
+  svn_boolean_t allowed = FALSE;
+  authz_svn__subreq_bypass_func_t allow_read_bypass = NULL;
+
+  /* Easy out:  if the admin has explicitly set 'SVNPathAuthz Off',
+     then this whole callback does nothing. */
+  if (! dav_svn__get_pathauthz_flag(r))
+    {
+      return TRUE;
+    }
+
+  /* If bypass is specified and authz has exported the provider.
+     Otherwise, we fall through to the full version.  This should be
+     safer than allowing or disallowing all accesses if there is a
+     configuration error.
+     XXX: Is this the proper thing to do in this case? */
+  allow_read_bypass = dav_svn__get_pathauthz_bypass(r);
+  if (allow_read_bypass != NULL)
+    {
+      if (allow_read_bypass(r, "/", repos_name) == OK)
+        return TRUE;
+      else
+        return FALSE;
+    }
+
+  /* Build a Public Resource uri representing repository root. */
+  uri =  svn_urlpath__join(dav_svn__get_root_dir(r),
+                           svn_path_uri_encode(repos_name, pool), pool);
+
+  /* Check if GET would work against this uri. */
+  subreq = ap_sub_req_method_uri("GET", uri, r, r->output_filters);
+
+  if (subreq)
+    {
+      if (subreq->status == HTTP_OK)
+        allowed = TRUE;
+
+      ap_destroy_sub_req(subreq);
+    }
+
+  return allowed;
+}
+
 /* This function implements 'svn_repos_authz_func_t', specifically
    for read authorization.
 

Modified: subversion/branches/wc-collate-path/subversion/mod_dav_svn/dav_svn.h
URL: http://svn.apache.org/viewvc/subversion/branches/wc-collate-path/subversion/mod_dav_svn/dav_svn.h?rev=1416996&r1=1416995&r2=1416996&view=diff
==============================================================================
--- subversion/branches/wc-collate-path/subversion/mod_dav_svn/dav_svn.h (original)
+++ subversion/branches/wc-collate-path/subversion/mod_dav_svn/dav_svn.h Tue Dec  4 15:35:13 2012
@@ -746,6 +746,20 @@ dav_svn__allow_read_resource(const dav_r
                              apr_pool_t *pool);
 
 
+/* Return TRUE iff the current user (as determined by Apache's
+   authentication system) has permission to read repository REPOS_NAME.
+   This will invoke any authz modules loaded into Apache unless this
+   Subversion location has been configured to bypass those in favor of a
+   direct lookup in the Subversion authz subsystem. Use POOL for any
+   temporary allocation.
+   IMPORTANT: R must be request for DAV_SVN_RESTYPE_PARENTPATH_COLLECTION
+   resource.
+*/
+svn_boolean_t
+dav_svn__allow_list_repos(request_rec *r,
+                          const char *repos_name,
+                          apr_pool_t *pool);
+
 /* If authz is enabled in the specified BATON, return a read authorization
    function. Otherwise, return NULL. */
 svn_repos_authz_func_t

Modified: subversion/branches/wc-collate-path/subversion/mod_dav_svn/reports/inherited-props.c
URL: http://svn.apache.org/viewvc/subversion/branches/wc-collate-path/subversion/mod_dav_svn/reports/inherited-props.c?rev=1416996&r1=1416995&r2=1416996&view=diff
==============================================================================
--- subversion/branches/wc-collate-path/subversion/mod_dav_svn/reports/inherited-props.c (original)
+++ subversion/branches/wc-collate-path/subversion/mod_dav_svn/reports/inherited-props.c Tue Dec  4 15:35:13 2012
@@ -113,7 +113,7 @@ dav_svn__get_inherited_props_report(cons
                                 "couldn't retrieve revision root",
                                 resource->pool);
 
-  serr = svn_repos_fs_get_inherited_props(&inherited_props, root, path,
+  serr = svn_repos_fs_get_inherited_props(&inherited_props, root, path, NULL,
                                           dav_svn__authz_read_func(&arb),
                                           &arb, resource->pool, iterpool);
   if (serr)

Modified: subversion/branches/wc-collate-path/subversion/mod_dav_svn/reports/update.c
URL: http://svn.apache.org/viewvc/subversion/branches/wc-collate-path/subversion/mod_dav_svn/reports/update.c?rev=1416996&r1=1416995&r2=1416996&view=diff
==============================================================================
--- subversion/branches/wc-collate-path/subversion/mod_dav_svn/reports/update.c (original)
+++ subversion/branches/wc-collate-path/subversion/mod_dav_svn/reports/update.c Tue Dec  4 15:35:13 2012
@@ -618,12 +618,8 @@ send_propchange(item_baton_t *b,
 {
   const char *qname;
 
-  /* Ensure that the property name is XML-safe.
-     apr_xml_quote_string() doesn't realloc if there is nothing to
-     quote, so dup the name, but only if necessary. */
-  qname = apr_xml_quote_string(b->pool, name, 1);
-  if (qname == name)
-    qname = apr_pstrdup(b->pool, name);
+  /* Ensure that the property name is XML-safe. */
+  qname = apr_xml_quote_string(pool, name, 1);
 
   if (value)
     {

Modified: subversion/branches/wc-collate-path/subversion/mod_dav_svn/repos.c
URL: http://svn.apache.org/viewvc/subversion/branches/wc-collate-path/subversion/mod_dav_svn/repos.c?rev=1416996&r1=1416995&r2=1416996&view=diff
==============================================================================
--- subversion/branches/wc-collate-path/subversion/mod_dav_svn/repos.c (original)
+++ subversion/branches/wc-collate-path/subversion/mod_dav_svn/repos.c Tue Dec  4 15:35:13 2012
@@ -2596,121 +2596,6 @@ is_parent_resource(const dav_resource *r
 }
 
 
-#if 0
-/* Given an apache request R and a ROOT_PATH to the svn location
-   block, set *KIND to the node-kind of the URI's associated
-   (revision, path) pair, if possible.
-
-   Public uris, baseline collections, version resources, and working
-   (non-baseline) resources all have associated (revision, path)
-   pairs, and thus one of {svn_node_file, svn_node_dir, svn_node_none}
-   will be returned.
-
-   If URI is something more abstract, then set *KIND to
-   svn_node_unknown.  This is true for baselines, working baselines,
-   version controled configurations, activities, histories, and other
-   private resources.
-*/
-static dav_error *
-resource_kind(request_rec *r,
-              const char *uri,
-              const char *root_path,
-              svn_node_kind_t *kind)
-{
-  dav_error *derr;
-  svn_error_t *serr;
-  dav_resource *resource;
-  svn_revnum_t base_rev;
-  svn_fs_root_t *base_rev_root;
-  char *saved_uri;
-
-  /* Temporarily insert the uri that the user actually wants us to
-     convert into a resource.  Typically, this is already r->uri, so
-     this is usually a no-op.  But sometimes the caller may pass in
-     the Destination: header uri.
-
-     ### WHAT WE REALLY WANT here is to refactor get_resource,
-     so that some alternate interface actually allows us to specify
-     the URI to process, i.e. not always process r->uri.
-  */
-  saved_uri = r->uri;
-  r->uri = apr_pstrdup(r->pool, uri);
-
-  /* parse the uri and prep the associated resource. */
-  derr = get_resource(r, root_path,
-                      /* ### I can't believe that every single
-                         parser ignores the LABEL and USE_CHECKED_IN
-                         args below!! */
-                      "ignored_label", 1,
-                      &resource);
-  /* Restore r back to normal. */
-  r->uri = saved_uri;
-
-  if (derr)
-    return derr;
-
-  if (resource->type == DAV_RESOURCE_TYPE_REGULAR)
-    {
-      /* Either a public URI or a bc.  In both cases, prep_regular()
-         has already set the 'exists' and 'collection' flags by
-         querying the appropriate revision root and path.  */
-      if (! resource->exists)
-        *kind = svn_node_none;
-      else
-        *kind = resource->collection ? svn_node_dir : svn_node_file;
-    }
-
-  else if (resource->type == DAV_RESOURCE_TYPE_VERSION)
-    {
-      if (resource->baselined)  /* bln */
-        *kind = svn_node_unknown;
-
-      else /* ver */
-        {
-          derr = fs_check_path(kind, resource->info->root.root,
-                               resource->info->repos_path, r->pool);
-          if (derr != NULL)
-            return derr;
-        }
-    }
-
-  else if (resource->type == DAV_RESOURCE_TYPE_WORKING)
-    {
-      if (resource->baselined) /* wbl */
-        *kind = svn_node_unknown;
-
-      else /* wrk */
-        {
-          /* don't call fs_check_path on the txn, but on the original
-             revision that the txn is based on. */
-          base_rev = svn_fs_txn_base_revision(resource->info->root.txn);
-          serr = svn_fs_revision_root(&base_rev_root,
-                                      resource->info->repos->fs,
-                                      base_rev, r->pool);
-          if (serr)
-            return dav_svn__convert_err
-              (serr, HTTP_INTERNAL_SERVER_ERROR,
-               apr_psprintf(r->pool,
-                            "Could not open root of revision %ld",
-                            base_rev),
-               r->pool);
-
-          derr = fs_check_path(kind, base_rev_root,
-                               resource->info->repos_path, r->pool);
-          if (derr != NULL)
-            return derr;
-        }
-    }
-
-  else
-    /* act, his, vcc, or some other private resource */
-    *kind = svn_node_unknown;
-
-  return NULL;
-}
-#endif
-
-
 static dav_error *
 open_stream(const dav_resource *resource,
             dav_stream_mode mode,
@@ -2730,14 +2615,13 @@ open_stream(const dav_resource *resource
         }
     }
 
-#if 1
+  /* ### TODO:  Can we support range writes someday? */
   if (mode == DAV_MODE_WRITE_SEEKABLE)
     {
       return dav_svn__new_error(resource->pool, HTTP_NOT_IMPLEMENTED, 0,
                                 "Resource body writes cannot use ranges "
                                 "(at this time).");
     }
-#endif
 
   /* start building the stream structure */
   *stream = apr_pcalloc(resource->pool, sizeof(**stream));
@@ -3469,9 +3353,9 @@ deliver(const dav_resource *resource, ap
             }
           else
             {
-              /* ### TODO:  We could test for readability of the root
-                     directory of each repository and hide those that
-                     the user can't see. */
+                if (! dav_svn__allow_list_repos(resource->info->r,
+                                                entry->name, entry_pool))
+                  continue;
             }
 
           /* append a trailing slash onto the name for directories. we NEED



Mime
View raw message