You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by da...@apache.org on 2010/03/30 22:58:01 UTC

svn commit: r929279 [14/20] - in /subversion/branches/svn-patch-improvements: ./ build/ac-macros/ build/generator/ build/generator/templates/ contrib/client-side/emacs/ notes/feedback/ notes/meetings/ notes/wc-ng/ subversion/ subversion/bindings/javahl...

Modified: subversion/branches/svn-patch-improvements/subversion/libsvn_wc/update_editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-patch-improvements/subversion/libsvn_wc/update_editor.c?rev=929279&r1=929278&r2=929279&view=diff
==============================================================================
--- subversion/branches/svn-patch-improvements/subversion/libsvn_wc/update_editor.c (original)
+++ subversion/branches/svn-patch-improvements/subversion/libsvn_wc/update_editor.c Tue Mar 30 20:57:53 2010
@@ -170,7 +170,7 @@ struct edit_baton
 
   /* 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,
@@ -203,15 +203,15 @@ struct edit_baton
      that the edit was completed successfully. */
   svn_boolean_t close_edit_complete;
 
-  /* If this is a 'switch' operation, the target URL (### corresponding to
-     the ANCHOR plus TARGET path?), else NULL. */
-  const char *switch_url;
+  /* 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). */
@@ -278,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;
@@ -336,7 +336,11 @@ struct dir_baton
   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. */
@@ -417,7 +421,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,
@@ -440,30 +454,54 @@ get_empty_tmp_file(const char **tmp_file
 }
 
 
-/* Return the url for LOCAL_ABSPATH 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 *
-node_get_url_ignore_errors(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__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);
 
-  err = svn_wc__node_get_url(&url, wc_ctx, local_abspath, result_pool,
-                                                          scratch_pool);
   if (err)
     {
       svn_error_clear(err);
-      url = NULL;
+      return NULL;
     }
 
-  return url;
+  if (relpath)
+    return relpath;
+
+  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_error_clear(svn_wc__db_scan_base_repos(&relpath, NULL, NULL,
+                                                 db, local_abspath,
+                                                 result_pool, scratch_pool));
+    }
+
+  return relpath;
 }
 
 /* Flush accumulated log entries to a log file on disk for DIR_BATON and
@@ -472,12 +510,8 @@ node_get_url_ignore_errors(svn_wc_contex
 static svn_error_t *
 flush_log(struct dir_baton *db, apr_pool_t *pool)
 {
-  if (! svn_stringbuf_isempty(db->log_accum))
-    {
-      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_WC__FLUSH_LOG_ACCUM(db->edit_baton->db, db->local_abspath,
+                          db->log_accum, pool);
 
   return SVN_NO_ERROR;
 }
@@ -494,7 +528,9 @@ cleanup_dir_baton(void *dir_baton)
 
   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
@@ -505,11 +541,7 @@ cleanup_dir_baton(void *dir_baton)
      associated with a pool distinct from the edit pool and so were
      removed separately. */
   if (!err && !eb->close_edit_complete)
-    {
-      svn_wc_context_t fake_ctx;
-      fake_ctx.db = eb->db;
-      err = svn_wc__release_write_lock(&fake_ctx, db->local_abspath, pool);
-    }
+    err = svn_wc__release_write_lock(eb->wc_ctx, db->local_abspath, pool);
 
   if (err)
     {
@@ -573,8 +605,8 @@ make_dir_baton(struct dir_baton **d_p,
       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
@@ -584,9 +616,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
@@ -595,10 +627,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 */
@@ -606,11 +638,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 = node_get_url_ignore_errors(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 */
@@ -663,6 +694,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
@@ -687,14 +737,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);
@@ -706,11 +756,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))
@@ -722,11 +771,6 @@ 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;
@@ -736,26 +780,13 @@ complete_directory(struct edit_baton *eb
   SVN_ERR(svn_wc__db_temp_op_set_base_incomplete(eb->db, local_abspath, FALSE,
                                                  pool));
 
-  /* ### If we are updating below a delete-* treeconflict, all the
-         entries are moved to the copied state. This duplicates the incomplete
-         state to WORKING_NODE, so also clear it there. */
-  {
-    svn_wc__db_status_t status;
-    SVN_ERR(svn_wc__db_read_info(&status, NULL, NULL, NULL, NULL, NULL, NULL,
-                                 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-                                 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-                                 NULL, NULL, NULL,
-                                 eb->db, local_abspath, pool, pool));
-
-    if (status == svn_wc__db_status_incomplete)
-      SVN_ERR(svn_wc__db_temp_op_set_working_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,
@@ -841,16 +872,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);
         }
     }
 
@@ -902,8 +928,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;
@@ -997,9 +1023,6 @@ struct file_baton
 
   /* Bump information for the directory this file lives in */
   struct bump_dir_info *bump_info;
-
-  /* log accumulator; will be flushed and run in close_file(). */
-  svn_stringbuf_t *log_accum;
 };
 
 
@@ -1025,19 +1048,12 @@ 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 = node_get_url_ignore_errors(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;
@@ -1049,8 +1065,6 @@ make_file_baton(struct file_baton **f_p,
   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 */
@@ -1060,24 +1074,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)
 {
@@ -1156,7 +1154,7 @@ 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;
 
@@ -1167,17 +1165,17 @@ 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));
 
   SVN_ERR(svn_wc_locked2(&locked_here, NULL, db->edit_baton->wc_ctx,
@@ -1204,18 +1202,27 @@ struct last_change_info
   const char *cmt_author;
 };
 
-/* Accumulate last change info in LAST_CHANGE to set on LOCAL_ABSPATH.
-   ENTRY_PROPS is an array of svn_prop_t* entry props.
-   If ENTRY_PROPS contains the removal of a lock token, the lock info is
-   directly removed from LOCAL_ABSPATH in DB 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. */
+/* 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_last_change(struct last_change_info **last_change,
                        svn_wc_notify_lock_state_t *lock_state,
                        svn_wc__db_t *db,
                        const char *local_abspath,
-                       apr_array_header_t *entry_props,
+                       const apr_array_header_t *entry_props,
                        apr_pool_t *scratch_pool,
                        apr_pool_t *result_pool)
 {
@@ -1233,6 +1240,7 @@ accumulate_last_change(struct last_chang
          defunct, so remove it directly. */
       if (! strcmp(prop->name, SVN_PROP_ENTRY_LOCK_TOKEN))
         {
+          SVN_ERR_ASSERT(prop->value == NULL);
           SVN_ERR(svn_wc__db_lock_remove(db, local_abspath, scratch_pool));
 
           if (lock_state)
@@ -1319,7 +1327,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,
@@ -1367,12 +1374,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;
     }
@@ -1380,33 +1383,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;
 
       /* 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;
-      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_set_base_incomplete(eb->db, db->local_abspath,
-                                                     TRUE, 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;
@@ -1488,6 +1481,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,
@@ -1573,10 +1567,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.
@@ -1590,7 +1585,7 @@ 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,
+                    const char *their_relpath,
                     apr_pool_t *pool)
 {
   svn_wc__db_status_t status;
@@ -1756,8 +1751,7 @@ check_tree_conflict(svn_wc_conflict_desc
     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)
+  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);
@@ -1775,8 +1769,8 @@ check_tree_conflict(svn_wc_conflict_desc
     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 
+
+    /* 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)
@@ -1842,8 +1836,7 @@ check_tree_conflict(svn_wc_conflict_desc
         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)
+        else if (base_kind == svn_wc__db_kind_dir)
           left_kind = svn_node_dir;
         else
           SVN_ERR_MALFUNCTION();
@@ -1852,13 +1845,12 @@ check_tree_conflict(svn_wc_conflict_desc
 
     /* Find the source-right information, i.e. the state in the repository
      * to which we would like to update. */
-    if (eb->switch_url != NULL)
+    if (eb->switch_relpath)
       {
         /* If this is a 'switch' operation, try to construct the switch
          * target's REPOS_RELPATH. */
-        if (their_url != NULL)
-          right_repos_relpath = svn_uri_is_child(repos_root_url, their_url,
-                                                 pool);
+        if (their_relpath != NULL)
+          right_repos_relpath = their_relpath;
         else
           {
             /* The complete source-right URL is not available, but it
@@ -1867,8 +1859,7 @@ check_tree_conflict(svn_wc_conflict_desc
              * ### 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 = svn_uri_is_child(repos_root_url,
-                                                   eb->switch_url, pool);
+            right_repos_relpath = eb->switch_relpath;
             right_repos_relpath = apr_pstrcat(pool, right_repos_relpath,
                                               "_THIS_IS_INCOMPLETE", NULL);
           }
@@ -1905,7 +1896,7 @@ check_tree_conflict(svn_wc_conflict_desc
                                                         left_revision,
                                                         left_kind,
                                                         pool);
-    
+
     src_right_version = svn_wc_conflict_version_create(repos_root_url,
                                                        right_repos_relpath,
                                                        *eb->target_revision,
@@ -1914,7 +1905,7 @@ check_tree_conflict(svn_wc_conflict_desc
 
     *pconflict = svn_wc_conflict_description_create_tree2(
                      local_abspath, conflict_node_kind,
-                     eb->switch_url ?
+                     eb->switch_relpath ?
                        svn_wc_operation_switch : svn_wc_operation_update,
                      src_left_version, src_right_version, pool);
     (*pconflict)->action = action;
@@ -2049,236 +2040,31 @@ node_already_conflicted(svn_boolean_t *c
   return SVN_NO_ERROR;
 }
 
-
-/* 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 */
-  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,
+                  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 = 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,
@@ -2288,12 +2074,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;
     }
@@ -2321,23 +2103,25 @@ do_entry_deletion(struct edit_baton *eb,
   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_url, pool));
+                                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_stringbuf_t *log_accum = NULL;
+
+        SVN_ERR(svn_wc__loggy_add_tree_conflict(&log_accum, tree_conflict,
+                                                pool));
+        SVN_ERR(svn_wc__wq_add_loggy(eb->db, dir_abspath, log_accum, 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)
         {
@@ -2352,12 +2136,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)
@@ -2381,12 +2166,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
@@ -2396,7 +2182,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));
 
@@ -2406,27 +2191,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
@@ -2443,7 +2232,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(
@@ -2459,18 +2248,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;
 }
@@ -2486,7 +2271,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);
 
@@ -2500,13 +2285,13 @@ 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);
+  their_relpath = svn_relpath_join(pb->new_relpath, base, pool);
 
   /* Flush parent log before potentially adding tree conflicts */
-  flush_log(pb, pool);
+  SVN_ERR(flush_log(pb, pool));
 
   return do_entry_deletion(pb->edit_baton, local_abspath,
-                           their_url,
+                           their_relpath,
                            pb->in_deleted_and_tree_conflicted_subtree,
                            pool);
 }
@@ -2588,12 +2373,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;
     }
@@ -2613,7 +2394,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)
@@ -2630,16 +2410,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,
@@ -2657,16 +2429,8 @@ add_directory(const char *path,
       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,
@@ -2700,32 +2464,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:
@@ -2781,7 +2538,7 @@ add_directory(const char *path,
                 SVN_ERR(check_tree_conflict(&tree_conflict, eb,
                                             db->local_abspath,
                                             svn_wc_conflict_action_add,
-                                            svn_node_dir, db->new_URL, pool));
+                                            svn_node_dir, db->new_relpath, pool));
 
               if (tree_conflict != NULL)
                 {
@@ -2797,13 +2554,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;
                 }
@@ -2887,10 +2639,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;
             }
 
@@ -2901,7 +2654,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));
 
@@ -2912,25 +2666,7 @@ add_directory(const char *path,
      entries. */
   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));
-
-      /* ### HACK: Remove the incomplete status or the next entry_modify2
-                    will move the incomplete status to WORKING_NODE */
-      SVN_ERR(svn_wc__db_temp_op_set_base_incomplete(eb->db, db->local_abspath,
-                                                     FALSE, pool));
-
-      /* Mark PATH's 'this dir' entry as scheduled for deletion. */
-      SVN_ERR(svn_wc__entry_modify2(eb->db, db->local_abspath,
-                                    svn_node_dir, FALSE,
-                                    &tmp_entry, modify_flags, pool));
+      SVN_ERR(svn_wc__db_temp_op_delete(eb->db, db->local_abspath, pool));
     }
 
   /* If this add was obstructed by dir scheduled for addition without
@@ -2940,7 +2676,6 @@ add_directory(const char *path,
      issued. */
   if (eb->notify_func && !db->already_notified && !db->add_existed)
     {
-      svn_wc_notify_t *notify;
       svn_wc_notify_action_t action;
 
       if (db->in_deleted_and_tree_conflicted_subtree)
@@ -2950,10 +2685,9 @@ add_directory(const char *path,
       else
         action = svn_wc_notify_update_add;
 
-      notify = svn_wc_create_notify(db->local_abspath, action, pool);
-      notify->kind = svn_node_dir;
-      eb->notify_func(eb->notify_baton, notify, pool);
       db->already_notified = TRUE;
+
+      do_notification(eb, db->local_abspath, svn_node_dir, action, pool);
     }
 
   return SVN_NO_ERROR;
@@ -2969,17 +2703,17 @@ open_directory(const char *path,
 {
   struct dir_baton *db, *pb = parent_baton;
   struct edit_baton *eb = pb->edit_baton;
-  svn_wc_entry_t tmp_entry;
-  apr_uint64_t flags = SVN_WC__ENTRY_MODIFY_REVISION |
-    SVN_WC__ENTRY_MODIFY_URL;
-
+  svn_boolean_t base_shadowed;
   svn_boolean_t already_conflicted;
   svn_wc_conflict_description2_t *tree_conflict = NULL;
-  svn_wc__db_status_t status;
+  svn_wc__db_status_t status, base_status;
 
   SVN_ERR(make_dir_baton(&db, path, eb, pb, FALSE, pool));
   *child_baton = db;
 
+  /* We should have a write lock on every directory touched.  */
+  SVN_ERR(svn_wc__write_check(eb->db, db->local_abspath, pool));
+
   if (pb->skip_descendants)
     {
       if (!pb->skip_this)
@@ -3002,11 +2736,20 @@ open_directory(const char *path,
   SVN_ERR(svn_wc__db_read_info(&status, NULL, &db->old_revision, NULL, NULL,
                                NULL, NULL, NULL, NULL, NULL,
                                &db->ambient_depth, 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, db->local_abspath, pool, pool));
 
-  db->was_incomplete = (status == svn_wc__db_status_incomplete);
+  if (!base_shadowed)
+    base_status = status;
+  else
+    SVN_ERR(svn_wc__db_base_get_info(&base_status, NULL, &db->old_revision,
+                                     NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+                                     &db->ambient_depth, NULL, NULL, NULL,
+                                     NULL,
+                                     eb->db, db->local_abspath, pool, pool));
+
+  db->was_incomplete = (base_status == svn_wc__db_status_incomplete);
 
   /* Is this path a conflict victim? */
   SVN_ERR(node_already_conflicted(&already_conflicted, eb->db,
@@ -3019,12 +2762,8 @@ open_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_skip,
-                                             pool),
-                        pool);
+      do_notification(eb, db->local_abspath, svn_node_unknown,
+                      svn_wc_notify_skip, pool);
 
       return SVN_NO_ERROR;
     }
@@ -3037,7 +2776,7 @@ open_directory(const char *path,
   if (!db->in_deleted_and_tree_conflicted_subtree)
     SVN_ERR(check_tree_conflict(&tree_conflict, eb, db->local_abspath,
                                 svn_wc_conflict_action_edit, svn_node_dir,
-                                db->new_URL, pool));
+                                db->new_relpath, pool));
 
   /* Remember the roots of any locally deleted trees. */
   if (tree_conflict != NULL)
@@ -3045,17 +2784,9 @@ open_directory(const char *path,
       SVN_ERR(svn_wc__loggy_add_tree_conflict(&pb->log_accum, tree_conflict,
                                               pool));
 
-      if (eb->notify_func)
-        {
-          svn_wc_notify_t *notify
-              = svn_wc_create_notify(db->local_abspath,
-                                     svn_wc_notify_tree_conflict,
-                                     pool);
-          notify->kind = svn_node_dir;
-
-          eb->notify_func(eb->notify_baton, notify, pool);
-          db->already_notified = TRUE;
-        }
+      do_notification(eb, db->local_abspath, svn_node_dir,
+                      svn_wc_notify_tree_conflict, pool);
+      db->already_notified = TRUE;
 
       /* Even if PATH is locally deleted we still need mark it as being
          at TARGET_REVISION, so fall through to the code below to do just
@@ -3074,16 +2805,10 @@ open_directory(const char *path,
     }
 
   /* Mark directory as being at target_revision and URL, but incomplete. */
-  tmp_entry.revision = *(eb->target_revision);
-  tmp_entry.url = db->new_URL;
-
-  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_set_base_incomplete(eb->db, db->local_abspath,
-                                                 TRUE, 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;
 }
@@ -3114,7 +2839,7 @@ change_dir_prop(void *dir_baton,
    null.  If PROPCHANGES contains more than one such change, return
    the first. */
 static const svn_prop_t *
-externals_prop_changed(apr_array_header_t *propchanges)
+externals_prop_changed(const apr_array_header_t *propchanges)
 {
   int i;
 
@@ -3189,10 +2914,12 @@ close_directory(void *dir_baton,
     {
       db->bump_info->skipped = TRUE;
 
-      SVN_ERR(flush_log(db, pool));
+      /* The log accumulator better be empty because we aren't going to
+         be running any logs in this directory.  */
+      SVN_ERR_ASSERT(svn_stringbuf_isempty(db->log_accum));
 
       /* Allow the parent to complete its update. */
-      SVN_ERR(maybe_bump_dir_info(db->edit_baton, db->bump_info, db->pool));
+      SVN_ERR(maybe_bump_dir_info(eb, db->bump_info, db->pool));
 
       return SVN_NO_ERROR;
     }
@@ -3210,7 +2937,7 @@ close_directory(void *dir_baton,
       apr_hash_t *props_to_delete;
       svn_wc__db_kind_t kind;
 
-      SVN_ERR(svn_wc__db_read_kind(&kind, db->edit_baton->db,
+      SVN_ERR(svn_wc__db_read_kind(&kind, eb->db,
                                    db->local_abspath, TRUE, pool));
       if (kind == svn_wc__db_kind_unknown)
         {
@@ -3220,7 +2947,7 @@ close_directory(void *dir_baton,
       else
         {
           SVN_ERR(svn_wc__load_props(&base_props, &working_props,
-                                     db->edit_baton->db, db->local_abspath,
+                                     eb->db, db->local_abspath,
                                      pool, pool));
         }
 
@@ -3244,15 +2971,12 @@ close_directory(void *dir_baton,
      to deal with them. */
   if (regular_props->nelts || entry_props->nelts || wc_props->nelts)
     {
-      /* Make a temporary log accumulator for dirprop changes.*/
-      svn_stringbuf_t *dirprop_log = svn_stringbuf_create("", pool);
-
       if (regular_props->nelts)
         {
           /* If recording traversal info, then see if the
              SVN_PROP_EXTERNALS property on this directory changed,
              and record before and after for the change. */
-            if (db->edit_baton->external_func)
+            if (eb->external_func)
             {
               const svn_prop_t *change = externals_prop_changed(regular_props);
 
@@ -3262,7 +2986,7 @@ close_directory(void *dir_baton,
                   const svn_string_t *old_val_s;
 
                   SVN_ERR(svn_wc__internal_propget(
-                           &old_val_s, db->edit_baton->db, db->local_abspath,
+                           &old_val_s, eb->db, db->local_abspath,
                            SVN_PROP_EXTERNALS, db->pool, db->pool));
 
                   if ((new_val_s == NULL) && (old_val_s == NULL))
@@ -3273,8 +2997,8 @@ close_directory(void *dir_baton,
                   else if (old_val_s || new_val_s)
                     /* something changed, record the change */
                     {
-                      SVN_ERR((db->edit_baton->external_func)(
-                                           db->edit_baton->external_baton,
+                      SVN_ERR((eb->external_func)(
+                                           eb->external_baton,
                                            db->local_abspath,
                                            old_val_s,
                                            new_val_s,
@@ -3286,8 +3010,7 @@ close_directory(void *dir_baton,
 
           /* Merge pending properties into temporary files (ignoring
              conflicts). */
-          SVN_ERR_W(svn_wc__merge_props(&dirprop_log,
-                                        &prop_state,
+          SVN_ERR_W(svn_wc__merge_props(&prop_state,
                                         &new_base_props,
                                         &new_actual_props,
                                         eb->db,
@@ -3299,10 +3022,10 @@ close_directory(void *dir_baton,
                                         regular_props,
                                         TRUE /* base_merge */,
                                         FALSE /* dry_run */,
-                                        db->edit_baton->conflict_func,
-                                        db->edit_baton->conflict_baton,
-                                        db->edit_baton->cancel_func,
-                                        db->edit_baton->cancel_baton,
+                                        eb->conflict_func,
+                                        eb->conflict_baton,
+                                        eb->cancel_func,
+                                        eb->cancel_baton,
                                         db->pool,
                                         pool),
                     _("Couldn't do property merge"));
@@ -3320,18 +3043,15 @@ close_directory(void *dir_baton,
                                                                      pool),
                                                 pool));
         }
-
-      /* Add the dirprop loggy entries to the baton's log
-         accumulator. */
-      svn_stringbuf_appendstr(db->log_accum, dirprop_log);
     }
 
+  /* Queue some items to install the properties.  */
   if (new_base_props || new_actual_props)
     SVN_ERR(svn_wc__install_props(eb->db, db->local_abspath,
                                   new_base_props, new_actual_props,
                                   TRUE /* write_base_props */, TRUE, pool));
 
-  /* Flush and run the log. */
+  /* Flush the log.  */
   SVN_ERR(flush_log(db, pool));
 
   if (last_change)
@@ -3341,12 +3061,15 @@ close_directory(void *dir_baton,
                                                     last_change->cmt_author,
                                                     pool));
 
-  SVN_ERR(svn_wc__run_log2(eb->db, db->local_abspath, pool));
+  /* Process all of the queued work items for this directory.  */
+  SVN_ERR(svn_wc__wq_run(eb->db, db->local_abspath,
+                         eb->cancel_func, eb->cancel_baton,
+                         pool));
 
   /* We're done with this directory, so remove one reference from the
      bump information. This may trigger a number of actions. See
      maybe_bump_dir_info() for more information.  */
-  SVN_ERR(maybe_bump_dir_info(db->edit_baton, db->bump_info, db->pool));
+  SVN_ERR(maybe_bump_dir_info(eb, db->bump_info, db->pool));
 
   /* Notify of any prop changes on this directory -- but do nothing if
      it's an added or skipped directory, because notification has already
@@ -3368,10 +3091,10 @@ close_directory(void *dir_baton,
       notify = svn_wc_create_notify(db->local_abspath, action, pool);
       notify->kind = svn_node_dir;
       notify->prop_state = prop_state;
-      notify->revision = *db->edit_baton->target_revision;
+      notify->revision = *eb->target_revision;
       notify->old_revision = db->old_revision;
 
-      eb->notify_func(db->edit_baton->notify_baton, notify, pool);
+      eb->notify_func(eb->notify_baton, notify, pool);
     }
 
   bdi = db->bump_info;
@@ -3693,8 +3416,8 @@ copy_regular_props(apr_hash_t *props_in,
 
   for (hi = apr_hash_first(pool, props_in); hi; hi = apr_hash_next(hi))
     {
-      const char *propname = svn_apr_hash_index_key(hi);
-      svn_string_t *propval = svn_apr_hash_index_val(hi);
+      const char *propname = svn__apr_hash_index_key(hi);
+      svn_string_t *propval = svn__apr_hash_index_val(hi);
 
       if (svn_property_kind(NULL, propname) == svn_prop_regular_kind)
         apr_hash_set(props_out, propname, APR_HASH_KEY_STRING, propval);
@@ -3726,7 +3449,6 @@ add_file_with_history(const char *path,
   apr_hash_t *base_props, *working_props;
   svn_error_t *err;
   svn_stream_t *copied_stream;
-  const char *temp_dir_abspath;
   const char *src_local_abspath;
   svn_wc__db_t *db = eb->db;
   const char *dir_repos_relpath, *dir_repos_root, *dir_repos_uuid;
@@ -3752,13 +3474,10 @@ add_file_with_history(const char *path,
   else
     SVN_ERR(err);
 
-  SVN_ERR(svn_wc__db_temp_wcroot_tempdir(&temp_dir_abspath, db, pb->local_abspath,
-                                         subpool, subpool));
-  SVN_ERR(svn_stream_open_unique(&copied_stream,
-                                 &tfb->copied_text_base,
-                                 temp_dir_abspath,
-                                 svn_io_file_del_none,
-                                 pool, pool));
+  /* Open the text base for writing (this will get us a temporary file).  */
+  SVN_ERR(svn_wc__open_writable_base(&copied_stream, &tfb->copied_text_base,
+                                     db, pb->local_abspath,
+                                     pool, pool));
 #ifdef SVN_EXPERIMENTAL
   /* Copy the 'copied_stream' into a WC-NG pristine temp file as well. */
   SVN_ERR(get_pristine_tee_stream(&copied_stream, &tfb->temp_pristine_abspath,
@@ -3805,6 +3524,11 @@ add_file_with_history(const char *path,
           SVN_ERR(svn_wc__get_pristine_contents(&source_text_base, db,
                                                 src_local_abspath,
                                                 subpool, subpool));
+
+          /* If this has no base, should we use an empty stream?
+           * This assert wants to verify that there are no such callers. */
+          SVN_ERR_ASSERT(source_text_base != NULL);
+          
           SVN_ERR(svn_wc__load_props(&base_props, &working_props, db,
                                      src_local_abspath, pool, subpool));
         }
@@ -3924,12 +3648,8 @@ add_file(const char *path,
       fb->skip_this = TRUE;
       fb->already_notified = TRUE;
 
-      if (eb->notify_func)
-        eb->notify_func(eb->notify_baton,
-                        svn_wc_create_notify(fb->local_abspath,
-                                             svn_wc_notify_skip,
-                                             subpool),
-                        subpool);
+      do_notification(eb, fb->local_abspath, svn_node_unknown,
+                      svn_wc_notify_skip, subpool);
 
       svn_pool_destroy(subpool);
 
@@ -3969,16 +3689,8 @@ add_file(const char *path,
        wc_kind != svn_wc__db_kind_symlink && IS_NODE_PRESENT(status)))
     {
       fb->already_notified = TRUE;
-      if (eb->notify_func)
-        {
-          svn_wc_notify_t *notify =
-                svn_wc_create_notify(fb->local_abspath,
-                                     svn_wc_notify_update_obstruction,
-                                     pool);
-
-          notify->kind = svn_node_file;
-          eb->notify_func(eb->notify_baton, notify, pool);
-        }
+      do_notification(eb, fb->local_abspath, svn_node_file,
+                      svn_wc_notify_update_obstruction, pool);
 
       return svn_error_createf(
                SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL,
@@ -3995,16 +3707,8 @@ add_file(const char *path,
 
       if (!eb->allow_unver_obstructions)
         {
-          if (eb->notify_func)
-            {
-              svn_wc_notify_t *notify =
-                      svn_wc_create_notify(fb->local_abspath,
-                                           svn_wc_notify_update_obstruction,
-                                           pool);
-
-              notify->kind = svn_node_file;
-              eb->notify_func(eb->notify_baton, notify, pool);
-            }
+          do_notification(eb, fb->local_abspath, svn_node_file,
+                          svn_wc_notify_update_obstruction, pool);
 
           return svn_error_createf(
              SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL,
@@ -4036,29 +3740,22 @@ add_file(const char *path,
                          svn_dirent_local_style(fb->local_abspath, pool));
             }
 
-          if (switched && !eb->switch_url)
+          if (switched && !eb->switch_relpath)
             {
               err = svn_error_createf(
                          SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL,
                          _("Switched file '%s' does not match "
                            "expected URL '%s'"),
                          svn_dirent_local_style(fb->local_abspath, pool),
-                         fb->new_URL);
+                         svn_path_url_add_component2(eb->repos_root,
+                                                     fb->new_relpath, pool));
             }
 
           if (err != NULL)
             {
               fb->already_notified = TRUE;
-              if (eb->notify_func)
-                {
-                  svn_wc_notify_t *notify =
-                        svn_wc_create_notify(fb->local_abspath,
-                                             svn_wc_notify_update_obstruction,
-                                             pool);
-
-                  notify->kind = svn_node_file;
-                  eb->notify_func(eb->notify_baton, notify, pool);
-                }
+              do_notification(eb, fb->local_abspath, svn_node_file,
+                              svn_wc_notify_update_obstruction, pool);
 
               return svn_error_return(err);
             }
@@ -4119,27 +3816,27 @@ add_file(const char *path,
                 SVN_ERR(check_tree_conflict(&tree_conflict, eb,
                                             fb->local_abspath,
                                             svn_wc_conflict_action_add,
-                                            svn_node_file, fb->new_URL,
+                                            svn_node_file, fb->new_relpath,
                                             subpool));
 
               if (tree_conflict != NULL)
                 {
+                  svn_stringbuf_t *log_accum = NULL;
+
                   /* Record the conflict so that the file is skipped silently
                      by the other callbacks. */
-                  SVN_ERR(svn_wc__loggy_add_tree_conflict(&fb->log_accum,
+                  SVN_ERR(svn_wc__loggy_add_tree_conflict(&log_accum,
                                                           tree_conflict,
                                                           subpool));
+                  SVN_ERR(svn_wc__wq_add_loggy(eb->db, pb->local_abspath,
+                                               log_accum, subpool));
+
                   SVN_ERR(remember_skipped_tree(eb, fb->local_abspath));
                   fb->skip_this = TRUE;
                   fb->already_notified = TRUE;
 
-                  if (eb->notify_func)
-                    eb->notify_func(eb->notify_baton,
-                                    svn_wc_create_notify(
-                                           fb->local_abspath,
-                                           svn_wc_notify_tree_conflict,
-                                           subpool),
-                                    subpool);
+                  do_notification(eb, fb->local_abspath, svn_node_unknown,
+                                  svn_wc_notify_tree_conflict, subpool);
 
                   return SVN_NO_ERROR;
                 }
@@ -4217,12 +3914,8 @@ open_file(const char *path,
       fb->skip_this = TRUE;
       fb->already_notified = TRUE;
 
-      if (eb->notify_func)
-        eb->notify_func(eb->notify_baton,
-                        svn_wc_create_notify(fb->local_abspath,
-                                             svn_wc_notify_skip,
-                                             subpool),
-                        subpool);
+      do_notification(eb, fb->local_abspath, svn_node_unknown,
+                      svn_wc_notify_skip, subpool);
 
       svn_pool_destroy(subpool);
 
@@ -4236,13 +3929,17 @@ open_file(const char *path,
   if (!pb->in_deleted_and_tree_conflicted_subtree)
     SVN_ERR(check_tree_conflict(&tree_conflict, eb, fb->local_abspath,
                                 svn_wc_conflict_action_edit, svn_node_file,
-                                fb->new_URL, pool));
+                                fb->new_relpath, pool));
 
   /* Is this path the victim of a newly-discovered tree conflict? */
   if (tree_conflict)
     {
-      SVN_ERR(svn_wc__loggy_add_tree_conflict(&fb->log_accum, tree_conflict,
+      svn_stringbuf_t *log_accum = NULL;
+
+      SVN_ERR(svn_wc__loggy_add_tree_conflict(&log_accum, tree_conflict,
                                               pool));
+      SVN_ERR(svn_wc__wq_add_loggy(eb->db, pb->local_abspath, log_accum,
+                                   pool));
 
       if (tree_conflict->reason == svn_wc_conflict_reason_deleted ||
           tree_conflict->reason == svn_wc_conflict_reason_replaced)
@@ -4256,12 +3953,8 @@ open_file(const char *path,
         fb->skip_this = TRUE;
 
       fb->already_notified = TRUE;
-      if (eb->notify_func)
-        eb->notify_func(eb->notify_baton,
-                        svn_wc_create_notify(fb->local_abspath,
-                                             svn_wc_notify_tree_conflict,
-                                             pool),
-                         pool);
+      do_notification(eb, fb->local_abspath, svn_node_unknown,
+                      svn_wc_notify_tree_conflict, pool);
     }
 
   svn_pool_destroy(subpool);
@@ -4269,8 +3962,8 @@ open_file(const char *path,
   return SVN_NO_ERROR;
 }
 
-/* For the given PATH, fill out OLD_TEXT_BASE with the permanent text-base
-   path, or (if the entry is replaced with history) to the permanent
+/* For the given LOCAL_ABSPATH, set *OLD_TEXT_BASE_ABSPATH to the permanent
+   text-base path, or (if the entry is replaced with history) to the permanent
    revert-base path.
 
    If REPLACED_P is non-NULL, set *REPLACED_P to whether or not the
@@ -4278,13 +3971,10 @@ open_file(const char *path,
    use the revert base).  If CHECKSUM_P is non-NULL and the path
    already has an entry, set *CHECKSUM_P to the entry's checksum.
 
-   ROOT_ACCESS is an access baton which can be used to find associated
-   batons for the directory that PATH resides within.
-
    Use SCRATCH_POOL for temporary allocation and for *CHECKSUM_P (if
-   applicable), but allocate OLD_TEXT_BASE in RESULT_POOL. */
+   applicable), but allocate OLD_TEXT_BASE_ABSPATH in RESULT_POOL. */
 static svn_error_t *
-choose_base_paths(const char **old_text_base,
+choose_base_paths(const char **old_text_base_abspath,
                   const char **checksum_p,
                   svn_boolean_t *replaced_p,
                   svn_wc__db_t *db,
@@ -4301,10 +3991,10 @@ choose_base_paths(const char **old_text_
   replaced = entry && entry->schedule == svn_wc_schedule_replace;
   /* ### Should use pristine api here */
   if (replaced)
-    SVN_ERR(svn_wc__text_revert_path(old_text_base,
+    SVN_ERR(svn_wc__text_revert_path(old_text_base_abspath,
                                      db, local_abspath, result_pool));
   else
-    SVN_ERR(svn_wc__text_base_path(old_text_base,
+    SVN_ERR(svn_wc__text_base_path(old_text_base_abspath,
                                    db, local_abspath, FALSE, result_pool));
 
   if (checksum_p)
@@ -4391,9 +4081,13 @@ apply_textdelta(void *file_baton,
                                             fb->local_abspath,
                                             handler_pool, handler_pool));
       else
-        SVN_ERR(svn_wc__get_pristine_contents(&source, fb->edit_baton->db,
-                                             fb->local_abspath,
-                                             handler_pool, handler_pool));
+        {
+          SVN_ERR(svn_wc__get_pristine_contents(&source, fb->edit_baton->db,
+                                                fb->local_abspath,
+                                                handler_pool, handler_pool));
+          if (source == NULL)
+            source = svn_stream_empty(handler_pool);
+        }
     }
   else
     {
@@ -4426,8 +4120,7 @@ apply_textdelta(void *file_baton,
 
   /* Open the text base for writing (this will get us a temporary file).  */
   err = svn_wc__open_writable_base(&target, &hb->work_abspath,
-                                   fb->local_abspath,
-                                   replaced /* need_revert_base */,
+                                   fb->edit_baton->db, fb->local_abspath,
                                    handler_pool, pool);
   if (err)
     {
@@ -4492,106 +4185,20 @@ change_file_prop(void *file_baton,
 }
 
 
-/* TODO ### Update to mention DB, FILE_ABSPATH, DIR_ABSPATH; not ADM_ACCESS.
-
-   Write log commands to merge PROP_CHANGES into the existing
-   properties of FILE_PATH.  PROP_CHANGES can contain regular
-   properties as well as entryprops and wcprops.  Update *PROP_STATE
-   to reflect the result of the regular prop merge.  Make *LOCK_STATE
-   reflect the possible removal of a lock token from FILE_PATH's
-   entryprops.  BASE_PROPS and WORKING_PROPS are hashes of the base and
-   working props of the file; if NULL they are read from the wc.
-
-   CONFICT_FUNC/BATON is a callback which allows the client to
-   possibly resolve a property conflict interactively.
-
-   ADM_ACCESS is the access baton for FILE_PATH.  Append log commands to
-   LOG_ACCUM.  Use POOL for temporary allocations. */
-static svn_error_t *
-merge_props(svn_stringbuf_t *log_accum,
-            svn_wc_notify_state_t *prop_state,
-            svn_wc_notify_lock_state_t *lock_state,
-            apr_hash_t **new_base_props,
-            apr_hash_t **new_actual_props,
-            struct last_change_info **last_change,
-            svn_wc__db_t *db,
-            const char *file_abspath,
-            const char *dir_abspath,
-            const svn_wc_conflict_version_t *left_version,
-            const svn_wc_conflict_version_t *right_version,
-            const apr_array_header_t *prop_changes,
-            apr_hash_t *base_props,
-            apr_hash_t *working_props,
-            svn_wc_conflict_resolver_func_t conflict_func,
-            void *conflict_baton,
-            svn_cancel_func_t cancel_func,
-            void *cancel_baton,
-            apr_pool_t *pool)
-{
-  apr_array_header_t *regular_props = NULL, *wc_props = NULL,
-    *entry_props = NULL;
-
-  /* Sort the property list into three arrays, based on kind. */
-  SVN_ERR(svn_categorize_props(prop_changes, &entry_props, &wc_props,
-                               &regular_props, pool));
-
-  /* Always initialize to unknown state. */
-  *prop_state = svn_wc_notify_state_unknown;
-
-  /* Merge the 'regular' props into the existing working proplist. */
-  if (regular_props)
-    {
-      /* This will merge the old and new props into a new prop db, and
-         write <cp> commands to the logfile to install the merged
-         props.  */
-      SVN_ERR(svn_wc__merge_props(&log_accum,
-                                  prop_state,
-                                  new_base_props,
-                                  new_actual_props,
-                                  db,
-                                  file_abspath,
-                                  left_version,
-                                  right_version,
-                                  NULL /* update, not merge */,
-                                  base_props,
-                                  working_props,
-                                  regular_props, TRUE, FALSE,
-                                  conflict_func, conflict_baton,
-                                  cancel_func, cancel_baton,
-                                  pool,
-                                  pool));
-    }
-
-  /* If there are any ENTRY PROPS, make sure those get appended to the
-     growing log as fields for the file's entry.
-
-     Note that no merging needs to happen; these kinds of props aren't
-     versioned, so if the property is present, we overwrite the value. */
-  if (entry_props)
-    SVN_ERR(accumulate_last_change(last_change, lock_state,
-                                   db, file_abspath, entry_props,
-                                   pool, pool));
-  else
-    *lock_state = svn_wc_notify_lock_state_unchanged;
-
-  /* This writes a whole bunch of log commands to install wcprops.  */
-  if (wc_props)
-    SVN_ERR(svn_wc__db_base_set_dav_cache(db, file_abspath,
-                                          prop_hash_from_array(wc_props, pool),
-                                          pool));
-
-  return SVN_NO_ERROR;
-}
 
 /* Append to LOG_ACCUM, log commands to update the entry for LOCAL_ABSPATH
-   with a NEW_REVISION and a NEW_URL (if non-NULL), making sure
+   with a NEW_REVISION and a NEW_RELPATH(if non-NULL), making sure
    the entry refers to a file and has no absent or deleted state.
-   Use POOL for temporary allocations. */
+   Use POOL for temporary allocations.
+
+   ### REPOS_ROOT must be the current repository root while still using
+       entries here */
 static svn_error_t *
-loggy_tweak_base_node(svn_stringbuf_t *log_accum,
+loggy_tweak_base_node(svn_stringbuf_t **log_accum,
                       const char *local_abspath,
                       svn_revnum_t new_revision,
-                      const char *new_URL,
+                      const char *repos_root,
+                      const char *new_relpath,
                       apr_pool_t *pool)
 {
   /* Write log entry which will bump the revision number.  Also, just
@@ -4621,14 +4228,15 @@ loggy_tweak_base_node(svn_stringbuf_t *l
   tmp_entry.text_time = 0;
 
   /* Possibly install a *non*-inherited URL in the entry. */
-  if (new_URL)
+  if (new_relpath)
     {
-      tmp_entry.url = new_URL;
+      tmp_entry.url = svn_path_url_add_component2(repos_root, new_relpath,
+                                                  pool);
       modify_flags |= SVN_WC__ENTRY_MODIFY_URL;
     }
 
   return svn_error_return(
-    svn_wc__loggy_entry_modify(&log_accum,
+    svn_wc__loggy_entry_modify(log_accum,
                                svn_dirent_dirname(local_abspath, pool),
                                local_abspath, &tmp_entry, modify_flags,
                                pool, pool));
@@ -4695,25 +4303,21 @@ install_text_base(svn_stringbuf_t **log_
  * POOL is used for all bookkeeping work during the installation.
  */
 static svn_error_t *
-merge_file(svn_wc_notify_state_t *content_state,
-           svn_wc_notify_state_t *prop_state,
-           svn_wc_notify_lock_state_t *lock_state,
-           apr_hash_t **new_base_props,
-           apr_hash_t **new_actual_props,
-           struct last_change_info **last_change,
+merge_file(svn_stringbuf_t **log_accum,
+           svn_wc_notify_state_t *content_state,
+           const svn_wc_entry_t *entry,
            struct file_baton *fb,
            const char *new_text_base_abspath,
            const svn_checksum_t *actual_checksum,
+           svn_boolean_t lock_removed,
            apr_pool_t *pool)
 {
   struct edit_baton *eb = fb->edit_baton;
   struct dir_baton *pb = fb->dir_baton;
-  svn_stringbuf_t *log_accum = svn_stringbuf_create("", pool);
   svn_boolean_t is_locally_modified;
   svn_boolean_t is_replaced = FALSE;
   svn_boolean_t magic_props_changed;
   enum svn_wc_merge_outcome_t merge_outcome = svn_wc_merge_unchanged;
-  const svn_wc_entry_t *entry;
   svn_wc_conflict_version_t *left_version = NULL; /* ### Fill */
   svn_wc_conflict_version_t *right_version = NULL; /* ### Fill */
 
@@ -4733,44 +4337,23 @@ merge_file(svn_wc_notify_state_t *conten
          - fb->old_text_base_path is the old pristine F.
            (This is only set if there's a new text base).
 
-      The goal is to update the local working copy of F to reflect
-      the changes received from the repository, preserving any local
-      modifications.
+     The goal is to update the local working copy of F to reflect
+     the changes received from the repository, preserving any local
+     modifications.
   */
 
+#if 0
+  /* ### this will break update_tests 43. see comment in close_file()  */
+  SVN_WC__FLUSH_LOG_ACCUM(eb->db, pb->local_abspath, *log_accum, pool);
+#endif
+
   /* Start by splitting the file path, getting an access baton for the parent,
      and an entry for the file if any. */
 
-  SVN_ERR(svn_wc__get_entry(&entry, eb->db, fb->local_abspath, TRUE,
-                            svn_node_file, FALSE, pool, pool));
-  if (! entry && ! fb->added)
-    return svn_error_createf(
-        SVN_ERR_UNVERSIONED_RESOURCE, NULL,
-        _("'%s' is not under version control"),
-        svn_dirent_local_style(fb->local_abspath, pool));
-
   /* Determine if any of the propchanges are the "magic" ones that
      might require changing the working file. */
   magic_props_changed = svn_wc__has_magic_property(fb->propchanges);
 
-  /* Set the new revision and URL in the entry and clean up some other
-     fields. This clears DELETED from any prior versioned file with the
-     same name (needed before attempting to install props).  */
-  SVN_ERR(loggy_tweak_base_node(log_accum, fb->local_abspath,
-                                *eb->target_revision, fb->new_URL, pool));
-
-  /* Install all kinds of properties.  It is important to do this before

[... 1102 lines stripped ...]