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 2013/01/22 00:37:04 UTC

svn commit: r1436688 [4/12] - in /subversion/branches/ev2-export: ./ contrib/client-side/emacs/ notes/commit-access-templates/ subversion/bindings/javahl/native/ subversion/bindings/swig/perl/native/t/ subversion/bindings/swig/ruby/test/ subversion/inc...

Modified: subversion/branches/ev2-export/subversion/libsvn_client/patch.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_client/patch.c?rev=1436688&r1=1436687&r2=1436688&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_client/patch.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_client/patch.c Mon Jan 21 23:37:01 2013
@@ -175,6 +175,9 @@ typedef struct patch_target_t {
    * CONTENT->existed). */
   apr_file_t *file;
 
+  /* The target file is a symlink */
+  svn_boolean_t is_symlink;
+
   /* The patched file.
    * This is equivalent to the target, except that in appropriate
    * places it contains the modified text as it appears in the patch file.
@@ -437,48 +440,37 @@ resolve_target_path(patch_target_t *targ
                        result_pool, scratch_pool);
   if (err)
     {
-      if (err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
-        svn_error_clear(err);
-      else
+      if (err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND)
         return svn_error_trace(err);
+
+      svn_error_clear(err);
+
+      target->locally_deleted = TRUE;
+      target->db_kind = svn_node_none;
+      status = NULL;
     }
   else if (status->node_status == svn_wc_status_ignored ||
            status->node_status == svn_wc_status_unversioned ||
            status->node_status == svn_wc_status_missing ||
-           status->node_status == svn_wc_status_obstructed)
+           status->node_status == svn_wc_status_obstructed ||
+           status->conflicted)
     {
       target->skipped = TRUE;
       return SVN_NO_ERROR;
     }
-
-  SVN_ERR(svn_io_check_path(target->local_abspath,
-                            &target->kind_on_disk, scratch_pool));
-  err = svn_wc__node_is_status_deleted(&target->locally_deleted,
-                                       wc_ctx, target->local_abspath,
-                                       scratch_pool);
-  if (err)
+  else if (status->node_status == svn_wc_status_deleted)
     {
-      if (err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
-        {
-          svn_error_clear(err);
-          target->locally_deleted = FALSE;
-        }
-      else
-        return svn_error_trace(err);
+      target->locally_deleted = TRUE;
     }
-  SVN_ERR(svn_wc_read_kind(&target->db_kind, wc_ctx, target->local_abspath,
-                           FALSE, scratch_pool));
 
-  /* If the target is a versioned directory present on disk,
-   * and there are only property changes in the patch, we accept
-   * a directory target. Else, we skip directories. */
-  if (target->db_kind == svn_node_dir && ! prop_changes_only)
-    {
-      /* ### We cannot yet replace a locally deleted dir with a file,
-       * ### but some day we might want to allow it. */
-      target->skipped = TRUE;
-      return SVN_NO_ERROR;
-    }
+  if (status && (status->kind != svn_node_unknown))
+    target->db_kind = status->kind;
+  else
+    target->db_kind = svn_node_none;
+
+  SVN_ERR(svn_io_check_special_path(target->local_abspath,
+                                    &target->kind_on_disk, &target->is_symlink,
+                                    scratch_pool));
 
   if (target->locally_deleted)
     {
@@ -498,8 +490,10 @@ resolve_target_path(patch_target_t *targ
           /* As far as we are concerned this target is not locally deleted. */
           target->locally_deleted = FALSE;
 
-          SVN_ERR(svn_io_check_path(target->local_abspath,
-                                    &target->kind_on_disk, scratch_pool));
+          SVN_ERR(svn_io_check_special_path(target->local_abspath,
+                                            &target->kind_on_disk,
+                                            &target->is_symlink,
+                                            scratch_pool));
         }
       else if (target->kind_on_disk != svn_node_none)
         {
@@ -523,6 +517,8 @@ typedef struct prop_read_baton_t {
  * the property value runs out in which case *EOF is set to TRUE.
  * The line-terminator is not stored in *STRINGBUF.
  *
+ * If the line is empty or could not be read, *line is set to NULL.
+ *
  * The line-terminator is detected automatically and stored in *EOL
  * if EOL is not NULL. If the end of the property value is reached
  * and does not end with a newline character, and EOL is not NULL,
@@ -536,17 +532,15 @@ readline_prop(void *baton, svn_stringbuf
               apr_pool_t *scratch_pool)
 {
   prop_read_baton_t *b = (prop_read_baton_t *)baton;
-  svn_stringbuf_t *str;
+  svn_stringbuf_t *str = NULL;
   const char *c;
   svn_boolean_t found_eof;
 
-  str = svn_stringbuf_create_ensure(80, result_pool);
-
   if ((apr_uint64_t)b->offset >= (apr_uint64_t)b->value->len)
     {
       *eol_str = NULL;
       *eof = TRUE;
-      *line = str;
+      *line = NULL;
       return SVN_NO_ERROR;
     }
 
@@ -578,7 +572,11 @@ readline_prop(void *baton, svn_stringbuf
             }
         }
       else
-        svn_stringbuf_appendbyte(str, *c);
+        {
+          if (str == NULL)
+            str = svn_stringbuf_create_ensure(80, result_pool);
+          svn_stringbuf_appendbyte(str, *c);
+        }
 
       if (*eol_str)
         break;
@@ -652,7 +650,7 @@ init_prop_target(prop_patch_target_t **p
   content->hunks = apr_array_make(result_pool, 0, sizeof(hunk_info_t *));
   content->keywords = apr_hash_make(result_pool);
 
-  new_prop_target = apr_palloc(result_pool, sizeof(*new_prop_target));
+  new_prop_target = apr_pcalloc(result_pool, sizeof(*new_prop_target));
   new_prop_target->name = apr_pstrdup(result_pool, prop_name);
   new_prop_target->operation = operation;
   new_prop_target->content = content;
@@ -675,7 +673,7 @@ init_prop_target(prop_patch_target_t **p
 
 
   /* Wire up the read and write callbacks. */
-  prop_read_baton = apr_palloc(result_pool, sizeof(*prop_read_baton));
+  prop_read_baton = apr_pcalloc(result_pool, sizeof(*prop_read_baton));
   prop_read_baton->value = value;
   prop_read_baton->offset = 0;
   content->readline = readline_prop;
@@ -696,6 +694,8 @@ init_prop_target(prop_patch_target_t **p
  * or if EOF is reached in which case *EOF is set to TRUE.
  * The line-terminator is not stored in *STRINGBUF.
  *
+ * If the line is empty or could not be read, *line is set to NULL.
+ *
  * The line-terminator is detected automatically and stored in *EOL
  * if EOL is not NULL. If EOF is reached and FILE does not end
  * with a newline character, and EOL is not NULL, *EOL is set to NULL.
@@ -708,13 +708,11 @@ readline_file(void *baton, svn_stringbuf
               apr_pool_t *scratch_pool)
 {
   apr_file_t *file = (apr_file_t *)baton;
-  svn_stringbuf_t *str;
+  svn_stringbuf_t *str = NULL;
   apr_size_t numbytes;
   char c;
   svn_boolean_t found_eof;
 
-  str = svn_stringbuf_create_ensure(80, result_pool);
-
   /* Read bytes into STR up to and including, but not storing,
    * the next EOL sequence. */
   *eol_str = NULL;
@@ -761,7 +759,11 @@ readline_file(void *baton, svn_stringbuf
             }
         }
       else
-        svn_stringbuf_appendbyte(str, c);
+        {
+          if (str == NULL)
+            str = svn_stringbuf_create_ensure(80, result_pool);
+          svn_stringbuf_appendbyte(str, c);
+        }
 
       if (*eol_str)
         break;
@@ -807,6 +809,118 @@ write_file(void *baton, const char *buf,
   return SVN_NO_ERROR;
 }
 
+/* Handling symbolic links:
+ *
+ * In Subversion, symlinks can be represented on disk in two distinct ways.
+ * On systems which support symlinks, a symlink is created on disk.
+ * On systems which do not support symlink, a file is created on disk
+ * which contains the "normal form" of the symlink, which looks like:
+ *   link TARGET
+ * where TARGET is the file the symlink points to.
+ *
+ * When reading symlinks (i.e. the link itself, not the file the symlink
+ * is pointing to) through the svn_subst_create_specialfile() function
+ * into a buffer, the buffer always contains the "normal form" of the symlink.
+ * Due to this representation symlinks always contain a single line of text.
+ *
+ * The functions below are needed to deal with the case where a patch
+ * wants to change the TARGET that a symlink points to.
+ */
+
+/* Baton for the (readline|tell|seek|write)_symlink functions. */
+struct symlink_baton_t
+{
+  /* The path to the symlink on disk (not the path to the target of the link) */
+  const char *local_abspath;
+
+  /* Indicates whether the "normal form" of the symlink has been read. */
+  svn_boolean_t at_eof;
+};
+
+/* Allocate *STRINGBUF in RESULT_POOL, and store into it the "normal form"
+ * of the symlink accessed via BATON.
+ *
+ * Otherwise behaves like readline_file(), which see.
+ */
+static svn_error_t *
+readline_symlink(void *baton, svn_stringbuf_t **line, const char **eol_str,
+                 svn_boolean_t *eof, apr_pool_t *result_pool,
+                 apr_pool_t *scratch_pool)
+{
+  struct symlink_baton_t *sb = baton;
+
+  if (eof)
+    *eof = TRUE;
+  if (eol_str)
+    *eol_str = NULL;
+
+  if (sb->at_eof)
+    {
+      *line = NULL;
+    }
+  else
+    {
+      svn_string_t *dest;
+
+      SVN_ERR(svn_io_read_link(&dest, sb->local_abspath, scratch_pool));
+      *line = svn_stringbuf_createf(result_pool, "link %s", dest->data);
+      sb->at_eof = TRUE;
+    }
+
+  return SVN_NO_ERROR;
+}
+
+/* Set *OFFSET to 1 or 0 depending on whether the "normal form" of
+ * the symlink has already been read. */
+static svn_error_t *
+tell_symlink(void *baton, apr_off_t *offset, apr_pool_t *scratch_pool)
+{
+  struct symlink_baton_t *sb = baton;
+
+  *offset = sb->at_eof ? 1 : 0;
+  return SVN_NO_ERROR;
+}
+
+/* If offset is non-zero, mark the symlink as having been read in its
+ * "normal form". Else, mark the symlink as not having been read yet. */
+static svn_error_t *
+seek_symlink(void *baton, apr_off_t offset, apr_pool_t *scratch_pool)
+{
+  struct symlink_baton_t *sb = baton;
+
+  sb->at_eof = (offset != 0);
+  return SVN_NO_ERROR;
+}
+
+
+/* Set the target of the symlink accessed via BATON.
+ * The contents of BUF must be a valid "normal form" of a symlink. */
+static svn_error_t *
+write_symlink(void *baton, const char *buf, apr_size_t len,
+              apr_pool_t *scratch_pool)
+{
+  const char *target_abspath = baton;
+  const char *new_name;
+  const char *link = apr_pstrndup(scratch_pool, buf, len);
+
+  if (strncmp(link, "link ", 5) != 0)
+    return svn_error_create(SVN_ERR_IO_WRITE_ERROR, NULL,
+                            _("Invalid link representation"));
+
+  link += 5; /* Skip "link " */
+
+  /* We assume the entire symlink is written at once, as the patch
+     format is line based */
+
+  SVN_ERR(svn_io_create_unique_link(&new_name, target_abspath, link,
+                                    ".tmp", scratch_pool));
+
+  SVN_ERR(svn_io_file_rename(new_name, target_abspath, scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+
 /* Return a suitable filename for the target of PATCH.
  * Examine the ``old'' and ``new'' file names, and choose the file name
  * with the fewest path components, the shortest basename, and the shortest
@@ -912,7 +1026,21 @@ init_patch_target(patch_target_t **patch
 
       /* Create a temporary file to write the patched result to.
        * Also grab various bits of information about the file. */
-      if (target->kind_on_disk == svn_node_file)
+      if (target->is_symlink)
+        {
+          struct symlink_baton_t *sb = apr_pcalloc(result_pool, sizeof(*sb));
+          content->existed = TRUE;
+
+          sb->local_abspath = target->local_abspath;
+
+          /* Wire up the read callbacks. */
+          content->read_baton = sb;
+
+          content->readline = readline_symlink;
+          content->seek = seek_symlink;
+          content->tell = tell_symlink;
+        }
+      else if (target->kind_on_disk == svn_node_file)
         {
           SVN_ERR(svn_io_file_open(&target->file, target->local_abspath,
                                    APR_READ | APR_BUFFERED,
@@ -950,17 +1078,34 @@ init_patch_target(patch_target_t **patch
       else if (patch->operation == svn_diff_op_deleted)
         target->deleted = TRUE;
 
-      /* Open a temporary file to write the patched result to. */
-      SVN_ERR(svn_io_open_unique_file3(&target->patched_file,
-                                       &target->patched_path, NULL,
-                                       remove_tempfiles ?
-                                         svn_io_file_del_on_pool_cleanup :
-                                         svn_io_file_del_none,
-                                       result_pool, scratch_pool));
+      if (! target->is_symlink)
+        {
+          /* Open a temporary file to write the patched result to. */
+          SVN_ERR(svn_io_open_unique_file3(&target->patched_file,
+                                           &target->patched_path, NULL,
+                                           remove_tempfiles ?
+                                             svn_io_file_del_on_pool_cleanup :
+                                             svn_io_file_del_none,
+                                           result_pool, scratch_pool));
+
+          /* Put the write callback in place. */
+          content->write = write_file;
+          content->write_baton = target->patched_file;
+        }
+      else
+        {
+          /* Put the write callback in place. */
+          SVN_ERR(svn_io_open_unique_file3(NULL,
+                                           &target->patched_path, NULL,
+                                           remove_tempfiles ?
+                                             svn_io_file_del_on_pool_cleanup :
+                                             svn_io_file_del_none,
+                                           result_pool, scratch_pool));
 
-      /* Put the write callback in place. */
-      content->write = write_file;
-      content->write_baton = target->patched_file;
+          content->write_baton = (void*)target->patched_path;
+
+          content->write = write_symlink;
+        }
 
       /* Open a temporary file to write rejected hunks to. */
       SVN_ERR(svn_io_open_unique_file3(&target->reject_file,
@@ -1009,7 +1154,9 @@ init_patch_target(patch_target_t **patch
 }
 
 /* Read a *LINE from CONTENT. If the line has not been read before
- * mark the line in CONTENT->LINES. Allocate *LINE in RESULT_POOL.
+ * mark the line in CONTENT->LINES.
+ * If a line could be read successfully, increase CONTENT->CURRENT_LINE,
+ * and allocate *LINE in RESULT_POOL.
  * Do temporary allocations in SCRATCH_POOL.
  */
 static svn_error_t *
@@ -1044,14 +1191,22 @@ readline(target_content_t *content,
   if (content->eol_style == svn_subst_eol_style_none)
     content->eol_str = eol_str;
 
-  /* Contract keywords. */
-  SVN_ERR(svn_subst_translate_cstring2(line_raw->data, line,
-                                       NULL, FALSE,
-                                       content->keywords, FALSE,
-                                       result_pool));
-  if (! content->eof)
+  if (line_raw)
+    {
+      /* Contract keywords. */
+      SVN_ERR(svn_subst_translate_cstring2(line_raw->data, line,
+                                           NULL, FALSE,
+                                           content->keywords, FALSE,
+                                           result_pool));
+    }
+  else
+    *line = "";
+
+  if ((line_raw && line_raw->len > 0) || eol_str)
     content->current_line++;
 
+  SVN_ERR_ASSERT(content->current_line > 0);
+
   return SVN_NO_ERROR;
 }
 
@@ -1383,26 +1538,45 @@ get_hunk_info(hunk_info_t **hi, patch_ta
    * the hunk applies at line 1. If the file already exists, the hunk
    * is rejected, unless the file is versioned and its content matches
    * the file the patch wants to create.  */
-  if (original_start == 0 && ! is_prop_hunk)
+  if (original_start == 0 && fuzz > 0)
+    {
+      matched_line = 0; /* reject any fuzz for new files */
+    }
+  else if (original_start == 0 && ! is_prop_hunk)
     {
       if (target->kind_on_disk == svn_node_file)
         {
-          if (target->db_kind == svn_node_file)
+          const svn_io_dirent2_t *dirent;
+          SVN_ERR(svn_io_stat_dirent2(&dirent, target->local_abspath, FALSE,
+                                      TRUE, scratch_pool, scratch_pool));
+
+          if (dirent->kind == svn_node_file
+              && !dirent->special
+              && dirent->filesize == 0)
+            {
+              matched_line = 1; /* Matched an on-disk empty file */
+            }
+          else
             {
-              svn_boolean_t file_matches;
+              if (target->db_kind == svn_node_file)
+                {
+                  svn_boolean_t file_matches;
 
-              SVN_ERR(match_existing_target(&file_matches, content, hunk,
+                  /* ### I can't reproduce anything but a no-match here.
+                         The content is already at eof, so any hunk fails */
+                  SVN_ERR(match_existing_target(&file_matches, content, hunk,
                                             scratch_pool));
-              if (file_matches)
-                {
-                  matched_line = 1;
-                  already_applied = TRUE;
+                  if (file_matches)
+                    {
+                      matched_line = 1;
+                      already_applied = TRUE;
+                    }
+                  else
+                    matched_line = 0; /* reject */
                 }
               else
                 matched_line = 0; /* reject */
             }
-          else
-            matched_line = 0; /* reject */
         }
       else
         matched_line = 1;
@@ -1518,7 +1692,7 @@ get_hunk_info(hunk_info_t **hi, patch_ta
       matched_line = 0;
     }
 
-  (*hi) = apr_palloc(result_pool, sizeof(hunk_info_t));
+  (*hi) = apr_pcalloc(result_pool, sizeof(hunk_info_t));
   (*hi)->hunk = hunk;
   (*hi)->matched_line = matched_line;
   (*hi)->rejected = (matched_line == 0);
@@ -2094,13 +2268,17 @@ apply_one_patch(patch_target_t **patch_t
 
   svn_pool_destroy(iterpool);
 
-  /* Now close files we don't need any longer to get their contents
-   * flushed to disk.
-   * But we're not closing the reject file -- it still needed and
-   * will be closed later in write_out_rejected_hunks(). */
-  if (target->kind_on_disk == svn_node_file)
-    SVN_ERR(svn_io_file_close(target->file, scratch_pool));
-  SVN_ERR(svn_io_file_close(target->patched_file, scratch_pool));
+  if (!target->is_symlink)
+    {
+      /* Now close files we don't need any longer to get their contents
+       * flushed to disk.
+       * But we're not closing the reject file -- it still needed and
+       * will be closed later in write_out_rejected_hunks(). */
+      if (target->kind_on_disk == svn_node_file)
+        SVN_ERR(svn_io_file_close(target->file, scratch_pool));
+  
+      SVN_ERR(svn_io_file_close(target->patched_file, scratch_pool));
+    }
 
   if (! target->skipped)
     {
@@ -2111,10 +2289,10 @@ apply_one_patch(patch_target_t **patch_t
        * We'll need those to figure out whether we should delete the
        * patched file. */
       SVN_ERR(svn_io_stat(&patched_file, target->patched_path,
-                          APR_FINFO_SIZE, scratch_pool));
+                          APR_FINFO_SIZE | APR_FINFO_LINK, scratch_pool));
       if (target->kind_on_disk == svn_node_file)
         SVN_ERR(svn_io_stat(&working_file, target->local_abspath,
-                            APR_FINFO_SIZE, scratch_pool));
+                            APR_FINFO_SIZE | APR_FINFO_LINK, scratch_pool));
       else
         working_file.size = 0;
 
@@ -2574,265 +2752,129 @@ install_patched_prop_targets(patch_targe
   return SVN_NO_ERROR;
 }
 
-/* Baton for find_existing_children() */
-struct status_baton
+/* Baton for can_delete_callback */
+struct can_delete_baton_t
 {
-  apr_array_header_t *existing_targets;
-  const char *parent_path;
-  apr_pool_t *result_pool;
+  svn_boolean_t must_keep;
+  const apr_array_header_t *targets_info;
+  const char *local_abspath;
 };
 
 /* Implements svn_wc_status_func4_t. */
 static svn_error_t *
-find_existing_children(void *baton,
-                       const char *abspath,
-                       const svn_wc_status3_t *status,
-                       apr_pool_t *pool)
+can_delete_callback(void *baton,
+                    const char *abspath,
+                    const svn_wc_status3_t *status,
+                    apr_pool_t *pool)
 {
-  struct status_baton *btn = baton;
+  struct can_delete_baton_t *cb = baton;
+  int i;
 
-  if (status->node_status != svn_wc_status_none
-      && status->node_status != svn_wc_status_deleted
-      && strcmp(abspath, btn->parent_path))
+  switch(status->node_status)
     {
-      APR_ARRAY_PUSH(btn->existing_targets,
-                     const char *) = apr_pstrdup(btn->result_pool,
-                                                 abspath);
-    }
+      case svn_wc_status_none:
+      case svn_wc_status_deleted:
+        return SVN_NO_ERROR;
 
-  return SVN_NO_ERROR;
-}
+      default:
+        if (! strcmp(cb->local_abspath, abspath))
+          return SVN_NO_ERROR; /* Only interested in descendants */
 
-/* Indicate in *EMPTY whether the directory at LOCAL_ABSPATH has any
- * versioned or unversioned children. Consider any DELETED_TARGETS,
- * as well as paths occuring as keys of DELETED_ABSPATHS_HASH (which may
- * be NULL) as already deleted. Use WC_CTX as the working copy context.
- * Do temporary allocations in SCRATCH_POOL. */
-static svn_error_t *
-check_dir_empty(svn_boolean_t *empty, const char *local_abspath,
-                svn_wc_context_t *wc_ctx,
-                apr_array_header_t *deleted_targets,
-                apr_hash_t *deleted_abspath_hash,
-                apr_pool_t *scratch_pool)
-{
-  struct status_baton btn;
-  svn_boolean_t is_wc_root;
-  int i;
+        for (i = 0; i < cb->targets_info->nelts; i++)
+          {
+            const patch_target_info_t *target_info =
+               APR_ARRAY_IDX(cb->targets_info, i, const patch_target_info_t *);
 
-  /* Working copy root cannot be deleted, so never consider it empty. */
-  SVN_ERR(svn_wc__is_wcroot(&is_wc_root, wc_ctx, local_abspath,
-                            scratch_pool));
-  if (is_wc_root)
-    {
-      *empty = FALSE;
-      return SVN_NO_ERROR;
-    }
+            if (! strcmp(target_info->local_abspath, abspath))
+              {
+                if (target_info->deleted)
+                  return SVN_NO_ERROR;
 
-  /* Find existing children of the directory. */
-  btn.existing_targets = apr_array_make(scratch_pool, 0,
-                                        sizeof(patch_target_t *));
-  btn.parent_path = local_abspath;
-  btn.result_pool = scratch_pool;
-  SVN_ERR(svn_wc_walk_status(wc_ctx, local_abspath, svn_depth_immediates,
-                             TRUE, TRUE, FALSE, NULL, find_existing_children,
-                             &btn, NULL, NULL, scratch_pool));
-  *empty = TRUE;
-
-  /* Do we delete all children? */
-  for (i = 0; i < btn.existing_targets->nelts; i++)
-    {
-      int j;
-      const char *found;
-      svn_boolean_t deleted;
-
-      deleted = FALSE;
-      found = APR_ARRAY_IDX(btn.existing_targets, i, const char *);
-
-      for (j = 0; j < deleted_targets->nelts; j++)
-        {
-          patch_target_info_t *target_info;
-
-          target_info = APR_ARRAY_IDX(deleted_targets, j,
-                                      patch_target_info_t *);
-          if (! svn_path_compare_paths(found, target_info->local_abspath))
-           {
-              deleted = TRUE;
-              break;
-           }
-        }
-      if (! deleted && deleted_abspath_hash)
-        {
-          apr_hash_index_t *hi;
+                break; /* Cease invocation; must keep */
+              }
+          }
 
-          for (hi = apr_hash_first(scratch_pool, deleted_abspath_hash);
-               hi;
-               hi = apr_hash_next(hi))
-            {
-              const char *abspath;
+        cb->must_keep = TRUE;
 
-              abspath = svn__apr_hash_index_key(hi);
-              if (! svn_path_compare_paths(found, abspath))
-               {
-                  deleted = TRUE;
-                  break;
-               }
-            }
-        }
-      if (! deleted)
-        {
-          *empty = FALSE;
-          break;
-        }
+        return svn_error_create(SVN_ERR_CEASE_INVOCATION, NULL, NULL);
     }
-
-  return SVN_NO_ERROR;
 }
 
-/* Delete all directories from the working copy which are left empty
- * by deleted TARGETS. Use client context CTX.
- * If DRY_RUN is TRUE, do not modify the working copy.
- * Do temporary allocations in SCRATCH_POOL. */
 static svn_error_t *
-delete_empty_dirs(apr_array_header_t *targets_info, svn_client_ctx_t *ctx,
-                  svn_boolean_t dry_run, apr_pool_t *scratch_pool)
+check_ancestor_delete(const char *deleted_target,
+                      apr_array_header_t *targets_info,
+                      const char *apply_root,
+                      svn_boolean_t dry_run,
+                      svn_client_ctx_t *ctx,
+                      apr_pool_t *result_pool,
+                      apr_pool_t *scratch_pool)
 {
-  apr_hash_t *empty_dirs;
-  apr_hash_t *non_empty_dirs;
-  apr_array_header_t *deleted_targets;
-  apr_pool_t *iterpool;
-  svn_boolean_t again;
-  int i;
-  apr_hash_index_t *hi;
-
-  /* Get a list of all deleted targets. */
-  deleted_targets = apr_array_make(scratch_pool, 0, sizeof(patch_target_t *));
-  for (i = 0; i < targets_info->nelts; i++)
-    {
-      patch_target_info_t *target_info;
-
-      target_info = APR_ARRAY_IDX(targets_info, i, patch_target_info_t *);
-      if (target_info->deleted)
-        APR_ARRAY_PUSH(deleted_targets, patch_target_info_t *) = target_info;
-    }
-
-  /* We have nothing to do if there aren't any deleted targets. */
-  if (deleted_targets->nelts == 0)
-    return SVN_NO_ERROR;
-
-  /* Look for empty parent directories of deleted targets. */
-  empty_dirs = apr_hash_make(scratch_pool);
-  non_empty_dirs = apr_hash_make(scratch_pool);
-  iterpool = svn_pool_create(scratch_pool);
-  for (i = 0; i < deleted_targets->nelts; i++)
-    {
-      svn_boolean_t parent_empty;
-      patch_target_info_t *target_info;
-      const char *parent;
-
-      svn_pool_clear(iterpool);
-
-      if (ctx->cancel_func)
-        SVN_ERR(ctx->cancel_func(ctx->cancel_baton));
-
-      target_info = APR_ARRAY_IDX(deleted_targets, i, patch_target_info_t *);
-
-      parent = svn_dirent_dirname(target_info->local_abspath, iterpool);
-
-      if (apr_hash_get(non_empty_dirs, parent, APR_HASH_KEY_STRING))
-        continue;
-      else if (apr_hash_get(empty_dirs, parent, APR_HASH_KEY_STRING))
-        continue;
+  struct can_delete_baton_t cb;
+  svn_error_t *err;
+  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
 
-      SVN_ERR(check_dir_empty(&parent_empty, parent, ctx->wc_ctx,
-                              deleted_targets, NULL, iterpool));
-      if (parent_empty)
-        apr_hash_set(empty_dirs, apr_pstrdup(scratch_pool, parent),
-                     APR_HASH_KEY_STRING, "");
-      else
-        apr_hash_set(non_empty_dirs, apr_pstrdup(scratch_pool, parent),
-                     APR_HASH_KEY_STRING, "");
-    }
+  const char *dir_abspath = svn_dirent_dirname(deleted_target, scratch_pool);
 
-  /* We have nothing to do if there aren't any empty directories. */
-  if (apr_hash_count(empty_dirs) == 0)
+  while (svn_dirent_is_child(apply_root, dir_abspath, iterpool))
     {
-      svn_pool_destroy(iterpool);
-      return SVN_NO_ERROR;
-    }
-
-  /* Determine the minimal set of empty directories we need to delete. */
-  do
-    {
-      apr_hash_t *empty_dirs_copy;
-
       svn_pool_clear(iterpool);
 
-      if (ctx->cancel_func)
-        SVN_ERR(ctx->cancel_func(ctx->cancel_baton));
-
-      /* Rebuild the empty dirs list, replacing empty dirs which have
-       * an empty parent with their parent. */
-      again = FALSE;
-      empty_dirs_copy = apr_hash_copy(iterpool, empty_dirs);
-      SVN_ERR(svn_hash__clear(empty_dirs, iterpool));
-
-      for (hi = apr_hash_first(iterpool, empty_dirs_copy);
-           hi;
-           hi = apr_hash_next(hi))
-        {
-          svn_boolean_t parent_empty;
-          const char *empty_dir;
-          const char *parent;
+      cb.local_abspath = dir_abspath;
+      cb.must_keep = FALSE;
+      cb.targets_info = targets_info;
+    
+      err = svn_wc_walk_status(ctx->wc_ctx, dir_abspath, svn_depth_infinity,
+                               TRUE, FALSE, FALSE, NULL,
+                               can_delete_callback, &cb,
+                               ctx->cancel_func, ctx->cancel_baton,
+                               iterpool);
+    
+      if (err)
+        {
+          if (err->apr_err != SVN_ERR_CEASE_INVOCATION)
+            return svn_error_trace(err);
 
-          empty_dir = svn__apr_hash_index_key(hi);
-          parent = svn_dirent_dirname(empty_dir, iterpool);
+          svn_error_clear(err);
+        }
 
-          if (apr_hash_get(empty_dirs, parent, APR_HASH_KEY_STRING))
-            continue;
+      if (cb.must_keep)
+      {
+        break;
+      }
 
-          SVN_ERR(check_dir_empty(&parent_empty, parent, ctx->wc_ctx,
-                                  deleted_targets, empty_dirs_copy,
-                                  iterpool));
-          if (parent_empty)
-            {
-              again = TRUE;
-              apr_hash_set(empty_dirs, apr_pstrdup(scratch_pool, parent),
-                           APR_HASH_KEY_STRING, "");
-            }
-          else
-            apr_hash_set(empty_dirs, apr_pstrdup(scratch_pool, empty_dir),
-                         APR_HASH_KEY_STRING, "");
+      if (! dry_run)
+        {
+          SVN_ERR(svn_wc_delete4(ctx->wc_ctx, dir_abspath, FALSE, FALSE,
+                                 ctx->cancel_func, ctx->cancel_baton,
+                                 NULL, NULL,
+                                 scratch_pool));
         }
-    }
-  while (again);
 
-  /* Finally, delete empty directories. */
-  for (hi = apr_hash_first(scratch_pool, empty_dirs);
-       hi;
-       hi = apr_hash_next(hi))
-    {
-      const char *empty_dir;
+      {
+        patch_target_info_t *pti = apr_pcalloc(result_pool, sizeof(*pti));
 
-      svn_pool_clear(iterpool);
+        pti->local_abspath = apr_pstrdup(result_pool, dir_abspath);
+        pti->deleted = TRUE;
+
+        APR_ARRAY_PUSH(targets_info, patch_target_info_t *) = pti;
+      }
 
-      if (ctx->cancel_func)
-        SVN_ERR(ctx->cancel_func(ctx->cancel_baton));
 
-      empty_dir = svn__apr_hash_index_key(hi);
-      if (! dry_run)
-        SVN_ERR(svn_wc_delete4(ctx->wc_ctx, empty_dir, FALSE, FALSE,
-                               ctx->cancel_func, ctx->cancel_baton,
-                               NULL, NULL, /* no duplicate notification */
-                               iterpool));
       if (ctx->notify_func2)
         {
           svn_wc_notify_t *notify;
 
-          notify = svn_wc_create_notify(empty_dir, svn_wc_notify_delete,
-                                        iterpool);
-          (*ctx->notify_func2)(ctx->notify_baton2, notify, iterpool);
+          notify = svn_wc_create_notify(dir_abspath, svn_wc_notify_delete,
+                                    iterpool);
+          notify->kind = svn_node_dir;
+
+          ctx->notify_func2(ctx->notify_baton2, notify, iterpool);
         }
+
+      /* And check if we must also delete the parent */
+      dir_abspath = svn_dirent_dirname(dir_abspath, scratch_pool);
     }
+
   svn_pool_destroy(iterpool);
 
   return SVN_NO_ERROR;
@@ -2897,7 +2939,7 @@ apply_patches(/* The path to the patch f
             {
               /* Save info we'll still need when we're done patching. */
               patch_target_info_t *target_info =
-                apr_palloc(scratch_pool, sizeof(patch_target_info_t));
+                apr_pcalloc(scratch_pool, sizeof(patch_target_info_t));
               target_info->local_abspath = apr_pstrdup(scratch_pool,
                                                        target->local_abspath);
               target_info->deleted = target->deleted;
@@ -2920,14 +2962,19 @@ apply_patches(/* The path to the patch f
                   SVN_ERR(write_out_rejected_hunks(target, dry_run, iterpool));
                 }
               SVN_ERR(send_patch_notification(target, ctx, iterpool));
+
+              if (target->deleted && !target->skipped)
+                {
+                  SVN_ERR(check_ancestor_delete(target_info->local_abspath,
+                                                targets_info, abs_wc_path,
+                                                dry_run, ctx,
+                                                scratch_pool, iterpool));
+                }
             }
         }
     }
   while (patch);
 
-  /* Delete directories which are empty after patching, if any. */
-  SVN_ERR(delete_empty_dirs(targets_info, ctx, dry_run, scratch_pool));
-
   SVN_ERR(svn_diff_close_patch_file(patch_file, iterpool));
   svn_pool_destroy(iterpool);
 

Modified: subversion/branches/ev2-export/subversion/libsvn_client/repos_diff.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_client/repos_diff.c?rev=1436688&r1=1436687&r2=1436688&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_client/repos_diff.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_client/repos_diff.c Mon Jan 21 23:37:01 2013
@@ -597,9 +597,8 @@ delete_entry(const char *path,
   svn_boolean_t tree_conflicted = FALSE;
   apr_pool_t *scratch_pool;
 
-  /* Skip *everything* within a newly tree-conflicted directory,
-   * and directories the children of which should be skipped. */
-  if (pb->skip || pb->tree_conflicted || pb->skip_children)
+  /* Process skips. */
+  if (pb->skip_children)
     return SVN_NO_ERROR;
 
   scratch_pool = svn_pool_create(eb->pool);
@@ -671,9 +670,10 @@ add_directory(const char *path,
 
   /* Skip *everything* within a newly tree-conflicted directory,
    * and directories the children of which should be skipped. */
-  if (pb->skip || pb->tree_conflicted || pb->skip_children)
+  if (pb->skip_children)
     {
       db->skip = TRUE;
+      db->skip_children = TRUE;
       return SVN_NO_ERROR;
     }
 
@@ -755,11 +755,11 @@ open_directory(const char *path,
 
   *child_baton = db;
 
-  /* Skip *everything* within a newly tree-conflicted directory
-   * and directories the children of which should be skipped. */
-  if (pb->skip || pb->tree_conflicted || pb->skip_children)
+  /* Process Skips. */
+  if (pb->skip_children)
     {
       db->skip = TRUE;
+      db->skip_children = TRUE;
       return SVN_NO_ERROR;
     }
 
@@ -789,9 +789,8 @@ add_file(const char *path,
   fb = make_file_baton(path, TRUE, pb->edit_baton, pool);
   *file_baton = fb;
 
-  /* Skip *everything* within a newly tree-conflicted directory.
-   * and directories the children of which should be skipped. */
-  if (pb->skip || pb->tree_conflicted || pb->skip_children)
+  /* Process Skips. */
+  if (pb->skip_children)
     {
       fb->skip = TRUE;
       return SVN_NO_ERROR;
@@ -816,9 +815,8 @@ open_file(const char *path,
   fb = make_file_baton(path, FALSE, pb->edit_baton, pool);
   *file_baton = fb;
 
-  /* Skip *everything* within a newly tree-conflicted directory
-   * and directories the children of which should be skipped. */
-  if (pb->skip || pb->tree_conflicted || pb->skip_children)
+  /* Process Skips. */
+  if (pb->skip_children)
     {
       fb->skip = TRUE;
       return SVN_NO_ERROR;
@@ -1097,16 +1095,9 @@ close_directory(void *dir_baton,
   apr_pool_t *scratch_pool;
   apr_hash_t *pristine_props;
 
-  /* Skip *everything* within a newly tree-conflicted directory. */
-  if (db->skip)
-    {
-      svn_pool_destroy(db->pool);
-      return SVN_NO_ERROR;
-    }
-
   scratch_pool = db->pool;
 
-  if (db->has_propchange)
+  if (db->has_propchange && !db->skip)
     {
       if (db->added)
         {
@@ -1180,7 +1171,7 @@ close_directory(void *dir_baton,
 
   /* Notify about this directory itself (unless it was added, in which
    * case the notification was done at that time). */
-  if (!db->added && eb->notify_func)
+  if (!db->added && eb->notify_func && !db->skip)
     {
       svn_wc_notify_t *notify;
       svn_wc_notify_action_t action;

Modified: subversion/branches/ev2-export/subversion/libsvn_client/status.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_client/status.c?rev=1436688&r1=1436687&r2=1436688&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_client/status.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_client/status.c Mon Jan 21 23:37:01 2013
@@ -530,6 +530,7 @@ svn_client_status5(svn_revnum_t *result_
       SVN_ERR(svn_client__do_external_status(ctx, external_map,
                                              depth, get_all,
                                              update, no_ignore,
+                                             sb.anchor_abspath, sb.anchor_relpath,
                                              status_func, status_baton, pool));
     }
 

Modified: subversion/branches/ev2-export/subversion/libsvn_client/update.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_client/update.c?rev=1436688&r1=1436687&r2=1436688&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_client/update.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_client/update.c Mon Jan 21 23:37:01 2013
@@ -376,23 +376,9 @@ update_internal(svn_revnum_t *result_rev
   dfb.target_revision = revnum;
   dfb.anchor_url = anchor_loc->url;
 
-  err = svn_client__get_inheritable_props(&wcroot_iprops, local_abspath,
-                                          revnum, depth, ra_session,
-                                          ctx, pool, pool);
-
-  /* We might be trying to update to a non-existant path-rev. */
-  if (err)
-    {
-      if (err->apr_err == SVN_ERR_FS_NOT_FOUND)
-        {
-          svn_error_clear(err);
-          err = NULL;
-        }
-      else
-        {
-          return svn_error_trace(err);
-        }
-    }
+  SVN_ERR(svn_client__get_inheritable_props(&wcroot_iprops, local_abspath,
+                                            revnum, depth, ra_session,
+                                            ctx, pool, pool));
 
   /* Fetch the update editor.  If REVISION is invalid, that's okay;
      the RA driver will call editor->set_target_revision later on. */

Modified: subversion/branches/ev2-export/subversion/libsvn_delta/editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_delta/editor.c?rev=1436688&r1=1436687&r2=1436688&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_delta/editor.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_delta/editor.c Mon Jan 21 23:37:01 2013
@@ -35,9 +35,18 @@
    introduce additional memory and runtime overhead, and should not be used
    in production builds.
 
-   ### Remove before release? */
+   ### Remove before release? 
+
+   ### Disabled for now.  If I call svn_editor_alter_directory(A) then
+       svn_editor_add_file(A/f) the latter fails on SHOULD_ALLOW_ADD.
+       If I modify svn_editor_alter_directory to MARK_ALLOW_ADD(child)
+       then if I call svn_editor_alter_directory(A) followed by
+       svn_editor_alter_directory(A/B/C) the latter fails on
+       VERIFY_PARENT_MAY_EXIST. */
+#if 0
 #define ENABLE_ORDERING_CHECK
 #endif
+#endif
 
 
 struct svn_editor_t
@@ -666,6 +675,7 @@ svn_editor_alter_directory(svn_editor_t 
 
         apr_hash_set(editor->pending_incomplete_children, child,
                      APR_HASH_KEY_STRING, "");
+        /* Perhaps MARK_ALLOW_ADD(editor, child); ? */
       }
   }
 #endif

Modified: subversion/branches/ev2-export/subversion/libsvn_fs/fs-loader.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_fs/fs-loader.c?rev=1436688&r1=1436687&r2=1436688&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_fs/fs-loader.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_fs/fs-loader.c Mon Jan 21 23:37:01 2013
@@ -485,6 +485,8 @@ svn_error_t *
 svn_fs_verify(const char *path,
               svn_cancel_func_t cancel_func,
               void *cancel_baton,
+              svn_fs_progress_notify_func_t notify_func,
+              void *notify_baton,
               svn_revnum_t start,
               svn_revnum_t end,
               apr_pool_t *pool)
@@ -497,7 +499,8 @@ svn_fs_verify(const char *path,
 
   SVN_MUTEX__WITH_LOCK(common_pool_lock,
                        vtable->verify_fs(fs, path, cancel_func, cancel_baton,
-                                         start, end, pool, common_pool));
+                                         notify_func, notify_baton, start,
+                                         end, pool, common_pool));
   return SVN_NO_ERROR;
 }
 
@@ -625,6 +628,16 @@ svn_fs_recover(const char *path,
 }
 
 svn_error_t *
+svn_fs_verify_rev(svn_fs_t *fs,
+                  svn_revnum_t revision,
+                  apr_pool_t *scratch_pool)
+{
+  SVN_ERR(fs->vtable->verify_rev(fs, revision, scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
 svn_fs_freeze(svn_fs_t *fs,
               svn_error_t *(*freeze_body)(void *baton, apr_pool_t *pool),
               void *baton,

Modified: subversion/branches/ev2-export/subversion/libsvn_fs/fs-loader.h
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_fs/fs-loader.h?rev=1436688&r1=1436687&r2=1436688&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_fs/fs-loader.h (original)
+++ subversion/branches/ev2-export/subversion/libsvn_fs/fs-loader.h Mon Jan 21 23:37:01 2013
@@ -88,8 +88,9 @@ typedef struct fs_library_vtable_t
   svn_error_t *(*upgrade_fs)(svn_fs_t *fs, const char *path, apr_pool_t *pool,
                              apr_pool_t *common_pool);
   svn_error_t *(*verify_fs)(svn_fs_t *fs, const char *path,
-                            /* ### notification? */
                             svn_cancel_func_t cancel_func, void *cancel_baton,
+                            svn_fs_progress_notify_func_t notify_func,
+                            void *notify_baton,
                             svn_revnum_t start,
                             svn_revnum_t end,
                             apr_pool_t *pool,
@@ -202,6 +203,9 @@ typedef struct fs_vtable_t
                             svn_fs_get_locks_callback_t get_locks_func,
                             void *get_locks_baton,
                             apr_pool_t *pool);
+  svn_error_t *(*verify_rev)(svn_fs_t *fs,
+                             svn_revnum_t revision,
+                             apr_pool_t *pool);
   svn_error_t *(*freeze)(svn_fs_t *fs,
                          svn_error_t *(*freeze_body)(void *, apr_pool_t *),
                          void *baton, apr_pool_t *pool);

Modified: subversion/branches/ev2-export/subversion/libsvn_fs_base/fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_fs_base/fs.c?rev=1436688&r1=1436687&r2=1436688&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_fs_base/fs.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_fs_base/fs.c Mon Jan 21 23:37:01 2013
@@ -472,6 +472,15 @@ bdb_write_config(svn_fs_t *fs)
 }
 
 static svn_error_t *
+base_bdb_verify_rev(svn_fs_t *fs,
+                    svn_revnum_t revision,
+                    apr_pool_t *scratch_pool)
+{
+  /* Verifying is currently a no op for BDB. */
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
 base_bdb_freeze(svn_fs_t *fs,
                 svn_error_t *(*freeze_body)(void *, apr_pool_t *),
                 void *baton,
@@ -500,6 +509,7 @@ static fs_vtable_t fs_vtable = {
   svn_fs_base__unlock,
   svn_fs_base__get_lock,
   svn_fs_base__get_locks,
+  base_bdb_verify_rev,
   base_bdb_freeze,
   base_bdb_set_errcall,
 };
@@ -894,6 +904,8 @@ static svn_error_t *
 base_verify(svn_fs_t *fs, const char *path,
             svn_cancel_func_t cancel_func,
             void *cancel_baton,
+            svn_fs_progress_notify_func_t notify_func,
+            void *notify_baton,
             svn_revnum_t start,
             svn_revnum_t end,
             apr_pool_t *pool,

Modified: subversion/branches/ev2-export/subversion/libsvn_fs_fs/fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_fs_fs/fs.c?rev=1436688&r1=1436687&r2=1436688&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_fs_fs/fs.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_fs_fs/fs.c Mon Jan 21 23:37:01 2013
@@ -184,6 +184,7 @@ static fs_vtable_t fs_vtable = {
   svn_fs_fs__unlock,
   svn_fs_fs__get_lock,
   svn_fs_fs__get_locks,
+  svn_fs_fs__verify_rev,
   fs_freeze,
   fs_set_errcall
 };
@@ -285,6 +286,8 @@ static svn_error_t *
 fs_verify(svn_fs_t *fs, const char *path,
           svn_cancel_func_t cancel_func,
           void *cancel_baton,
+          svn_fs_progress_notify_func_t notify_func,
+          void *notify_baton,
           svn_revnum_t start,
           svn_revnum_t end,
           apr_pool_t *pool,
@@ -295,7 +298,8 @@ fs_verify(svn_fs_t *fs, const char *path
   SVN_ERR(svn_fs_fs__open(fs, path, pool));
   SVN_ERR(svn_fs_fs__initialize_caches(fs, pool));
   SVN_ERR(fs_serialized_init(fs, common_pool, pool));
-  return svn_fs_fs__verify(fs, cancel_func, cancel_baton, start, end, pool);
+  return svn_fs_fs__verify(fs, cancel_func, cancel_baton, notify_func,
+                           notify_baton, start, end, pool);
 }
 
 static svn_error_t *

Modified: subversion/branches/ev2-export/subversion/libsvn_fs_fs/fs_fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_fs_fs/fs_fs.c?rev=1436688&r1=1436687&r2=1436688&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_fs_fs/fs_fs.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_fs_fs/fs_fs.c Mon Jan 21 23:37:01 2013
@@ -10289,6 +10289,28 @@ svn_fs_fs__pack(svn_fs_t *fs,
 
 /** Verifying. **/
 
+/* Baton type expected by verify_walker().  The purpose is to reuse open
+ * rev / pack file handles between calls.  Its contents need to be cleaned
+ * periodically to limit resource usage.
+ */
+typedef struct verify_walker_baton_t
+{
+  /* number of calls to verify_walker() since the last clean */
+  int iteration_count;
+  
+  /* number of files opened since the last clean */
+  int file_count;
+
+  /* current file handle (or NULL) */
+  apr_file_t *file_hint;
+
+  /* corresponding revision (or SVN_INVALID_REVNUM) */
+  svn_revnum_t rev_hint;
+
+  /* pool to use for the file handles etc. */
+  apr_pool_t *pool;
+} verify_walker_baton_t;
+
 /* Used by svn_fs_fs__verify().
    Implements svn_fs_fs__walk_rep_reference().walker.  */
 static svn_error_t *
@@ -10300,13 +10322,40 @@ verify_walker(representation_t *rep,
   struct rep_state *rs;
   struct rep_args *rep_args;
 
-#ifdef SVN_DEBUG
-  /* verify_walker() is called directly by get_shared_rep() with baton=NULL. */
-  SVN_ERR_ASSERT(!baton);
-#endif
+  if (baton)
+    {
+      verify_walker_baton_t *walker_baton = baton;
+      apr_file_t * previous_file;
+
+      /* free resources periodically */
+      if (   walker_baton->iteration_count > 1000
+          || walker_baton->file_count > 16)
+        {
+          svn_pool_clear(walker_baton->pool);
+          
+          walker_baton->iteration_count = 0;
+          walker_baton->file_count = 0;
+          walker_baton->file_hint = NULL;
+          walker_baton->rev_hint = SVN_INVALID_REVNUM;
+        }
 
-  /* ### Should this be using read_rep_line() directly? */
-  SVN_ERR(create_rep_state(&rs, &rep_args, NULL, NULL, rep, fs, scratch_pool));
+      /* access the repo data */
+      previous_file = walker_baton->file_hint;
+      SVN_ERR(create_rep_state(&rs, &rep_args, &walker_baton->file_hint,
+                               &walker_baton->rev_hint, rep, fs,
+                               walker_baton->pool));
+
+      /* update resource usage counters */
+      walker_baton->iteration_count++;
+      if (previous_file != walker_baton->file_hint)
+        walker_baton->file_count++;
+    }
+  else
+    {
+      /* ### Should this be using read_rep_line() directly? */
+      SVN_ERR(create_rep_state(&rs, &rep_args, NULL, NULL, rep, fs,
+                               scratch_pool));
+    }
 
   return SVN_NO_ERROR;
 }
@@ -10315,6 +10364,8 @@ svn_error_t *
 svn_fs_fs__verify(svn_fs_t *fs,
                   svn_cancel_func_t cancel_func,
                   void *cancel_baton,
+                  svn_fs_progress_notify_func_t notify_func,
+                  void *notify_baton,
                   svn_revnum_t start,
                   svn_revnum_t end,
                   apr_pool_t *pool)
@@ -10322,7 +10373,6 @@ svn_fs_fs__verify(svn_fs_t *fs,
   fs_fs_data_t *ffd = fs->fsap_data;
   svn_boolean_t exists;
   svn_revnum_t youngest = ffd->youngest_rev_cache; /* cache is current */
-  apr_pool_t *iterpool = svn_pool_create(pool);
 
   if (ffd->format < SVN_FS_FS__MIN_REP_SHARING_FORMAT)
     return SVN_NO_ERROR;
@@ -10332,42 +10382,54 @@ svn_fs_fs__verify(svn_fs_t *fs,
     start = 0;
   if (! SVN_IS_VALID_REVNUM(end))
     end = youngest;
-  SVN_ERR(ensure_revision_exists(fs, start, iterpool));
-  SVN_ERR(ensure_revision_exists(fs, end, iterpool));
+  SVN_ERR(ensure_revision_exists(fs, start, pool));
+  SVN_ERR(ensure_revision_exists(fs, end, pool));
 
   /* rep-cache verification. */
   SVN_ERR(svn_fs_fs__exists_rep_cache(&exists, fs, pool));
   if (exists)
-    /* Do not attempt to walk the rep-cache database if its file does not exist,
-       since doing so would create it --- which may confuse the administrator.
-       Don't take any lock. */
-    SVN_ERR(svn_fs_fs__walk_rep_reference(fs, verify_walker, NULL,
-                                          cancel_func, cancel_baton,
-                                          start, end,
-                                          pool));
+    {
+      /* provide a baton to allow the reuse of open file handles between
+         iterations (saves 2/3 of OS level file operations). */
+      verify_walker_baton_t *baton = apr_pcalloc(pool, sizeof(*baton));
+      baton->rev_hint = SVN_INVALID_REVNUM;
+      baton->pool = svn_pool_create(pool);
+      
+      /* Do not attempt to walk the rep-cache database if its file does
+         not exist,  since doing so would create it --- which may confuse
+         the administrator.   Don't take any lock. */
+      SVN_ERR(svn_fs_fs__walk_rep_reference(fs, verify_walker, baton,
+                                            cancel_func, cancel_baton,
+                                            notify_func, notify_baton,
+                                            start, end,
+                                            pool));
+
+      /* walker resource cleanup */
+      svn_pool_destroy(baton->pool);
+    }
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_fs_fs__verify_rev(svn_fs_t *fs,
+                      svn_revnum_t revision,
+                      apr_pool_t *pool)
+{
+  svn_fs_root_t *root;
 
   /* Issue #4129: bogus pred-counts and minfo-cnt's on the root node-rev
      (and elsewhere).  This code makes more thorough checks than the
      commit-time checks in validate_root_noderev(). */
-  {
-    svn_revnum_t i;
-    for (i = start; i <= end; i++)
-      {
-        svn_fs_root_t *root;
-
-        svn_pool_clear(iterpool);
-
-        /* ### TODO: Make sure caches are disabled.
-
-           When this code is called in the library, we want to ensure we
-           use the on-disk data --- rather than some data that was read
-           in the possibly-distance past and cached since. */
-        SVN_ERR(svn_fs_fs__revision_root(&root, fs, i, iterpool));
-        SVN_ERR(svn_fs_fs__verify_root(root, iterpool));
-      }
-  }
 
-  svn_pool_destroy(iterpool);
+  /* ### TODO: Make sure caches are disabled.
+
+     When this code is called in the library, we want to ensure we
+     use the on-disk data --- rather than some data that was read
+     in the possibly-distance past and cached since. */
+  SVN_ERR(svn_fs_fs__revision_root(&root, fs, revision, pool));
+  SVN_ERR(svn_fs_fs__verify_root(root, pool));
+
   return SVN_NO_ERROR;
 }
 

Modified: subversion/branches/ev2-export/subversion/libsvn_fs_fs/fs_fs.h
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_fs_fs/fs_fs.h?rev=1436688&r1=1436687&r2=1436688&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_fs_fs/fs_fs.h (original)
+++ subversion/branches/ev2-export/subversion/libsvn_fs_fs/fs_fs.h Mon Jan 21 23:37:01 2013
@@ -42,10 +42,18 @@ svn_error_t *svn_fs_fs__upgrade(svn_fs_t
 svn_error_t *svn_fs_fs__verify(svn_fs_t *fs,
                                svn_cancel_func_t cancel_func,
                                void *cancel_baton,
+                               svn_fs_progress_notify_func_t notify_func,
+                               void *notify_baton,
                                svn_revnum_t start,
                                svn_revnum_t end,
                                apr_pool_t *pool);
 
+/* Verify REVISION in filesystem FS.  Use POOL for temporary allocations. */
+svn_error_t *
+svn_fs_fs__verify_rev(svn_fs_t *fs,
+                      svn_revnum_t revision,
+                      apr_pool_t *pool);
+
 /* Copy the fsfs filesystem SRC_FS at SRC_PATH into a new copy DST_FS at
  * DST_PATH. If INCREMENTAL is TRUE, do not re-copy data which already
  * exists in DST_FS. Use POOL for temporary allocations. */

Modified: subversion/branches/ev2-export/subversion/libsvn_fs_fs/rep-cache.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_fs_fs/rep-cache.c?rev=1436688&r1=1436687&r2=1436688&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_fs_fs/rep-cache.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_fs_fs/rep-cache.c Mon Jan 21 23:37:01 2013
@@ -135,6 +135,8 @@ svn_fs_fs__walk_rep_reference(svn_fs_t *
                               void *walker_baton,
                               svn_cancel_func_t cancel_func,
                               void *cancel_baton,
+                              svn_fs_progress_notify_func_t notify_func,
+                              void *notify_baton,
                               svn_revnum_t start,
                               svn_revnum_t end,
                               apr_pool_t *pool)
@@ -143,6 +145,7 @@ svn_fs_fs__walk_rep_reference(svn_fs_t *
   svn_sqlite__stmt_t *stmt;
   svn_boolean_t have_row;
   int iterations = 0;
+  svn_revnum_t last_notified_revision = SVN_INVALID_REVNUM;
 
   apr_pool_t *iterpool = svn_pool_create(pool);
 
@@ -164,6 +167,9 @@ svn_fs_fs__walk_rep_reference(svn_fs_t *
       SVN_ERR(svn_sqlite__reset(stmt));
       if (SVN_IS_VALID_REVNUM(max))  /* The rep-cache could be empty. */
         SVN_ERR(svn_fs_fs__revision_exists(max, fs, iterpool));
+
+      if (notify_func)
+        notify_func(SVN_INVALID_REVNUM, notify_baton, iterpool);
     }
 
   SVN_ERR(svn_sqlite__get_statement(&stmt, ffd->rep_cache_db,
@@ -210,6 +216,16 @@ svn_fs_fs__walk_rep_reference(svn_fs_t *
         return svn_error_compose_create(err, svn_sqlite__reset(stmt));
 
       SVN_ERR(svn_sqlite__step(&have_row, stmt));
+
+      /* Notify (occasionally, because walking is fast and we can't
+         guarantee a properly ordered notification sequence anyway) */
+      if (   notify_func
+          && (iterations % 1024 == 0)
+          && (rep->revision != last_notified_revision))
+        {
+          notify_func(rep->revision, notify_baton, iterpool);
+          last_notified_revision = rep->revision;
+        }
     }
 
   SVN_ERR(svn_sqlite__reset(stmt));

Modified: subversion/branches/ev2-export/subversion/libsvn_fs_fs/rep-cache.h
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_fs_fs/rep-cache.h?rev=1436688&r1=1436687&r2=1436688&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_fs_fs/rep-cache.h (original)
+++ subversion/branches/ev2-export/subversion/libsvn_fs_fs/rep-cache.h Mon Jan 21 23:37:01 2013
@@ -55,6 +55,8 @@ svn_fs_fs__walk_rep_reference(svn_fs_t *
                               void *walker_baton,
                               svn_cancel_func_t cancel_func,
                               void *cancel_baton,
+                              svn_fs_progress_notify_func_t notify_func,
+                              void *notify_baton,
                               svn_revnum_t start,
                               svn_revnum_t end,
                               apr_pool_t *pool);

Modified: subversion/branches/ev2-export/subversion/libsvn_ra_local/ra_plugin.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_ra_local/ra_plugin.c?rev=1436688&r1=1436687&r2=1436688&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_ra_local/ra_plugin.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_ra_local/ra_plugin.c Mon Jan 21 23:37:01 2013
@@ -1220,7 +1220,7 @@ svn_ra_local__get_dir(svn_ra_session_t *
           apr_hash_t *prophash;
           const char *datestring, *entryname, *fullpath;
           svn_fs_dirent_t *fs_entry;
-          svn_dirent_t *entry = apr_pcalloc(pool, sizeof(*entry));
+          svn_dirent_t *entry = svn_dirent_create(pool);
 
           svn_pool_clear(subpool);
 

Modified: subversion/branches/ev2-export/subversion/libsvn_ra_serf/ra_serf.h
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_ra_serf/ra_serf.h?rev=1436688&r1=1436687&r2=1436688&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_ra_serf/ra_serf.h (original)
+++ subversion/branches/ev2-export/subversion/libsvn_ra_serf/ra_serf.h Mon Jan 21 23:37:01 2013
@@ -230,10 +230,12 @@ struct svn_ra_serf__session_t {
 
   svn_ra_serf__blncache_t *blncache;
 
-  /* Flag that indicates if we request the server for bulk updates (TRUE) with
-     all the properties and content in the update-report response. If FALSE,
-     request a skelta update-report with inlined properties. */
-  svn_boolean_t bulk_updates;
+  /* Trisate flag that indicates user preference for using bulk updates
+     (svn_tristate_true) with all the properties and content in the
+     update-report response. If svn_tristate_false, request a skelta
+     update-report with inlined properties. If svn_tristate_unknown then use
+     server preference. */
+  svn_tristate_t bulk_updates;
 
   /* Indicates if the server wants bulk update requests (Prefer) or only
      accepts skelta requests (Off). If this value is On both options are 

Modified: subversion/branches/ev2-export/subversion/libsvn_ra_serf/serf.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_ra_serf/serf.c?rev=1436688&r1=1436687&r2=1436688&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_ra_serf/serf.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_ra_serf/serf.c Mon Jan 21 23:37:01 2013
@@ -187,24 +187,21 @@ load_config(svn_ra_serf__session_t *sess
   /* Use the default proxy-specific settings if and only if
      "http-proxy-exceptions" is not set to exclude this host. */
   svn_config_get(config, &exceptions, SVN_CONFIG_SECTION_GLOBAL,
-                 SVN_CONFIG_OPTION_HTTP_PROXY_EXCEPTIONS, NULL);
-  if (exceptions)
-    {
-      if (! svn_cstring_match_glob_list(session->session_url.hostname,
-                                        svn_cstring_split(exceptions, ",",
-                                                          TRUE, pool)))
-        {
-          svn_config_get(config, &proxy_host, SVN_CONFIG_SECTION_GLOBAL,
-                         SVN_CONFIG_OPTION_HTTP_PROXY_HOST, NULL);
-          svn_config_get(config, &port_str, SVN_CONFIG_SECTION_GLOBAL,
-                         SVN_CONFIG_OPTION_HTTP_PROXY_PORT, NULL);
-          svn_config_get(config, &session->proxy_username,
-                         SVN_CONFIG_SECTION_GLOBAL,
-                         SVN_CONFIG_OPTION_HTTP_PROXY_USERNAME, NULL);
-          svn_config_get(config, &session->proxy_password,
-                         SVN_CONFIG_SECTION_GLOBAL,
-                         SVN_CONFIG_OPTION_HTTP_PROXY_PASSWORD, NULL);
-        }
+                 SVN_CONFIG_OPTION_HTTP_PROXY_EXCEPTIONS, "");
+  if (! svn_cstring_match_glob_list(session->session_url.hostname,
+                                    svn_cstring_split(exceptions, ",",
+                                                      TRUE, pool)))
+    {
+      svn_config_get(config, &proxy_host, SVN_CONFIG_SECTION_GLOBAL,
+                     SVN_CONFIG_OPTION_HTTP_PROXY_HOST, NULL);
+      svn_config_get(config, &port_str, SVN_CONFIG_SECTION_GLOBAL,
+                     SVN_CONFIG_OPTION_HTTP_PROXY_PORT, NULL);
+      svn_config_get(config, &session->proxy_username,
+                     SVN_CONFIG_SECTION_GLOBAL,
+                     SVN_CONFIG_OPTION_HTTP_PROXY_USERNAME, NULL);
+      svn_config_get(config, &session->proxy_password,
+                     SVN_CONFIG_SECTION_GLOBAL,
+                     SVN_CONFIG_OPTION_HTTP_PROXY_PASSWORD, NULL);
     }
 
   /* Load the global ssl settings, if set. */
@@ -217,10 +214,11 @@ load_config(svn_ra_serf__session_t *sess
 
   /* If set, read the flag that tells us to do bulk updates or not. Defaults
      to skelta updates. */
-  SVN_ERR(svn_config_get_bool(config, &session->bulk_updates,
-                              SVN_CONFIG_SECTION_GLOBAL,
-                              SVN_CONFIG_OPTION_HTTP_BULK_UPDATES,
-                              FALSE));
+  SVN_ERR(svn_config_get_tristate(config, &session->bulk_updates,
+                                  SVN_CONFIG_SECTION_GLOBAL,
+                                  SVN_CONFIG_OPTION_HTTP_BULK_UPDATES,
+                                  "auto",
+                                  svn_tristate_unknown));
 
   /* Load the maximum number of parallel session connections. */
   svn_config_get_int64(config, &session->max_connections,
@@ -272,10 +270,11 @@ load_config(svn_ra_serf__session_t *sess
                      session->ssl_authorities);
 
       /* Load the group bulk updates flag. */
-      SVN_ERR(svn_config_get_bool(config, &session->bulk_updates,
-                                  server_group,
-                                  SVN_CONFIG_OPTION_HTTP_BULK_UPDATES,
-                                  session->bulk_updates));
+      SVN_ERR(svn_config_get_tristate(config, &session->bulk_updates,
+                                      server_group,
+                                      SVN_CONFIG_OPTION_HTTP_BULK_UPDATES,
+                                      "auto",
+                                      session->bulk_updates));
 
       /* Load the maximum number of parallel session connections,
          overriding global values. */
@@ -803,7 +802,7 @@ path_dirent_walker(void *baton,
     {
       const char *base_name;
 
-      entry = apr_pcalloc(pool, sizeof(*entry));
+      entry = svn_dirent_create(pool);
 
       apr_hash_set(dirents->full_paths, path, path_len, entry);
 
@@ -921,7 +920,7 @@ svn_ra_serf__stat(svn_ra_session_t *ra_s
         return svn_error_trace(err);
     }
 
-  dwb.entry = apr_pcalloc(pool, sizeof(*dwb.entry));
+  dwb.entry = svn_dirent_create(pool);
   dwb.supports_deadprop_count = &deadprop_count;
   dwb.result_pool = pool;
   SVN_ERR(svn_ra_serf__walk_node_props(props, dirent_walker, &dwb, pool));

Modified: subversion/branches/ev2-export/subversion/libsvn_ra_serf/update.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_ra_serf/update.c?rev=1436688&r1=1436687&r2=1436688&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_ra_serf/update.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_ra_serf/update.c Mon Jan 21 23:37:01 2013
@@ -1644,7 +1644,12 @@ start_report(svn_ra_serf__xml_parser_t *
 
       val = svn_xml_get_attr_value("send-all", attrs);
       if (val && (strcmp(val, "true") == 0))
-        ctx->send_all_mode = TRUE;
+        {
+          ctx->send_all_mode = TRUE;
+
+          /* All properties are included in send-all mode. */
+          ctx->add_props_included = TRUE;
+        }
     }
   else if (state == NONE && strcmp(name.name, "target-revision") == 0)
     {
@@ -3131,6 +3136,7 @@ make_update_reporter(svn_ra_session_t *r
   svn_boolean_t server_supports_depth;
   svn_ra_serf__session_t *sess = ra_session->priv;
   svn_stringbuf_t *buf = NULL;
+  svn_boolean_t use_bulk_updates;
 
   SVN_ERR(svn_ra_serf__has_capability(ra_session, &server_supports_depth,
                                       SVN_RA_CAPABILITY_DEPTH, scratch_pool));
@@ -3177,42 +3183,58 @@ make_update_reporter(svn_ra_session_t *r
                                    svn_io_file_del_on_pool_cleanup,
                                    report->pool, scratch_pool));
 
-  if (sess->server_allows_bulk)
+  if (sess->bulk_updates == svn_tristate_true)
     {
-      if (apr_strnatcasecmp(sess->server_allows_bulk, "off") == 0)
-        {
-          /* Server doesn't want bulk updates */
-          sess->bulk_updates = FALSE;
-        }
-      else if (apr_strnatcasecmp(sess->server_allows_bulk, "prefer") == 0)
-        {
-          /* Server prefers bulk updates, and we respect that */
-          sess->bulk_updates = TRUE;
-        }
-      else
-        {
-          /* Server allows bulk updates, but doesn't dictate its use. Do
-             whatever is the default or what the user defined in the config. */
-        }
+      /* User would like to use bulk updates. */
+      use_bulk_updates = TRUE;
+    }
+  else if (sess->bulk_updates == svn_tristate_false)
+    {
+      /* User doesn't want bulk updates. */
+      use_bulk_updates = FALSE;
     }
   else
     {
-      /* Pre-1.8 server didn't send the bulk_updates header. Check if server
-         supports inlining properties in update editor report. */
-      if (sess->supports_inline_props)
+      /* User doesn't have any preferences on bulk updates. Decide on server
+         preferences and capabilities. */
+      if (sess->server_allows_bulk)
         {
-          /* Inline props supported: do not use bulk updates. */
-          sess->bulk_updates = FALSE;
+          if (apr_strnatcasecmp(sess->server_allows_bulk, "off") == 0)
+            {
+              /* Server doesn't want bulk updates */
+              use_bulk_updates = FALSE;
+            }
+          else if (apr_strnatcasecmp(sess->server_allows_bulk, "prefer") == 0)
+            {
+              /* Server prefers bulk updates, and we respect that */
+              use_bulk_updates = TRUE;
+            }
+          else
+            {
+              /* Server allows bulk updates, but doesn't dictate its use. Do
+                 whatever is the default. */
+              use_bulk_updates = FALSE;
+            }
         }
       else
         {
-          /* Inline props are noot supported: use bulk updates to avoid
-           * PROPFINDs for every added node. */
-          sess->bulk_updates = TRUE;
+          /* Pre-1.8 server didn't send the bulk_updates header. Check if server
+             supports inlining properties in update editor report. */
+          if (sess->supports_inline_props)
+            {
+              /* Inline props supported: do not use bulk updates. */
+              use_bulk_updates = FALSE;
+            }
+          else
+            {
+              /* Inline props are not supported: use bulk updates to avoid
+               * PROPFINDs for every added node. */
+              use_bulk_updates = TRUE;
+            }
         }
     }
 
-  if (sess->bulk_updates)
+  if (use_bulk_updates)
     {
       svn_xml_make_open_tag(&buf, scratch_pool, svn_xml_normal,
                             "S:update-report",

Modified: subversion/branches/ev2-export/subversion/libsvn_ra_svn/client.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_ra_svn/client.c?rev=1436688&r1=1436687&r2=1436688&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_ra_svn/client.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_ra_svn/client.c Mon Jan 21 23:37:01 2013
@@ -1274,7 +1274,7 @@ static svn_error_t *ra_svn_get_dir(svn_r
                                      &name, &kind, &size, &has_props,
                                      &crev, &cdate, &cauthor));
       name = svn_relpath_canonicalize(name, pool);
-      dirent = apr_palloc(pool, sizeof(*dirent));
+      dirent = svn_dirent_create(pool);
       dirent->kind = svn_node_kind_from_word(kind);
       dirent->size = size;/* FIXME: svn_filesize_t */
       dirent->has_props = has_props;
@@ -1748,7 +1748,7 @@ static svn_error_t *ra_svn_stat(svn_ra_s
                                      &kind, &size, &has_props,
                                      &crev, &cdate, &cauthor));
 
-      the_dirent = apr_palloc(pool, sizeof(*the_dirent));
+      the_dirent = svn_dirent_create(pool);
       the_dirent->kind = svn_node_kind_from_word(kind);
       the_dirent->size = size;/* FIXME: svn_filesize_t */
       the_dirent->has_props = has_props;

Modified: subversion/branches/ev2-export/subversion/libsvn_ra_svn/editorp.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_ra_svn/editorp.c?rev=1436688&r1=1436687&r2=1436688&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_ra_svn/editorp.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_ra_svn/editorp.c Mon Jan 21 23:37:01 2013
@@ -976,7 +976,7 @@ svn_error_t *svn_ra_svn_drive_editor2(sv
           else
             {
               err = svn_error_createf(SVN_ERR_RA_SVN_UNKNOWN_CMD, NULL,
-                                      _("Unknown command '%s'"), cmd);
+                                      _("Unknown editor command '%s'"), cmd);
               err = svn_error_create(SVN_ERR_RA_SVN_CMD_ERR, err, NULL);
             }
         }

Modified: subversion/branches/ev2-export/subversion/libsvn_ra_svn/marshal.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_ra_svn/marshal.c?rev=1436688&r1=1436687&r2=1436688&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_ra_svn/marshal.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_ra_svn/marshal.c Mon Jan 21 23:37:01 2013
@@ -1799,7 +1799,7 @@ svn_error_t *svn_ra_svn_handle_commands2
       else
         {
           err = svn_error_createf(SVN_ERR_RA_SVN_UNKNOWN_CMD, NULL,
-                                  _("Unknown command '%s'"), cmdname);
+                                  _("Unknown editor command '%s'"), cmdname);
           err = svn_error_create(SVN_ERR_RA_SVN_CMD_ERR, err, NULL);
         }
 

Modified: subversion/branches/ev2-export/subversion/libsvn_repos/dump.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_repos/dump.c?rev=1436688&r1=1436687&r2=1436688&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_repos/dump.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_repos/dump.c Mon Jan 21 23:37:01 2013
@@ -1321,13 +1321,15 @@ verify_directory_entry(void *baton, cons
                        void *val, apr_pool_t *pool)
 {
   struct dir_baton *db = baton;
+  svn_fs_dirent_t *dirent = (svn_fs_dirent_t *)val;
   char *path = svn_relpath_join(db->path, (const char *)key, pool);
-  svn_node_kind_t kind;
   apr_hash_t *dirents;
   svn_filesize_t len;
 
-  SVN_ERR(svn_fs_check_path(&kind, db->edit_baton->fs_root, path, pool));
-  switch (kind) {
+  /* since we can't access the directory entries directly by their ID,
+     we need to navigate from the FS_ROOT to them (relatively expensive
+     because we may start at a never rev than the last change to node). */
+  switch (dirent->kind) {
   case svn_node_dir:
     /* Getting this directory's contents is enough to ensure that our
        link to it is correct. */
@@ -1340,7 +1342,8 @@ verify_directory_entry(void *baton, cons
     break;
   default:
     return svn_error_createf(SVN_ERR_NODE_UNEXPECTED_KIND, NULL,
-                             _("Unexpected node kind %d for '%s'"), kind, path);
+                             _("Unexpected node kind %d for '%s'"),
+                             dirent->kind, path);
   }
 
   return SVN_NO_ERROR;
@@ -1359,6 +1362,32 @@ verify_close_directory(void *dir_baton,
   return close_directory(dir_baton, pool);
 }
 
+/* Baton type used for forwarding notifications from FS API to REPOS API. */
+struct verify_fs2_notify_func_baton_t
+{
+   /* notification function to call (must not be NULL) */
+   svn_repos_notify_func_t notify_func;
+
+   /* baton to use for it */
+   void *notify_baton;
+
+   /* type of notification to send (we will simply plug in the revision) */
+   svn_repos_notify_t *notify;
+};
+
+/* Forward the notification to BATON. */
+static void
+verify_fs2_notify_func(svn_revnum_t revision,
+                       void *baton,
+                       apr_pool_t *pool)
+{
+  struct verify_fs2_notify_func_baton_t *notify_baton = baton;
+
+  notify_baton->notify->revision = revision;
+  notify_baton->notify_func(notify_baton->notify_baton,
+                            notify_baton->notify, pool);
+}
+
 svn_error_t *
 svn_repos_verify_fs2(svn_repos_t *repos,
                      svn_revnum_t start_rev,
@@ -1374,6 +1403,8 @@ svn_repos_verify_fs2(svn_repos_t *repos,
   svn_revnum_t rev;
   apr_pool_t *iterpool = svn_pool_create(pool);
   svn_repos_notify_t *notify;
+  svn_fs_progress_notify_func_t verify_notify = NULL;
+  struct verify_fs2_notify_func_baton_t *verify_notify_baton = NULL;
 
   /* Determine the current youngest revision of the filesystem. */
   SVN_ERR(svn_fs_youngest_rev(&youngest, fs, pool));
@@ -1396,15 +1427,26 @@ svn_repos_verify_fs2(svn_repos_t *repos,
                                "(youngest revision is %ld)"),
                              end_rev, youngest);
 
+  /* Create a notify object that we can reuse within the loop and a
+     forwarding structure for notifications from inside svn_fs_verify(). */
+  if (notify_func)
+    {
+      notify = svn_repos_notify_create(svn_repos_notify_verify_rev_end,
+                                       pool);
+
+      verify_notify = verify_fs2_notify_func;
+      verify_notify_baton = apr_palloc(pool, sizeof(*verify_notify_baton));
+      verify_notify_baton->notify_func = notify_func;
+      verify_notify_baton->notify_baton = notify_baton;
+      verify_notify_baton->notify
+        = svn_repos_notify_create(svn_repos_notify_verify_struc_rev, pool);
+    }
+
   /* Verify global/auxiliary data and backend-specific data first. */
   SVN_ERR(svn_fs_verify(svn_fs_path(fs, pool), cancel_func, cancel_baton,
+                        verify_notify, verify_notify_baton,
                         start_rev, end_rev, pool));
 
-  /* Create a notify object that we can reuse within the loop. */
-  if (notify_func)
-    notify = svn_repos_notify_create(svn_repos_notify_verify_rev_end,
-                                     pool);
-
   for (rev = start_rev; rev <= end_rev; rev++)
     {
       const svn_delta_editor_t *dump_editor;
@@ -1432,6 +1474,8 @@ svn_repos_verify_fs2(svn_repos_t *repos,
                                                 &cancel_edit_baton,
                                                 iterpool));
 
+      SVN_ERR(svn_fs_verify_rev(fs, rev, iterpool));
+
       SVN_ERR(svn_fs_revision_root(&to_root, fs, rev, iterpool));
       SVN_ERR(svn_repos_replay2(to_root, "", SVN_INVALID_REVNUM, FALSE,
                                 cancel_editor, cancel_edit_baton,

Modified: subversion/branches/ev2-export/subversion/libsvn_repos/reporter.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_repos/reporter.c?rev=1436688&r1=1436687&r2=1436688&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_repos/reporter.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_repos/reporter.c Mon Jan 21 23:37:01 2013
@@ -447,7 +447,8 @@ static svn_error_t *
 change_dir_prop(report_baton_t *b, void *dir_baton, const char *name,
                 const svn_string_t *value, apr_pool_t *pool)
 {
-  return b->editor->change_dir_prop(dir_baton, name, value, pool);
+  return svn_error_trace(b->editor->change_dir_prop(dir_baton, name, value,
+                                                    pool));
 }
 
 /* Call the file property-setting function of B->editor to set the
@@ -456,7 +457,8 @@ static svn_error_t *
 change_file_prop(report_baton_t *b, void *file_baton, const char *name,
                  const svn_string_t *value, apr_pool_t *pool)
 {
-  return b->editor->change_file_prop(file_baton, name, value, pool);
+  return svn_error_trace(b->editor->change_file_prop(file_baton, name, value,
+                                                     pool));
 }
 
 /* For the report B, return the relevant revprop data of revision REV in
@@ -752,8 +754,8 @@ check_auth(report_baton_t *b, svn_boolea
            apr_pool_t *pool)
 {
   if (b->authz_read_func)
-    return b->authz_read_func(allowed, b->t_root, path,
-                              b->authz_read_baton, pool);
+    return svn_error_trace(b->authz_read_func(allowed, b->t_root, path,
+                                              b->authz_read_baton, pool));
   *allowed = TRUE;
   return SVN_NO_ERROR;
 }
@@ -879,9 +881,9 @@ add_file_smartly(report_baton_t *b,
         }
     }
 
-  return b->editor->add_file(path, parent_baton,
-                             *copyfrom_path, *copyfrom_rev,
-                             pool, new_file_baton);
+  return svn_error_trace(b->editor->add_file(path, parent_baton,
+                                             *copyfrom_path, *copyfrom_rev,
+                                             pool, new_file_baton));
 }
 
 
@@ -1016,7 +1018,7 @@ update_entry(report_baton_t *b, svn_revn
 
   /* If there's no target, we have nothing more to do. */
   if (!t_entry)
-    return skip_path_info(b, e_path);
+    return svn_error_trace(skip_path_info(b, e_path));
 
   /* Check if the user is authorized to find out about the target. */
   SVN_ERR(check_auth(b, &allowed, t_path, pool));
@@ -1026,7 +1028,7 @@ update_entry(report_baton_t *b, svn_revn
         SVN_ERR(b->editor->absent_directory(e_path, dir_baton, pool));
       else
         SVN_ERR(b->editor->absent_file(e_path, dir_baton, pool));
-      return skip_path_info(b, e_path);
+      return svn_error_trace(skip_path_info(b, e_path));
     }
 
   if (t_entry->kind == svn_node_dir)
@@ -1042,7 +1044,7 @@ update_entry(report_baton_t *b, svn_revn
       SVN_ERR(delta_dirs(b, s_rev, s_path, t_path, new_baton, e_path,
                          info ? info->start_empty : FALSE,
                          wc_depth, requested_depth, pool));
-      return b->editor->close_directory(new_baton, pool);
+      return svn_error_trace(b->editor->close_directory(new_baton, pool));
     }
   else
     {
@@ -1074,7 +1076,8 @@ update_entry(report_baton_t *b, svn_revn
       SVN_ERR(svn_fs_file_checksum(&checksum, svn_checksum_md5, b->t_root,
                                    t_path, TRUE, pool));
       hex_digest = svn_checksum_to_cstring(checksum, pool);
-      return b->editor->close_file(new_baton, hex_digest, pool);
+      return svn_error_trace(b->editor->close_file(new_baton, hex_digest,
+                                                   pool));
     }
 }
 
@@ -1353,8 +1356,6 @@ drive(report_baton_t *b, svn_revnum_t s_
 
   /* Collect information about the source and target nodes. */
   s_fullpath = svn_fspath__join(b->fs_base, b->s_operand, pool);
-  /* ### Weird: When I have a file external defined as "^/A/a X/xa",
-   * ### S_FULLPATH becomes "/A/a/xa" here, which is complete nonsense. */
   SVN_ERR(get_source_root(b, &s_root, s_rev));
   SVN_ERR(fake_dirent(&s_entry, s_root, s_fullpath, pool));
   SVN_ERR(fake_dirent(&t_entry, b->t_root, b->t_path, pool));
@@ -1392,7 +1393,7 @@ drive(report_baton_t *b, svn_revnum_t s_
                          t_entry, root_baton, b->s_operand, info,
                          info->depth, b->requested_depth, pool));
 
-  return b->editor->close_directory(root_baton, pool);
+  return svn_error_trace(b->editor->close_directory(root_baton, pool));
 }
 
 /* Initialize the baton fields for editor-driving, and drive the editor. */
@@ -1448,7 +1449,8 @@ finish_report(report_baton_t *b, apr_poo
     b->s_roots[i] = NULL;
 
   {
-    svn_error_t *err = drive(b, s_rev, info, pool);
+    svn_error_t *err = svn_error_trace(drive(b, s_rev, info, pool));
+
     if (err == SVN_NO_ERROR)
       return svn_error_trace(b->editor->close_edit(b->edit_baton, pool));
 
@@ -1500,7 +1502,8 @@ write_path_info(report_baton_t *b, const
   rep = apr_psprintf(pool, "+%" APR_SIZE_T_FMT ":%s%s%s%s%c%s",
                      strlen(path), path, lrep, rrep, drep,
                      start_empty ? '+' : '-', ltrep);
-  return svn_spillbuf__reader_write(b->reader, rep, strlen(rep), pool);
+  return svn_error_trace(
+            svn_spillbuf__reader_write(b->reader, rep, strlen(rep), pool));
 }
 
 svn_error_t *
@@ -1508,8 +1511,9 @@ svn_repos_set_path3(void *baton, const c
                     svn_depth_t depth, svn_boolean_t start_empty,
                     const char *lock_token, apr_pool_t *pool)
 {
-  return write_path_info(baton, path, NULL, rev, depth, start_empty,
-                         lock_token, pool);
+  return svn_error_trace(
+            write_path_info(baton, path, NULL, rev, depth, start_empty,
+                            lock_token, pool));
 }
 
 svn_error_t *
@@ -1522,8 +1526,9 @@ svn_repos_link_path3(void *baton, const 
     return svn_error_create(SVN_ERR_REPOS_BAD_ARGS, NULL,
                             _("Depth 'exclude' not supported for link"));
 
-  return write_path_info(baton, path, link_path, rev, depth,
-                         start_empty, lock_token, pool);
+  return svn_error_trace(
+            write_path_info(baton, path, link_path, rev, depth,
+                            start_empty, lock_token, pool));
 }
 
 svn_error_t *
@@ -1531,8 +1536,9 @@ svn_repos_delete_path(void *baton, const
 {
   /* We pass svn_depth_infinity because deletion of a path always
      deletes everything underneath it. */
-  return write_path_info(baton, path, NULL, SVN_INVALID_REVNUM,
-                         svn_depth_infinity, FALSE, NULL, pool);
+  return svn_error_trace(
+            write_path_info(baton, path, NULL, SVN_INVALID_REVNUM,
+                            svn_depth_infinity, FALSE, NULL, pool));
 }
 
 svn_error_t *

Modified: subversion/branches/ev2-export/subversion/libsvn_repos/repos.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_repos/repos.c?rev=1436688&r1=1436687&r2=1436688&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_repos/repos.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_repos/repos.c Mon Jan 21 23:37:01 2013
@@ -2122,7 +2122,7 @@ svn_repos_stat(svn_dirent_t **dirent,
       return SVN_NO_ERROR;
     }
 
-  ent = apr_pcalloc(pool, sizeof(*ent));
+  ent = svn_dirent_create(pool);
   ent->kind = kind;
 
   if (kind == svn_node_file)

Modified: subversion/branches/ev2-export/subversion/libsvn_subr/config.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_subr/config.c?rev=1436688&r1=1436687&r2=1436688&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_subr/config.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_subr/config.c Mon Jan 21 23:37:01 2013
@@ -796,6 +796,36 @@ svn_config_get_yes_no_ask(svn_config_t *
   return SVN_NO_ERROR;
 }
 
+svn_error_t *
+svn_config_get_tristate(svn_config_t *cfg, svn_tristate_t *valuep,
+                        const char *section, const char *option,
+                        const char *unknown_value,
+                        svn_tristate_t default_value)
+{
+  const char *tmp_value;
+
+  svn_config_get(cfg, &tmp_value, section, option, NULL);
+
+  if (! tmp_value)
+    {
+      *valuep = default_value;
+    }
+  else if (0 == svn_cstring_casecmp(tmp_value, unknown_value))
+    {
+      *valuep = svn_tristate_unknown;
+    }
+  else
+    {
+      svn_boolean_t bool_val;
+      /* We already incorporated default_value into tmp_value if
+         necessary, so the FALSE below will be ignored unless the
+         caller is doing something it shouldn't be doing. */
+      SVN_ERR(get_bool(&bool_val, tmp_value, FALSE, section, option));
+      *valuep = bool_val ? svn_tristate_true : svn_tristate_false;
+    }
+
+  return SVN_NO_ERROR;
+}
 
 int
 svn_config_enumerate_sections(svn_config_t *cfg,

Modified: subversion/branches/ev2-export/subversion/libsvn_subr/deprecated.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_subr/deprecated.c?rev=1436688&r1=1436687&r2=1436688&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_subr/deprecated.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_subr/deprecated.c Mon Jan 21 23:37:01 2013
@@ -878,6 +878,22 @@ svn_io_dir_walk(const char *dirname,
                                           &baton, pool));
 }
 
+svn_error_t *
+svn_io_stat_dirent(const svn_io_dirent2_t **dirent_p,
+                   const char *path,
+                   svn_boolean_t ignore_enoent,
+                   apr_pool_t *result_pool,
+                   apr_pool_t *scratch_pool)
+{
+  return svn_error_trace(
+            svn_io_stat_dirent2(dirent_p,
+                                path,
+                                FALSE,
+                                ignore_enoent,
+                                result_pool,
+                                scratch_pool));
+}
+
 /*** From constructors.c ***/
 svn_log_changed_path_t *
 svn_log_changed_path_dup(const svn_log_changed_path_t *changed_path,