subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From hwri...@apache.org
Subject svn commit: r1231318 [21/35] - in /subversion/branches/revprop-packing: ./ build/ build/ac-macros/ build/generator/ build/generator/templates/ build/win32/ contrib/client-side/emacs/ contrib/server-side/mod_dontdothat/ notes/ notes/http-and-webdav/ not...
Date Fri, 13 Jan 2012 21:40:38 GMT
Modified: subversion/branches/revprop-packing/subversion/libsvn_wc/status.c
URL: http://svn.apache.org/viewvc/subversion/branches/revprop-packing/subversion/libsvn_wc/status.c?rev=1231318&r1=1231317&r2=1231318&view=diff
==============================================================================
--- subversion/branches/revprop-packing/subversion/libsvn_wc/status.c (original)
+++ subversion/branches/revprop-packing/subversion/libsvn_wc/status.c Fri Jan 13 21:40:26 2012
@@ -184,6 +184,9 @@ struct dir_baton
   /* The pool in which this baton itself is allocated. */
   apr_pool_t *pool;
 
+  /* The repository root relative path to this item in the repository. */
+  const char *repos_relpath;
+
   /* out-of-date info corresponding to ood_* fields in svn_wc_status3_t. */
   svn_node_kind_t ood_kind;
   svn_revnum_t ood_changed_rev;
@@ -223,6 +226,9 @@ struct file_baton
      the code that syncs up the adm dir and working copy. */
   svn_boolean_t prop_changed;
 
+  /* The repository root relative path to this item in the repository. */
+  const char *repos_relpath;
+
   /* out-of-date info corresponding to ood_* fields in svn_wc_status3_t. */
   svn_node_kind_t ood_kind;
   svn_revnum_t ood_changed_rev;
@@ -266,14 +272,24 @@ read_info(const struct svn_wc__db_info_t
      happy... (It might be completely unrelated, but...) */
   if (mtb->have_base
       && (mtb->status == svn_wc__db_status_added
-         || mtb->status == svn_wc__db_status_deleted))
+          || mtb->status == svn_wc__db_status_deleted
+          || mtb->kind == svn_kind_file))
     {
+      svn_boolean_t update_root;
+      svn_wc__db_lock_t **lock_arg = NULL;
+
+      if (mtb->status == svn_wc__db_status_added
+          || mtb->status == svn_wc__db_status_deleted)
+        lock_arg = &mtb->lock;
+
       SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, NULL, NULL, NULL, NULL,
                                        NULL, NULL, NULL, NULL, NULL, NULL,
-                                       &mtb->lock, NULL, NULL,
+                                       lock_arg, NULL, &update_root,
                                        db, local_abspath,
                                        result_pool, scratch_pool));
 
+      mtb->file_external = (update_root && mtb->kind == svn_kind_file);
+
       if (mtb->status == svn_wc__db_status_deleted)
         {
           const char *moved_to_abspath;
@@ -328,19 +344,22 @@ read_info(const struct svn_wc__db_info_t
   if (mtb->status == svn_wc__db_status_added)
     {
       const char *moved_from_abspath = NULL;
-      SVN_ERR(svn_wc__db_scan_addition(NULL, NULL, NULL, NULL, NULL,
+      svn_wc__db_status_t status;
+
+      SVN_ERR(svn_wc__db_scan_addition(&status, NULL, NULL, NULL, NULL,
                                        NULL, NULL, NULL, NULL,
                                        &moved_from_abspath,
                                        NULL,
                                        db, local_abspath,
                                        result_pool, scratch_pool));
       mtb->moved_here = (moved_from_abspath != NULL);
+      mtb->incomplete = (status == svn_wc__db_status_incomplete);
     }
 
   mtb->has_checksum = (checksum != NULL);
 
 #ifdef HAVE_SYMLINK
-  if (mtb->kind == svn_wc__db_kind_file
+  if (mtb->kind == svn_kind_file
       && (mtb->had_props || mtb->props_mod))
     {
       apr_hash_t *properties;
@@ -493,9 +512,9 @@ assemble_status(svn_wc_status3_t **statu
 
   /* Examine whether our target is missing or obstructed. To detect
    * obstructions, we have to look at the on-disk status in DIRENT. */
-  if (info->kind == svn_wc__db_kind_dir)
+  if (info->kind == svn_kind_dir)
     {
-      if (info->status == svn_wc__db_status_incomplete)
+      if (info->status == svn_wc__db_status_incomplete || info->incomplete)
         {
           /* Highest precedence.  */
           node_status = svn_wc_status_incomplete;
@@ -556,7 +575,7 @@ assemble_status(svn_wc_status3_t **statu
 
      If it was changed, then the subdir is incomplete or missing/obstructed.
    */
-  if (info->kind != svn_wc__db_kind_dir
+  if (info->kind != svn_kind_dir
       && node_status == svn_wc_status_normal)
     {
       svn_boolean_t text_modified_p = FALSE;
@@ -568,8 +587,8 @@ assemble_status(svn_wc_status3_t **statu
             precedence over M. */
 
       /* If the entry is a file, check for textual modifications */
-      if ((info->kind == svn_wc__db_kind_file
-          || info->kind == svn_wc__db_kind_symlink)
+      if ((info->kind == svn_kind_file
+          || info->kind == svn_kind_symlink)
 #ifdef HAVE_SYMLINK
              && (info->special == (dirent && dirent->special))
 #endif /* HAVE_SYMLINK */
@@ -644,7 +663,7 @@ assemble_status(svn_wc_status3_t **statu
         {
           if (!info->op_root)
             copied = TRUE; /* And keep status normal */
-          else if (info->kind == svn_wc__db_kind_file
+          else if (info->kind == svn_kind_file
                    && !info->have_base && !info->have_more_work)
             {
               /* Simple addition or copy, no replacement */
@@ -716,14 +735,14 @@ assemble_status(svn_wc_status3_t **statu
 
   switch (info->kind)
     {
-      case svn_wc__db_kind_dir:
+      case svn_kind_dir:
         stat->kind = svn_node_dir;
         break;
-      case svn_wc__db_kind_file:
-      case svn_wc__db_kind_symlink:
+      case svn_kind_file:
+      case svn_kind_symlink:
         stat->kind = svn_node_file;
         break;
-      case svn_wc__db_kind_unknown:
+      case svn_kind_unknown:
       default:
         stat->kind = svn_node_unknown;
     }
@@ -772,6 +791,8 @@ assemble_status(svn_wc_status3_t **statu
   stat->moved_from_abspath = moved_from_abspath;
   stat->moved_to_abspath = info->moved_to_abspath;
 
+  stat->file_external = info->file_external;
+
   *status = stat;
 
   return SVN_NO_ERROR;
@@ -1046,29 +1067,189 @@ send_unversioned_item(const struct walk_
   return SVN_NO_ERROR;
 }
 
-/* Send svn_wc_status3_t * structures for the directory LOCAL_ABSPATH and
-   for all its entries through STATUS_FUNC/STATUS_BATON, or, if SELECTED
-   is non-NULL, only for that directory entry.
+static svn_error_t *
+get_dir_status(const struct walk_status_baton *wb,
+               const char *local_abspath,
+               svn_boolean_t skip_this_dir,
+               const char *parent_repos_root_url,
+               const char *parent_repos_relpath,
+               const char *parent_repos_uuid,
+               const struct svn_wc__db_info_t *dir_info,
+               const svn_io_dirent2_t *dirent,
+               const apr_array_header_t *ignore_patterns,
+               svn_depth_t depth,
+               svn_boolean_t get_all,
+               svn_boolean_t no_ignore,
+               svn_wc_status_func4_t status_func,
+               void *status_baton,
+               svn_cancel_func_t cancel_func,
+               void *cancel_baton,
+               apr_pool_t *scratch_pool);
+
+/* Send out a status structure according to the information gathered on one
+ * child node. (Basically this function is the guts of the loop in
+ * get_dir_status() and of get_child_status().)
+ *
+ * Send a status structure of LOCAL_ABSPATH. PARENT_ABSPATH must be the
+ * dirname of LOCAL_ABSPATH.
+ *
+ * INFO should reflect the information on LOCAL_ABSPATH; LOCAL_ABSPATH must
+ * be an unversioned file or dir, or a versioned file.  For versioned
+ * directories use get_dir_status() instead.
+ *
+ * INFO may be NULL for an unversioned node. If such node has a tree conflict,
+ * UNVERSIONED_TREE_CONFLICTED may be set to TRUE. If INFO is non-NULL,
+ * UNVERSIONED_TREE_CONFLICTED is ignored.
+ *
+ * DIRENT should reflect LOCAL_ABSPATH's dirent information.
+ *
+ * DIR_REPOS_* should reflect LOCAL_ABSPATH's parent URL, i.e. LOCAL_ABSPATH's
+ * URL treated with svn_uri_dirname(). ### TODO verify this (externals)
+ *
+ * If *COLLECTED_IGNORE_PATTERNS is NULL and ignore patterns are needed in
+ * this call, *COLLECTED_IGNORE_PATTERNS will be set to an apr_array_header_t*
+ * containing all ignore patterns, as returned by collect_ignore_patterns() on
+ * PARENT_ABSPATH and IGNORE_PATTERNS. If *COLLECTED_IGNORE_PATTERNS is passed
+ * non-NULL, it is assumed to already hold that result. This speeds up
+ * repeated calls with the same PARENT_ABSPATH.
+ *
+ * *COLLECTED_IGNORE_PATTERNS will be allocated in RESULT_POOL. All other
+ * allocations are made in SCRATCH_POOL.
+ *
+ * The remaining parameters correspond to get_dir_status(). */
+static svn_error_t*
+one_child_status(const struct walk_status_baton *wb,
+                 const char *local_abspath,
+                 const char *parent_abspath,
+                 const struct svn_wc__db_info_t *info,
+                 const svn_io_dirent2_t *dirent,
+                 const char *dir_repos_root_url,
+                 const char *dir_repos_relpath,
+                 const char *dir_repos_uuid,
+                 svn_boolean_t unversioned_tree_conflicted,
+                 apr_array_header_t **collected_ignore_patterns,
+                 const apr_array_header_t *ignore_patterns,
+                 svn_depth_t depth,
+                 svn_boolean_t get_all,
+                 svn_boolean_t no_ignore,
+                 svn_wc_status_func4_t status_func,
+                 void *status_baton,
+                 svn_cancel_func_t cancel_func,
+                 void *cancel_baton,
+                 apr_pool_t *result_pool,
+                 apr_pool_t *scratch_pool)
+{
+  svn_boolean_t conflicted = info ? info->conflicted
+                                  : unversioned_tree_conflicted;
+
+  if (info
+      && info->status != svn_wc__db_status_not_present
+      && info->status != svn_wc__db_status_excluded
+      && info->status != svn_wc__db_status_server_excluded
+      && !(info->kind == svn_kind_unknown
+           && info->status == svn_wc__db_status_normal))
+    {
+      if (depth == svn_depth_files
+          && info->kind == svn_kind_dir)
+        {
+          return SVN_NO_ERROR;
+        }
+
+      SVN_ERR(send_status_structure(wb, local_abspath,
+                                    dir_repos_root_url,
+                                    dir_repos_relpath,
+                                    dir_repos_uuid,
+                                    info, dirent, get_all,
+                                    status_func, status_baton,
+                                    scratch_pool));
+
+      /* Descend in subdirectories. */
+      if (depth == svn_depth_infinity
+          && info->kind == svn_kind_dir)
+        {
+          SVN_ERR(get_dir_status(wb, local_abspath, TRUE,
+                                 dir_repos_root_url, dir_repos_relpath,
+                                 dir_repos_uuid, info,
+                                 dirent, ignore_patterns,
+                                 svn_depth_infinity, get_all,
+                                 no_ignore,
+                                 status_func, status_baton,
+                                 cancel_func, cancel_baton,
+                                 scratch_pool));
+        }
+
+      return SVN_NO_ERROR;
+    }
+
+  /* If conflicted, fall right through to unversioned.
+   * With depth_files, show all conflicts, even if their report is only
+   * about directories. A tree conflict may actually report two different
+   * kinds, so it's not so easy to define what depth=files means. We could go
+   * look up the kinds in the conflict ... just show all. */
+  if (! conflicted)
+    {
+      /* Selected node, but not found */
+      if (dirent == NULL)
+        return SVN_NO_ERROR;
+
+      if (depth == svn_depth_files && dirent->kind == svn_node_dir)
+        return SVN_NO_ERROR;
 
-   PARENT_ENTRY is the entry for the parent of the directory or NULL
-   if LOCAL_ABSPATH is a working copy root.
+      if (svn_wc_is_adm_dir(svn_dirent_basename(local_abspath, scratch_pool),
+                            scratch_pool))
+        return SVN_NO_ERROR;
+    }
+
+  /* The node exists on disk but there is no versioned information about it,
+   * or it doesn't exist but is a tree conflicted path or should be
+   * reported not-present. */
+   
+  /* Why pass ignore patterns on a tree conflicted node, even if it should
+   * always show up in clients' status reports anyway? Because the calling
+   * client decides whether to ignore, and thus this flag needs to be
+   * determined.  For example, in 'svn status', plain unversioned nodes show
+   * as '?  C', where ignored ones show as 'I  C'. */
+
+  if (ignore_patterns && ! *collected_ignore_patterns)
+    SVN_ERR(collect_ignore_patterns(collected_ignore_patterns, wb->db,
+                                    parent_abspath, ignore_patterns,
+                                    result_pool, scratch_pool));
+
+  SVN_ERR(send_unversioned_item(wb,
+                                local_abspath,
+                                dirent,
+                                conflicted,
+                                *collected_ignore_patterns,
+                                no_ignore,
+                                status_func, status_baton,
+                                scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+/* Send svn_wc_status3_t * structures for the directory LOCAL_ABSPATH and
+   for all its child nodes (according to DEPTH) through STATUS_FUNC /
+   STATUS_BATON.
 
    If SKIP_THIS_DIR is TRUE, the directory's own status will not be reported.
-   However, upon recursing, all subdirs *will* be reported, regardless of this
+   All subdirs reached by recursion will be reported regardless of this
    parameter's value.
 
-   DIRENT is LOCAL_ABSPATH's own dirent and is only needed if it is reported,
-   so if SKIP_THIS_DIR or SELECTED is not-NULL DIRENT can be left NULL.
+   PARENT_REPOS_* parameters can be set to refer to LOCAL_ABSPATH's parent's
+   URL, i.e. the URL the WC reflects at the dirname of LOCAL_ABSPATH, to avoid
+   retrieving them again. Otherwise they must be NULL.
 
    DIR_INFO can be set to the information of LOCAL_ABSPATH, to avoid retrieving
-   it again.
+   it again. Otherwise it must be NULL.
+
+   DIRENT is LOCAL_ABSPATH's own dirent and is only needed if it is reported,
+   so if SKIP_THIS_DIR is TRUE, DIRENT can be left NULL.
 
    Other arguments are the same as those passed to
    svn_wc_get_status_editor5().  */
 static svn_error_t *
 get_dir_status(const struct walk_status_baton *wb,
                const char *local_abspath,
-               const char *selected,
                svn_boolean_t skip_this_dir,
                const char *parent_repos_root_url,
                const char *parent_repos_relpath,
@@ -1090,7 +1271,7 @@ get_dir_status(const struct walk_status_
   const char *dir_repos_relpath;
   const char *dir_repos_uuid;
   apr_hash_t *dirents, *nodes, *conflicts, *all_children;
-  apr_array_header_t *patterns = NULL;
+  apr_array_header_t *collected_ignore_patterns = NULL;
   apr_pool_t *iterpool, *subpool = svn_pool_create(scratch_pool);
   svn_error_t *err;
 
@@ -1123,178 +1304,156 @@ get_dir_status(const struct walk_status_
                                      parent_repos_root_url, parent_repos_uuid,
                                      wb->db, local_abspath,
                                      subpool, iterpool));
-  if (selected == NULL)
-    {
-      /* Create a hash containing all children.  The source hashes
-         don't all map the same types, but only the keys of the result
-         hash are subsequently used. */
-      SVN_ERR(svn_wc__db_read_children_info(&nodes, &conflicts,
-                                            wb->db, local_abspath,
-                                            subpool, iterpool));
-
-      all_children = apr_hash_overlay(subpool, nodes, dirents);
-      if (apr_hash_count(conflicts) > 0)
-        all_children = apr_hash_overlay(subpool, conflicts, all_children);
-    }
-  else
-    {
-      const struct svn_wc__db_info_t *info;
-      const char *selected_abspath = svn_dirent_join(local_abspath, selected,
-                                                     iterpool);
-      /* Create a hash containing just selected */
-      all_children = apr_hash_make(subpool);
-      nodes = apr_hash_make(subpool);
-      conflicts = apr_hash_make(subpool);
-
-      err = read_info(&info, selected_abspath, wb->db, subpool, iterpool);
 
-      if (err)
-        {
-          if (err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND)
-            return svn_error_trace(err);
-          svn_error_clear(err);
-          /* The node is neither a tree conflict nor a versioned node */
-        }
-      else
-        {
-          if (!info->conflicted
-              || info->status != svn_wc__db_status_normal
-              || info->kind != svn_wc__db_kind_unknown)
-             {
-               /* The node is a normal versioned node */
-               apr_hash_set(nodes, selected, APR_HASH_KEY_STRING, info);
-             }
-
-          /* Drop it in the list of possible conflicts */
-          if (info->conflicted)
-            apr_hash_set(conflicts, selected, APR_HASH_KEY_STRING, info);
-        }
-
-      apr_hash_set(all_children, selected, APR_HASH_KEY_STRING, selected);
-    }
-
-  if (!selected)
-    {
-      /* Handle "this-dir" first. */
-      if (! skip_this_dir)
-        SVN_ERR(send_status_structure(wb, local_abspath,
-                                      parent_repos_root_url,
-                                      parent_repos_relpath,
-                                      parent_repos_uuid,
-                                      dir_info, dirent, get_all,
-                                      status_func, status_baton,
-                                      iterpool));
+  /* Create a hash containing all children.  The source hashes
+     don't all map the same types, but only the keys of the result
+     hash are subsequently used. */
+  SVN_ERR(svn_wc__db_read_children_info(&nodes, &conflicts,
+                                        wb->db, local_abspath,
+                                        subpool, iterpool));
+
+  all_children = apr_hash_overlay(subpool, nodes, dirents);
+  if (apr_hash_count(conflicts) > 0)
+    all_children = apr_hash_overlay(subpool, conflicts, all_children);
+
+  /* Handle "this-dir" first. */
+  if (! skip_this_dir)
+    SVN_ERR(send_status_structure(wb, local_abspath,
+                                  parent_repos_root_url,
+                                  parent_repos_relpath,
+                                  parent_repos_uuid,
+                                  dir_info, dirent, get_all,
+                                  status_func, status_baton,
+                                  iterpool));
 
-      /* If the requested depth is empty, we only need status on this-dir. */
-      if (depth == svn_depth_empty)
-        return SVN_NO_ERROR;
-    }
+  /* If the requested depth is empty, we only need status on this-dir. */
+  if (depth == svn_depth_empty)
+    return SVN_NO_ERROR;
 
   /* Walk all the children of this directory. */
   for (hi = apr_hash_first(subpool, all_children); hi; hi = apr_hash_next(hi))
     {
       const void *key;
       apr_ssize_t klen;
-      const char *node_abspath;
-      svn_io_dirent2_t *dirent_p;
-      const struct svn_wc__db_info_t *info;
+      const char *child_abspath;
+      svn_io_dirent2_t *child_dirent;
+      const struct svn_wc__db_info_t *child_info;
 
       svn_pool_clear(iterpool);
 
       apr_hash_this(hi, &key, &klen, NULL);
 
-      node_abspath = svn_dirent_join(local_abspath, key, iterpool);
-
-      dirent_p = apr_hash_get(dirents, key, klen);
-
-      info = apr_hash_get(nodes, key, klen);
-      if (info)
-        {
-          if (info->status != svn_wc__db_status_not_present
-              && info->status != svn_wc__db_status_excluded
-              && info->status != svn_wc__db_status_server_excluded)
-            {
-              if (depth == svn_depth_files
-                  && info->kind == svn_wc__db_kind_dir)
-                {
-                  continue;
-                }
+      child_abspath = svn_dirent_join(local_abspath, key, iterpool);
 
-              SVN_ERR(send_status_structure(wb, node_abspath,
-                                            dir_repos_root_url,
-                                            dir_repos_relpath,
-                                            dir_repos_uuid,
-                                            info, dirent_p, get_all,
-                                            status_func, status_baton,
-                                            iterpool));
-
-              /* Descend in subdirectories. */
-              if (depth == svn_depth_infinity
-                  && info->kind == svn_wc__db_kind_dir)
-                {
-                  SVN_ERR(get_dir_status(wb, node_abspath, NULL, TRUE,
-                                         dir_repos_root_url, dir_repos_relpath,
-                                         dir_repos_uuid, info,
-                                         dirent_p, ignore_patterns,
-                                         svn_depth_infinity, get_all,
-                                         no_ignore,
-                                         status_func, status_baton,
-                                         cancel_func, cancel_baton,
-                                         iterpool));
-                }
-
-              continue;
-            }
-        }
+      child_dirent = apr_hash_get(dirents, key, klen);
+      child_info = apr_hash_get(nodes, key, klen);
 
-      if (apr_hash_get(conflicts, key, klen))
-        {
-          /* Tree conflict */
+      SVN_ERR(one_child_status(wb,
+                               child_abspath,
+                               local_abspath,
+                               child_info,
+                               child_dirent,
+                               dir_repos_root_url,
+                               dir_repos_relpath,
+                               dir_repos_uuid,
+                               apr_hash_get(conflicts, key, klen) != NULL,
+                               &collected_ignore_patterns,
+                               ignore_patterns,
+                               depth,
+                               get_all,
+                               no_ignore,
+                               status_func,
+                               status_baton,
+                               cancel_func,
+                               cancel_baton,
+                               subpool,
+                               iterpool));
+    }
 
-          if (ignore_patterns && ! patterns)
-            SVN_ERR(collect_ignore_patterns(&patterns, wb->db, local_abspath,
-                                            ignore_patterns, subpool,
-                                            iterpool));
-
-          SVN_ERR(send_unversioned_item(wb,
-                                        node_abspath,
-                                        dirent_p, TRUE,
-                                        patterns,
-                                        no_ignore,
-                                        status_func,
-                                        status_baton,
-                                        iterpool));
+  /* Destroy our subpools. */
+  svn_pool_destroy(subpool);
 
-          continue;
-        }
+  return SVN_NO_ERROR;
+}
 
-      /* Unversioned node */
-      if (dirent_p == NULL)
-        continue; /* Selected node, but not found */
+/* Send an svn_wc_status3_t * structure for the versioned file, or for the
+ * unversioned file or directory, LOCAL_ABSPATH, which is not ignored (an
+ * explicit target). Does not recurse.
+ *
+ * INFO should reflect LOCAL_ABSPATH's information, but should be NULL for
+ * unversioned nodes. An unversioned and tree-conflicted node however should
+ * pass a non-NULL INFO as returned by read_info() (INFO->CONFLICTED = TRUE).
+ *
+ * DIRENT should reflect LOCAL_ABSPATH.
+ *
+ * All allocations made in SCRATCH_POOL.
+ *
+ * The remaining parameters correspond to get_dir_status(). */
+static svn_error_t *
+get_child_status(const struct walk_status_baton *wb,
+                 const char *local_abspath,
+                 const struct svn_wc__db_info_t *info,
+                 const svn_io_dirent2_t *dirent,
+                 const apr_array_header_t *ignore_patterns,
+                 svn_boolean_t get_all,
+                 svn_wc_status_func4_t status_func,
+                 void *status_baton,
+                 svn_cancel_func_t cancel_func,
+                 void *cancel_baton,
+                 apr_pool_t *scratch_pool)
+{
+  const char *dir_repos_root_url;
+  const char *dir_repos_relpath;
+  const char *dir_repos_uuid;
+  const struct svn_wc__db_info_t *dir_info;
+  apr_array_header_t *collected_ignore_patterns = NULL;
+  const svn_io_dirent2_t *dirent_p;
+  const char *parent_abspath = svn_dirent_dirname(local_abspath,
+                                                  scratch_pool);
 
-      if (depth == svn_depth_files && dirent_p->kind == svn_node_dir)
-        continue;
+  if (cancel_func)
+    SVN_ERR(cancel_func(cancel_baton));
 
-      if (svn_wc_is_adm_dir(key, iterpool))
-        continue;
+  SVN_ERR(svn_io_stat_dirent(&dirent_p, local_abspath, TRUE,
+                             scratch_pool, scratch_pool));
 
-      if (ignore_patterns && ! patterns)
-        SVN_ERR(collect_ignore_patterns(&patterns, wb->db, local_abspath,
-                                        ignore_patterns, subpool,
-                                        iterpool));
+  if (dirent_p->kind == svn_node_none)
+    dirent_p = NULL;
 
-      SVN_ERR(send_unversioned_item(wb,
-                                    node_abspath,
-                                    dirent_p, FALSE,
-                                    patterns,
-                                    no_ignore || selected,
-                                    status_func, status_baton,
-                                    iterpool));
-    }
+  SVN_ERR(read_info(&dir_info, parent_abspath, wb->db,
+                    scratch_pool, scratch_pool));
 
-  /* Destroy our subpools. */
-  svn_pool_destroy(subpool);
+  SVN_ERR(get_repos_root_url_relpath(&dir_repos_relpath, &dir_repos_root_url,
+                                     &dir_repos_uuid, dir_info,
+                                     NULL, NULL, NULL,
+                                     wb->db, parent_abspath,
+                                     scratch_pool, scratch_pool));
 
+  /* An unversioned node with a tree conflict will see an INFO != NULL here,
+   * in which case the FALSE passed for UNVERSIONED_TREE_CONFLICTED has no
+   * effect and INFO->CONFLICTED counts.
+   * ### Maybe svn_wc__db_read_children_info() and read_info() should be more
+   * ### alike? */
+  SVN_ERR(one_child_status(wb,
+                           local_abspath,
+                           parent_abspath,
+                           info,
+                           dirent_p,
+                           dir_repos_root_url,
+                           dir_repos_relpath,
+                           dir_repos_uuid,
+                           FALSE, /* unversioned_tree_conflicted */
+                           &collected_ignore_patterns,
+                           ignore_patterns,
+                           svn_depth_empty,
+                           get_all,
+                           TRUE, /* no_ignore. This is an explicit target. */
+                           status_func,
+                           status_baton,
+                           cancel_func,
+                           cancel_baton,
+                           scratch_pool,
+                           scratch_pool));
   return SVN_NO_ERROR;
 }
 
@@ -1420,6 +1579,27 @@ tweak_statushash(void *baton,
     {
       struct dir_baton *b = this_dir_baton;
 
+      if (!statstruct->repos_relpath && b->repos_relpath)
+        {
+          if (statstruct->repos_node_status == svn_wc_status_deleted)
+            {
+              /* When deleting PATH, BATON is for PATH's parent,
+                 so we must construct PATH's real statstruct->url. */
+              statstruct->repos_relpath =
+                            svn_relpath_join(b->repos_relpath,
+                                             svn_dirent_basename(local_abspath,
+                                                                 NULL),
+                                             pool);
+            }
+          else
+            statstruct->repos_relpath = apr_pstrdup(pool, b->repos_relpath);
+
+          statstruct->repos_root_url = 
+                              b->edit_baton->anchor_status->repos_root_url;
+          statstruct->repos_uuid = 
+                              b->edit_baton->anchor_status->repos_uuid;
+        }
+
       /* The last committed date, and author for deleted items
          isn't available. */
       if (statstruct->repos_node_status == svn_wc_status_deleted)
@@ -1453,6 +1633,14 @@ tweak_statushash(void *baton,
       struct file_baton *b = baton;
       statstruct->ood_changed_rev = b->ood_changed_rev;
       statstruct->ood_changed_date = b->ood_changed_date;
+      if (!statstruct->repos_relpath && b->repos_relpath)
+        {
+          statstruct->repos_relpath = apr_pstrdup(pool, b->repos_relpath);
+          statstruct->repos_root_url =
+                          b->edit_baton->anchor_status->repos_root_url;
+          statstruct->repos_uuid =
+                          b->edit_baton->anchor_status->repos_uuid;
+        }
       statstruct->ood_kind = b->ood_kind;
       if (b->ood_changed_author)
         statstruct->ood_changed_author =
@@ -1461,7 +1649,7 @@ tweak_statushash(void *baton,
   return SVN_NO_ERROR;
 }
 
-/* Returns the URL for DB, or NULL: */
+/* Returns the URL for DB */
 static const char *
 find_dir_repos_relpath(const struct dir_baton *db, apr_pool_t *pool)
 {
@@ -1475,17 +1663,14 @@ find_dir_repos_relpath(const struct dir_
       const svn_wc_status3_t *status = apr_hash_get(pb->statii,
                                                     db->local_abspath,
                                                     APR_HASH_KEY_STRING);
-      /* Note that status->url is NULL in the case of a missing
-       * directory, which means we need to recurse up another level to
-       * get a useful URL. */
-      if (status)
+      /* Note that status->repos_relpath could be NULL in the case of a missing
+       * directory, which means we need to recurse up another level to get
+       * a useful relpath. */
+      if (status && status->repos_relpath)
         return status->repos_relpath;
 
       repos_relpath = find_dir_repos_relpath(pb, pool);
-      if (repos_relpath)
-        return svn_relpath_join(repos_relpath, db->name, pool);
-      else
-        return NULL;
+      return svn_relpath_join(repos_relpath, db->name, pool);
     }
 }
 
@@ -1522,6 +1707,7 @@ make_dir_baton(void **dir_baton,
   d->statii = apr_hash_make(pool);
   d->ood_changed_rev = SVN_INVALID_REVNUM;
   d->ood_changed_date = 0;
+  d->repos_relpath = apr_pstrdup(pool, find_dir_repos_relpath(d, pool));
   d->ood_kind = svn_node_dir;
   d->ood_changed_author = NULL;
 
@@ -1566,7 +1752,7 @@ make_dir_baton(void **dir_baton,
       const svn_wc_status3_t *this_dir_status;
       const apr_array_header_t *ignores = eb->ignores;
 
-      SVN_ERR(get_dir_status(&eb->wb, local_abspath, NULL, TRUE,
+      SVN_ERR(get_dir_status(&eb->wb, local_abspath, TRUE,
                              status_in_parent->repos_root_url,
                              NULL /*parent_repos_relpath*/,
                              status_in_parent->repos_uuid,
@@ -1615,6 +1801,8 @@ make_file_baton(struct dir_baton *parent
   f->edit_baton = eb;
   f->ood_changed_rev = SVN_INVALID_REVNUM;
   f->ood_changed_date = 0;
+  f->repos_relpath = svn_relpath_join(find_dir_repos_relpath(pb, pool),
+                                      f->name, pool);
   f->ood_kind = svn_node_file;
   f->ood_changed_author = NULL;
   return f;
@@ -1749,7 +1937,7 @@ handle_statii(struct edit_baton *eb,
               || depth == svn_depth_infinity))
         {
           SVN_ERR(get_dir_status(&eb->wb,
-                                 local_abspath, NULL, TRUE,
+                                 local_abspath, TRUE,
                                  dir_repos_root_url, dir_repos_relpath,
                                  dir_repos_uuid,
                                  NULL,
@@ -1812,7 +2000,7 @@ delete_entry(const char *path,
   struct dir_baton *db = parent_baton;
   struct edit_baton *eb = db->edit_baton;
   const char *local_abspath = svn_dirent_join(eb->anchor_abspath, path, pool);
-  svn_wc__db_kind_t kind;
+  svn_kind_t kind;
 
   /* Note:  when something is deleted, it's okay to tweak the
      statushash immediately.  No need to wait until close_file or
@@ -1821,7 +2009,7 @@ delete_entry(const char *path,
 
   SVN_ERR(svn_wc__db_read_kind(&kind, eb->db, local_abspath, FALSE, pool));
   SVN_ERR(tweak_statushash(db, db, TRUE, eb->db,
-                           local_abspath, kind == svn_wc__db_kind_dir,
+                           local_abspath, kind == svn_kind_dir,
                            svn_wc_status_deleted, 0, 0, revision, NULL, pool));
 
   /* Mark the parent dir -- it lost an entry (unless that parent dir
@@ -1830,7 +2018,7 @@ delete_entry(const char *path,
   if (db->parent_baton && (! *eb->target_basename))
     SVN_ERR(tweak_statushash(db->parent_baton, db, TRUE,eb->db,
                              db->local_abspath,
-                             kind == svn_wc__db_kind_dir,
+                             kind == svn_kind_dir,
                              svn_wc_status_modified, svn_wc_status_modified,
                              0, SVN_INVALID_REVNUM, NULL, pool));
 
@@ -2021,7 +2209,7 @@ close_directory(void *dir_baton,
                   && tgt_status->kind == svn_node_dir)
                 {
                   SVN_ERR(get_dir_status(&eb->wb,
-                                         eb->target_abspath, NULL, TRUE,
+                                         eb->target_abspath, TRUE,
                                          NULL, NULL, NULL, NULL,
                                          NULL /* dirent */,
                                          eb->ignores,
@@ -2178,19 +2366,15 @@ close_file(void *file_baton,
           const char *dir_repos_relpath = find_dir_repos_relpath(fb->dir_baton,
                                                                  pool);
 
-          if (dir_repos_relpath)
-            {
-              /* repos_lock still uses the deprecated filesystem absolute path
-                 format */
-
-              const char *repos_relpath = svn_relpath_join(dir_repos_relpath,
-                                                           fb->name, pool);
+          /* repos_lock still uses the deprecated filesystem absolute path
+             format */
+          const char *repos_relpath = svn_relpath_join(dir_repos_relpath,
+                                                       fb->name, pool);
 
-              repos_lock = apr_hash_get(fb->edit_baton->wb.repos_locks,
-                                        svn_fspath__join("/", repos_relpath,
-                                                         pool),
-                                        APR_HASH_KEY_STRING);
-            }
+          repos_lock = apr_hash_get(fb->edit_baton->wb.repos_locks,
+                                    svn_fspath__join("/", repos_relpath,
+                                                     pool),
+                                    APR_HASH_KEY_STRING);
         }
     }
   else
@@ -2264,7 +2448,10 @@ svn_wc_get_status_editor5(const svn_delt
   struct edit_baton *eb;
   svn_delta_editor_t *tree_editor = svn_delta_default_editor(result_pool);
   void *inner_baton;
+  struct svn_wc__shim_fetch_baton_t *sfb;
   const svn_delta_editor_t *inner_editor;
+  svn_delta_shim_callbacks_t *shim_callbacks =
+                                svn_delta_shim_callbacks_default(result_pool);
 
   /* Construct an edit baton. */
   eb = apr_pcalloc(result_pool, sizeof(*eb));
@@ -2352,6 +2539,20 @@ svn_wc_get_status_editor5(const svn_delt
   if (set_locks_baton)
     *set_locks_baton = eb;
 
+  sfb = apr_palloc(result_pool, sizeof(*sfb));
+  sfb->db = wc_ctx->db;
+  sfb->base_abspath = eb->anchor_abspath;
+  sfb->fetch_base = FALSE;
+
+  shim_callbacks->fetch_kind_func = svn_wc__fetch_kind_func;
+  shim_callbacks->fetch_props_func = svn_wc__fetch_props_func;
+  shim_callbacks->fetch_base_func = svn_wc__fetch_base_func;
+  shim_callbacks->fetch_baton = sfb;
+
+  SVN_ERR(svn_editor__insert_shims(editor, edit_baton, *editor, *edit_baton,
+                                   shim_callbacks,
+                                   result_pool, scratch_pool));
+
   return SVN_NO_ERROR;
 }
 
@@ -2371,9 +2572,7 @@ svn_wc__internal_walk_status(svn_wc__db_
 {
   struct walk_status_baton wb;
   const svn_io_dirent2_t *dirent;
-  const char *anchor_abspath, *target_name;
-  svn_boolean_t skip_root;
-  const struct svn_wc__db_info_t *dir_info;
+  const struct svn_wc__db_info_t *info;
   svn_error_t *err;
 
   wb.db = db;
@@ -2395,45 +2594,53 @@ svn_wc__internal_walk_status(svn_wc__db_
       ignore_patterns = ignores;
     }
 
-  err = read_info(&dir_info, local_abspath, db, scratch_pool, scratch_pool);
+  err = read_info(&info, local_abspath, db, scratch_pool, scratch_pool);
 
-  if (!err && dir_info->kind == svn_wc__db_kind_dir)
+  if (err)
     {
-      anchor_abspath = local_abspath;
-      target_name = NULL;
-      skip_root = FALSE;
-    }
-  else if (err && err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND)
-    return svn_error_trace(err);
-  else
-    {
-      svn_error_clear(err);
-      dir_info = NULL; /* Don't pass information of the child */
-
-      /* Walk the status of the parent of LOCAL_ABSPATH, but only report
-         status on its child LOCAL_ABSPATH. */
-      anchor_abspath = svn_dirent_dirname(local_abspath, scratch_pool);
-      target_name = svn_dirent_basename(local_abspath, NULL);
-      skip_root = TRUE;
+      if (err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
+        {
+          svn_error_clear(err);
+          info = NULL;
+        }
+      else
+        return svn_error_trace(err);
     }
 
   SVN_ERR(svn_io_stat_dirent(&dirent, local_abspath, TRUE,
                              scratch_pool, scratch_pool));
 
-  SVN_ERR(get_dir_status(&wb,
-                         anchor_abspath,
-                         target_name,
-                         skip_root,
-                         NULL, NULL, NULL,
-                         dir_info,
-                         dirent,
-                         ignore_patterns,
-                         depth,
-                         get_all,
-                         no_ignore,
-                         status_func, status_baton,
-                         cancel_func, cancel_baton,
-                         scratch_pool));
+  if (info && info->kind == svn_kind_dir)
+    {
+      SVN_ERR(get_dir_status(&wb,
+                             local_abspath,
+                             FALSE /* skip_root */,
+                             NULL, NULL, NULL,
+                             info,
+                             dirent,
+                             ignore_patterns,
+                             depth,
+                             get_all,
+                             no_ignore,
+                             status_func, status_baton,
+                             cancel_func, cancel_baton,
+                             scratch_pool));
+    }
+  else
+    {
+      /* It may be a file or an unversioned item. And this is an explicit
+       * target, so no ignoring. An unversioned item (file or dir) shows a
+       * status like '?', and can yield a tree conflicted path. */
+      SVN_ERR(get_child_status(&wb,
+                               local_abspath,
+                               info,
+                               dirent,
+                               ignore_patterns,
+                               get_all,
+                               status_func, status_baton,
+                               cancel_func, cancel_baton,
+                               scratch_pool));
+    }
 
   return SVN_NO_ERROR;
 }
@@ -2515,7 +2722,7 @@ internal_status(svn_wc_status3_t **statu
                 apr_pool_t *scratch_pool)
 {
   const svn_io_dirent2_t *dirent;
-  svn_wc__db_kind_t node_kind;
+  svn_kind_t node_kind;
   const char *parent_repos_relpath;
   const char *parent_repos_root_url;
   const char *parent_repos_uuid;
@@ -2539,7 +2746,7 @@ internal_status(svn_wc_status3_t **statu
   if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
     {
       svn_error_clear(err);
-      node_kind = svn_wc__db_kind_unknown;
+      node_kind = svn_kind_unknown;
       /* Ensure conflicted is always set, but don't hide tree conflicts
          on 'hidden' nodes. */
       conflicted = FALSE;
@@ -2552,10 +2759,10 @@ internal_status(svn_wc_status3_t **statu
            || node_status == svn_wc__db_status_server_excluded
            || node_status == svn_wc__db_status_excluded)
     {
-      node_kind = svn_wc__db_kind_unknown;
+      node_kind = svn_kind_unknown;
     }
 
-  if (node_kind == svn_wc__db_kind_unknown)
+  if (node_kind == svn_kind_unknown)
     return svn_error_trace(assemble_unversioned(status,
                                                 db, local_abspath,
                                                 dirent, conflicted,

Modified: subversion/branches/revprop-packing/subversion/libsvn_wc/translate.c
URL: http://svn.apache.org/viewvc/subversion/branches/revprop-packing/subversion/libsvn_wc/translate.c?rev=1231318&r1=1231317&r2=1231318&view=diff
==============================================================================
--- subversion/branches/revprop-packing/subversion/libsvn_wc/translate.c (original)
+++ subversion/branches/revprop-packing/subversion/libsvn_wc/translate.c Fri Jan 13 21:40:26 2012
@@ -365,7 +365,7 @@ svn_wc__sync_flags_with_props(svn_boolea
                               apr_pool_t *scratch_pool)
 {
   svn_wc__db_status_t status;
-  svn_wc__db_kind_t kind;
+  svn_kind_t kind;
   svn_wc__db_lock_t *lock;
   apr_hash_t *props = NULL;
 
@@ -387,7 +387,7 @@ svn_wc__sync_flags_with_props(svn_boolea
 
   /* We actually only care about the following flags on files, so just
      early-out for all other types. */
-  if (kind != svn_wc__db_kind_file)
+  if (kind != svn_kind_file)
     return SVN_NO_ERROR;
 
   /* If we get this far, we're going to change *something*, so just set

Modified: subversion/branches/revprop-packing/subversion/libsvn_wc/tree_conflicts.c
URL: http://svn.apache.org/viewvc/subversion/branches/revprop-packing/subversion/libsvn_wc/tree_conflicts.c?rev=1231318&r1=1231317&r2=1231318&view=diff
==============================================================================
--- subversion/branches/revprop-packing/subversion/libsvn_wc/tree_conflicts.c (original)
+++ subversion/branches/revprop-packing/subversion/libsvn_wc/tree_conflicts.c Fri Jan 13 21:40:26 2012
@@ -76,8 +76,9 @@ const svn_token_map_t svn_wc__conflict_r
   { "added",       svn_wc_conflict_reason_added },
   { "replaced",    svn_wc_conflict_reason_replaced },
   { "unversioned", svn_wc_conflict_reason_unversioned },
-  { "moved-here", svn_wc_conflict_reason_moved_here },
   { "moved-away", svn_wc_conflict_reason_moved_away },
+  { "moved-away-and-edited", svn_wc_conflict_reason_moved_away_and_edited },
+  { "moved-here", svn_wc_conflict_reason_moved_here },
   { NULL }
 };
 
@@ -365,7 +366,7 @@ svn_wc__serialize_conflict(svn_skel_t **
 
   /* Victim path (escaping separator chars). */
   victim_basename = svn_dirent_basename(conflict->local_abspath, result_pool);
-  SVN_ERR_ASSERT(strlen(victim_basename) > 0);
+  SVN_ERR_ASSERT(victim_basename[0]);
   svn_skel__prepend(svn_skel__str_atom(victim_basename, result_pool), c_skel);
 
   svn_skel__prepend(svn_skel__str_atom("conflict", result_pool), c_skel);

Modified: subversion/branches/revprop-packing/subversion/libsvn_wc/update_editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/revprop-packing/subversion/libsvn_wc/update_editor.c?rev=1231318&r1=1231317&r2=1231318&view=diff
==============================================================================
--- subversion/branches/revprop-packing/subversion/libsvn_wc/update_editor.c (original)
+++ subversion/branches/revprop-packing/subversion/libsvn_wc/update_editor.c Fri Jan 13 21:40:26 2012
@@ -35,6 +35,7 @@
 #include "svn_types.h"
 #include "svn_pools.h"
 #include "svn_delta.h"
+#include "svn_hash.h"
 #include "svn_string.h"
 #include "svn_dirent_uri.h"
 #include "svn_path.h"
@@ -283,6 +284,13 @@ struct dir_baton
   /* Absolute path of this directory */
   const char *local_abspath;
 
+  /* Absolute path to the new location of the directory if it was moved away,
+   * and the op-root of the move operation.
+   * This is set on the root of a move operation and all children.
+   * If the directory was not moved away, this is NULL. */
+  const char *moved_to_abspath;
+  const char *moved_to_op_root_abspath;
+
   /* The repository relative path this directory will correspond to. */
   const char *new_relpath;
 
@@ -617,6 +625,8 @@ make_dir_baton(struct dir_baton **d_p,
   d->adding_dir   = adding;
   d->changed_rev  = SVN_INVALID_REVNUM;
   d->not_present_files = apr_hash_make(dir_pool);
+  d->moved_to_abspath = NULL;
+  d->moved_to_op_root_abspath = NULL;
 
   /* Copy some flags from the parent baton */
   if (pb)
@@ -1083,6 +1093,7 @@ open_root(void *edit_baton,
   struct dir_baton *db;
   svn_boolean_t already_conflicted;
   svn_error_t *err;
+  svn_wc__db_status_t status;
 
   /* Note that something interesting is actually happening in this
      edit run. */
@@ -1118,7 +1129,6 @@ open_root(void *edit_baton,
   if (*eb->target_basename == '\0')
     {
       /* For an update with a NULL target, this is equivalent to open_dir(): */
-      svn_wc__db_status_t status;
 
       /* Read the depth from the entry. */
       SVN_ERR(svn_wc__db_base_get_info(&status, NULL, NULL, NULL, NULL, NULL,
@@ -1136,6 +1146,25 @@ open_root(void *edit_baton,
                                                         pool));
     }
 
+  /* Check if this directory was moved away. */
+  err = svn_wc__db_read_info(&status, NULL, NULL, NULL, NULL, NULL, NULL,
+                             NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+                             NULL, NULL, NULL, NULL, NULL, NULL,
+                             NULL, NULL, NULL, NULL,
+                             NULL, NULL, NULL,
+                             eb->db, db->local_abspath, pool, pool);
+  if (err)
+    {
+      if (err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
+        svn_error_clear(err);
+      else
+        return svn_error_trace(err);
+    }
+  else if (status == svn_wc__db_status_deleted)
+    SVN_ERR(svn_wc__db_scan_deletion(NULL, &db->moved_to_abspath, NULL,
+                                     &db->moved_to_op_root_abspath,
+                                     eb->db, db->local_abspath, db->pool, pool));
+
   return SVN_NO_ERROR;
 }
 
@@ -1148,6 +1177,7 @@ typedef struct modcheck_baton_t {
   svn_wc__db_t *db;         /* wc_db to access nodes */
   svn_boolean_t found_mod;  /* whether a modification has been found */
   svn_boolean_t found_not_delete;  /* Found a not-delete modification */
+  svn_boolean_t is_copy; /* check for post-copy modifications only */
 } modcheck_baton_t;
 
 /* An implementation of svn_wc_status_func4_t. */
@@ -1162,6 +1192,7 @@ modcheck_callback(void *baton,
   switch (status->node_status)
     {
       case svn_wc_status_normal:
+      case svn_wc_status_incomplete:
       case svn_wc_status_ignored:
       case svn_wc_status_none:
       case svn_wc_status_unversioned:
@@ -1178,8 +1209,17 @@ modcheck_callback(void *baton,
           break;
         /* Fall through in the found modification case */
 
-      default:
       case svn_wc_status_added:
+        if (!mb->is_copy)
+          {
+            mb->found_mod = TRUE;
+            mb->found_not_delete = TRUE;
+            /* Exit from the status walker: We know what we want to know */
+            return svn_error_create(SVN_ERR_CEASE_INVOCATION, NULL, NULL);
+          }
+        break;
+
+      default:
       case svn_wc_status_replaced:
       case svn_wc_status_modified:
         mb->found_mod = TRUE;
@@ -1196,20 +1236,24 @@ modcheck_callback(void *baton,
  * tree rooted at LOCAL_ABSPATH, using DB. If *MODIFIED
  * is set to true and all the local modifications were deletes then set
  * *ALL_EDITS_ARE_DELETES to true, set it to false otherwise.  LOCAL_ABSPATH
- * may be a file or a directory. */
+ * may be a file or a directory. If IS_COPY is TRUE, LOCAL_ABSPATH is a
+ * copied (or moved) node, and nodes at or within LOCAL_ABSPATH are only
+ * considered modified if they were modified post-copy. */
 static svn_error_t *
 node_has_local_mods(svn_boolean_t *modified,
                     svn_boolean_t *all_edits_are_deletes,
+                    svn_boolean_t is_copy,
                     svn_wc__db_t *db,
                     const char *local_abspath,
                     svn_cancel_func_t cancel_func,
                     void *cancel_baton,
                     apr_pool_t *scratch_pool)
 {
-  modcheck_baton_t modcheck_baton = { NULL, FALSE, FALSE };
+  modcheck_baton_t modcheck_baton = { NULL, FALSE, FALSE, FALSE };
   svn_error_t *err;
 
   modcheck_baton.db = db;
+  modcheck_baton.is_copy = is_copy;
 
   /* Walk the WC tree for status with depth infinity, looking for any local
    * modifications. If it's a "sparse" directory, that's OK: there can be
@@ -1325,13 +1369,14 @@ create_tree_conflict(svn_wc_conflict_des
   else
     {
       /* A BASE node should exist. */
-      svn_wc__db_kind_t base_kind;
+      svn_kind_t base_kind;
 
       /* If anything else shows up, then this assertion is probably naive
        * and that other case should also be handled. */
       SVN_ERR_ASSERT(reason == svn_wc_conflict_reason_edited
                      || reason == svn_wc_conflict_reason_deleted
                      || reason == svn_wc_conflict_reason_moved_away
+                     || reason == svn_wc_conflict_reason_moved_away_and_edited
                      || reason == svn_wc_conflict_reason_replaced
                      || reason == svn_wc_conflict_reason_obstructed);
 
@@ -1346,10 +1391,10 @@ create_tree_conflict(svn_wc_conflict_des
                                        result_pool,
                                        scratch_pool));
       /* Translate the node kind. */
-      if (base_kind == svn_wc__db_kind_file
-          || base_kind == svn_wc__db_kind_symlink)
+      if (base_kind == svn_kind_file
+          || base_kind == svn_kind_symlink)
         left_kind = svn_node_file;
-      else if (base_kind == svn_wc__db_kind_dir)
+      else if (base_kind == svn_kind_dir)
         left_kind = svn_node_dir;
       else
         SVN_ERR_MALFUNCTION();
@@ -1452,7 +1497,7 @@ check_tree_conflict(svn_wc_conflict_desc
                     struct edit_baton *eb,
                     const char *local_abspath,
                     svn_wc__db_status_t working_status,
-                    svn_wc__db_kind_t working_kind,
+                    svn_kind_t working_kind,
                     svn_boolean_t exists_in_repos,
                     svn_wc_conflict_action_t action,
                     svn_node_kind_t their_node_kind,
@@ -1527,6 +1572,26 @@ check_tree_conflict(svn_wc_conflict_desc
       case svn_wc__db_status_deleted:
         if (!moved_to_abspath)
           reason = svn_wc_conflict_reason_deleted;
+        else if (action == svn_wc_conflict_action_delete)
+          {
+            svn_boolean_t all_edits_are_deletes = FALSE;
+
+            /* The update wants to delete a node which was locally moved
+             * away. We allow this only if the node wasn't modified post-move.
+             * If the only post-move changes within a subtree are deletions,
+             * allow the update to delete the entire subtree. */
+            if (working_kind == svn_kind_dir)
+              SVN_ERR(node_has_local_mods(&modified, &all_edits_are_deletes,
+                                          TRUE, eb->db, moved_to_abspath,
+                                          eb->cancel_func, eb->cancel_baton,
+                                          scratch_pool));
+            else
+              SVN_ERR(svn_wc__internal_file_modified_p(&modified, eb->db,
+                                                       moved_to_abspath,
+                                                       FALSE, scratch_pool));
+            if (modified && !all_edits_are_deletes)
+              reason = svn_wc_conflict_reason_moved_away_and_edited;
+          }
         break;
 
       case svn_wc__db_status_incomplete:
@@ -1551,7 +1616,7 @@ check_tree_conflict(svn_wc_conflict_desc
          * not visit the subdirectories of a directory that it wants to delete.
          * Therefore, we need to start a separate crawl here. */
 
-        SVN_ERR(node_has_local_mods(&modified, &all_mods_are_deletes,
+        SVN_ERR(node_has_local_mods(&modified, &all_mods_are_deletes, FALSE,
                                     eb->db, local_abspath,
                                     eb->cancel_func, eb->cancel_baton,
                                     scratch_pool));
@@ -1592,6 +1657,7 @@ check_tree_conflict(svn_wc_conflict_desc
   if (reason == svn_wc_conflict_reason_edited
       || reason == svn_wc_conflict_reason_deleted
       || reason == svn_wc_conflict_reason_moved_away
+      || reason == svn_wc_conflict_reason_moved_away_and_edited
       || reason == svn_wc_conflict_reason_replaced)
     /* When the node existed before (it was locally deleted, replaced or
      * edited), then 'update' cannot add it "again". So it can only send
@@ -1706,7 +1772,8 @@ delete_entry(const char *path,
   const char *base = svn_relpath_basename(path, NULL);
   const char *local_abspath;
   const char *repos_relpath;
-  svn_wc__db_kind_t kind, base_kind;
+  const char *moved_to_abspath = NULL;
+  svn_kind_t kind, base_kind;
   svn_boolean_t conflicted;
   svn_boolean_t have_base;
   svn_boolean_t have_work;
@@ -1805,6 +1872,13 @@ delete_entry(const char *path,
       return SVN_NO_ERROR;
     }
 
+  /* Has the to-be-deleted node been moved away? */
+  if (status == svn_wc__db_status_deleted)
+    SVN_ERR(svn_wc__db_scan_deletion(NULL, &moved_to_abspath, NULL,
+                                     NULL, eb->db, local_abspath,
+                                     pool, pool));
+
+
   /* Is this path the victim of a newly-discovered tree conflict?  If so,
    * remember it and notify the client. Then (if it was existing and
    * modified), re-schedule the node to be added back again, as a (modified)
@@ -1817,7 +1891,8 @@ delete_entry(const char *path,
       SVN_ERR(check_tree_conflict(&tree_conflict, eb, local_abspath,
                                   status, kind, TRUE,
                                   svn_wc_conflict_action_delete, svn_node_none,
-                                  repos_relpath, NULL, pb->pool, scratch_pool));
+                                  repos_relpath, moved_to_abspath,
+                                  pb->pool, scratch_pool));
     }
 
   if (tree_conflict != NULL)
@@ -1856,6 +1931,8 @@ delete_entry(const char *path,
         }
       else if (tree_conflict->reason == svn_wc_conflict_reason_deleted
                || tree_conflict->reason == svn_wc_conflict_reason_moved_away
+               || tree_conflict->reason ==
+                     svn_wc_conflict_reason_moved_away_and_edited
                || tree_conflict->reason == svn_wc_conflict_reason_replaced)
         {
           /* The item does not exist locally because it was already shadowed.
@@ -1867,6 +1944,23 @@ delete_entry(const char *path,
       else
         SVN_ERR_MALFUNCTION();  /* other reasons are not expected here */
     }
+  else if (moved_to_abspath)
+    {
+      /* No tree conflict was flagged, and the node was moved-away.
+       * Automatically merge the incoming deletion with the local move
+       * by deleting the node from the moved-away subtree. */
+      /* ### This should probably use a work queue. */
+      SVN_ERR(svn_wc__db_op_delete(eb->db, moved_to_abspath, NULL,
+                                   NULL, NULL, /* notify below */
+                                   eb->cancel_func, eb->cancel_baton,
+                                   scratch_pool));
+      if (kind == svn_kind_dir)
+        SVN_ERR(svn_io_remove_dir2(moved_to_abspath, TRUE,
+                                   eb->cancel_func, eb->cancel_baton,
+                                   scratch_pool));
+      else
+        SVN_ERR(svn_io_remove_file2(moved_to_abspath, TRUE, scratch_pool));
+    }
 
   /* Issue a wq operation to delete the BASE_NODE data and to delete actual
      nodes based on that from disk, but leave any WORKING_NODEs on disk.
@@ -1882,7 +1976,7 @@ delete_entry(const char *path,
       SVN_ERR(svn_wc__wq_build_base_remove(&work_item,
                                            eb->db, local_abspath,
                                            SVN_INVALID_REVNUM,
-                                           svn_wc__db_kind_unknown,
+                                           svn_kind_unknown,
                                            scratch_pool, scratch_pool));
     }
   else
@@ -1912,12 +2006,13 @@ delete_entry(const char *path,
       if (pb->shadowed)
         action = svn_wc_notify_update_shadowed_delete;
 
-      if (kind == svn_wc__db_kind_dir)
+      if (kind == svn_kind_dir)
         node_kind = svn_node_dir;
       else
         node_kind = svn_node_file;
 
-      do_notification(eb, local_abspath, node_kind, action, scratch_pool);
+      do_notification(eb, moved_to_abspath ? moved_to_abspath : local_abspath,
+                      node_kind, action, scratch_pool);
     }
 
   svn_pool_destroy(scratch_pool);
@@ -1939,7 +2034,7 @@ add_directory(const char *path,
   struct dir_baton *db;
   svn_node_kind_t kind;
   svn_wc__db_status_t status;
-  svn_wc__db_kind_t wc_kind;
+  svn_kind_t wc_kind;
   svn_boolean_t conflicted;
   svn_boolean_t versioned_locally_and_present;
   svn_wc_conflict_description2_t *tree_conflict = NULL;
@@ -1995,13 +2090,13 @@ add_directory(const char *path,
         return svn_error_trace(err);
 
       svn_error_clear(err);
-      wc_kind = svn_wc__db_kind_unknown;
+      wc_kind = svn_kind_unknown;
       status = svn_wc__db_status_normal;
       conflicted = FALSE;
 
       versioned_locally_and_present = FALSE;
     }
-  else if (wc_kind == svn_wc__db_kind_dir
+  else if (wc_kind == svn_kind_dir
            && status == svn_wc__db_status_normal)
     {
       /* !! We found the root of a separate working copy obstructing the wc !!
@@ -2019,7 +2114,7 @@ add_directory(const char *path,
                                                    eb->repos_root,
                                                    eb->repos_uuid,
                                                    *eb->target_revision,
-                                                   svn_wc__db_kind_file,
+                                                   svn_kind_file,
                                                    NULL, NULL,
                                                    pool));
 
@@ -2033,8 +2128,8 @@ add_directory(const char *path,
       return SVN_NO_ERROR;
     }
   else if (status == svn_wc__db_status_normal
-           && (wc_kind == svn_wc__db_kind_file
-               || wc_kind == svn_wc__db_kind_symlink))
+           && (wc_kind == svn_kind_file
+               || wc_kind == svn_kind_symlink))
     {
       /* We found a file external occupating the place we need in BASE.
 
@@ -2056,7 +2151,7 @@ add_directory(const char *path,
 
       return SVN_NO_ERROR;
     }
-  else if (wc_kind == svn_wc__db_kind_unknown)
+  else if (wc_kind == svn_kind_unknown)
     versioned_locally_and_present = FALSE; /* Tree conflict ACTUAL-only node */
   else
     versioned_locally_and_present = IS_NODE_PRESENT(status);
@@ -2116,7 +2211,7 @@ add_directory(const char *path,
                                                    eb->repos_root,
                                                    eb->repos_uuid,
                                                    *eb->target_revision,
-                                                   svn_wc__db_kind_dir,
+                                                   svn_kind_dir,
                                                    NULL, NULL,
                                                    pool));
 
@@ -2155,7 +2250,7 @@ add_directory(const char *path,
 
 
       /* Is there *something* that is not a dir? */
-      local_is_non_dir = (wc_kind != svn_wc__db_kind_dir
+      local_is_non_dir = (wc_kind != svn_kind_dir
                           && status != svn_wc__db_status_deleted);
 
       /* Do tree conflict checking if
@@ -2216,8 +2311,8 @@ add_directory(const char *path,
                                                        pool));
 
   /* Make sure there is a real directory at LOCAL_ABSPATH, unless we are just
-     updating the DB */
-  if (!db->shadowed)
+     updating the DB or the parent was moved away. */
+  if (!db->shadowed && !pb->moved_to_abspath)
     SVN_ERR(svn_wc__ensure_directory(db->local_abspath, pool));
 
   if (!db->shadowed && status == svn_wc__db_status_added)
@@ -2245,6 +2340,16 @@ add_directory(const char *path,
       do_notification(eb, db->local_abspath, svn_node_dir,
                       svn_wc_notify_tree_conflict, pool);
     }
+  else if (wc_kind == svn_kind_unknown &&
+           versioned_locally_and_present == FALSE &&
+           pb->moved_to_abspath)
+    {
+      /* The parent directory of the directory we're adding was moved.
+       * Add the new directory at the new location. */
+      db->moved_to_abspath = svn_dirent_join(pb->moved_to_abspath,
+                                             db->name, db->pool);
+      db->moved_to_op_root_abspath = pb->moved_to_op_root_abspath;
+    }
 
 
 
@@ -2266,7 +2371,9 @@ add_directory(const char *path,
 
       db->already_notified = TRUE;
 
-      do_notification(eb, db->local_abspath, svn_node_dir, action, pool);
+      do_notification(eb, db->moved_to_abspath ? db->moved_to_abspath
+                                               : db->local_abspath,
+                      svn_node_dir, action, pool);
     }
 
   return SVN_NO_ERROR;
@@ -2286,7 +2393,8 @@ open_directory(const char *path,
   svn_boolean_t conflicted;
   svn_wc_conflict_description2_t *tree_conflict = NULL;
   svn_wc__db_status_t status, base_status;
-  svn_wc__db_kind_t wc_kind;
+  svn_kind_t wc_kind;
+  svn_error_t *err;
 
   SVN_ERR(make_dir_baton(&db, path, eb, pb, FALSE, pool));
   *child_baton = db;
@@ -2361,13 +2469,34 @@ open_directory(const char *path,
   /* Is this path a fresh tree conflict victim?  If so, skip the tree
      with one notification. */
 
+  /* Check if this directory was moved away. */
+  err = svn_wc__db_read_info(&status, NULL, NULL, NULL, NULL, NULL, NULL,
+                             NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+                             NULL, NULL, NULL, NULL, NULL, NULL,
+                             NULL, NULL, NULL, NULL,
+                             NULL, NULL, NULL,
+                             eb->db, db->local_abspath, pool, pool);
+  if (err)
+    {
+      if (err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
+        svn_error_clear(err);
+      else
+        return svn_error_trace(err);
+    }
+  else if (status == svn_wc__db_status_deleted)
+    SVN_ERR(svn_wc__db_scan_deletion(NULL, &db->moved_to_abspath, NULL,
+                                     &db->moved_to_op_root_abspath,
+                                     eb->db, db->local_abspath,
+                                     db->pool, pool));
+
   /* Check for conflicts only when we haven't already recorded
    * a tree-conflict on a parent node. */
   if (!db->shadowed)
     SVN_ERR(check_tree_conflict(&tree_conflict, eb, db->local_abspath,
                                 status, wc_kind, TRUE,
                                 svn_wc_conflict_action_edit, svn_node_dir,
-                                db->new_relpath, NULL, db->pool, pool));
+                                db->new_relpath, db->moved_to_abspath,
+                                db->pool, pool));
 
   /* Remember the roots of any locally deleted trees. */
   if (tree_conflict != NULL)
@@ -2377,6 +2506,8 @@ open_directory(const char *path,
       SVN_ERR_ASSERT(
                 tree_conflict->reason == svn_wc_conflict_reason_deleted ||
                 tree_conflict->reason == svn_wc_conflict_reason_moved_away ||
+                tree_conflict->reason ==
+                  svn_wc_conflict_reason_moved_away_and_edited ||
                 tree_conflict->reason == svn_wc_conflict_reason_replaced);
 
       /* Continue updating BASE */
@@ -2594,7 +2725,7 @@ close_directory(void *dir_baton,
                                     &new_actual_props,
                                     eb->db,
                                     db->local_abspath,
-                                    svn_wc__db_kind_dir,
+                                    svn_kind_dir,
                                     NULL, /* left_version */
                                     NULL, /* right_version */
                                     NULL /* use baseprops */,
@@ -2640,7 +2771,7 @@ close_directory(void *dir_baton,
             const char *child_relpath;
             const svn_dirent_t *dirent;
             svn_wc__db_status_t status;
-            svn_wc__db_kind_t child_kind;
+            svn_kind_t child_kind;
             svn_error_t *err;
 
             svn_pool_clear(iterpool);
@@ -2651,11 +2782,11 @@ close_directory(void *dir_baton,
 
             dirent = svn__apr_hash_index_val(hi);
             child_kind = (dirent->kind == svn_node_dir)
-                                        ? svn_wc__db_kind_dir
-                                        : svn_wc__db_kind_file;
+                                        ? svn_kind_dir
+                                        : svn_kind_file;
 
             if (db->ambient_depth < svn_depth_immediates
-                && child_kind == svn_wc__db_kind_dir)
+                && child_kind == svn_kind_dir)
               continue; /* We don't need the subdirs */
 
             /* ### We just check if there is some node in BASE at this path */
@@ -2726,7 +2857,7 @@ close_directory(void *dir_baton,
                                                        eb->repos_root,
                                                        eb->repos_uuid,
                                                        *eb->target_revision,
-                                                       svn_wc__db_kind_file,
+                                                       svn_kind_file,
                                                        NULL, NULL,
                                                        iterpool));
         }
@@ -2804,6 +2935,41 @@ close_directory(void *dir_baton,
                 new_actual_props,
                 all_work_items,
                 scratch_pool));
+
+      if (db->moved_to_abspath)
+        {
+          /* Perform another in-DB move of the directory to sync meta-data
+           * of the moved-away node with the new BASE node. */
+          apr_array_header_t *children = NULL;
+          apr_hash_t *children_hash = apr_hash_get(eb->dir_dirents,
+                                                   db->new_relpath,
+                                                   APR_HASH_KEY_STRING);
+          /* The op-root of the move needs to retain its moved-here flag.
+           * Its children are normal copied children. */
+          svn_boolean_t is_move = (strcmp(db->moved_to_op_root_abspath,
+                                          db->moved_to_abspath) == 0);
+
+          /* Add the new directory as a copy and create it on disk. */
+          if (children_hash)
+            SVN_ERR(svn_hash_keys(&children, children_hash, scratch_pool));
+          SVN_ERR(svn_wc__db_op_copy_dir(eb->db, db->moved_to_abspath,
+                                         new_actual_props ? new_actual_props
+                                                          : actual_props,
+                                         db->changed_rev,
+                                         db->changed_date,
+                                         db->changed_author,
+                                         db->new_relpath,
+                                         eb->repos_root,
+                                         eb->repos_uuid,
+                                         *eb->target_revision,
+                                         children,
+                                         is_move,
+                                         db->ambient_depth,
+                                         NULL /* conflict */,
+                                         NULL, /* no work, just modify DB */
+                                         scratch_pool));
+          SVN_ERR(svn_wc__ensure_directory(db->moved_to_abspath, pool));
+        }
     }
 
   /* Process all of the queued work items for this directory.  */
@@ -2848,7 +3014,7 @@ close_directory(void *dir_baton,
 /* Common code for 'absent_file' and 'absent_directory'. */
 static svn_error_t *
 absent_node(const char *path,
-            svn_wc__db_kind_t absent_kind,
+            svn_kind_t absent_kind,
             void *parent_baton,
             apr_pool_t *pool)
 {
@@ -2859,7 +3025,7 @@ absent_node(const char *path,
   const char *local_abspath;
   svn_error_t *err;
   svn_wc__db_status_t status;
-  svn_wc__db_kind_t kind;
+  svn_kind_t kind;
 
   if (pb->skip_this)
     return SVN_NO_ERROR;
@@ -2884,11 +3050,11 @@ absent_node(const char *path,
 
       svn_error_clear(err);
       status = svn_wc__db_status_not_present;
-      kind = svn_wc__db_kind_unknown;
+      kind = svn_kind_unknown;
     }
 
   if (status == svn_wc__db_status_normal
-      && kind == svn_wc__db_kind_dir)
+      && kind == svn_kind_dir)
     {
       /* We found an obstructing working copy!
 
@@ -2954,7 +3120,7 @@ absent_file(const char *path,
             void *parent_baton,
             apr_pool_t *pool)
 {
-  return absent_node(path, svn_wc__db_kind_file, parent_baton, pool);
+  return absent_node(path, svn_kind_file, parent_baton, pool);
 }
 
 
@@ -2964,7 +3130,7 @@ absent_directory(const char *path,
                  void *parent_baton,
                  apr_pool_t *pool)
 {
-  return absent_node(path, svn_wc__db_kind_dir, parent_baton, pool);
+  return absent_node(path, svn_kind_dir, parent_baton, pool);
 }
 
 
@@ -2981,7 +3147,7 @@ add_file(const char *path,
   struct edit_baton *eb = pb->edit_baton;
   struct file_baton *fb;
   svn_node_kind_t kind = svn_node_none;
-  svn_wc__db_kind_t wc_kind = svn_wc__db_kind_unknown;
+  svn_kind_t wc_kind = svn_kind_unknown;
   svn_wc__db_status_t status = svn_wc__db_status_normal;
   apr_pool_t *scratch_pool;
   svn_boolean_t conflicted = FALSE;
@@ -3030,12 +3196,12 @@ add_file(const char *path,
         return svn_error_trace(err);
 
       svn_error_clear(err);
-      wc_kind = svn_wc__db_kind_unknown;
+      wc_kind = svn_kind_unknown;
       conflicted = FALSE;
 
       versioned_locally_and_present = FALSE;
     }
-  else if (wc_kind == svn_wc__db_kind_dir
+  else if (wc_kind == svn_kind_dir
            && status == svn_wc__db_status_normal)
     {
       /* !! We found the root of a separate working copy obstructing the wc !!
@@ -3061,8 +3227,8 @@ add_file(const char *path,
       return SVN_NO_ERROR;
     }
   else if (status == svn_wc__db_status_normal
-           && (wc_kind == svn_wc__db_kind_file
-               || wc_kind == svn_wc__db_kind_symlink))
+           && (wc_kind == svn_kind_file
+               || wc_kind == svn_kind_symlink))
     {
       /* We found a file external occupating the place we need in BASE.
 
@@ -3085,7 +3251,7 @@ add_file(const char *path,
 
       return SVN_NO_ERROR;
     }
-  else if (wc_kind == svn_wc__db_kind_unknown)
+  else if (wc_kind == svn_kind_unknown)
     versioned_locally_and_present = FALSE; /* Tree conflict ACTUAL-only node */
   else
     versioned_locally_and_present = IS_NODE_PRESENT(status);
@@ -3093,7 +3259,6 @@ add_file(const char *path,
 
   /* Is this path a conflict victim? */
   if (conflicted)
-    if (conflicted)
     {
       if (pb->deletion_conflicts)
         tree_conflict = apr_hash_get(pb->deletion_conflicts, fb->name,
@@ -3182,8 +3347,8 @@ add_file(const char *path,
                                          scratch_pool, scratch_pool));
 
       /* Is there something that is a file? */
-      local_is_file = (wc_kind == svn_wc__db_kind_file
-                       || wc_kind == svn_wc__db_kind_symlink);
+      local_is_file = (wc_kind == svn_kind_file
+                       || wc_kind == svn_kind_symlink);
 
       /* Do tree conflict checking if
        *  - if there is a local copy.
@@ -3257,6 +3422,15 @@ add_file(const char *path,
       do_notification(eb, fb->local_abspath, svn_node_file,
                       svn_wc_notify_tree_conflict, scratch_pool);
     }
+  else if (wc_kind == svn_kind_unknown &&
+           versioned_locally_and_present == FALSE &&
+           pb->moved_to_abspath)
+    {
+      /* The parent directory of the file we're adding was moved.
+       * Add the new file at the new location. */
+      fb->moved_to_abspath = svn_dirent_join(pb->moved_to_abspath,
+                                             fb->name, fb->pool);
+    }
 
   svn_pool_destroy(scratch_pool);
 
@@ -3278,7 +3452,7 @@ open_file(const char *path,
   svn_boolean_t conflicted;
   svn_boolean_t have_work;
   svn_wc__db_status_t status;
-  svn_wc__db_kind_t wc_kind;
+  svn_kind_t wc_kind;
   svn_wc_conflict_description2_t *tree_conflict = NULL;
 
   /* the file_pool can stick around for a *long* time, so we want to use
@@ -3378,7 +3552,9 @@ open_file(const char *path,
       /* Other modifications wouldn't be a tree conflict */
       SVN_ERR_ASSERT(
                 tree_conflict->reason == svn_wc_conflict_reason_deleted ||
-                tree_conflict->reason == svn_wc_conflict_reason_moved_away||
+                tree_conflict->reason == svn_wc_conflict_reason_moved_away ||
+                tree_conflict->reason ==
+                  svn_wc_conflict_reason_moved_away_and_edited ||
                 tree_conflict->reason == svn_wc_conflict_reason_replaced);
 
       /* Continue updating BASE */
@@ -4086,28 +4262,28 @@ close_file(void *file_baton,
   if (!fb->shadowed
       && (! fb->adding_file || fb->add_existed))
     {
-      svn_boolean_t local_is_link = FALSE;
-      svn_boolean_t incoming_is_link = FALSE;
+      svn_boolean_t local_is_link;
+      svn_boolean_t incoming_is_link;
+      int i;
 
       local_is_link = apr_hash_get(local_actual_props,
                                 SVN_PROP_SPECIAL,
                                 APR_HASH_KEY_STRING) != NULL;
 
-      {
-        int i;
-
-        for (i = 0; i < regular_prop_changes->nelts; ++i)
-          {
-            const svn_prop_t *prop = &APR_ARRAY_IDX(regular_prop_changes, i,
-                                                    svn_prop_t);
+      incoming_is_link = local_is_link;
 
-            if (strcmp(prop->name, SVN_PROP_SPECIAL) == 0)
-              {
-                incoming_is_link = TRUE;
-              }
-          }
-      }
+      /* Does an incoming propchange affect symlink-ness? */
+      for (i = 0; i < regular_prop_changes->nelts; ++i)
+        {
+          const svn_prop_t *prop = &APR_ARRAY_IDX(regular_prop_changes, i,
+                                                  svn_prop_t);
 
+          if (strcmp(prop->name, SVN_PROP_SPECIAL) == 0)
+            {
+              incoming_is_link = (prop->value != NULL);
+              break;
+            }
+        }
 
       if (local_is_link != incoming_is_link)
         {
@@ -4117,15 +4293,12 @@ close_file(void *file_baton,
           fb->obstruction_found = TRUE;
           fb->add_existed = FALSE;
 
-          /* ### Performance: We should just create the conflict here, without
-             ### verifying again */
-          SVN_ERR(check_tree_conflict(&tree_conflict, eb, fb->local_abspath,
-                                      svn_wc__db_status_added,
-                                      svn_wc__db_kind_file, TRUE,
-                                      svn_wc_conflict_action_add,
-                                      svn_node_file, fb->new_relpath, NULL,
-                                      scratch_pool, scratch_pool));
-          SVN_ERR_ASSERT(tree_conflict != NULL);
+          SVN_ERR(create_tree_conflict(&tree_conflict, eb,
+                                       fb->local_abspath,
+                                       svn_wc_conflict_reason_added,
+                                       svn_wc_conflict_action_add,
+                                       svn_node_file, fb->new_relpath,
+                                       scratch_pool, scratch_pool));
           SVN_ERR(svn_wc__db_op_set_tree_conflict(eb->db,
                                                   fb->local_abspath,
                                                   tree_conflict,
@@ -4154,7 +4327,7 @@ close_file(void *file_baton,
                                   &new_actual_props,
                                   eb->db,
                                   working_abspath,
-                                  svn_wc__db_kind_file,
+                                  svn_kind_file,
                                   NULL /* left_version */,
                                   NULL /* right_version */,
                                   NULL /* server_baseprops (update, not merge)  */,
@@ -4293,7 +4466,7 @@ close_file(void *file_baton,
                                   &new_actual_props,
                                   eb->db,
                                   fb->local_abspath,
-                                  svn_wc__db_kind_file,
+                                  svn_kind_file,
                                   NULL /* left_version */,
                                   NULL /* right_version */,
                                   NULL /* server_baseprops (not merging) */,
@@ -4543,6 +4716,46 @@ close_edit(void *edit_baton,
 }
 
 
+static svn_error_t *
+fetch_props_func(apr_hash_t **props,
+                 void *baton,
+                 const char *path,
+                 svn_revnum_t base_revision,
+                 apr_pool_t *result_pool,
+                 apr_pool_t *scratch_pool)
+{
+  struct svn_wc__shim_fetch_baton_t *sfb = baton;
+  const char *local_abspath = svn_dirent_join(sfb->base_abspath, path,
+                                              scratch_pool);
+  svn_error_t *err;
+
+  if (sfb->fetch_base)
+    err = svn_wc__db_base_get_props(props, sfb->db, local_abspath, result_pool,
+                                    scratch_pool);
+  else
+    err = svn_wc__db_read_props(props, sfb->db, local_abspath,
+                                result_pool, scratch_pool);
+
+  /* If the path doesn't exist, just return an empty set of props. */
+  if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
+    {
+      svn_error_clear(err);
+      *props = apr_hash_make(result_pool);
+    }
+  else if (err)
+    return svn_error_trace(err);
+
+  /* Add a bogus LOCK_TOKEN if we don't already have one, so as to catch
+     any deletions thereto. */
+  if (!apr_hash_get(*props, SVN_PROP_ENTRY_LOCK_TOKEN, APR_HASH_KEY_STRING))
+    {
+      apr_hash_set(*props, SVN_PROP_ENTRY_LOCK_TOKEN, APR_HASH_KEY_STRING,
+                   svn_string_create("This is completely bogus", result_pool));
+    }
+
+  return SVN_NO_ERROR;
+}
+
 
 /*** Returning editors. ***/
 
@@ -4583,6 +4796,9 @@ make_editor(svn_revnum_t *target_revisio
   svn_delta_editor_t *tree_editor = svn_delta_default_editor(edit_pool);
   const svn_delta_editor_t *inner_editor;
   const char *repos_root, *repos_uuid;
+  struct svn_wc__shim_fetch_baton_t *sfb;
+  svn_delta_shim_callbacks_t *shim_callbacks =
+                                svn_delta_shim_callbacks_default(edit_pool);
 
   /* An unknown depth can't be sticky. */
   if (depth == svn_depth_unknown)
@@ -4681,7 +4897,7 @@ make_editor(svn_revnum_t *target_revisio
          depth. In this case the update won't describe additions that would
          have been reported if we updated at the ambient depth. */
       svn_error_t *err;
-      svn_wc__db_kind_t dir_kind;
+      svn_kind_t dir_kind;
       svn_wc__db_status_t dir_status;
       const char *dir_repos_relpath;
       svn_depth_t dir_depth;
@@ -4695,7 +4911,7 @@ make_editor(svn_revnum_t *target_revisio
                                      scratch_pool, scratch_pool);
 
       if (!err
-          && dir_kind == svn_wc__db_kind_dir
+          && dir_kind == svn_kind_dir
           && dir_status == svn_wc__db_status_normal)
         {
           if (dir_depth > depth)
@@ -4751,7 +4967,7 @@ make_editor(svn_revnum_t *target_revisio
                                                    db, child_abspath,
                                                    iterpool, iterpool));
 
-                  if (dir_kind == svn_wc__db_kind_dir
+                  if (dir_kind == svn_kind_dir
                       && dir_status == svn_wc__db_status_normal
                       && dir_depth > svn_depth_empty)
                     {
@@ -4802,13 +5018,28 @@ make_editor(svn_revnum_t *target_revisio
                                                 inner_baton,
                                                 result_pool));
 
-  return svn_delta_get_cancellation_editor(cancel_func,
-                                           cancel_baton,
-                                           inner_editor,
-                                           inner_baton,
-                                           editor,
-                                           edit_baton,
-                                           result_pool);
+  SVN_ERR(svn_delta_get_cancellation_editor(cancel_func,
+                                            cancel_baton,
+                                            inner_editor,
+                                            inner_baton,
+                                            editor,
+                                            edit_baton,
+                                            result_pool));
+
+  sfb = apr_palloc(result_pool, sizeof(*sfb));
+  sfb->db = db;
+  sfb->base_abspath = eb->anchor_abspath;
+  sfb->fetch_base = TRUE;
+
+  shim_callbacks->fetch_kind_func = svn_wc__fetch_kind_func;
+  shim_callbacks->fetch_props_func = fetch_props_func;
+  shim_callbacks->fetch_base_func = svn_wc__fetch_base_func;
+  shim_callbacks->fetch_baton = sfb;
+
+  SVN_ERR(svn_editor__insert_shims(editor, edit_baton, *editor, *edit_baton,
+                                   shim_callbacks, result_pool, scratch_pool));
+
+  return SVN_NO_ERROR;
 }
 
 
@@ -5008,7 +5239,7 @@ svn_wc_get_switch_editor4(const svn_delt
 
 svn_error_t *
 svn_wc__check_wc_root(svn_boolean_t *wc_root,
-                      svn_wc__db_kind_t *kind,
+                      svn_kind_t *kind,
                       svn_boolean_t *switched,
                       svn_wc__db_t *db,
                       const char *local_abspath,
@@ -5017,7 +5248,7 @@ svn_wc__check_wc_root(svn_boolean_t *wc_
   const char *parent_abspath, *name;
   const char *repos_relpath, *repos_root, *repos_uuid;
   svn_wc__db_status_t status;
-  svn_wc__db_kind_t my_kind;
+  svn_kind_t my_kind;
 
   if (!kind)
     kind = &my_kind;
@@ -5041,7 +5272,7 @@ svn_wc__check_wc_root(svn_boolean_t *wc_
       *wc_root = FALSE;
       return SVN_NO_ERROR;
     }
-  if (*kind != svn_wc__db_kind_dir)
+  if (*kind != svn_kind_dir)
     {
       /* File/symlinks cannot be a root.  */
       *wc_root = FALSE;
@@ -5125,7 +5356,7 @@ svn_wc_is_wc_root2(svn_boolean_t *wc_roo
 {
   svn_boolean_t is_root;
   svn_boolean_t is_switched;
-  svn_wc__db_kind_t kind;
+  svn_kind_t kind;
   svn_error_t *err;
   SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
 
@@ -5141,7 +5372,7 @@ svn_wc_is_wc_root2(svn_boolean_t *wc_roo
       return svn_error_create(SVN_ERR_ENTRY_NOT_FOUND, err, err->message);
     }
 
-  *wc_root = is_root || (kind == svn_wc__db_kind_dir && is_switched);
+  *wc_root = is_root || (kind == svn_kind_dir && is_switched);
 
   return SVN_NO_ERROR;
 }
@@ -5181,7 +5412,7 @@ svn_wc_get_actual_target2(const char **a
                           apr_pool_t *scratch_pool)
 {
   svn_boolean_t is_wc_root, is_switched;
-  svn_wc__db_kind_t kind;
+  svn_kind_t kind;
   const char *local_abspath;
   svn_error_t *err;
 
@@ -5203,7 +5434,7 @@ svn_wc_get_actual_target2(const char **a
     }
 
   /* If PATH is not a WC root, or if it is a file, lop off a basename. */
-  if (!(is_wc_root || is_switched) || (kind != svn_wc__db_kind_dir))
+  if (!(is_wc_root || is_switched) || (kind != svn_kind_dir))
     {
       svn_dirent_split(anchor, target, path, result_pool);
     }
@@ -5241,7 +5472,7 @@ svn_wc_add_repos_file4(svn_wc_context_t 
   svn_wc__db_t *db = wc_ctx->db;
   const char *dir_abspath = svn_dirent_dirname(local_abspath, scratch_pool);
   svn_wc__db_status_t status;
-  svn_wc__db_kind_t kind;
+  svn_kind_t kind;
   const char *tmp_text_base_abspath;
   svn_checksum_t *new_text_base_md5_checksum;
   svn_checksum_t *new_text_base_sha1_checksum;
@@ -5312,7 +5543,7 @@ svn_wc_add_repos_file4(svn_wc_context_t 
                                  svn_dirent_local_style(local_abspath,
                                                         scratch_pool));
     }
-  if (kind != svn_wc__db_kind_dir)
+  if (kind != svn_kind_dir)
     return svn_error_createf(SVN_ERR_NODE_UNEXPECTED_KIND, NULL,
                              _("Can't schedule an addition of '%s'"
                                " below a not-directory node"),
@@ -5331,14 +5562,14 @@ svn_wc_add_repos_file4(svn_wc_context_t 
                                               dir_abspath,
                                               pool, pool));
 
-      if (!svn_uri__is_ancestor(original_root_url, copyfrom_url))
+      original_repos_relpath =
+        svn_uri_skip_ancestor(original_root_url, copyfrom_url, pool);
+
+      if (!original_repos_relpath)
         return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
                                  _("Copyfrom-url '%s' has different repository"
                                    " root than '%s'"),
                                  copyfrom_url, original_root_url);
-
-      original_repos_relpath =
-        svn_uri_skip_ancestor(original_root_url, copyfrom_url, pool);
     }
   else
     {



Mime
View raw message