You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2011/10/11 21:52:46 UTC

svn commit: r1182053 [18/30] - in /subversion/branches/svn_mutex: ./ build/ build/ac-macros/ build/generator/ build/generator/swig/ build/generator/templates/ contrib/client-side/ contrib/hook-scripts/enforcer/ contrib/server-side/ notes/ notes/merge-t...

Modified: subversion/branches/svn_mutex/subversion/libsvn_wc/status.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn_mutex/subversion/libsvn_wc/status.c?rev=1182053&r1=1182052&r2=1182053&view=diff
==============================================================================
--- subversion/branches/svn_mutex/subversion/libsvn_wc/status.c (original)
+++ subversion/branches/svn_mutex/subversion/libsvn_wc/status.c Tue Oct 11 19:52:34 2011
@@ -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;
@@ -248,9 +254,10 @@ read_info(const struct svn_wc__db_info_t
 
   SVN_ERR(svn_wc__db_read_info(&mtb->status, &mtb->kind,
                                &mtb->revnum, &mtb->repos_relpath,
-                               &mtb->repos_root_url, NULL, &mtb->changed_rev,
-                               &mtb->changed_date, &mtb->changed_author,
-                               &mtb->depth, &checksum, NULL, NULL, NULL, NULL,
+                               &mtb->repos_root_url, &mtb->repos_uuid,
+                               &mtb->changed_rev, &mtb->changed_date,
+                               &mtb->changed_author, &mtb->depth,
+                               &checksum, NULL, NULL, NULL, NULL,
                                NULL, &mtb->lock, &mtb->recorded_size,
                                &mtb->recorded_mod_time, &mtb->changelist,
                                &mtb->conflicted, &mtb->op_root,
@@ -265,19 +272,95 @@ 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;
+          const char *moved_to_op_root_abspath;
+          
+          /* NOTE: we can't use op-root-ness as a condition here since a base
+           * node can be the root of a move and still not be an explicit
+           * op-root (having a working node with op_depth == pathelements).
+           *
+           * Both these (almost identical) situations showcase this:
+           *   svn mv a/b bb
+           *   svn del a
+           * and
+           *   svn mv a aa  
+           *   svn mv aa/b bb
+           * In both, 'bb' is moved from 'a/b', but 'a/b' has no op_depth>0
+           * node at all, as its parent 'a' is locally deleted. */
+
+          SVN_ERR(svn_wc__db_scan_deletion(NULL,
+                                           &moved_to_abspath,
+                                           NULL,
+                                           &moved_to_op_root_abspath,
+                                           db, local_abspath,
+                                           scratch_pool, scratch_pool));
+          if (moved_to_abspath != NULL
+              && moved_to_op_root_abspath != NULL
+              && strcmp(moved_to_abspath, moved_to_op_root_abspath) == 0)
+            {
+              mtb->moved_to_abspath = apr_pstrdup(result_pool,
+                                                  moved_to_abspath);
+            }
+          /* ### ^^^ THIS SUCKS. For at least two reasons:
+           * 1) We scan the node deletion and that's technically not necessary.
+           *    We'd be fine to know if this is an actual root of a move.
+           * 2) From the elaborately calculated results, we backwards-guess
+           *    whether this is a root.
+           * It works ok, and this code only gets called when a node is an
+           * explicit target of a 'status'. But it would be better to do this
+           * differently.
+           * We could return moved-to via svn_wc__db_base_get_info() (called
+           * just above), but as moved-to is only intended to be returned for
+           * roots of a move, that doesn't fit too well. */
+        }
+    }
+
+  /* ### svn_wc__db_read_info() could easily return the moved-here flag. But
+   * for now... (The per-dir query for recursive status is far more optimal.)
+   * Note that this actually scans around to get the full path, for a bool.
+   * This bool then gets returned, later is evaluated, and if true leads to
+   * the same paths being scanned again. We'd want to obtain this bool here as
+   * cheaply as svn_wc__db_read_children_info() does. */
+  if (mtb->status == svn_wc__db_status_added)
+    {
+      const char *moved_from_abspath = 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->had_props || mtb->props_mod)
+  if (mtb->kind == svn_kind_file
+      && (mtb->had_props || mtb->props_mod))
     {
       apr_hash_t *properties;
 
@@ -304,9 +387,11 @@ read_info(const struct svn_wc__db_info_t
 static svn_error_t *
 get_repos_root_url_relpath(const char **repos_relpath,
                            const char **repos_root_url,
+                           const char **repos_uuid,
                            const struct svn_wc__db_info_t *info,
                            const char *parent_repos_relpath,
                            const char *parent_repos_root_url,
+                           const char *parent_repos_uuid,
                            svn_wc__db_t *db,
                            const char *local_abspath,
                            apr_pool_t *result_pool,
@@ -316,6 +401,7 @@ get_repos_root_url_relpath(const char **
     {
       *repos_relpath = info->repos_relpath;
       *repos_root_url = info->repos_root_url;
+      *repos_uuid = info->repos_uuid;
     }
   else if (parent_repos_relpath && parent_repos_root_url)
     {
@@ -324,18 +410,20 @@ get_repos_root_url_relpath(const char **
                                                             NULL),
                                         result_pool);
       *repos_root_url = parent_repos_root_url;
+      *repos_uuid = parent_repos_uuid;
     }
   else if (info->status == svn_wc__db_status_added)
     {
       SVN_ERR(svn_wc__db_scan_addition(NULL, NULL,
                                        repos_relpath, repos_root_url,
-                                       NULL, NULL, NULL, NULL, NULL,
-                                       db, local_abspath,
+                                       repos_uuid, NULL, NULL, NULL, NULL,
+                                       NULL, NULL, db, local_abspath,
                                        result_pool, scratch_pool));
     }
   else if (info->have_base)
     {
-      SVN_ERR(svn_wc__db_scan_base_repos(repos_relpath, repos_root_url, NULL,
+      SVN_ERR(svn_wc__db_scan_base_repos(repos_relpath, repos_root_url,
+                                         repos_uuid,
                                          db, local_abspath,
                                          result_pool, scratch_pool));
     }
@@ -343,6 +431,7 @@ get_repos_root_url_relpath(const char **
     {
       *repos_relpath = NULL;
       *repos_root_url = NULL;
+      *repos_uuid = NULL;
     }
   return SVN_NO_ERROR;
 }
@@ -357,7 +446,7 @@ internal_status(svn_wc_status3_t **statu
 /* Fill in *STATUS for LOCAL_ABSPATH, using DB. Allocate *STATUS in
    RESULT_POOL and use SCRATCH_POOL for temporary allocations.
 
-   PARENT_REPOS_ROOT_URL and PARENT_REPOS_RELPATH are the the repository root
+   PARENT_REPOS_ROOT_URL and PARENT_REPOS_RELPATH are the repository root
    and repository relative path of the parent of LOCAL_ABSPATH or NULL if
    LOCAL_ABSPATH doesn't have a versioned parent directory.
 
@@ -378,6 +467,7 @@ assemble_status(svn_wc_status3_t **statu
                 const char *local_abspath,
                 const char *parent_repos_root_url,
                 const char *parent_repos_relpath,
+                const char *parent_repos_uuid,
                 const struct svn_wc__db_info_t *info,
                 const svn_io_dirent2_t *dirent,
                 svn_boolean_t get_all,
@@ -393,6 +483,8 @@ assemble_status(svn_wc_status3_t **statu
   svn_error_t *err;
   const char *repos_relpath;
   const char *repos_root_url;
+  const char *repos_uuid;
+  const char *moved_from_abspath = NULL;
   svn_filesize_t filesize = (dirent && (dirent->kind == svn_node_file))
                                 ? dirent->filesize
                                 : SVN_INVALID_FILESIZE;
@@ -411,22 +503,18 @@ assemble_status(svn_wc_status3_t **statu
   else
     {
       /* A node is switched if it doesn't have the implied repos_relpath */
-      const char *name = svn_relpath__is_child(parent_repos_relpath,
-                                               info->repos_relpath, NULL);
-      switched_p = !name || (strcmp(name, svn_dirent_basename(local_abspath, NULL)) != 0);
-    }
-
-  /* Examine whether our target is missing or obstructed or missing.
-
-     While we are not completely in single-db mode yet, data about
-     obstructed or missing nodes might be incomplete here. This is
-     reported by svn_wc_db_status_obstructed_XXXX. In single-db
-     mode these obstructions are no longer reported and we have
-     to detect obstructions by looking at the on disk status in DIRENT.
-     */
-  if (info->kind == svn_wc__db_kind_dir)
+      const char *name = svn_relpath_skip_ancestor(parent_repos_relpath,
+                                                   info->repos_relpath);
+      switched_p = !name || (strcmp(name,
+                                    svn_dirent_basename(local_abspath, NULL))
+                             != 0);
+    }
+
+  /* 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_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;
@@ -487,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;
@@ -499,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 */
@@ -528,7 +616,7 @@ assemble_status(svn_wc_status3_t **statu
 
               if (err)
                 {
-                  if (!APR_STATUS_IS_EACCES(err->apr_err))
+                  if (err->apr_err != SVN_ERR_WC_PATH_ACCESS_DENIED)
                     return svn_error_trace(err);
 
                   /* An access denied is very common on Windows when another
@@ -575,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 */
@@ -595,9 +683,19 @@ assemble_status(svn_wc_status3_t **statu
               else if (schedule == svn_wc_schedule_replace)
                 node_status = svn_wc_status_replaced;
             }
+
+          /* Get moved-from info (only for potential op-roots of a move). */
+          if (info->moved_here && info->op_root)
+            SVN_ERR(svn_wc__db_scan_addition(NULL, NULL, NULL, NULL, NULL,
+                                             NULL, NULL, NULL, NULL,
+                                             &moved_from_abspath,
+                                             NULL,
+                                             db, local_abspath,
+                                             result_pool, scratch_pool));
         }
     }
 
+
   if (node_status == svn_wc_status_normal)
     node_status = text_status;
 
@@ -623,9 +721,11 @@ assemble_status(svn_wc_status3_t **statu
         return SVN_NO_ERROR;
       }
 
-  SVN_ERR(get_repos_root_url_relpath(&repos_relpath, &repos_root_url, info,
+  SVN_ERR(get_repos_root_url_relpath(&repos_relpath, &repos_root_url,
+                                     &repos_uuid, info,
                                      parent_repos_relpath,
                                      parent_repos_root_url,
+                                     parent_repos_uuid,
                                      db, local_abspath,
                                      scratch_pool, scratch_pool));
 
@@ -635,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;
     }
@@ -686,6 +786,12 @@ assemble_status(svn_wc_status3_t **statu
   stat->changelist = info->changelist;
   stat->repos_root_url = repos_root_url;
   stat->repos_relpath = repos_relpath;
+  stat->repos_uuid = repos_uuid;
+
+  stat->moved_from_abspath = moved_from_abspath;
+  stat->moved_to_abspath = info->moved_to_abspath;
+
+  stat->file_external = info->file_external;
 
   *status = stat;
 
@@ -704,36 +810,23 @@ static svn_error_t *
 assemble_unversioned(svn_wc_status3_t **status,
                      svn_wc__db_t *db,
                      const char *local_abspath,
-                     svn_node_kind_t path_kind,
+                     const svn_io_dirent2_t *dirent,
+                     svn_boolean_t tree_conflicted,
                      svn_boolean_t is_ignored,
                      apr_pool_t *result_pool,
                      apr_pool_t *scratch_pool)
 {
   svn_wc_status3_t *stat;
-  const svn_wc_conflict_description2_t *tree_conflict;
-  svn_error_t *err;
-
-  /* Find out whether the path is a tree conflict victim.
-     This function will set tree_conflict to NULL if the path
-     is not a victim. */
-  err = svn_wc__db_op_read_tree_conflict(&tree_conflict,
-                                         db, local_abspath,
-                                         scratch_pool, scratch_pool);
-
-  if (path_kind == svn_node_dir &&
-      err &&
-      err->apr_err == SVN_ERR_WC_UPGRADE_REQUIRED)
-    svn_error_clear(err);
-  else
-    SVN_ERR(err);
 
   /* return a fairly blank structure. */
-  stat = apr_pcalloc(result_pool, sizeof(**status));
+  stat = apr_pcalloc(result_pool, sizeof(*stat));
 
   /*stat->versioned = FALSE;*/
   stat->kind = svn_node_unknown; /* not versioned */
   stat->depth = svn_depth_unknown;
-  stat->filesize = SVN_INVALID_FILESIZE;
+  stat->filesize = (dirent && dirent->kind == svn_node_file)
+                        ? dirent->filesize
+                        : SVN_INVALID_FILESIZE;
   stat->node_status = svn_wc_status_none;
   stat->text_status = svn_wc_status_none;
   stat->prop_status = svn_wc_status_none;
@@ -746,18 +839,18 @@ assemble_unversioned(svn_wc_status3_t **
      to matching an ignore-pattern), the node_status is set to
      svn_wc_status_ignored.  Otherwise the node_status is set to
      svn_wc_status_unversioned. */
-  if (path_kind != svn_node_none)
+  if (dirent && dirent->kind != svn_node_none)
     {
       if (is_ignored)
         stat->node_status = svn_wc_status_ignored;
       else
         stat->node_status = svn_wc_status_unversioned;
     }
-  else if (tree_conflict != NULL)
+  else if (tree_conflicted)
     {
       /* If this path has no entry, is NOT present on disk, and IS a
-         tree conflict victim, count it as missing. */
-      stat->node_status = svn_wc_status_missing;
+         tree conflict victim, report it as conflicted. */
+      stat->node_status = svn_wc_status_conflicted;
     }
 
   stat->revision = SVN_INVALID_REVNUM;
@@ -767,7 +860,7 @@ assemble_unversioned(svn_wc_status3_t **
 
   /* For the case of an incoming delete to a locally deleted path during
      an update, we get a tree conflict. */
-  stat->conflicted = (tree_conflict != NULL);
+  stat->conflicted = tree_conflicted;
   stat->changelist = NULL;
 
   *status = stat;
@@ -783,6 +876,7 @@ send_status_structure(const struct walk_
                       const char *local_abspath,
                       const char *parent_repos_root_url,
                       const char *parent_repos_relpath,
+                      const char *parent_repos_uuid,
                       const struct svn_wc__db_info_t *info,
                       const svn_io_dirent2_t *dirent,
                       svn_boolean_t get_all,
@@ -796,11 +890,13 @@ send_status_structure(const struct walk_
   /* Check for a repository lock. */
   if (wb->repos_locks)
     {
-      const char *repos_relpath, *repos_root_url;
+      const char *repos_relpath, *repos_root_url, *repos_uuid;
 
       SVN_ERR(get_repos_root_url_relpath(&repos_relpath, &repos_root_url,
+                                         &repos_uuid,
                                          info, parent_repos_relpath,
                                          parent_repos_root_url,
+                                         parent_repos_uuid,
                                          wb->db, local_abspath,
                                          scratch_pool, scratch_pool));
       if (repos_relpath)
@@ -816,6 +912,7 @@ send_status_structure(const struct walk_
 
   SVN_ERR(assemble_status(&statstruct, wb->db, local_abspath,
                           parent_repos_root_url, parent_repos_relpath,
+                          parent_repos_uuid,
                           info, dirent, get_all, wb->ignore_text_mods,
                           repos_lock, scratch_pool, scratch_pool));
 
@@ -930,7 +1027,8 @@ is_external_path(apr_hash_t *externals,
 static svn_error_t *
 send_unversioned_item(const struct walk_status_baton *wb,
                       const char *local_abspath,
-                      svn_node_kind_t path_kind,
+                      const svn_io_dirent2_t *dirent,
+                      svn_boolean_t tree_conflicted,
                       const apr_array_header_t *patterns,
                       svn_boolean_t no_ignore,
                       svn_wc_status_func4_t status_func,
@@ -947,7 +1045,7 @@ send_unversioned_item(const struct walk_
 
   SVN_ERR(assemble_unversioned(&status,
                                wb->db, local_abspath,
-                               path_kind, is_ignored,
+                               dirent, tree_conflicted, is_ignored,
                                scratch_pool, scratch_pool));
 
   is_external = is_external_path(wb->externals, local_abspath, scratch_pool);
@@ -969,32 +1067,193 @@ 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;
+
+      if (svn_wc_is_adm_dir(svn_dirent_basename(local_abspath, scratch_pool),
+                            scratch_pool))
+        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.
+  /* 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,
+               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,
@@ -1010,8 +1269,9 @@ get_dir_status(const struct walk_status_
   apr_hash_index_t *hi;
   const char *dir_repos_root_url;
   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;
 
@@ -1039,181 +1299,161 @@ get_dir_status(const struct walk_status_
                       subpool, iterpool));
 
   SVN_ERR(get_repos_root_url_relpath(&dir_repos_relpath, &dir_repos_root_url,
-                                     dir_info, parent_repos_relpath,
-                                     parent_repos_root_url,
+                                     &dir_repos_uuid, dir_info,
+                                     parent_repos_relpath,
+                                     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,
+
+  /* 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,
-                                      dir_info, dirent, get_all,
-                                      status_func, status_baton,
-                                      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;
-                }
-
-              SVN_ERR(send_status_structure(wb, node_abspath,
-                                            dir_repos_root_url,
-                                            dir_repos_relpath,
-                                            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,
-                                         info,
-                                         dirent_p, ignore_patterns,
-                                         svn_depth_infinity, get_all,
-                                         no_ignore,
-                                         status_func, status_baton,
-                                         cancel_func, cancel_baton,
-                                         iterpool));
-                }
+      child_abspath = svn_dirent_join(local_abspath, key, 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 ? dirent_p->kind
-                                                 : svn_node_none,
-                                        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->kind,
-                                    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;
 }
 
@@ -1339,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)
@@ -1372,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 =
@@ -1394,9 +1663,9 @@ 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. */
+      /* 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)
         return status->repos_relpath;
 
@@ -1441,6 +1710,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;
 
@@ -1485,9 +1755,10 @@ 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,
                              NULL,
                              NULL /* dirent */, ignores,
                              d->depth == svn_depth_files
@@ -1533,6 +1804,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;
@@ -1557,6 +1830,9 @@ is_sendable_status(const svn_wc_status3_
   if (status->repos_lock)
     return TRUE;
 
+  if (status->conflicted)
+    return TRUE;
+
   /* If the item is ignored, and we don't want ignores, skip it. */
   if ((status->node_status == svn_wc_status_ignored) && (! no_ignore))
     return FALSE;
@@ -1574,8 +1850,6 @@ is_sendable_status(const svn_wc_status3_
   if ((status->node_status != svn_wc_status_none
        && (status->node_status != svn_wc_status_normal)))
     return TRUE;
-  if (status->conflicted)
-    return TRUE;
 
   /* If it's switched, send it. */
   if (status->switched)
@@ -1629,6 +1903,7 @@ static svn_error_t *
 handle_statii(struct edit_baton *eb,
               const char *dir_repos_root_url,
               const char *dir_repos_relpath,
+              const char *dir_repos_uuid,
               apr_hash_t *statii,
               svn_boolean_t dir_was_deleted,
               svn_depth_t depth,
@@ -1665,8 +1940,9 @@ 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,
                                  NULL /* dirent */,
                                  ignores, depth, eb->get_all, eb->no_ignore,
@@ -1692,7 +1968,7 @@ handle_statii(struct edit_baton *eb,
 
 /*** The callbacks we'll plug into an svn_delta_editor_t structure. ***/
 
-/* */
+/* An svn_delta_editor_t function. */
 static svn_error_t *
 set_target_revision(void *edit_baton,
                     svn_revnum_t target_revision,
@@ -1704,7 +1980,7 @@ set_target_revision(void *edit_baton,
 }
 
 
-/* */
+/* An svn_delta_editor_t function. */
 static svn_error_t *
 open_root(void *edit_baton,
           svn_revnum_t base_revision,
@@ -1717,7 +1993,7 @@ open_root(void *edit_baton,
 }
 
 
-/* */
+/* An svn_delta_editor_t function. */
 static svn_error_t *
 delete_entry(const char *path,
              svn_revnum_t revision,
@@ -1727,7 +2003,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
@@ -1736,7 +2012,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
@@ -1745,7 +2021,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));
 
@@ -1753,7 +2029,7 @@ delete_entry(const char *path,
 }
 
 
-/* */
+/* An svn_delta_editor_t function. */
 static svn_error_t *
 add_directory(const char *path,
               void *parent_baton,
@@ -1779,7 +2055,7 @@ add_directory(const char *path,
 }
 
 
-/* */
+/* An svn_delta_editor_t function. */
 static svn_error_t *
 open_directory(const char *path,
                void *parent_baton,
@@ -1792,7 +2068,7 @@ open_directory(const char *path,
 }
 
 
-/* */
+/* An svn_delta_editor_t function. */
 static svn_error_t *
 change_dir_prop(void *dir_baton,
                 const char *name,
@@ -1823,7 +2099,7 @@ change_dir_prop(void *dir_baton,
 
 
 
-/* */
+/* An svn_delta_editor_t function. */
 static svn_error_t *
 close_directory(void *dir_baton,
                 apr_pool_t *pool)
@@ -1912,6 +2188,7 @@ close_directory(void *dir_baton,
       SVN_ERR(handle_statii(eb,
                             dir_status ? dir_status->repos_root_url : NULL,
                             dir_status ? dir_status->repos_relpath : NULL,
+                            dir_status ? dir_status->repos_uuid : NULL,
                             db->statii, was_deleted, db->depth, pool));
       if (dir_status && is_sendable_status(dir_status, eb->no_ignore,
                                            eb->get_all))
@@ -1935,8 +2212,9 @@ close_directory(void *dir_baton,
                   && tgt_status->kind == svn_node_dir)
                 {
                   SVN_ERR(get_dir_status(&eb->wb,
-                                         eb->target_abspath, NULL, TRUE,
-                                         NULL, NULL, NULL, NULL /* dirent */,
+                                         eb->target_abspath, TRUE,
+                                         NULL, NULL, NULL, NULL,
+                                         NULL /* dirent */,
                                          eb->ignores,
                                          eb->default_depth,
                                          eb->get_all, eb->no_ignore,
@@ -1957,6 +2235,7 @@ close_directory(void *dir_baton,
           SVN_ERR(handle_statii(eb,
                                 eb->anchor_status->repos_root_url,
                                 eb->anchor_status->repos_relpath,
+                                eb->anchor_status->repos_uuid,
                                 db->statii, FALSE, eb->default_depth, pool));
           if (is_sendable_status(eb->anchor_status, eb->no_ignore,
                                  eb->get_all))
@@ -1970,7 +2249,7 @@ close_directory(void *dir_baton,
 
 
 
-/* */
+/* An svn_delta_editor_t function. */
 static svn_error_t *
 add_file(const char *path,
          void *parent_baton,
@@ -1993,7 +2272,7 @@ add_file(const char *path,
 }
 
 
-/* */
+/* An svn_delta_editor_t function. */
 static svn_error_t *
 open_file(const char *path,
           void *parent_baton,
@@ -2009,7 +2288,7 @@ open_file(const char *path,
 }
 
 
-/* */
+/* An svn_delta_editor_t function. */
 static svn_error_t *
 apply_textdelta(void *file_baton,
                 const char *base_checksum,
@@ -2030,7 +2309,7 @@ apply_textdelta(void *file_baton,
 }
 
 
-/* */
+/* An svn_delta_editor_t function. */
 static svn_error_t *
 change_file_prop(void *file_baton,
                  const char *name,
@@ -2062,7 +2341,7 @@ change_file_prop(void *file_baton,
 }
 
 
-/* */
+/* An svn_delta_editor_t function. */
 static svn_error_t *
 close_file(void *file_baton,
            const char *text_checksum,  /* ignored, as we receive no data */
@@ -2119,7 +2398,7 @@ close_file(void *file_baton,
                           SVN_INVALID_REVNUM, repos_lock, pool);
 }
 
-/* */
+/* An svn_delta_editor_t function. */
 static svn_error_t *
 close_edit(void *edit_baton,
            apr_pool_t *pool)
@@ -2163,6 +2442,7 @@ svn_wc_get_status_editor5(const svn_delt
                           svn_depth_t depth,
                           svn_boolean_t get_all,
                           svn_boolean_t no_ignore,
+                          svn_boolean_t depth_as_sticky,
                           svn_boolean_t server_performs_filtering,
                           const apr_array_header_t *ignore_patterns,
                           svn_wc_status_func4_t status_func,
@@ -2244,7 +2524,7 @@ svn_wc_get_status_editor5(const svn_delt
   inner_baton = eb;
 
   if (!server_performs_filtering
-      && depth == svn_depth_unknown)
+      && !depth_as_sticky)
     SVN_ERR(svn_wc__ambient_depth_filter_editor(&inner_editor,
                                                 &inner_baton,
                                                 wc_ctx->db,
@@ -2263,6 +2543,10 @@ svn_wc_get_status_editor5(const svn_delt
   if (set_locks_baton)
     *set_locks_baton = eb;
 
+  SVN_ERR(svn_editor__insert_shims(editor, edit_baton, *editor, *edit_baton,
+                                   NULL, NULL, NULL, NULL,
+                                   result_pool, scratch_pool));
+
   return SVN_NO_ERROR;
 }
 
@@ -2282,9 +2566,8 @@ 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;
-  svn_wc__db_kind_t kind;
+  const struct svn_wc__db_info_t *info;
+  svn_error_t *err;
 
   wb.db = db;
   wb.target_abspath = local_abspath;
@@ -2305,42 +2588,53 @@ svn_wc__internal_walk_status(svn_wc__db_
       ignore_patterns = ignores;
     }
 
-  SVN_ERR(svn_wc__db_read_kind(&kind, db, local_abspath, TRUE, scratch_pool));
-  SVN_ERR(svn_io_stat_dirent(&dirent, local_abspath, TRUE,
-                             scratch_pool, scratch_pool));
+  err = read_info(&info, local_abspath, db, scratch_pool, scratch_pool);
 
-  if (kind == svn_wc__db_kind_file && dirent->kind == svn_node_file)
+  if (err)
     {
-      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);
     }
-  else if (kind == svn_wc__db_kind_dir && dirent->kind == svn_node_dir)
+
+  SVN_ERR(svn_io_stat_dirent(&dirent, local_abspath, TRUE,
+                             scratch_pool, scratch_pool));
+
+  if (info && info->kind == svn_kind_dir)
     {
-      anchor_abspath = local_abspath;
-      target_name = NULL;
-      skip_root = FALSE;
+      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
     {
-      anchor_abspath = svn_dirent_dirname(local_abspath, scratch_pool);
-      target_name = svn_dirent_basename(local_abspath, NULL);
-      skip_root = FALSE;
-    }
-
-  SVN_ERR(get_dir_status(&wb,
-                         anchor_abspath,
-                         target_name,
-                         skip_root,
-                         NULL, NULL, NULL, /* parent info */
-                         dirent,
-                         ignore_patterns,
-                         depth,
-                         get_all,
-                         no_ignore,
-                         status_func, status_baton,
-                         cancel_func, cancel_baton,
-                         scratch_pool));
+      /* 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;
 }
@@ -2422,10 +2716,12 @@ 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;
   svn_wc__db_status_t node_status;
+  svn_boolean_t conflicted;
   svn_boolean_t is_root = FALSE;
   svn_error_t *err;
 
@@ -2436,26 +2732,34 @@ internal_status(svn_wc_status3_t **statu
 
   err = svn_wc__db_read_info(&node_status, &node_kind, 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, NULL, NULL, NULL, NULL, NULL, &conflicted,
+                             NULL, NULL, NULL, NULL, NULL, NULL,
                              db, local_abspath,
                              scratch_pool, scratch_pool);
 
-  if ((err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
-      || node_status == svn_wc__db_status_not_present
-      || node_status == svn_wc__db_status_server_excluded
-      || node_status == svn_wc__db_status_excluded)
+  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;
+    }
+  else if (err)
+    {
+        return svn_error_trace(err);
+    }
+  else if (node_status == svn_wc__db_status_not_present
+           || node_status == svn_wc__db_status_server_excluded
+           || node_status == svn_wc__db_status_excluded)
+    {
+      node_kind = svn_kind_unknown;
     }
-  else
-    SVN_ERR(err);
 
-  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->kind,
+                                                dirent, conflicted,
                                                 FALSE /* is_ignored */,
                                                 result_pool, scratch_pool));
 
@@ -2472,7 +2776,7 @@ internal_status(svn_wc_status3_t **statu
 
       err = svn_wc__db_read_info(&parent_status, NULL, NULL,
                                  &parent_repos_relpath, &parent_repos_root_url,
-                                 NULL, NULL, NULL, NULL,
+                                 &parent_repos_uuid, NULL, NULL, NULL,
                                  NULL, NULL, NULL, NULL, NULL, NULL, NULL,
                                  NULL, NULL, NULL, NULL, NULL, NULL, NULL,
                                  NULL, NULL, NULL, NULL,
@@ -2485,28 +2789,21 @@ internal_status(svn_wc_status3_t **statu
           svn_error_clear(err);
           parent_repos_root_url = NULL;
           parent_repos_relpath = NULL;
+          parent_repos_uuid = NULL;
         }
-      else if (err)
-        return svn_error_trace(err);
-
-      if (!err
-          && parent_repos_relpath == NULL
-          && parent_status != svn_wc__db_status_added
-          && parent_status != svn_wc__db_status_deleted)
-        SVN_ERR(svn_wc__db_scan_base_repos(&parent_repos_relpath,
-                                           &parent_repos_root_url, NULL,
-                                           db, local_abspath,
-                                           result_pool, scratch_pool));
+      else SVN_ERR(err);
     }
   else
     {
       parent_repos_root_url = NULL;
       parent_repos_relpath = NULL;
+      parent_repos_uuid = NULL;
     }
 
   return svn_error_trace(assemble_status(status, db, local_abspath,
                                          parent_repos_root_url,
                                          parent_repos_relpath,
+                                         parent_repos_uuid,
                                          NULL,
                                          dirent,
                                          TRUE /* get_all */,
@@ -2563,6 +2860,18 @@ svn_wc_dup_status3(const svn_wc_status3_
     new_stat->repos_relpath
       = apr_pstrdup(pool, orig_stat->repos_relpath);
 
+  if (orig_stat->repos_uuid)
+    new_stat->repos_uuid
+      = apr_pstrdup(pool, orig_stat->repos_uuid);
+
+  if (orig_stat->moved_from_abspath)
+    new_stat->moved_from_abspath
+      = apr_pstrdup(pool, orig_stat->moved_from_abspath);
+
+  if (orig_stat->moved_to_abspath)
+    new_stat->moved_to_abspath
+      = apr_pstrdup(pool, orig_stat->moved_to_abspath);
+
   /* Return the new hotness. */
   return new_stat;
 }

Modified: subversion/branches/svn_mutex/subversion/libsvn_wc/translate.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn_mutex/subversion/libsvn_wc/translate.c?rev=1182053&r1=1182052&r2=1182053&view=diff
==============================================================================
--- subversion/branches/svn_mutex/subversion/libsvn_wc/translate.c (original)
+++ subversion/branches/svn_mutex/subversion/libsvn_wc/translate.c Tue Oct 11 19:52:34 2011
@@ -263,7 +263,7 @@ svn_wc__get_translate_info(svn_subst_eol
                            apr_pool_t *result_pool,
                            apr_pool_t *scratch_pool)
 {
-  svn_string_t *propval;
+  const char *propval;
   SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
 
   if (props == NULL)
@@ -272,29 +272,26 @@ svn_wc__get_translate_info(svn_subst_eol
 
   if (eol)
     {
-      propval = props ? apr_hash_get(props, SVN_PROP_EOL_STYLE,
-                                     APR_HASH_KEY_STRING) : NULL;
+      propval = svn_prop_get_value(props, SVN_PROP_EOL_STYLE);
 
-      svn_subst_eol_style_from_value(style, eol, propval ? propval->data : NULL);
+      svn_subst_eol_style_from_value(style, eol, propval);
     }
 
   if (keywords)
     {
-      propval = props ? apr_hash_get(props, SVN_PROP_KEYWORDS,
-                                     APR_HASH_KEY_STRING) : NULL;
+      propval = svn_prop_get_value(props, SVN_PROP_KEYWORDS);
 
-      if (!propval || propval->len == 0)
+      if (!propval || *propval == '\0')
         *keywords = NULL;
       else
         SVN_ERR(svn_wc__expand_keywords(keywords,
                                         db, local_abspath, NULL,
-                                        propval->data, for_normalization,
+                                        propval, for_normalization,
                                         result_pool, scratch_pool));
     }
   if (special)
     {
-      propval = props ? apr_hash_get(props, SVN_PROP_SPECIAL,
-                                     APR_HASH_KEY_STRING) : NULL;
+      propval = svn_prop_get_value(props, SVN_PROP_SPECIAL);
 
       *special = (propval != NULL);
     }
@@ -368,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;
 
@@ -390,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/svn_mutex/subversion/libsvn_wc/tree_conflicts.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn_mutex/subversion/libsvn_wc/tree_conflicts.c?rev=1182053&r1=1182052&r2=1182053&view=diff
==============================================================================
--- subversion/branches/svn_mutex/subversion/libsvn_wc/tree_conflicts.c (original)
+++ subversion/branches/svn_mutex/subversion/libsvn_wc/tree_conflicts.c Tue Oct 11 19:52:34 2011
@@ -76,6 +76,8 @@ 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 },
   { NULL }
 };