You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by hw...@apache.org on 2010/08/10 20:06:33 UTC

svn commit: r984153 [25/39] - in /subversion/branches/ignore-mergeinfo: ./ build/ build/ac-macros/ build/generator/ build/generator/templates/ build/hudson/ build/hudson/jobs/subversion-1.6.x-solaris/ build/hudson/jobs/subversion-1.6.x-ubuntu/ build/hu...

Modified: subversion/branches/ignore-mergeinfo/subversion/libsvn_wc/update_editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/ignore-mergeinfo/subversion/libsvn_wc/update_editor.c?rev=984153&r1=984152&r2=984153&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_wc/update_editor.c (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_wc/update_editor.c Tue Aug 10 18:06:17 2010
@@ -168,12 +168,9 @@ struct edit_baton
   svn_wc__db_t *db;
   svn_wc_context_t *wc_ctx;
 
-  /* ADM_ACCESS is an access baton that includes the ANCHOR directory */
-  svn_wc_adm_access_t *adm_access;
-
   /* Array of file extension patterns to preserve as extensions in
      generated conflict files. */
-  apr_array_header_t *ext_patterns;
+  const apr_array_header_t *ext_patterns;
 
   /* The revision we're targeting...or something like that.  This
      starts off as a pointer to the revision to which we are updating,
@@ -201,15 +198,20 @@ struct edit_baton
   /* Allow unversioned obstructions when adding a path. */
   svn_boolean_t allow_unver_obstructions;
 
-  /* If this is a 'switch' operation, the target URL (### corresponding to
-     the ANCHOR plus TARGET path?), else NULL. */
-  const char *switch_url;
+  /* The close_edit method destroys the edit pool and so runs the
+     cleanup_dir_baton cleanup handlers.  This flag is set to indicate
+     that the edit was completed successfully. */
+  svn_boolean_t close_edit_complete;
+
+  /* If this is a 'switch' operation, the new relpath of target_abspath,
+     else NULL. */
+  const char *switch_relpath;
 
-  /* The URL to the root of the repository, or NULL. */
-  const char *repos;
+  /* The URL to the root of the repository. */
+  const char *repos_root;
 
   /* The UUID of the repos, or NULL. */
-  const char *uuid;
+  const char *repos_uuid;
 
   /* External diff3 to use for merges (can be null, in which case
      internal merge code is used). */
@@ -276,8 +278,8 @@ struct dir_baton
   /* Absolute path of this directory */
   const char *local_abspath;
 
-  /* The repository URL this directory will correspond to. */
-  const char *new_URL;
+  /* The repository relative path this directory will correspond to. */
+  const char *new_relpath;
 
   /* The revision of the directory before updating */
   svn_revnum_t old_revision;
@@ -301,15 +303,11 @@ struct dir_baton
   /* Set on a node and its descendants when a node gets tree conflicted
      and descendants should still be updated (not skipped).
      These nodes should all be marked as deleted. */
-  svn_boolean_t inside_deleted_subtree;
-
-  /* Set iff this is a new directory that is not yet versioned and not
-     yet in the parent's list of entries */
-  svn_boolean_t added;
+  svn_boolean_t in_deleted_and_tree_conflicted_subtree;
 
   /* Set if an unversioned dir of the same name already existed in
      this directory. */
-  svn_boolean_t existed;
+  svn_boolean_t obstruction_found;
 
   /* Set if a dir of the same name already exists and is
      scheduled for addition without history. */
@@ -322,19 +320,16 @@ struct dir_baton
   /* The bump information for this directory. */
   struct bump_dir_info *bump_info;
 
-  /* The current log buffer. The content of this accumulator may be
-     flushed and run at any time (in pool cleanup), so only append
-     complete sets of operations to it; you may need to build up a
-     buffer of operations and append it atomically with
-     svn_stringbuf_appendstr. */
-  svn_stringbuf_t *log_accum;
-
   /* The depth of the directory in the wc (or inferred if added).  Not
      used for filtering; we have a separate wrapping editor for that. */
   svn_depth_t ambient_depth;
 
   /* Was the directory marked as incomplete before the update?
-     (In other words, are we resuming an interrupted update?) */
+     (In other words, are we resuming an interrupted update?)
+
+     If WAS_INCOMPLETE is set to TRUE we expect to receive all child nodes
+     and properties for/of the directory. If WAS_INCOMPLETE is FALSE then
+     we only receive the changes in/for children and properties.*/
   svn_boolean_t was_incomplete;
 
   /* The pool in which this baton itself is allocated. */
@@ -377,7 +372,11 @@ struct handler_baton
   struct file_baton *fb;
 
   /* Where we are assembling the new file. */
-  const char *work_path;
+  const char *work_abspath;
+#ifdef SVN_EXPERIMENTAL
+  /* Where the pristine is before we can copy it into the correct location. */
+  const char *temp_pristine_abspath;
+#endif
 
     /* The expected checksum of the text source or NULL if no base
      checksum is available */
@@ -401,11 +400,6 @@ struct handler_baton
   /* The stream used to calculate the source checksums */
   svn_stream_t *source_checksum_stream;
 
-#ifdef SVN_EXPERIMENTAL
-  /* Where the pristine is before we can copy it into the correct location. */
-  const char *temp_pristine_abspath;
-#endif
-
   /* This is initialized to all zeroes when the baton is created, then
      populated with the MD5 digest of the resultant fulltext after the
      last window is handled by the handler returned from
@@ -416,7 +410,17 @@ struct handler_baton
 
 /* Get an empty file in the temporary area for WRI_ABSPATH.  The file will
    not be set for automatic deletion, and the name will be returned in
-   TMP_FILENAME. */
+   TMP_FILENAME.
+
+   This implementation creates a new empty file with a unique name.
+
+   ### This is inefficient for callers that just want an empty file to read
+   ### from.  There could be (and there used to be) a permanent, shared
+   ### empty file for this purpose.
+
+   ### This is inefficient for callers that just want to reserve a unique
+   ### file name to create later.  A better way may not be readily available.
+ */
 static svn_error_t *
 get_empty_tmp_file(const char **tmp_filename,
                    svn_wc__db_t *db,
@@ -425,63 +429,71 @@ get_empty_tmp_file(const char **tmp_file
                    apr_pool_t *scratch_pool)
 {
   const char *temp_dir_path;
-  svn_stream_t *empty_stream;
+  apr_file_t *file;
 
   SVN_ERR(svn_wc__db_temp_wcroot_tempdir(&temp_dir_path, db, wri_abspath,
                                          scratch_pool, scratch_pool));
-  SVN_ERR(svn_stream_open_unique(&empty_stream, tmp_filename, temp_dir_path,
-                                 svn_io_file_del_none, scratch_pool,
-                                 scratch_pool));
-  SVN_ERR(svn_stream_close(empty_stream));
+  SVN_ERR(svn_io_open_unique_file3(&file, tmp_filename, temp_dir_path,
+                                   svn_io_file_del_none,
+                                   scratch_pool, scratch_pool));
+  SVN_ERR(svn_io_file_close(file, scratch_pool));
 
   return svn_error_return(svn_dirent_get_absolute(tmp_filename, *tmp_filename,
                                                   result_pool));
 }
 
 
-/* Return the url for LOCAL_ABSPATH of type KIND which can be unknown,
- * allocated in RESULT_POOL, or null if unable to obtain a url.
+/* Return the repository relative path for LOCAL_ABSPATH allocated in
+ * RESULT_POOL, or NULL if unable to obtain.
  *
- * Use WC_CTX to retrieve information on LOCAL_ABSPATH, and do
- * all temporary allocation in SCRATCH_POOL.
+ * Use DB to retrieve information on LOCAL_ABSPATH, and do all temporary
+ * allocation in SCRATCH_POOL.
  */
 static const char *
-get_entry_url(svn_wc_context_t *wc_ctx,
-              const char *local_abspath,
-              apr_pool_t *result_pool,
-              apr_pool_t *scratch_pool)
+node_get_relpath_ignore_errors(svn_wc__db_t *db,
+                               const char *local_abspath,
+                               apr_pool_t *result_pool,
+                               apr_pool_t *scratch_pool)
 {
+  svn_wc__db_status_t status;
   svn_error_t *err;
-  const char *url;
+  const char *relpath = NULL;
 
-  err = svn_wc__node_get_url(&url, wc_ctx, local_abspath, result_pool,
-                                                          scratch_pool);
+  err = svn_wc__db_read_info(&status, NULL, NULL, &relpath, NULL, NULL, NULL,
+                             NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+                             NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+                             NULL,
+                             db, local_abspath, result_pool, scratch_pool);
 
-  if (err || !url)
+  if (err)
     {
       svn_error_clear(err);
       return NULL;
     }
 
-  return url;
-}
+  if (relpath)
+    return relpath;
 
-/* Flush accumulated log entries to a log file on disk for DIR_BATON and
- * increase the log number of the dir baton.
- * Use POOL for temporary allocations. */
-static svn_error_t *
-flush_log(struct dir_baton *db, apr_pool_t *pool)
-{
-  if (! svn_stringbuf_isempty(db->log_accum))
+  if (status == svn_wc__db_status_added ||
+      status == svn_wc__db_status_obstructed_add)
+    {
+      svn_error_clear(svn_wc__db_scan_addition(NULL, NULL, &relpath, NULL,
+                                               NULL, NULL, NULL, NULL, NULL,
+                                               db, local_abspath,
+                                               result_pool, scratch_pool));
+    }
+  else if (status != svn_wc__db_status_deleted &&
+           status != svn_wc__db_status_obstructed_delete)
     {
-      SVN_ERR(svn_wc__wq_add_loggy(db->edit_baton->db, db->local_abspath,
-                                   db->log_accum, pool));
-      svn_stringbuf_setempty(db->log_accum);
+      svn_error_clear(svn_wc__db_scan_base_repos(&relpath, NULL, NULL,
+                                                 db, local_abspath,
+                                                 result_pool, scratch_pool));
     }
 
-  return SVN_NO_ERROR;
+  return relpath;
 }
 
+
 /* An APR pool cleanup handler.  This runs the log file for a
    directory baton. */
 static apr_status_t
@@ -492,9 +504,20 @@ cleanup_dir_baton(void *dir_baton)
   svn_error_t *err;
   apr_pool_t *pool = apr_pool_parent_get(db->pool);
 
-  err = flush_log(db, pool);
-  if (!err)
-    err = svn_wc__run_log2(eb->db, db->local_abspath, pool);
+  err = svn_wc__wq_run(eb->db, db->local_abspath,
+                       eb->cancel_func, eb->cancel_baton,
+                       pool);
+
+  /* If the editor aborts for some sort of error, the command line
+     client relies on pool cleanup to run outstanding work queues and
+     remove locks.  This avoids leaving the working copy locked in
+     many cases, but plays havoc with operations that do multiple
+     updates (think externals). So we flag updates that complete
+     successfully and avoid removing locks.  In 1.6 locks were
+     associated with a pool distinct from the edit pool and so were
+     removed separately. */
+  if (!err && !eb->close_edit_complete)
+    err = svn_wc__release_write_lock(eb->wc_ctx, db->local_abspath, pool);
 
   if (err)
     {
@@ -526,7 +549,6 @@ make_dir_baton(struct dir_baton **d_p,
                const char *path,
                struct edit_baton *eb,
                struct dir_baton *pb,
-               svn_boolean_t added,
                apr_pool_t *scratch_pool)
 {
   apr_pool_t *dir_pool;
@@ -548,16 +570,18 @@ make_dir_baton(struct dir_baton **d_p,
     {
       d->name = svn_dirent_basename(path, dir_pool);
       d->local_abspath = svn_dirent_join(pb->local_abspath, d->name, dir_pool);
-      d->inside_deleted_subtree = pb->inside_deleted_subtree;
+      d->in_deleted_and_tree_conflicted_subtree =
+          pb->in_deleted_and_tree_conflicted_subtree;
     }
   else
     {
+      /* This is the root baton. */
       d->name = NULL;
       d->local_abspath = eb->anchor_abspath;
     }
 
-  /* Figure out the new_URL for this directory. */
-  if (eb->switch_url)
+  /* Figure out the new_relpath for this directory. */
+  if (eb->switch_relpath)
     {
       /* Switches are, shall we say, complex.  If this directory is
          the root directory (it has no parent), then it either gets
@@ -567,9 +591,9 @@ make_dir_baton(struct dir_baton **d_p,
       if (! pb)
         {
           if (! *eb->target_basename) /* anchor is also target */
-            d->new_URL = apr_pstrdup(dir_pool, eb->switch_url);
+            d->new_relpath = apr_pstrdup(dir_pool, eb->switch_relpath);
           else
-            d->new_URL = svn_uri_dirname(eb->switch_url, dir_pool);
+            d->new_relpath = svn_relpath_dirname(eb->switch_relpath, dir_pool);
         }
       /* Else this directory is *not* the root (has a parent).  If it
          is the target (there is a target, and this directory has no
@@ -578,10 +602,10 @@ make_dir_baton(struct dir_baton **d_p,
       else
         {
           if (*eb->target_basename && (! pb->parent_baton))
-            d->new_URL = apr_pstrdup(dir_pool, eb->switch_url);
+            d->new_relpath = apr_pstrdup(dir_pool, eb->switch_relpath);
           else
-            d->new_URL = svn_path_url_add_component2(pb->new_URL,
-                                                     d->name, dir_pool);
+            d->new_relpath = svn_relpath_join(pb->new_relpath, d->name,
+                                              dir_pool);
         }
     }
   else  /* must be an update */
@@ -589,11 +613,10 @@ make_dir_baton(struct dir_baton **d_p,
       /* updates are the odds ones.  if we're updating a path already
          present on disk, we use its original URL.  otherwise, we'll
          telescope based on its parent's URL. */
-      d->new_URL = get_entry_url(eb->wc_ctx, d->local_abspath,
-                                 dir_pool, scratch_pool);
-      if ((! d->new_URL) && pb)
-        d->new_URL = svn_path_url_add_component2(pb->new_URL, d->name,
-                                                 dir_pool);
+      d->new_relpath = node_get_relpath_ignore_errors(eb->db, d->local_abspath,
+                                                      dir_pool, scratch_pool);
+      if ((! d->new_relpath) && pb)
+        d->new_relpath = svn_relpath_join(pb->new_relpath, d->name, dir_pool);
     }
 
   /* the bump information lives in the edit pool */
@@ -612,11 +635,9 @@ make_dir_baton(struct dir_baton **d_p,
   d->parent_baton = pb;
   d->pool         = dir_pool;
   d->propchanges  = apr_array_make(dir_pool, 1, sizeof(svn_prop_t));
-  d->added        = added;
-  d->existed      = FALSE;
+  d->obstruction_found = FALSE;
   d->add_existed  = FALSE;
   d->bump_info    = bdi;
-  d->log_accum    = svn_stringbuf_create("", dir_pool);
   d->old_revision = SVN_INVALID_REVNUM;
 
   /* The caller of this function needs to fill these in. */
@@ -636,7 +657,7 @@ static svn_error_t *
 do_entry_deletion(struct edit_baton *eb,
                   const char *local_abspath,
                   const char *their_url,
-                  svn_boolean_t inside_deleted_subtree,
+                  svn_boolean_t in_deleted_and_tree_conflicted_subtree,
                   apr_pool_t *pool);
 
 static svn_error_t *
@@ -646,6 +667,25 @@ already_in_a_tree_conflict(svn_boolean_t
                            apr_pool_t *scratch_pool);
 
 
+static void
+do_notification(const struct edit_baton *eb,
+                const char *local_abspath,
+                svn_node_kind_t kind,
+                svn_wc_notify_action_t action,
+                apr_pool_t *scratch_pool)
+{
+  svn_wc_notify_t *notify;
+
+  if (eb->notify_func == NULL)
+    return;
+
+  notify = svn_wc_create_notify(local_abspath, action, scratch_pool);
+  notify->kind = kind;
+
+  (*eb->notify_func)(eb->notify_baton, notify, scratch_pool);
+}
+
+
 /* Helper for maybe_bump_dir_info():
 
    In a single atomic action, (1) remove any 'deleted' entries from a
@@ -662,7 +702,6 @@ complete_directory(struct edit_baton *eb
   const apr_array_header_t *children;
   int i;
   apr_pool_t *iterpool;
-  svn_wc_entry_t tmp_entry;
 
   /* If this is the root directory and there is a target, we can't
      mark this directory complete. */
@@ -671,14 +710,14 @@ complete_directory(struct edit_baton *eb
       /* Before we can finish, we may need to clear the exclude flag for
          target. Also give a chance to the target that is explicitly pulled
          in. */
-      svn_depth_t depth;
       svn_wc__db_kind_t kind;
+      svn_wc__db_status_t status;
       svn_error_t *err;
 
       SVN_ERR_ASSERT(strcmp(local_abspath, eb->anchor_abspath) == 0);
 
-      err = svn_wc__db_read_info(NULL, &kind, NULL, NULL, NULL, NULL, NULL,
-                                 NULL, NULL, NULL, &depth, NULL, NULL, NULL,
+      err = svn_wc__db_read_info(&status, &kind, NULL, NULL, NULL, NULL, NULL,
+                                 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
                                  NULL, NULL, NULL, NULL, NULL, NULL, NULL,
                                  NULL, NULL, NULL,
                                  eb->db, eb->target_abspath, pool, pool);
@@ -690,11 +729,10 @@ complete_directory(struct edit_baton *eb
       else if (err)
         return svn_error_return(err);
 
-      if (depth == svn_depth_exclude)
+      if (status == svn_wc__db_status_excluded)
         {
           /* There is a small chance that the target is gone in the
-             repository.  If so, we should get rid of the entry
-             (and thus get rid of the exclude flag) now. */
+             repository.  If so, we should get rid of the entry now. */
 
           if (kind == svn_wc__db_kind_dir &&
               svn_wc__adm_missing(eb->db, eb->target_abspath, pool))
@@ -706,26 +744,22 @@ complete_directory(struct edit_baton *eb
               SVN_ERR(do_entry_deletion(eb, eb->target_abspath,
                                         NULL, FALSE, pool));
             }
-          else
-            {
-              SVN_ERR(svn_wc__set_depth(eb->db, eb->target_abspath,
-                                        eb->requested_depth, pool));
-            }
         }
 
       return SVN_NO_ERROR;
     }
 
   /* Mark THIS_DIR complete. */
-  tmp_entry.incomplete = FALSE;
-  SVN_ERR(svn_wc__entry_modify2(eb->db, local_abspath, svn_node_dir, FALSE,
-                                &tmp_entry, SVN_WC__ENTRY_MODIFY_INCOMPLETE,
-                                pool));
+  SVN_ERR(svn_wc__db_temp_op_set_base_incomplete(eb->db, local_abspath, FALSE,
+                                                 pool));
 
   if (eb->depth_is_sticky)
     {
       svn_depth_t depth;
 
+      /* ### We should specifically check BASE_NODE here and then only remove
+             the BASE_NODE if there is a WORKING_NODE. */
+
       SVN_ERR(svn_wc__db_read_info(NULL, NULL, NULL, NULL, NULL, NULL, NULL,
                                    NULL, NULL, NULL, &depth, NULL, NULL, NULL,
                                    NULL, NULL, NULL, NULL, NULL, NULL, NULL,
@@ -811,16 +845,11 @@ complete_directory(struct edit_baton *eb
         {
           SVN_ERR(svn_wc__entry_remove(eb->db, node_abspath, iterpool));
 
-          if (eb->notify_func)
-            {
-              svn_wc_notify_t *notify
-                = svn_wc_create_notify(node_abspath,
-                                       svn_wc_notify_update_delete,
-                                       iterpool);
-              notify->kind = (kind == svn_wc__db_kind_dir) ? svn_node_dir
-                                                           : svn_node_file;
-              (* eb->notify_func)(eb->notify_baton, notify, iterpool);
-            }
+          do_notification(eb, node_abspath, svn_wc_notify_update_delete,
+                          (kind == svn_wc__db_kind_dir)
+                            ? svn_node_dir
+                            : svn_node_file,
+                          iterpool);
         }
     }
 
@@ -846,8 +875,6 @@ maybe_bump_dir_info(struct edit_baton *e
      or a directory is not yet "done".  */
   while (bdi != NULL)
     {
-      apr_pool_t *destroy_pool;
-
       if (--bdi->ref_count > 0)
         return SVN_NO_ERROR;    /* directory isn't done yet */
 
@@ -856,10 +883,7 @@ maybe_bump_dir_info(struct edit_baton *e
       if (! bdi->skipped)
         SVN_ERR(complete_directory(eb, bdi->local_abspath,
                                    bdi->parent == NULL, pool));
-
-      destroy_pool = bdi->pool;
       bdi = bdi->parent;
-      svn_pool_destroy(destroy_pool);
     }
   /* we exited the for loop because there are no more parents */
 
@@ -877,8 +901,8 @@ struct file_baton
   /* Absolute path to this file */
   const char *local_abspath;
 
-  /* The repository URL this file will correspond to. */
-  const char *new_URL;
+  /* The repository relative path this file will correspond to. */
+  const char *new_relpath;
 
   /* The revision of the file before updating */
   svn_revnum_t old_revision;
@@ -896,14 +920,14 @@ struct file_baton
   svn_boolean_t already_notified;
 
   /* Set if this file is new. */
-  svn_boolean_t added;
+  svn_boolean_t adding_file;
 
   /* Set if this file is new with history. */
   svn_boolean_t added_with_history;
 
   /* Set if an unversioned file of the same name already existed in
      this directory. */
-  svn_boolean_t existed;
+  svn_boolean_t obstruction_found;
 
   /* Set if a file of the same name already exists and is
      scheduled for addition without history. */
@@ -920,7 +944,11 @@ struct file_baton
   /* The path to the incoming text base (that is, to a text-base-file-
      in-progress in the tmp area).  This gets set if there are file
      content changes. */
-  const char *new_text_base_path;
+  const char *new_text_base_abspath;
+#ifdef SVN_EXPERIMENTAL
+  /* Where the pristine is before we can copy it into the correct location. */
+  const char *temp_pristine_abspath;
+#endif
 
   /* The checksum for the file located at NEW_TEXT_BASE_PATH. */
   svn_checksum_t *md5_actual_checksum;
@@ -968,14 +996,6 @@ struct file_baton
 
   /* Bump information for the directory this file lives in */
   struct bump_dir_info *bump_info;
-
-#ifdef SVN_EXPERIMENTAL
-  /* Where the pristine is before we can copy it into the correct location. */
-  const char *temp_pristine_abspath;
-#endif
-
-  /* log accumulator; will be flushed and run in close_file(). */
-  svn_stringbuf_t *log_accum;
 };
 
 
@@ -1001,31 +1021,23 @@ make_file_baton(struct file_baton **f_p,
   f->local_abspath = svn_dirent_join(pb->local_abspath, f->name, file_pool);
 
   /* Figure out the new_URL for this file. */
-  if (pb->edit_baton->switch_url)
-    {
-      f->new_URL = svn_path_url_add_component2(pb->new_URL, f->name,
-                                               file_pool);
-    }
+  if (pb->edit_baton->switch_relpath)
+    f->new_relpath = svn_relpath_join(pb->new_relpath, f->name, file_pool);
   else
-    {
-      f->new_URL = get_entry_url(pb->edit_baton->wc_ctx,
-                                 svn_dirent_join(pb->local_abspath,
-                                                 f->name, scratch_pool),
-                                 file_pool, scratch_pool);
-    }
+    f->new_relpath = node_get_relpath_ignore_errors(pb->edit_baton->db,
+                                                    f->local_abspath,
+                                                    file_pool, scratch_pool);
 
   f->pool              = file_pool;
   f->edit_baton        = pb->edit_baton;
   f->propchanges       = apr_array_make(file_pool, 1, sizeof(svn_prop_t));
   f->bump_info         = pb->bump_info;
-  f->added             = adding;
-  f->existed           = FALSE;
+  f->adding_file       = adding;
+  f->obstruction_found = FALSE;
   f->add_existed       = FALSE;
   f->deleted           = FALSE;
   f->dir_baton         = pb;
 
-  f->log_accum = svn_stringbuf_create("", file_pool);
-
   /* No need to initialize f->digest, since we used pcalloc(). */
 
   /* the directory's bump info has one more referer now */
@@ -1035,24 +1047,8 @@ make_file_baton(struct file_baton **f_p,
   return SVN_NO_ERROR;
 }
 
-static svn_error_t *
-flush_file_log(struct file_baton *fb, apr_pool_t *pool)
-{
-  if (! svn_stringbuf_isempty(fb->log_accum))
-    {
-      SVN_ERR(svn_wc__wq_add_loggy(fb->edit_baton->db,
-                                   fb->dir_baton->local_abspath,
-                                   fb->log_accum, pool));
-      svn_stringbuf_setempty(fb->log_accum);
-    }
-
-  return SVN_NO_ERROR;
-}
-
-
-
-/*** Helpers for the editor callbacks. ***/
 
+/* */
 static svn_error_t *
 window_handler(svn_txdelta_window_t *window, void *baton)
 {
@@ -1091,7 +1087,7 @@ window_handler(svn_txdelta_window_t *win
   if (err)
     {
       /* We failed to apply the delta; clean up the temporary file.  */
-      svn_error_clear(svn_io_remove_file2(hb->work_path, TRUE, hb->pool));
+      svn_error_clear(svn_io_remove_file2(hb->work_abspath, TRUE, hb->pool));
 #ifdef SVN_EXPERIMENTAL
       svn_error_clear(svn_io_remove_file2(hb->temp_pristine_abspath, TRUE,
                                           hb->pool));
@@ -1100,16 +1096,15 @@ window_handler(svn_txdelta_window_t *win
   else
     {
       /* Tell the file baton about the new text base. */
-      fb->new_text_base_path = apr_pstrdup(fb->pool, hb->work_path);
-
-      /* ... and its checksum. */
-      fb->md5_actual_checksum =
-        svn_checksum__from_digest(hb->digest, svn_checksum_md5, fb->pool);
-
+      fb->new_text_base_abspath = apr_pstrdup(fb->pool, hb->work_abspath);
 #ifdef SVN_EXPERIMENTAL
       fb->temp_pristine_abspath = apr_pstrdup(fb->pool,
                                               hb->temp_pristine_abspath);
 #endif
+
+      /* ... and its checksums. */
+      fb->md5_actual_checksum =
+        svn_checksum__from_digest(hb->digest, svn_checksum_md5, fb->pool);
       fb->sha1_actual_checksum =
         svn_checksum_dup(hb->sha1_actual_checksum, fb->pool);
     }
@@ -1132,8 +1127,9 @@ prep_directory(struct dir_baton *db,
                svn_revnum_t ancestor_revision,
                apr_pool_t *pool)
 {
-  const char *repos;
+  const char *repos_root;
   const char *dir_abspath;
+  svn_boolean_t locked_here;
 
   dir_abspath = db->local_abspath;
 
@@ -1142,61 +1138,68 @@ prep_directory(struct dir_baton *db,
 
   /* Use the repository root of the anchor, but only if it actually is an
      ancestor of the URL of this directory. */
-  if (db->edit_baton->repos
-      && svn_uri_is_ancestor(db->edit_baton->repos, ancestor_url))
-    repos = db->edit_baton->repos;
+  if (svn_uri_is_ancestor(db->edit_baton->repos_root, ancestor_url))
+    repos_root = db->edit_baton->repos_root;
   else
-    repos = NULL;
+    repos_root = NULL;
 
   /* Make sure it's the right working copy, either by creating it so,
      or by checking that it is so already. */
   SVN_ERR(svn_wc__internal_ensure_adm(db->edit_baton->db, dir_abspath,
-                                      ancestor_url, repos,
-                                      db->edit_baton->uuid, ancestor_revision,
+                                      ancestor_url, repos_root,
+                                      db->edit_baton->repos_uuid,
+                                      ancestor_revision,
                                       db->ambient_depth, pool));
 
-  if (NULL == svn_wc__adm_retrieve_internal2(db->edit_baton->db, dir_abspath,
-                                             pool))
-    {
-      svn_wc_adm_access_t *adm_access;
-      apr_pool_t *adm_access_pool;
-      const char *rel_path;
-
-      SVN_ERR(svn_wc__temp_get_relpath(&rel_path, db->edit_baton->db,
+  SVN_ERR(svn_wc_locked2(&locked_here, NULL, db->edit_baton->wc_ctx,
+                         dir_abspath, pool));
+  if (!locked_here)
+    /* Recursive lock release on parent will release this lock. */
+    SVN_ERR(svn_wc__acquire_write_lock(NULL, db->edit_baton->wc_ctx,
                                        dir_abspath, pool, pool));
 
-      adm_access_pool = svn_wc_adm_access_pool(db->edit_baton->adm_access);
-
-      SVN_ERR(svn_wc__adm_open_in_context(&adm_access, db->edit_baton->wc_ctx,
-                                          rel_path, TRUE, -1,
-                                          db->edit_baton->cancel_func,
-                                          db->edit_baton->cancel_baton,
-                                          adm_access_pool));
-    }
-
   return SVN_NO_ERROR;
 }
 
 
-/* Accumulate tags in LOG_ACCUM (associated with ADM_ABSPATH) to set
-   ENTRY_PROPS for PATH.
-   ENTRY_PROPS is an array of svn_prop_t* entry props.
-   If ENTRY_PROPS contains the removal of a lock token, all entryprops
-   related to a lock will be removed and LOCK_STATE, if non-NULL, will be
-   set to svn_wc_notify_lock_state_unlocked.  Else, LOCK_STATE, if non-NULL
-   will be set to svn_wc_lock_state_unchanged. */
+/* Container for the common "Entry props" */
+struct last_change_info
+{
+  /** last revision this was changed */
+  svn_revnum_t cmt_rev;
+
+  /** last date this was changed */
+  apr_time_t cmt_date;
+
+  /** last commit author of this item */
+  const char *cmt_author;
+};
+
+/* Update the fields of *LAST_CHANGE to represent the last-change info found
+   in ENTRY_PROPS, an array of svn_prop_t* entry props.  Update each field
+   separately, ignoring any unexpected properties and any properties with
+   null values (except the lock token as described below).
+
+   If ENTRY_PROPS contains a lock token property with a null value, remove
+   the lock info directly from LOCAL_ABSPATH in DB and set *LOCK_STATE (if
+   LOCK_STATE is non-NULL) to svn_wc_notify_lock_state_unlocked, else set
+   *LOCK_STATE (if LOCK_STATE is non-NULL) to svn_wc_lock_state_unchanged.
+   ENTRY_PROPS must not contain a lock token with a non-null value.
+
+   If *LAST_CHANGE was NULL, first set it to a new structure allocated from
+   RESULT_POOL and initialize each field to its appropriate null or invalid
+   value.
+ */
 static svn_error_t *
-accumulate_entry_props(svn_stringbuf_t *log_accum,
-                       svn_wc__db_t *db,
-                       const char *adm_abspath,
+accumulate_last_change(struct last_change_info **last_change,
                        svn_wc_notify_lock_state_t *lock_state,
-                       const char *path,
-                       apr_array_header_t *entry_props,
-                       apr_pool_t *pool)
+                       svn_wc__db_t *db,
+                       const char *local_abspath,
+                       const apr_array_header_t *entry_props,
+                       apr_pool_t *scratch_pool,
+                       apr_pool_t *result_pool)
 {
   int i;
-  svn_wc_entry_t tmp_entry;
-  apr_uint64_t flags = 0;
 
   if (lock_state)
     *lock_state = svn_wc_notify_lock_state_unchanged;
@@ -1207,11 +1210,11 @@ accumulate_entry_props(svn_stringbuf_t *
       const char *val;
 
       /* The removal of the lock-token entryprop means that the lock was
-         defunct. */
+         defunct, so remove it directly. */
       if (! strcmp(prop->name, SVN_PROP_ENTRY_LOCK_TOKEN))
         {
-          SVN_WC__FLUSH_LOG_ACCUM(db, adm_abspath, log_accum, pool);
-          SVN_ERR(svn_wc__loggy_delete_lock(db, adm_abspath, path, pool));
+          SVN_ERR_ASSERT(prop->value == NULL);
+          SVN_ERR(svn_wc__db_lock_remove(db, local_abspath, scratch_pool));
 
           if (lock_state)
             *lock_state = svn_wc_notify_lock_state_unlocked;
@@ -1226,29 +1229,23 @@ accumulate_entry_props(svn_stringbuf_t *
 
       val = prop->value->data;
 
-      if (! strcmp(prop->name, SVN_PROP_ENTRY_LAST_AUTHOR))
+      if (*last_change == NULL)
         {
-          flags |= SVN_WC__ENTRY_MODIFY_CMT_AUTHOR;
-          tmp_entry.cmt_author = val;
+          *last_change = apr_pcalloc(result_pool, sizeof(**last_change));
+          (*last_change)->cmt_rev = SVN_INVALID_REVNUM;
         }
+
+      if (! strcmp(prop->name, SVN_PROP_ENTRY_LAST_AUTHOR))
+        (*last_change)->cmt_author = apr_pstrdup(result_pool, val);
       else if (! strcmp(prop->name, SVN_PROP_ENTRY_COMMITTED_REV))
-        {
-          flags |= SVN_WC__ENTRY_MODIFY_CMT_REV;
-          tmp_entry.cmt_rev = SVN_STR_TO_REV(val);
-        }
+        (*last_change)->cmt_rev = SVN_STR_TO_REV(val);
       else if (! strcmp(prop->name, SVN_PROP_ENTRY_COMMITTED_DATE))
-        {
-          flags |= SVN_WC__ENTRY_MODIFY_CMT_DATE;
-          SVN_ERR(svn_time_from_cstring(&tmp_entry.cmt_date, val, pool));
-        }
+        SVN_ERR(svn_time_from_cstring(&((*last_change)->cmt_date), val,
+                                      scratch_pool));
       /* Starting with Subversion 1.7 we ignore the SVN_PROP_ENTRY_UUID
          property here. */
     }
 
-  if (flags)
-    SVN_ERR(svn_wc__loggy_entry_modify(&log_accum, adm_abspath,
-                                       path, &tmp_entry, flags, pool, pool));
-
   return SVN_NO_ERROR;
 }
 
@@ -1303,7 +1300,6 @@ set_target_revision(void *edit_baton,
   return SVN_NO_ERROR;
 }
 
-
 /* An svn_delta_editor_t function. */
 static svn_error_t *
 open_root(void *edit_baton,
@@ -1321,7 +1317,7 @@ open_root(void *edit_baton,
      edit run. */
   eb->root_opened = TRUE;
 
-  SVN_ERR(make_dir_baton(&db, NULL, eb, NULL, FALSE, pool));
+  SVN_ERR(make_dir_baton(&db, NULL, eb, NULL, pool));
   *dir_baton = db;
 
   SVN_ERR(svn_wc__db_read_kind(&kind, eb->db, db->local_abspath, TRUE, pool));
@@ -1351,12 +1347,8 @@ open_root(void *edit_baton,
 
       /* Notify that we skipped the target, while we actually skipped
          the anchor */
-      if (eb->notify_func)
-        eb->notify_func(eb->notify_baton,
-                        svn_wc_create_notify(eb->target_abspath,
-                                             svn_wc_notify_skip,
-                                             pool),
-                        pool);
+      do_notification(eb, eb->target_abspath, svn_node_unknown,
+                      svn_wc_notify_skip, pool);
 
       return SVN_NO_ERROR;
     }
@@ -1364,31 +1356,23 @@ open_root(void *edit_baton,
   if (! *eb->target_basename)
     {
       /* For an update with a NULL target, this is equivalent to open_dir(): */
-      svn_wc_entry_t tmp_entry;
       svn_depth_t depth;
       svn_wc__db_status_t status;
-      apr_uint64_t flags = SVN_WC__ENTRY_MODIFY_REVISION |
-        SVN_WC__ENTRY_MODIFY_URL | SVN_WC__ENTRY_MODIFY_INCOMPLETE;
 
       /* Read the depth from the entry. */
-      SVN_ERR(svn_wc__db_read_info(&status, NULL, NULL, NULL, NULL, NULL, NULL,
+      SVN_ERR(svn_wc__db_base_get_info(&status, NULL, NULL, NULL, NULL, NULL, NULL,
                                    NULL, NULL, NULL, &depth, NULL, NULL, NULL,
-                                   NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-                                   NULL, NULL, NULL,
-                                   eb->db, db->local_abspath, pool, pool));
+                                   NULL, eb->db, db->local_abspath, pool, pool));
       db->ambient_depth = depth;
       db->was_incomplete = (status == svn_wc__db_status_incomplete);
 
       /* ### TODO: Skip if inside a conflicted tree. */
 
-      /* Mark directory as being at target_revision, but incomplete. */
-      tmp_entry.revision = *(eb->target_revision);
-      tmp_entry.url = db->new_URL;
-      tmp_entry.incomplete = TRUE;
-      SVN_ERR(svn_wc__entry_modify2(eb->db, db->local_abspath, svn_node_dir,
-                                    FALSE,
-                                    &tmp_entry, flags,
-                                    pool));
+      SVN_ERR(svn_wc__db_temp_op_start_directory_update(eb->db,
+                                                        db->local_abspath,
+                                                        db->new_relpath,
+                                                        *eb->target_revision,
+                                                        pool));
     }
 
   return SVN_NO_ERROR;
@@ -1438,14 +1422,15 @@ static svn_error_t *
 entry_has_local_mods(svn_boolean_t *modified,
                      svn_wc__db_t *db,
                      const char *local_abspath,
-                     svn_node_kind_t kind,
+                     svn_wc__db_kind_t kind,
                      apr_pool_t *scratch_pool)
 {
   svn_boolean_t text_modified;
   svn_boolean_t props_modified;
 
   /* Check for text modifications */
-  if (kind == svn_node_file)
+  if (kind == svn_wc__db_kind_file
+      || kind == svn_wc__db_kind_symlink)
     SVN_ERR(svn_wc__internal_text_modified_p(&text_modified, db, local_abspath,
                                              FALSE, TRUE, scratch_pool));
   else
@@ -1469,6 +1454,7 @@ typedef struct modcheck_baton_t {
                                           then this field has no meaning. */
 } modcheck_baton_t;
 
+/* */
 static svn_error_t *
 modcheck_found_node(const char *local_abspath,
                     void *walk_baton,
@@ -1490,10 +1476,7 @@ modcheck_found_node(const char *local_ab
     modified = TRUE;
   else
     SVN_ERR(entry_has_local_mods(&modified, baton->db, local_abspath,
-                                 (kind == svn_wc__db_kind_file
-                                  || kind == svn_wc__db_kind_symlink)
-                                   ? svn_node_file : svn_node_dir,
-                                 scratch_pool));
+                                 kind, scratch_pool));
 
   if (modified)
     {
@@ -1540,6 +1523,9 @@ tree_has_local_mods(svn_boolean_t *modif
 }
 
 
+/* Indicates an unset svn_wc_conflict_reason_t. */
+#define SVN_WC_CONFLICT_REASON_NONE (svn_wc_conflict_reason_t)(-1)
+
 /* Check whether the incoming change ACTION on FULL_PATH would conflict with
  * LOCAL_ABSPATH's scheduled change. If so, then raise a tree conflict with
  * LOCAL_ABSPATH as the victim.
@@ -1554,10 +1540,11 @@ tree_has_local_mods(svn_boolean_t *modif
  * function. E.g. dir_opened() should pass svn_node_dir, etc.
  * In some cases of delete, svn_node_none may be used here.
  *
- * THEIR_URL is the involved node's URL on the source-right side, the
- * side that the target should become after the update. Simply put,
- * that's the URL obtained from the node's dir_baton->new_URL or
- * file_baton->new_URL (but it's more complex for a delete).
+ * THEIR_RELPATH is the involved node's repository relative path on the
+ * source-right side, the side that the target should become after the
+ * update. Simply put, that's the URL obtained from the node's
+ * dir_baton->new_relpath or file_baton->new_relpath (but it's more
+ * complex for a delete).
  *
  * ACCEPT_DELETED is true if one of the ancestors got tree conflicted, but
  * the operation continued updating a deleted base tree.
@@ -1571,190 +1558,332 @@ check_tree_conflict(svn_wc_conflict_desc
                     const char *local_abspath,
                     svn_wc_conflict_action_t action,
                     svn_node_kind_t their_node_kind,
-                    const char *their_url,
-                    svn_boolean_t inside_deleted_subtree,
+                    const char *their_relpath,
                     apr_pool_t *pool)
 {
-  svn_wc_conflict_reason_t reason = (svn_wc_conflict_reason_t)(-1);
+  svn_wc__db_status_t status;
+  svn_wc__db_kind_t db_node_kind;
+  svn_boolean_t base_shadowed;
+  svn_wc_conflict_reason_t reason = SVN_WC_CONFLICT_REASON_NONE;
+  svn_boolean_t locally_replaced = FALSE;
+  svn_boolean_t modified = FALSE;
   svn_boolean_t all_mods_are_deletes = FALSE;
-  const svn_wc_entry_t *entry;
-  svn_error_t *err;
 
-  err = svn_wc__get_entry(&entry, eb->db, local_abspath, TRUE,
-                          svn_node_unknown, FALSE, pool, pool);
+  *pconflict = NULL;
 
-  if (err && err->apr_err == SVN_ERR_NODE_UNEXPECTED_KIND)
-    svn_error_clear(err);
-  else
-    SVN_ERR(err);
+  SVN_ERR(svn_wc__db_read_info(&status,
+                               &db_node_kind,
+                               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+                               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+                               NULL, NULL, NULL,
+                               &base_shadowed,
+                               NULL, NULL,
+                               eb->db,
+                               local_abspath,
+                               pool,
+                               pool));
 
-  if (entry)
-    {
-      svn_boolean_t hidden;
-      SVN_ERR(svn_wc__db_node_hidden(&hidden, eb->db, local_abspath, pool));
+  /* Find out if there are any local changes to this node that may
+   * be the "reason" of a tree-conflict with the incoming "action". */
+  switch (status)
+    {
+      case svn_wc__db_status_added:
+      case svn_wc__db_status_obstructed_add:
+      case svn_wc__db_status_moved_here:
+      case svn_wc__db_status_copied:
+        /* Is it a replace? */
+        if (base_shadowed)
+          {
+            svn_wc__db_status_t base_status;
+            SVN_ERR(svn_wc__db_base_get_info(&base_status, NULL, NULL,
+                                             NULL, NULL, NULL, NULL, NULL,
+                                             NULL, NULL, NULL, NULL, NULL,
+                                             NULL, NULL,
+                                             eb->db, local_abspath,
+                                             pool,
+                                             pool));
+            if (base_status != svn_wc__db_status_not_present)
+              locally_replaced = TRUE;
+          }
 
-      if (hidden)
-        entry = NULL;
-    }
+        if (!locally_replaced)
+          {
+            /* The node is locally added, and it did not exist before.  This
+             * is an 'update', so the local add can only conflict with an
+             * incoming 'add'.  In fact, if we receive anything else than an
+             * svn_wc_conflict_action_add (which includes 'added',
+             * 'copied-here' and 'moved-here') during update on a node that
+             * did not exist before, then something is very wrong.
+             * Note that if there was no action on the node, this code
+             * would not have been called in the first place. */
+            SVN_ERR_ASSERT(action == svn_wc_conflict_action_add);
 
-  switch (action)
-    {
-    case svn_wc_conflict_action_edit:
-      /* Use case 1: Modifying a locally-deleted item.
-         If LOCAL_ABSPATH is an incoming leaf edit within a local
-         tree deletion then we will already have recorded a tree
-         conflict on the locally deleted parent tree.  No need
-         to record a conflict within the conflict. */
-      if ((entry->schedule == svn_wc_schedule_delete
-           || entry->schedule == svn_wc_schedule_replace)
-          && !inside_deleted_subtree)
-        reason = entry->schedule == svn_wc_schedule_delete
-                                    ? svn_wc_conflict_reason_deleted
-                                    : svn_wc_conflict_reason_replaced;
-      break;
+            reason = svn_wc_conflict_reason_added;
+          }
+        else
+          {
+            /* The node is locally replaced. */
+            reason = svn_wc_conflict_reason_replaced;
+          }
+        break;
 
-    case svn_wc_conflict_action_add:
-      /* Use case "3.5": Adding a locally-added item.
-       *
-       * When checking out a file-external, add_file() is called twice:
-       * 1.) In the main update, a minimal entry is created.
-       * 2.) In the external update, the file is added properly.
-       * Don't raise a tree conflict the second time! */
-      if (entry && !entry->file_external_path)
-        reason = svn_wc_conflict_reason_added;
-      break;
-
-    case svn_wc_conflict_action_delete:
-    case svn_wc_conflict_action_replace:
-      /* Use case 3: Deleting a locally-deleted item. */
-      if (entry->schedule == svn_wc_schedule_delete
-          || entry->schedule == svn_wc_schedule_replace)
-        {
-          /* If LOCAL_ABSPATH is an incoming leaf deletion within a local
-             tree deletion then we will already have recorded a tree
-             conflict on the locally deleted parent tree.  No need
-             to record a conflict within the conflict. */
-          if (!inside_deleted_subtree)
-            reason = entry->schedule == svn_wc_schedule_delete
-                                        ? svn_wc_conflict_reason_deleted
-                                        : svn_wc_conflict_reason_replaced;
-        }
-      else
-        {
-          svn_boolean_t modified = FALSE;
 
-          /* Use case 2: Deleting a locally-modified item. */
-          if (entry->kind == svn_node_file)
-            {
-              if (entry->schedule != svn_wc_schedule_normal)
-                modified = TRUE;
-              else
-                SVN_ERR(entry_has_local_mods(&modified, eb->db, local_abspath,
-                                             entry->kind, pool));
-              if (entry->schedule == svn_wc_schedule_delete)
-                all_mods_are_deletes = TRUE;
-            }
-          else if (entry->kind == svn_node_dir)
-            {
+      case svn_wc__db_status_deleted:
+      case svn_wc__db_status_obstructed_delete:
+        /* The node is locally deleted. */
+        reason = svn_wc_conflict_reason_deleted;
+        break;
+
+      case svn_wc__db_status_incomplete:
+        /* We used svn_wc__db_read_info(), so 'incomplete' means
+         * - there is no node in the WORKING tree
+         * - a BASE node is known to exist
+         * So the node exists and is essentially 'normal'. We still need to
+         * check prop and text mods, and those checks will retrieve the
+         * missing information (hopefully). */
+      case svn_wc__db_status_obstructed:
+        /* Tree-conflicts during update are only concerned with local
+         * modifications. We can safely update BASE, disregarding the
+         * obstruction. So let's treat this as normal. */
+      case svn_wc__db_status_normal:
+        if (action == svn_wc_conflict_action_edit)
+          /* An edit onto a local edit or onto *no* local changes is no
+           * tree-conflict. (It's possibly a text- or prop-conflict,
+           * but we don't handle those here.) */
+          return SVN_NO_ERROR;
+
+        /* Check if the update wants to delete or replace a locally
+         * modified node. */
+        switch (db_node_kind)
+          {
+            case svn_wc__db_kind_file:
+            case svn_wc__db_kind_symlink:
+              all_mods_are_deletes = FALSE;
+              SVN_ERR(entry_has_local_mods(&modified, eb->db, local_abspath,
+                                           db_node_kind, pool));
+              break;
+
+            case svn_wc__db_kind_dir:
               /* We must detect deep modifications in a directory tree,
                * but the update editor will not visit the subdirectories
                * of a directory that it wants to delete.  Therefore, we
                * need to start a separate crawl here. */
-
               if (!svn_wc__adm_missing(eb->db, local_abspath, pool))
                 SVN_ERR(tree_has_local_mods(&modified, &all_mods_are_deletes,
                                             eb->db, local_abspath,
                                             eb->cancel_func, eb->cancel_baton,
                                             pool));
-            }
+              break;
 
-          if (modified)
-            {
-              if (all_mods_are_deletes)
-                reason = svn_wc_conflict_reason_deleted;
-              else
-                reason = svn_wc_conflict_reason_edited;
-            }
+            default:
+              /* It's supposed to be in 'normal' status. So how can it be
+               * neither file nor folder? */
+              SVN_ERR_MALFUNCTION();
+              break;
+          }
+
+        if (modified)
+          {
+            if (all_mods_are_deletes)
+              reason = svn_wc_conflict_reason_deleted;
+            else
+              reason = svn_wc_conflict_reason_edited;
+          }
+        break;
+
+      case svn_wc__db_status_absent:
+        /* Not allowed to view the node. Not allowed to report tree
+         * conflicts. */
+      case svn_wc__db_status_excluded:
+        /* Locally marked as excluded. No conflicts wanted. */
+      case svn_wc__db_status_not_present:
+        /* A committed delete (but parent not updated). The delete is
+           committed, so no conflict possible during update. */
+        return SVN_NO_ERROR;
+
+      case svn_wc__db_status_base_deleted:
+        /* An internal status. Should never show up here. */
+        SVN_ERR_MALFUNCTION();
+        break;
 
-        }
-      break;
     }
 
-  *pconflict = NULL;
+  if (reason == SVN_WC_CONFLICT_REASON_NONE)
+    /* No conflict with the current action. */
+    return SVN_NO_ERROR;
+
+
+  /* Sanity checks. Note that if there was no action on the node, this function
+   * would not have been called in the first place.*/
+  if (reason == svn_wc_conflict_reason_edited
+      || reason == svn_wc_conflict_reason_deleted
+      || 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
+     * _action_edit, _delete or _replace. */
+    SVN_ERR_ASSERT(action == svn_wc_conflict_action_edit
+                   || action == svn_wc_conflict_action_delete
+                   || action == svn_wc_conflict_action_replace);
+  else if (reason == svn_wc_conflict_reason_added)
+    /* When the node did not exist before (it was locally added), then 'update'
+     * cannot want to modify it in any way. It can only send _action_add. */
+    SVN_ERR_ASSERT(action == svn_wc_conflict_action_add);
 
-  /* If a conflict was detected, append log commands to the log accumulator
+
+  /* A conflict was detected. Append log commands to the log accumulator
    * to record it. */
-  if (reason != (svn_wc_conflict_reason_t)(-1))
-    {
-      svn_wc_conflict_description2_t *conflict;
-      const svn_wc_conflict_version_t *src_left_version;
-      const svn_wc_conflict_version_t *src_right_version;
-      const char *repos_url = NULL;
-      const char *path_in_repos = NULL;
-      svn_node_kind_t left_kind = (entry->schedule == svn_wc_schedule_add)
-                                  ? svn_node_none
-                                  : (entry->schedule == svn_wc_schedule_delete)
-                                    ? svn_node_unknown
-                                    : entry->kind;
-
-      /* Source-left repository root URL and path in repository.
-       * The Source-right ones will be the same for update.
-       * For switch, only the path in repository will differ, because
-       * a cross-repository switch is not possible. */
-      repos_url = entry->repos;
-      path_in_repos = svn_uri_is_child(repos_url, entry->url, pool);
-      if (path_in_repos == NULL)
-        path_in_repos = "";
-
-      src_left_version = svn_wc_conflict_version_create(repos_url,
-                                                        path_in_repos,
-                                                        entry->revision,
-                                                        left_kind,
-                                                        pool);
+  {
+    const char *repos_root_url = NULL;
+    const char *left_repos_relpath;
+    svn_revnum_t left_revision;
+    svn_node_kind_t left_kind;
+    const char *right_repos_relpath;
+    const char *added_repos_relpath = NULL;
+    svn_node_kind_t conflict_node_kind;
+    svn_wc_conflict_version_t *src_left_version;
+    svn_wc_conflict_version_t *src_right_version;
+
+    /* Get the source-left information, i.e. the local state of the node
+     * before any changes were made to the working copy, i.e. the state the
+     * node would have if it was reverted. */
+    if (reason == svn_wc_conflict_reason_added)
+      {
+        svn_wc__db_status_t added_status;
 
-      /* entry->kind is both base kind and working kind, because schedule
-       * replace-by-different-kind is not supported. */
-      /* ### TODO: but in case the entry is locally removed, entry->kind
-       * is svn_node_none and doesn't reflect the older kind. Then we
-       * need to find out the older kind in a different way! */
+        /* ###TODO: It would be nice to tell the user at which URL and
+         * ### revision source-left was empty, which could be quite difficult
+         * ### to code, and is a slight theoretical leap of the svn mind.
+         * ### Update should show
+         * ###   URL: svn_wc__db_scan_addition( &repos_relpath )
+         * ###   REV: The base revision of the parent of before this update
+         * ###        started
+         * ###        ### BUT what if parent was updated/switched away with
+         * ###        ### depth=empty after this node was added?
+         * ### Switch should show
+         * ###   URL: scan_addition URL of before this switch started
+         * ###   REV: same as above */
+
+        /* In case of a local addition, source-left is non-existent / empty. */
+        left_kind = svn_node_none;
+        left_revision = SVN_INVALID_REVNUM;
+        left_repos_relpath = NULL;
+
+        /* Still get the repository root needed by both 'update' and 'switch',
+         * and the would-be repos_relpath needed to construct the source-right
+         * in case of an 'update'. Check sanity while we're at it. */
+        SVN_ERR(svn_wc__db_scan_addition(&added_status, NULL,
+                                         &added_repos_relpath,
+                                         &repos_root_url,
+                                         NULL, NULL, NULL, NULL, NULL,
+                                         eb->db, local_abspath, pool, pool));
+
+        /* This better really be an added status. */
+        SVN_ERR_ASSERT(added_status == svn_wc__db_status_added
+                       || added_status == svn_wc__db_status_obstructed_add
+                       || added_status == svn_wc__db_status_copied
+                       || added_status == svn_wc__db_status_moved_here);
+      }
+    else
+      {
+        /* A BASE node should exist. */
+        svn_wc__db_kind_t base_kind;
 
-      /* For switch, find out the proper PATH_IN_REPOS for source-right. */
-      if (eb->switch_url != NULL)
-        {
-          if (their_url != NULL)
-            path_in_repos = svn_uri_is_child(repos_url, their_url, pool);
-          else
-            {
-              /* The complete source-right URL is not available, but it
-               * is somewhere below the SWITCH_URL. For now, just go
-               * without it.
-               * ### TODO: Construct a proper THEIR_URL in some of the
-               * delete cases that still pass NULL for THEIR_URL when
-               * calling this function. Do that on the caller's side. */
-              path_in_repos = svn_uri_is_child(repos_url, eb->switch_url,
-                                               pool);
-              path_in_repos = apr_pstrcat(
-                                pool, path_in_repos,
-                                "_THIS_IS_INCOMPLETE",
-                                NULL);
-            }
-        }
+        /* 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_replaced
+                       || reason == svn_wc_conflict_reason_obstructed);
+
+        SVN_ERR(svn_wc__db_base_get_info(NULL, &base_kind,
+                                         &left_revision,
+                                         &left_repos_relpath,
+                                         &repos_root_url,
+                                         NULL, NULL, NULL, NULL, NULL, NULL,
+                                         NULL, NULL, NULL, NULL,
+                                         eb->db,
+                                         local_abspath,
+                                         pool,
+                                         pool));
+        /* Translate the node kind. */
+        if (base_kind == svn_wc__db_kind_file
+            || base_kind == svn_wc__db_kind_symlink)
+          left_kind = svn_node_file;
+        else if (base_kind == svn_wc__db_kind_dir)
+          left_kind = svn_node_dir;
+        else
+          SVN_ERR_MALFUNCTION();
+      }
 
-      src_right_version = svn_wc_conflict_version_create(repos_url,
-                                                         path_in_repos,
-                                                         *eb->target_revision,
-                                                         their_node_kind,
-                                                         pool);
-
-      conflict = svn_wc_conflict_description_create_tree2(
-        local_abspath, entry->kind,
-        eb->switch_url ? svn_wc_operation_switch : svn_wc_operation_update,
-        src_left_version, src_right_version, pool);
-      conflict->action = action;
-      conflict->reason = reason;
 
-      *pconflict = conflict;
-    }
+    /* Find the source-right information, i.e. the state in the repository
+     * to which we would like to update. */
+    if (eb->switch_relpath)
+      {
+        /* If this is a 'switch' operation, try to construct the switch
+         * target's REPOS_RELPATH. */
+        if (their_relpath != NULL)
+          right_repos_relpath = their_relpath;
+        else
+          {
+            /* The complete source-right URL is not available, but it
+             * is somewhere below the SWITCH_URL. For now, just go
+             * without it.
+             * ### TODO: Construct a proper THEIR_URL in some of the
+             * delete cases that still pass NULL for THEIR_URL when
+             * calling this function. Do that on the caller's side. */
+            right_repos_relpath = eb->switch_relpath;
+            right_repos_relpath = apr_pstrcat(pool, right_repos_relpath,
+                                              "_THIS_IS_INCOMPLETE", NULL);
+          }
+      }
+    else
+      {
+        /* This is an 'update', so REPOS_RELPATH would be the same as for
+         * source-left. However, we don't have a source-left for locally
+         * added files. */
+        right_repos_relpath = (reason == svn_wc_conflict_reason_added ?
+                               added_repos_relpath : left_repos_relpath);
+      }
+
+    /* Determine PCONFLICT's overall node kind, which is not allowed to be
+     * svn_node_none. We give it the source-right revision (THEIR_NODE_KIND)
+     * -- unless source-right is deleted and hence == svn_node_none, in which
+     * case we take it from source-left, which has to be the node kind that
+     * was deleted. */
+    conflict_node_kind = (action == svn_wc_conflict_action_delete ?
+                          left_kind : their_node_kind);
+    SVN_ERR_ASSERT(conflict_node_kind == svn_node_file
+                   || conflict_node_kind == svn_node_dir);
+
+
+    /* Construct the tree conflict info structs. */
+
+    if (left_repos_relpath == NULL)
+      /* A locally added path in conflict with an incoming add.
+       * Send an 'empty' left revision. */
+      src_left_version = NULL;
+    else
+      src_left_version = svn_wc_conflict_version_create(repos_root_url,
+                                                        left_repos_relpath,
+                                                        left_revision,
+                                                        left_kind,
+                                                        pool);
+
+    src_right_version = svn_wc_conflict_version_create(repos_root_url,
+                                                       right_repos_relpath,
+                                                       *eb->target_revision,
+                                                       their_node_kind,
+                                                       pool);
+
+    *pconflict = svn_wc_conflict_description_create_tree2(
+                     local_abspath, conflict_node_kind,
+                     eb->switch_relpath ?
+                       svn_wc_operation_switch : svn_wc_operation_update,
+                     src_left_version, src_right_version, pool);
+    (*pconflict)->action = action;
+    (*pconflict)->reason = reason;
+  }
 
   return SVN_NO_ERROR;
 }
@@ -1885,236 +2014,31 @@ node_already_conflicted(svn_boolean_t *c
 }
 
 
-/* A walk baton for schedule_existing_item_for_re_add()'s call
-   to svn_wc_walk_entries3(). */
-struct set_copied_baton_t
-{
-  struct edit_baton *eb;
-
-  /* The PATH arg to schedule_existing_item_for_re_add(). */
-  const char *added_subtree_root_path;
-};
-
-/* An svn_wc__node_found_func_t callback function.
- * Set the 'copied' flag on the given ENTRY for every PATH
- * under ((set_copied_baton_t *)WALK_BATON)->ADDED_SUBTREE_ROOT_PATH
- * which has a normal schedule. */
-static svn_error_t *
-set_copied_callback(const char *local_abspath,
-                    void *walk_baton,
-                    apr_pool_t *scratch_pool)
-{
-  struct set_copied_baton_t *b = walk_baton;
-  svn_wc__db_status_t status;
-  svn_wc__db_kind_t kind;
-
-  if (strcmp(local_abspath, b->added_subtree_root_path) == 0)
-    return SVN_NO_ERROR; /* Don't touch the root */
-
-  SVN_ERR(svn_wc__db_read_info(&status, &kind, NULL, NULL, NULL,
-                               NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-                               NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-                               NULL, NULL, NULL, NULL, NULL,
-                               b->eb->db, local_abspath,
-                               scratch_pool, scratch_pool));
-
-  if (kind == svn_wc__db_kind_dir)
-    {
-      /* We don't want to mark a deleted PATH as copied.  If PATH
-         is added without history we don't want to make it look like
-         it has history.  If PATH is replaced we don't want to make
-         it look like it has history if it doesn't.  Only if PATH is
-         schedule normal do we need to mark it as copied. */
-      if (status == svn_wc__db_status_normal)
-        {
-          svn_wc_entry_t tmp_entry;
-
-          /* Set the 'copied' flag and write the entry out to disk. */
-          tmp_entry.copied = TRUE;
-          SVN_ERR(svn_wc__entry_modify2(b->eb->db,
-                                        local_abspath,
-                                        svn_node_dir,
-                                        TRUE,
-                                        &tmp_entry,
-                                        SVN_WC__ENTRY_MODIFY_COPIED,
-                                        scratch_pool));
-        }
-    }
-
-  /* We don't want to mark a deleted PATH as copied.  If PATH
-     is added without history we don't want to make it look like
-     it has history.  If PATH is replaced we don't want to make
-     it look like it has history if it doesn't.  Only if PATH is
-     schedule normal do we need to mark it as copied. */
-  if (status == svn_wc__db_status_normal)
-    {
-      svn_wc_entry_t tmp_entry;
-      apr_hash_t *props;
-
-      /* We switch the node from BASE to WORKING.. We have to move the
-         properties with it */
-      SVN_ERR(svn_wc__db_read_pristine_props(&props, b->eb->db, local_abspath,
-                                             scratch_pool, scratch_pool));
-
-      /* Set the 'copied' flag and write the entry out to disk. */
-      tmp_entry.copied = TRUE;
-      SVN_ERR(svn_wc__entry_modify2(b->eb->db,
-                                    local_abspath,
-                                    kind == svn_wc__db_kind_dir
-                                      ? svn_node_dir
-                                      : svn_node_file,
-                                    FALSE,
-                                    &tmp_entry,
-                                    SVN_WC__ENTRY_MODIFY_COPIED,
-                                    scratch_pool));
-
-      SVN_ERR(svn_wc__db_temp_op_set_pristine_props(b->eb->db, local_abspath, props,
-                                                    TRUE, scratch_pool));
-    }
-  return SVN_NO_ERROR;
-}
-
-/* Schedule the WC item LOCAL_ABSPATH, whose entry is ENTRY, for re-addition.
- * If MODIFY_COPYFROM is TRUE, re-add the item as a copy with history
- * of (ENTRY->url)@(ENTRY->rev).
- * Assume that the item exists locally and is scheduled as still existing with
- * some local modifications relative to its (old) base, but does not exist in
- * the repository at the target revision.
- *
- * Use the local content of the item, even if it
- * If the item is a directory, recursively schedule its contents to be the
- * contents of the re-added tree, even if they are locally modified relative
- * to it.
- *
- * THEIR_URL is the deleted node's URL on the source-right side, the
- * side that the target should become after the update. In other words,
- * that's the new URL the node would have if it were not deleted.
- *
- * Make changes to entries immediately, not loggily, because that is easier
- * to keep track of when multiple directories are involved.
- *  */
-static svn_error_t *
-schedule_existing_item_for_re_add(const svn_wc_entry_t *entry,
-                                  struct edit_baton *eb,
-                                  const char *local_abspath,
-                                  const char *their_url,
-                                  svn_boolean_t modify_copyfrom,
-                                  apr_pool_t *pool)
-{
-  svn_wc_entry_t tmp_entry;
-  apr_uint64_t flags = 0;
-  apr_hash_t *props;
-
-  SVN_ERR(svn_wc__db_read_pristine_props(&props, eb->db, local_abspath,
-                                         pool, pool));
-
-  /* Update the details of the base rev/url to reflect the incoming
-   * delete, while leaving the working version as it is, scheduling it
-   * for re-addition unless it was already non-existent. */
-  tmp_entry.url = their_url;
-  flags |= SVN_WC__ENTRY_MODIFY_URL;
-
-  /* Schedule the working version to be re-added. */
-  tmp_entry.schedule = svn_wc_schedule_add;
-  flags |= SVN_WC__ENTRY_MODIFY_SCHEDULE;
-  flags |= SVN_WC__ENTRY_MODIFY_FORCE;
-
-  if (modify_copyfrom)
-    {
-      tmp_entry.copyfrom_url = entry->url;
-      flags |= SVN_WC__ENTRY_MODIFY_COPYFROM_URL;
-      tmp_entry.copyfrom_rev = entry->revision;
-      flags |= SVN_WC__ENTRY_MODIFY_COPYFROM_REV;
-      tmp_entry.copied = TRUE;
-      flags |= SVN_WC__ENTRY_MODIFY_COPIED;
-    }
-
-  /* ### Need to change the "base" into a "revert-base" ? */
-
-  /* Determine which adm dir holds this node's entry */
-  /* ### But this will fail if eb->adm_access holds only a shallow lock. */
-  SVN_ERR(svn_wc__entry_modify2(eb->db,
-                                local_abspath,
-                                entry->kind,
-                                FALSE,
-                                &tmp_entry,
-                                flags, pool));
-
-  SVN_ERR(svn_wc__db_temp_op_set_pristine_props(eb->db, local_abspath, props,
-                                                TRUE, pool));
-
-  /* If it's a directory, set the 'copied' flag recursively. The rest of the
-   * directory tree's state can stay exactly as it was before being
-   * scheduled for re-add. */
-  /* ### BH: I don't think this code handles switched subpaths, excluded
-         and absent items in any usefull way. Needs carefull redesign */
-  if (entry->kind == svn_node_dir)
-    {
-      struct set_copied_baton_t set_copied_baton;
-
-      /* Set the 'copied' flag recursively, to support the
-       * cases where this is a directory. */
-      set_copied_baton.eb = eb;
-      set_copied_baton.added_subtree_root_path = local_abspath;
-      SVN_ERR(svn_wc__internal_walk_children(eb->db, local_abspath, FALSE,
-                                             set_copied_callback,
-                                             &set_copied_baton,
-                                             svn_depth_infinity,
-                                             NULL, NULL, pool));
-
-      /* If PATH is a directory then we must also record in PARENT_PATH's
-         entry that we are re-adding PATH. */
-      flags &= ~SVN_WC__ENTRY_MODIFY_URL;
-      SVN_ERR(svn_wc__entry_modify2(eb->db, local_abspath, svn_node_dir, TRUE,
-                                   &tmp_entry, flags, pool));
-
-      /* ### Need to do something more, such as change 'base' into
-         ### 'revert-base'? */
-    }
-
-  return SVN_NO_ERROR;
-}
-
 /* Delete PATH from its immediate parent PARENT_PATH, in the edit
  * represented by EB. PATH is relative to EB->anchor.
  * PARENT_PATH is relative to the current working directory.
  *
- * THEIR_URL is the deleted node's URL on the source-right side, the
- * side that the target should become after the update. In other words,
- * that's the new URL the node would have if it were not deleted.
+ * THEIR_RELPATH is the deleted node's repository relative path on the
+ * source-right side, the side that the target should become after the
+ * update. In other words, that's the new URL the node would have if it
+ * were not deleted.
  *
  * Perform all allocations in POOL.
  */
 static svn_error_t *
 do_entry_deletion(struct edit_baton *eb,
                   const char *local_abspath,
-                  const char *their_url,
-                  svn_boolean_t inside_deleted_subtree,
+                  const char *their_relpath,
+                  svn_boolean_t in_deleted_and_tree_conflicted_subtree,
                   apr_pool_t *pool)
 {
-  svn_error_t *err;
-  const svn_wc_entry_t *entry;
+  svn_wc__db_kind_t kind;
   svn_boolean_t already_conflicted;
-  svn_stringbuf_t *log_item = svn_stringbuf_create("", pool);
-  svn_wc_conflict_description2_t *tree_conflict;
+  svn_wc_conflict_description2_t *tree_conflict = NULL;
   const char *dir_abspath = svn_dirent_dirname(local_abspath, pool);
   svn_boolean_t hidden;
 
-  /* ### hmm. in case we need to re-add the node, we use some fields from
-     ### this entry. I believe the required fields are filled in, but getting
-     ### just the stub might be a problem.  */
-  err = svn_wc__get_entry(&entry, eb->db, local_abspath,
-                          FALSE /* allow_unversioned */, svn_node_unknown,
-                          TRUE /* need_parent_stub */, pool, pool);
-  if (err)
-    {
-      if (err->apr_err != SVN_ERR_NODE_UNEXPECTED_KIND)
-        return svn_error_return(err);
-
-      /* The node was a file, and we got the "real" entry, not the stub.
-         That is just what we'd like.  */
-      svn_error_clear(err);
-    }
+  SVN_ERR(svn_wc__db_read_kind(&kind, eb->db, local_abspath, FALSE, pool));
 
   /* Is this path a conflict victim? */
   SVN_ERR(node_already_conflicted(&already_conflicted, eb->db,
@@ -2124,12 +2048,8 @@ do_entry_deletion(struct edit_baton *eb,
       SVN_ERR(remember_skipped_tree(eb, local_abspath));
 
       /* ### TODO: Also print victim_path in the skip msg. */
-      if (eb->notify_func)
-        eb->notify_func(eb->notify_baton,
-                        svn_wc_create_notify(local_abspath,
-                                             svn_wc_notify_skip,
-                                             pool),
-                        pool);
+      do_notification(eb, local_abspath, svn_node_unknown, svn_wc_notify_skip,
+                      pool);
 
       return SVN_NO_ERROR;
     }
@@ -2150,26 +2070,27 @@ do_entry_deletion(struct edit_baton *eb,
   /* 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)
-   * copy of the previous base version.
-   */
-  SVN_ERR(check_tree_conflict(&tree_conflict, eb, local_abspath,
-                              svn_wc_conflict_action_delete, svn_node_none,
-                              their_url, inside_deleted_subtree, pool));
+   * copy of the previous base version.  */
+
+  /* Check for conflicts only when we haven't already recorded
+   * a tree-conflict on a parent node. */
+  if (!in_deleted_and_tree_conflicted_subtree)
+    SVN_ERR(check_tree_conflict(&tree_conflict, eb, local_abspath,
+                                svn_wc_conflict_action_delete, svn_node_none,
+                                their_relpath, pool));
+
   if (tree_conflict != NULL)
     {
       /* When we raise a tree conflict on a directory, we want to avoid
        * making any changes inside it. (Will an update ever try to make
        * further changes to or inside a directory it's just deleted?) */
-      SVN_ERR(svn_wc__loggy_add_tree_conflict(&log_item, tree_conflict, pool));
+      SVN_ERR(svn_wc__loggy_add_tree_conflict(eb->db, dir_abspath,
+                                              tree_conflict, pool));
 
       SVN_ERR(remember_skipped_tree(eb, local_abspath));
 
-      if (eb->notify_func)
-        eb->notify_func(eb->notify_baton,
-                        svn_wc_create_notify(local_abspath,
-                                             svn_wc_notify_tree_conflict,
-                                             pool),
-                        pool);
+      do_notification(eb, local_abspath, svn_node_unknown,
+                      svn_wc_notify_tree_conflict, pool);
 
       if (tree_conflict->reason == svn_wc_conflict_reason_edited)
         {
@@ -2184,12 +2105,13 @@ do_entry_deletion(struct edit_baton *eb,
           /* Run the log in the parent dir, to record the tree conflict.
            * Do this before schedule_existing_item_for_re_add(), in case
            * that needs to modify the same entries. */
-          SVN_ERR(svn_wc__wq_add_loggy(eb->db, dir_abspath, log_item, pool));
-          SVN_ERR(svn_wc__run_log2(eb->db, dir_abspath, pool));
+          SVN_ERR(svn_wc__wq_run(eb->db, dir_abspath,
+                                 eb->cancel_func, eb->cancel_baton,
+                                 pool));
+
+          SVN_ERR(svn_wc__db_temp_op_make_copy(eb->db, local_abspath, TRUE,
+                                               pool));
 
-          SVN_ERR(schedule_existing_item_for_re_add(entry, eb,
-                                                    local_abspath, their_url,
-                                                    TRUE, pool));
           return SVN_NO_ERROR;
         }
       else if (tree_conflict->reason == svn_wc_conflict_reason_deleted)
@@ -2213,12 +2135,13 @@ do_entry_deletion(struct edit_baton *eb,
           /* Run the log in the parent dir, to record the tree conflict.
            * Do this before schedule_existing_item_for_re_add(), in case
            * that needs to modify the same entries. */
-          SVN_ERR(svn_wc__wq_add_loggy(eb->db, dir_abspath, log_item, pool));
-          SVN_ERR(svn_wc__run_log2(eb->db, dir_abspath, pool));
+          SVN_ERR(svn_wc__wq_run(eb->db, dir_abspath,
+                                 eb->cancel_func, eb->cancel_baton,
+                                 pool));
+
+          SVN_ERR(svn_wc__db_temp_op_make_copy(eb->db, local_abspath, TRUE,
+                                               pool));
 
-          SVN_ERR(schedule_existing_item_for_re_add(entry, eb,
-                                                    local_abspath, their_url,
-                                                    FALSE, pool));
           return SVN_NO_ERROR;
         }
       else
@@ -2228,7 +2151,6 @@ do_entry_deletion(struct edit_baton *eb,
   /* Issue a loggy command to delete the entry from version control and to
    * delete it from disk if unmodified, but leave any modified files on disk
    * unversioned. */
-  SVN_WC__FLUSH_LOG_ACCUM(eb->db, dir_abspath, log_item, pool);
   SVN_ERR(svn_wc__loggy_delete_entry(eb->db, dir_abspath, local_abspath,
                                      pool));
 
@@ -2238,27 +2160,31 @@ do_entry_deletion(struct edit_baton *eb,
   if (strcmp(local_abspath, eb->target_abspath) == 0)
     {
       svn_wc_entry_t tmp_entry;
+      svn_stringbuf_t *log_accum = NULL;
 
       tmp_entry.revision = *(eb->target_revision);
       /* ### Why not URL as well? This might be a switch. ... */
       /* tmp_entry.url = *(eb->target_url) or db->new_URL ? */
-      tmp_entry.kind = entry->kind;
+      if (kind == svn_wc__db_kind_dir)
+        tmp_entry.kind = svn_node_dir;
+      else /* kind == svn_wc__db_kind_file || kind == svn_wc__db_kind_symlink*/
+        tmp_entry.kind = svn_node_file;
+
       tmp_entry.deleted = TRUE;
 
-      SVN_ERR(svn_wc__loggy_entry_modify(&log_item,
+      SVN_ERR(svn_wc__loggy_entry_modify(&log_accum,
                                dir_abspath, local_abspath,
                                &tmp_entry,
                                SVN_WC__ENTRY_MODIFY_REVISION
                                | SVN_WC__ENTRY_MODIFY_KIND
                                | SVN_WC__ENTRY_MODIFY_DELETED,
                                pool, pool));
+      SVN_ERR(svn_wc__wq_add_loggy(eb->db, dir_abspath, log_accum, pool));
 
       eb->target_deleted = TRUE;
     }
 
-  SVN_ERR(svn_wc__wq_add_loggy(eb->db, dir_abspath, log_item, pool));
-
-  if (eb->switch_url)
+  if (eb->switch_relpath)
     {
       /* The SVN_WC__LOG_DELETE_ENTRY log item will cause
        * svn_wc_remove_from_revision_control() to be run.  But that
@@ -2275,7 +2201,7 @@ do_entry_deletion(struct edit_baton *eb,
        * the log item is to remove the entry in the parent directory.
        */
 
-      if (entry->kind == svn_node_dir)
+      if (kind == svn_wc__db_kind_dir)
         {
           SVN_ERR(leftmod_error_chain(
                     svn_wc__internal_remove_from_revision_control(
@@ -2291,18 +2217,14 @@ do_entry_deletion(struct edit_baton *eb,
 
   /* Note: these two lines are duplicated in the tree-conflicts bail out
    * above. */
-  SVN_ERR(svn_wc__run_log2(eb->db, dir_abspath, pool));
+  SVN_ERR(svn_wc__wq_run(eb->db, dir_abspath,
+                         eb->cancel_func, eb->cancel_baton,
+                         pool));
 
   /* Notify. (If tree_conflict, we've already notified.) */
-  if (eb->notify_func
-      && tree_conflict == NULL)
-    {
-      eb->notify_func(eb->notify_baton,
-                      svn_wc_create_notify(local_abspath,
-                                           svn_wc_notify_update_delete,
-                                           pool),
-                      pool);
-    }
+  if (tree_conflict == NULL)
+    do_notification(eb, local_abspath, svn_node_unknown,
+                    svn_wc_notify_update_delete, pool);
 
   return SVN_NO_ERROR;
 }
@@ -2318,7 +2240,7 @@ delete_entry(const char *path,
   struct dir_baton *pb = parent_baton;
   const char *base = svn_relpath_basename(path, pool);
   const char *local_abspath;
-  const char *their_url;
+  const char *their_relpath;
 
   local_abspath = svn_dirent_join(pb->local_abspath, base, pool);
 
@@ -2332,13 +2254,12 @@ delete_entry(const char *path,
 
   SVN_ERR(check_path_under_root(pb->local_abspath, base, pool));
 
-  their_url = svn_path_url_add_component2(pb->new_URL, base, pool);
-
-  /* Flush parent log before potentially adding tree conflicts */
-  flush_log(pb, pool);
+  their_relpath = svn_relpath_join(pb->new_relpath, base, pool);
 
   return do_entry_deletion(pb->edit_baton, local_abspath,
-                           their_url, pb->inside_deleted_subtree, pool);
+                           their_relpath,
+                           pb->in_deleted_and_tree_conflicted_subtree,
+                           pool);
 }
 
 
@@ -2366,7 +2287,7 @@ add_directory(const char *path,
                  || (!copyfrom_path &&
                      !SVN_IS_VALID_REVNUM(copyfrom_revision)));
 
-  SVN_ERR(make_dir_baton(&db, path, eb, pb, TRUE, pool));
+  SVN_ERR(make_dir_baton(&db, path, eb, pb, pool));
   *child_baton = db;
 
   if (pb->skip_descendants)
@@ -2402,9 +2323,6 @@ add_directory(const char *path,
       db->ambient_depth = svn_depth_infinity;
     }
 
-  /* Flush the log for the parent directory before going into this subtree. */
-  SVN_ERR(flush_log(pb, pool));
-
   /* Is this path a conflict victim? */
   SVN_ERR(node_already_conflicted(&already_conflicted, eb->db,
                                   db->local_abspath, pool));
@@ -2418,12 +2336,8 @@ add_directory(const char *path,
       db->already_notified = TRUE;
 
       /* ### TODO: Also print victim_path in the skip msg. */
-      if (eb->notify_func)
-        eb->notify_func(eb->notify_baton,
-                        svn_wc_create_notify(db->local_abspath,
-                                             svn_wc_notify_skip,
-                                             pool),
-                        pool);
+      do_notification(eb, db->local_abspath, svn_node_unknown,
+                      svn_wc_notify_skip, pool);
 
       return SVN_NO_ERROR;
     }
@@ -2443,7 +2357,6 @@ add_directory(const char *path,
                              NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
                              NULL,
                              eb->db, db->local_abspath, db->pool, db->pool);
-
   if (err)
     {
       if (err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND)
@@ -2460,16 +2373,8 @@ add_directory(const char *path,
        wc_kind != svn_wc__db_kind_dir && IS_NODE_PRESENT(status)))
     {
       db->already_notified = TRUE;
-      if (eb->notify_func)
-        {
-          svn_wc_notify_t *notify =
-                svn_wc_create_notify(db->local_abspath,
-                                     svn_wc_notify_update_obstruction,
-                                     pool);
-
-          notify->kind = svn_node_dir;
-          eb->notify_func(eb->notify_baton, notify, pool);
-        }
+      do_notification(eb, db->local_abspath, svn_node_dir,
+                      svn_wc_notify_update_obstruction, pool);
 
       return svn_error_createf(
        SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL,
@@ -2482,21 +2387,13 @@ add_directory(const char *path,
       (wc_kind == svn_wc__db_kind_unknown || !IS_NODE_PRESENT(status)))
     {
       /* Found an unversioned directory */
-      db->existed = TRUE;
+      db->obstruction_found = TRUE;
 
       if (!eb->allow_unver_obstructions)
         {
           db->already_notified = TRUE;
-          if (eb->notify_func)
-            {
-              svn_wc_notify_t *notify =
-                    svn_wc_create_notify(db->local_abspath,
-                                         svn_wc_notify_update_obstruction,
-                                         pool);
-
-              notify->kind = svn_node_dir;
-              eb->notify_func(eb->notify_baton, notify, pool);
-            }
+          do_notification(eb, db->local_abspath, svn_node_dir,
+                          svn_wc_notify_update_obstruction, pool);
 
           return svn_error_createf(
              SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL,
@@ -2530,32 +2427,25 @@ add_directory(const char *path,
                          svn_dirent_local_style(db->local_abspath, pool));
             }
 
-          if (switched && !eb->switch_url)
+          if (!err && switched && !eb->switch_relpath)
             {
               err = svn_error_createf(
                          SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL,
                          _("Switched directory '%s' does not match "
                            "expected URL '%s'"),
                          svn_dirent_local_style(db->local_abspath, pool),
-                         db->new_URL);
+                         svn_path_url_add_component2(eb->repos_root,
+                                                     db->new_relpath, pool));
             }
-        }
 
-      if (err != NULL)
-        {
-          db->already_notified = TRUE;
-          if (eb->notify_func)
+          if (err != NULL)
             {
-              svn_wc_notify_t *notify =
-                    svn_wc_create_notify(db->local_abspath,
-                                         svn_wc_notify_update_obstruction,
-                                         pool);
+              db->already_notified = TRUE;
+              do_notification(eb, db->local_abspath, svn_node_dir,
+                              svn_wc_notify_update_obstruction, pool);
 
-              notify->kind = svn_node_dir;
-              eb->notify_func(eb->notify_baton, notify, pool);
+              return svn_error_return(err);
             }
-
-          return svn_error_return(err);
         }
 
       /* What to do with a versioned or schedule-add dir:
@@ -2572,10 +2462,9 @@ add_directory(const char *path,
       if (status == svn_wc__db_status_added)
         {
           /* Specialize the added case to added, copied, moved */
-          SVN_ERR(svn_wc__db_scan_addition(&status, NULL, NULL, NULL, NULL, NULL,
-                                           NULL, NULL, NULL,
-                                           eb->db, db->local_abspath,
-                                           pool, pool));
+          SVN_ERR(svn_wc__db_scan_addition(&status, NULL, NULL, NULL, NULL,
+                                           NULL, NULL, NULL, NULL, eb->db,
+                                           db->local_abspath, pool, pool));
         }
 
       switch (status)
@@ -2604,21 +2493,22 @@ add_directory(const char *path,
             break;
           default:
             {
-              svn_wc_conflict_description2_t *tree_conflict;
+              svn_wc_conflict_description2_t *tree_conflict = NULL;
 
-              /* Raise a tree conflict. */
-              SVN_ERR(check_tree_conflict(&tree_conflict, eb,
-                                          db->local_abspath,
-                                          svn_wc_conflict_action_add,
-                                          svn_node_dir, db->new_URL,
-                                          db->inside_deleted_subtree,
-                                          pool));
+              /* Check for conflicts only when we haven't already recorded
+               * a tree-conflict on a parent node. */
+              if (!db->in_deleted_and_tree_conflicted_subtree)
+                SVN_ERR(check_tree_conflict(&tree_conflict, eb,
+                                            db->local_abspath,
+                                            svn_wc_conflict_action_add,
+                                            svn_node_dir, db->new_relpath, pool));
 
               if (tree_conflict != NULL)
                 {
-                  /* Record this conflict so that its descendants are
-                     skipped silently. */
-                  SVN_ERR(svn_wc__loggy_add_tree_conflict(&pb->log_accum,
+                  /* Queue this conflict in the parent so that its descendants
+                     are skipped silently. */
+                  SVN_ERR(svn_wc__loggy_add_tree_conflict(eb->db,
+                                                          pb->local_abspath,
                                                           tree_conflict,
                                                           pool));
 
@@ -2628,13 +2518,8 @@ add_directory(const char *path,
                   db->skip_descendants = TRUE;
                   db->already_notified = TRUE;
 
-                  if (eb->notify_func)
-                    eb->notify_func(eb->notify_baton,
-                                    svn_wc_create_notify(
-                                               db->local_abspath,
-                                               svn_wc_notify_tree_conflict,
-                                               pool),
-                                    pool);
+                  do_notification(eb, db->local_abspath, svn_node_unknown,
+                                  svn_wc_notify_tree_conflict, pool);
 
                   return SVN_NO_ERROR;
                 }
@@ -2718,10 +2603,11 @@ add_directory(const char *path,
 
           tmp_entry.revision = *(eb->target_revision);
 
-          if (eb->switch_url)
+          if (eb->switch_relpath)
             {
-              tmp_entry.url = svn_path_url_add_component2(eb->switch_url,
-                                                          db->name, pool);
+              tmp_entry.url = svn_path_url_add_component2(eb->repos_root,
+                                                          db->new_relpath,
+                                                          pool);
               modify_flags |= SVN_WC__ENTRY_MODIFY_URL;
             }
 
@@ -2732,7 +2618,8 @@ add_directory(const char *path,
     }
 
   SVN_ERR(prep_directory(db,
-                         db->new_URL,
+                         svn_path_url_add_component2(eb->repos_root,
+                                                     db->new_relpath, pool),
                          *(eb->target_revision),
                          db->pool));
 
@@ -2741,22 +2628,9 @@ add_directory(const char *path,
      prep_directory() otherwise the administrative area for DB->PATH
      is not present, nor is there an entry for DB->PATH in DB->PATH's
      entries. */
-  if (pb->inside_deleted_subtree)
+  if (pb->in_deleted_and_tree_conflicted_subtree)
     {
-      svn_wc_entry_t tmp_entry;
-      apr_uint64_t modify_flags = SVN_WC__ENTRY_MODIFY_SCHEDULE;
-
-      tmp_entry.schedule = svn_wc_schedule_delete;
-
-      /* Mark PATH as scheduled for deletion in its parent. */
-      SVN_ERR(svn_wc__entry_modify2(eb->db, db->local_abspath,
-                                    svn_node_dir, TRUE,
-                                    &tmp_entry, modify_flags, pool));
-
-      /* Mark PATH's 'this dir' entry as scheduled for deletion. */
-      SVN_ERR(svn_wc__entry_modify2(eb->db, db->local_abspath,

[... 2296 lines stripped ...]