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

svn commit: r1044516 [8/22] - in /subversion/branches/ignore-mergeinfo: ./ build/ac-macros/ build/generator/ contrib/server-side/ notes/ notes/wc-ng/ subversion/bindings/javahl/native/ subversion/bindings/javahl/src/org/apache/subversion/javahl/ subver...

Modified: subversion/branches/ignore-mergeinfo/subversion/libsvn_client/merge.c
URL: http://svn.apache.org/viewvc/subversion/branches/ignore-mergeinfo/subversion/libsvn_client/merge.c?rev=1044516&r1=1044515&r2=1044516&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_client/merge.c (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_client/merge.c Fri Dec 10 21:23:03 2010
@@ -437,27 +437,7 @@ obstructed_or_missing(svn_wc_notify_stat
                                              local_abspath,
                                              pool));
       if (is_deleted)
-        {
-          /* ### While we are not at single-db: detect missing .svn dirs.
-             ### Once we switch to single db expected kind should be always
-             ### none, just like for files */
-          if (kind_expected == svn_node_dir)
-            {
-              if (kind_on_disk == svn_node_none)
-                {
-                  svn_boolean_t is_obstructed;
-                  
-                  SVN_ERR(svn_wc__node_is_status_obstructed(&is_obstructed,
-                                                            merge_b->ctx->wc_ctx,
-                                                            local_abspath,
-                                                            pool));
-                  if (!is_obstructed)
-                    kind_expected = svn_node_none; 
-                }
-            }
-          else
-            kind_expected = svn_node_none;
-        }
+        kind_expected = svn_node_none;
     }
 
   if (kind_expected == kind_on_disk)
@@ -3367,6 +3347,7 @@ get_full_mergeinfo(svn_mergeinfo_t *reco
       svn_revnum_t target_rev;
       svn_opt_revision_t peg_revision;
       apr_pool_t *sesspool = NULL;
+      svn_error_t *err;
 
       /* Assert that we have sane input. */
       SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(start)
@@ -3374,9 +3355,26 @@ get_full_mergeinfo(svn_mergeinfo_t *reco
                  && (start > end));
 
       peg_revision.kind = svn_opt_revision_working;
-      SVN_ERR(svn_client__derive_location(&url, &target_rev, target_abspath,
-                                          &peg_revision, ra_session,
-                                          ctx, result_pool, scratch_pool));
+      err = svn_client__derive_location(&url, &target_rev, target_abspath,
+                                        &peg_revision, ra_session,
+                                        ctx, result_pool, scratch_pool);
+
+      if (err)
+        {
+          if (err->apr_err == SVN_ERR_CLIENT_VERSIONED_PATH_REQUIRED)
+            {
+              /* We've been asked to operate on a target which has no location
+               * in the repository. Either it's unversioned (but attempts to
+               * merge into unversioned targets should not get as far as here),
+               * or it is locally added, in which case the target's implicit
+               * mergeinfo is empty. */
+              svn_error_clear(err);
+              *implicit_mergeinfo = apr_hash_make(result_pool);
+              return SVN_NO_ERROR;
+            }
+          else
+            return svn_error_return(err);
+        }
 
       if (target_rev <= end)
         {
@@ -5284,6 +5282,17 @@ struct get_mergeinfo_walk_baton
 {
   /* Array of paths that have explicit mergeinfo and/or are switched. */
   apr_array_header_t *children_with_mergeinfo;
+
+  /* A hash of MERGE_TARGET_ABSPATH's subdirectories' dirents.  Maps
+     const char * absolute working copy paths to dirent hashes as obtained
+     by svn_io_get_dirents3().  Contents are allocated in CB_POOL. */
+  apr_hash_t *subtree_dirents;
+
+  /* A hash to keep track of any subtrees in the merge target which are
+     unexpectedly missing from disk.  Maps const char * absolute working
+     copy paths to the same.  Contents are allocated in CB_POOL. */
+  apr_hash_t *missing_subtrees;
+
   /* Merge source canonical path. */
   const char* merge_src_canon_path;
 
@@ -5304,8 +5313,111 @@ struct get_mergeinfo_walk_baton
 
   /* Pool from which to allocate new elements of CHILDREN_WITH_MERGEINFO. */
   apr_pool_t *pool;
+
+  /* Pool with a lifetime guaranteed over all the get_mergeinfo_walk_cb
+     callbacks. */
+  apr_pool_t *cb_pool;
 };
 
+/* Helper for the svn_wc__node_found_func_t callback get_mergeinfo_walk_cb().
+
+   Checks for issue #2915 subtrees, i.e. those that the WC thinks are on disk
+   but have been removed due to an OS-level deletion.
+
+   If the supposed working path LOCAL_ABSPATH, of kind KIND, is the root
+   of a missing subtree, then add a (const char *) WC absolute path to
+   (const char *) WC absolute path mapping to MISSING_SUBTREES, where the
+   paths are both a copy of LOCAL_ABSPATH, allocated in RESULT_POOL.
+
+   If LOCAL_ABSPATH is a directory and is not missing from disk, then add
+   a (const char *) WC absolute path to (svn_io_dirent2_t *) dirent mapping
+   to SUBTREE_DIRENTS, again allocated in RESULT_POOL (see
+   svn_io_get_dirents3).
+
+   SCRATCH_POOL is used for temporary allocations.
+
+   Note: Since this is effetively a svn_wc__node_found_func_t callback, it
+   must be called in depth-first order. */
+static svn_error_t *
+record_missing_subtree_roots(const char *local_abspath,
+                             svn_node_kind_t kind,
+                             apr_hash_t *subtree_dirents,
+                             apr_hash_t *missing_subtrees,
+                             apr_pool_t *result_pool,
+                             apr_pool_t *scratch_pool)
+{
+  svn_boolean_t missing_subtree_root = FALSE;
+
+  /* Store the dirents for each directory in SUBTREE_DIRENTS. */
+  if (kind == svn_node_dir)
+    {
+      /* If SUBTREE_DIRENTS is empty LOCAL_ABSPATH is merge target. */
+      if (apr_hash_count(subtree_dirents) == 0 
+          || apr_hash_get(subtree_dirents,
+                          svn_dirent_dirname(local_abspath,
+                                             scratch_pool),
+                                             APR_HASH_KEY_STRING))
+        {
+          apr_hash_t *dirents;
+          svn_error_t *err = svn_io_get_dirents3(&dirents, local_abspath,
+                                                 TRUE, result_pool,
+                                                 scratch_pool);
+          if (err)
+            {
+              if (APR_STATUS_IS_ENOENT(err->apr_err)
+                  || SVN__APR_STATUS_IS_ENOTDIR(err->apr_err))
+                {
+                  /* We can't get this directory's dirents, it's missing
+                     from disk. */
+                  svn_error_clear(err);
+                  missing_subtree_root = TRUE;
+                }
+              else
+                {
+                  return err;
+                }
+            }
+          else
+            {
+              apr_hash_set(subtree_dirents,
+                           apr_pstrdup(result_pool, local_abspath),
+                           APR_HASH_KEY_STRING, dirents);
+            }      
+        }
+    }
+  else /* kind != svn_node_dir */
+    {
+      /* Is this non-directory missing from disk?  Check LOCAL_ABSPATH's
+         parent's dirents. */
+      apr_hash_t *parent_dirents = apr_hash_get(subtree_dirents,
+                                                svn_dirent_dirname(local_abspath,
+                                                                   scratch_pool),
+                                                APR_HASH_KEY_STRING);
+
+      /* If the parent_dirents is NULL, then LOCAL_ABSPATH is the
+         subtree of a missing subtree.  Since we only report the roots
+         of missing subtrees there is nothing more to do in that case. */
+      if (parent_dirents)
+        {
+          svn_io_dirent2_t *dirent =
+            apr_hash_get(parent_dirents,
+                         svn_dirent_basename(local_abspath, scratch_pool),
+                         APR_HASH_KEY_STRING);
+          if (!dirent)
+            missing_subtree_root = TRUE;
+        }
+    }
+
+  if (missing_subtree_root)
+    {
+      const char *path = apr_pstrdup(result_pool, local_abspath);
+
+      apr_hash_set(missing_subtrees, path,
+                   APR_HASH_KEY_STRING, path);
+    }
+
+  return SVN_NO_ERROR;
+}
 
 /* svn_wc__node_found_func_t callback for get_mergeinfo_paths().
 
@@ -5333,7 +5445,6 @@ get_mergeinfo_walk_cb(const char *local_
   svn_boolean_t is_present;
   svn_boolean_t deleted;
   svn_boolean_t absent;
-  svn_boolean_t obstructed;
   svn_boolean_t immediate_child_dir;
 
   /* TODO(#2843) How to deal with a excluded item on merge? */
@@ -5345,14 +5456,12 @@ get_mergeinfo_walk_cb(const char *local_
   if (!is_present)
     return SVN_NO_ERROR;
 
-  SVN_ERR(svn_wc__node_is_status_obstructed(&obstructed, wb->ctx->wc_ctx,
-                                            local_abspath, scratch_pool));
   SVN_ERR(svn_wc__node_is_status_deleted(&deleted, wb->ctx->wc_ctx,
                                          local_abspath, scratch_pool));
   SVN_ERR(svn_wc__node_is_status_absent(&absent, wb->ctx->wc_ctx,
                                         local_abspath, scratch_pool));
 
-   if (obstructed || deleted || absent)
+   if (deleted || absent)
     {
       propval = NULL;
       switched = FALSE;
@@ -5382,6 +5491,13 @@ get_mergeinfo_walk_cb(const char *local_
                          &&(kind == svn_node_dir)
                          && (strcmp(abs_parent_path,
                                     wb->merge_target_abspath) == 0));
+  /* Make sure what the WC thinks is present on disk really is. */
+   if (!absent && !deleted)
+    SVN_ERR(record_missing_subtree_roots(local_abspath, kind,
+                                         wb->subtree_dirents,
+                                         wb->missing_subtrees,
+                                         wb->cb_pool,
+                                         scratch_pool));
 
   /* Store PATHs with explict mergeinfo, which are switched, are missing
      children due to a sparse checkout, are scheduled for deletion are absent
@@ -5600,7 +5716,7 @@ insert_parent_and_sibs_of_sw_absent_del_
 /* Helper for do_directory_merge()
 
    If HONOR_MERGEINFO is TRUE, then perform a depth first walk of the working
-   copy tree rooted at MERGE_CMD_BATON->TARGET_ABSPATH.
+   copy tree rooted at MERGE_CMD_BATON->TARGET_ABSPATH to depth DEPTH.
    Create an svn_client__merge_path_t * for any path which meets one or more
    of the following criteria:
 
@@ -5628,6 +5744,9 @@ insert_parent_and_sibs_of_sw_absent_del_
    If HONOR_MERGEINFO is FALSE, then create an svn_client__merge_path_t * only
    for MERGE_CMD_BATON->TARGET_ABSPATH (i.e. only criteria 7 is applied).
 
+   If subtrees within the requested DEPTH are unexpectedly missing disk,
+   then raise SVN_ERR_CLIENT_NOT_READY_TO_MERGE.
+
    Store the svn_client__merge_path_t *'s in *CHILDREN_WITH_MERGEINFO in
    depth-first order based on the svn_client__merge_path_t *s path member as
    sorted by svn_path_compare_paths().  Set the remaining_ranges field of each
@@ -5667,6 +5786,9 @@ get_mergeinfo_paths(apr_array_header_t *
   struct get_mergeinfo_walk_baton wb = { 0 };
 
   wb.children_with_mergeinfo = children_with_mergeinfo;
+  wb.cb_pool = svn_pool_create(scratch_pool);
+  wb.subtree_dirents = apr_hash_make(wb.cb_pool);
+  wb.missing_subtrees = apr_hash_make(wb.cb_pool);
   wb.merge_src_canon_path = merge_src_canon_path;
   wb.merge_target_abspath = merge_cmd_baton->target_abspath;
   wb.source_root_url = source_root_url;
@@ -5690,6 +5812,35 @@ get_mergeinfo_paths(apr_array_header_t *
                                      merge_cmd_baton->ctx->cancel_baton,
                                      scratch_pool));
 
+  if (apr_hash_count(wb.missing_subtrees))
+    {
+      apr_hash_index_t *hi;
+      svn_stringbuf_t *missing_subtree_err_buf =
+        svn_stringbuf_create(_("Merge tracking not allowed with missing "
+                               "subtrees; try restoring these items "
+                               "first:\n"), scratch_pool);
+
+      iterpool = svn_pool_create(scratch_pool);
+
+      for (hi = apr_hash_first(scratch_pool, wb.missing_subtrees);
+           hi;
+           hi = apr_hash_next(hi))
+        {
+          svn_pool_clear(iterpool);
+          svn_stringbuf_appendcstr(missing_subtree_err_buf,
+                                   svn_dirent_local_style(
+                                     svn__apr_hash_index_key(hi), iterpool));
+          svn_stringbuf_appendcstr(missing_subtree_err_buf, "\n");
+        }
+
+    return svn_error_create(SVN_ERR_CLIENT_NOT_READY_TO_MERGE,
+                            NULL, missing_subtree_err_buf->data);
+  }
+
+  /* This pool is only needed across all the callbacks to detect
+     missing subtrees. */
+  svn_pool_destroy(wb.cb_pool);
+
   /* CHILDREN_WITH_MERGEINFO must be in depth first order, but the node
      walk code returns nodes in a non particular order.  Also, we may need
      to add elements to the array to cover case 3) through 5) from the
@@ -7192,7 +7343,8 @@ record_mergeinfo_for_dir_merge(svn_merge
      merge target, with no pre-existing explicit mergeinfo, during a --depth
      immediates merge).  Stash those that are inoperative at any depth in
      INOPERATIVE_IMMEDIATE_CHILDREN. */
-  if (!merge_b->record_only && range.start <= range.end)
+  if (!merge_b->record_only && range.start <= range.end
+      && depth == svn_depth_immediates)
     SVN_ERR(get_inoperative_immediate_children(
       &inoperative_immediate_children,
       notify_b->children_with_mergeinfo,
@@ -8316,6 +8468,11 @@ do_merge(apr_hash_t **modified_subtrees,
 
   SVN_ERR(svn_wc_read_kind(&target_kind, ctx->wc_ctx, target_abspath, FALSE,
                            pool));
+  if (target_kind != svn_node_dir && target_kind != svn_node_file)
+    return svn_error_return(svn_error_createf(
+                              SVN_ERR_ILLEGAL_TARGET, NULL,
+                              _("Merge target '%s' does not exist in the "
+                                "working copy"), target_abspath));
 
   /* Ensure a known depth. */
   if (depth == svn_depth_unknown)
@@ -8693,12 +8850,26 @@ merge_locked(const char *source1,
   apr_pool_t *sesspool;
   svn_boolean_t same_repos;
   const char *source_repos_uuid1, *source_repos_uuid2;
+  svn_node_kind_t target_kind;
 
-  /* Sanity check our input -- we require specified revisions. */
+  /* Make sure the target is really there. */
+  SVN_ERR(svn_io_check_path(target_abspath, &target_kind, scratch_pool));
+  if (target_kind == svn_node_none)
+    return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
+                             _("Path '%s' does not exist"),
+                             svn_dirent_local_style(target_abspath,
+                                                    scratch_pool));
+
+  /* Sanity check our input -- we require specified revisions,
+   * and either 2 paths or 2 URLs. */
   if ((revision1->kind == svn_opt_revision_unspecified)
       || (revision2->kind == svn_opt_revision_unspecified))
     return svn_error_create(SVN_ERR_CLIENT_BAD_REVISION, NULL,
                             _("Not all required revisions are specified"));
+  if (svn_path_is_url(source1) != svn_path_is_url(source2))
+    return svn_error_return(svn_error_create(SVN_ERR_ILLEGAL_TARGET, NULL,
+                                             _("Merge sources must both be "
+                                               "either paths or URLs")));
 
   /* ### FIXME: This function really ought to do a history check on
      the left and right sides of the merge source, and -- if one is an
@@ -8726,6 +8897,14 @@ merge_locked(const char *source1,
                              _("'%s' has no URL"),
                              svn_dirent_local_style(source2, scratch_pool));
 
+  SVN_ERR(svn_wc_read_kind(&target_kind, ctx->wc_ctx, target_abspath, FALSE,
+                           scratch_pool));
+  if (target_kind != svn_node_dir && target_kind != svn_node_file)
+    return svn_error_return(svn_error_createf(
+                              SVN_ERR_ILLEGAL_TARGET, NULL,
+                              _("Merge target '%s' does not exist in the "
+                                "working copy"), target_abspath));
+
   /* Determine the working copy target's repository root URL. */
   working_rev.kind = svn_opt_revision_working;
   SVN_ERR(svn_client__get_repos_root(&wc_repos_root, target_abspath,
@@ -9956,6 +10135,15 @@ merge_reintegrate_locked(const char *sou
   struct get_subtree_mergeinfo_walk_baton wb;
   const char *target_url;
   svn_revnum_t target_base_rev;
+  svn_node_kind_t kind;
+
+  /* Make sure the target is really there. */
+  SVN_ERR(svn_io_check_path(target_abspath, &kind, scratch_pool));
+  if (kind == svn_node_none)
+    return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
+                             _("Path '%s' does not exist"),
+                             svn_dirent_local_style(target_abspath,
+                                                    scratch_pool));
 
   /* Make sure we're dealing with a real URL. */
   SVN_ERR(svn_client_url_from_path2(&url2, source, ctx,
@@ -10216,8 +10404,17 @@ merge_peg_locked(const char *source,
   svn_boolean_t use_sleep = FALSE;
   svn_error_t *err;
   svn_boolean_t same_repos;
+  svn_node_kind_t target_kind;
 
   SVN_ERR_ASSERT(svn_dirent_is_absolute(target_abspath));
+  
+  /* Make sure the target is really there. */
+  SVN_ERR(svn_io_check_path(target_abspath, &target_kind, scratch_pool));
+  if (target_kind == svn_node_none)
+    return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
+                             _("Path '%s' does not exist"),
+                             svn_dirent_local_style(target_abspath,
+                                                    scratch_pool));
 
   /* Make sure we're dealing with a real URL. */
   SVN_ERR(svn_client_url_from_path2(&URL, source, ctx,
@@ -10227,6 +10424,14 @@ merge_peg_locked(const char *source,
                              _("'%s' has no URL"),
                              svn_dirent_local_style(source, scratch_pool));
 
+  SVN_ERR(svn_wc_read_kind(&target_kind, ctx->wc_ctx, target_abspath, FALSE,
+                           scratch_pool));
+  if (target_kind != svn_node_dir && target_kind != svn_node_file)
+    return svn_error_return(svn_error_createf(
+                              SVN_ERR_ILLEGAL_TARGET, NULL,
+                              _("Merge target '%s' does not exist in the "
+                                "working copy"), target_abspath));
+
   /* Determine the working copy target's repository root URL. */
   working_rev.kind = svn_opt_revision_working;
   SVN_ERR(svn_client__get_repos_root(&wc_repos_root, target_abspath,

Modified: subversion/branches/ignore-mergeinfo/subversion/libsvn_client/patch.c
URL: http://svn.apache.org/viewvc/subversion/branches/ignore-mergeinfo/subversion/libsvn_client/patch.c?rev=1044516&r1=1044515&r2=1044516&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_client/patch.c (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_client/patch.c Fri Dec 10 21:23:03 2010
@@ -48,7 +48,7 @@
 
 typedef struct hunk_info_t {
   /* The hunk. */
-  const svn_hunk_t *hunk;
+  const svn_diff_hunk_t *hunk;
 
   /* The line where the hunk matched in the target file. */
   svn_linenum_t matched_line;
@@ -176,7 +176,7 @@ typedef struct patch_target_t {
   /* True if at least one hunk was rejected. */
   svn_boolean_t had_rejects;
 
-  /* True if atleast one property hunk was rejected. */
+  /* True if at least one property hunk was rejected. */
   svn_boolean_t had_prop_rejects;
 
   /* True if the target file had local modifications before the
@@ -197,10 +197,10 @@ typedef struct patch_target_t {
   /* True if the target has the executable bit set. */
   svn_boolean_t executable;
 
-  /* True if the patch changes the text of the target */
+  /* True if the patch changed the text of the target. */
   svn_boolean_t has_text_changes;
 
-  /* True if the patch changes any of the properties of the target */
+  /* True if the patch changed any of the properties of the target. */
   svn_boolean_t has_prop_changes;
 
   /* All the information that is specific to the content of the target. */
@@ -256,7 +256,8 @@ strip_path(const char **result, const ch
   return SVN_NO_ERROR;
 }
 
-/* Obtain KEYWORDS, EOL_STYLE and EOL_STR for LOCAL_ABSPATH, from WC_CTX.
+/* Obtain KEYWORDS, EOL_STYLE and EOL_STR for LOCAL_ABSPATH.
+ * WC_CTX is a context for the working copy the patch is applied to.
  * Use RESULT_POOL for allocations of fields in TARGET.
  * Use SCRATCH_POOL for all other allocations. */
 static svn_error_t *
@@ -271,7 +272,6 @@ obtain_eol_and_keywords_for_file(apr_has
   apr_hash_t *props;
   svn_string_t *keywords_val, *eol_style_val;
 
-  /* Handle svn:keyword and svn:eol-style properties. */
   SVN_ERR(svn_wc_prop_list2(&props, wc_ctx, local_abspath,
                             scratch_pool, scratch_pool));
   keywords_val = apr_hash_get(props, SVN_PROP_KEYWORDS,
@@ -322,8 +322,9 @@ obtain_eol_and_keywords_for_file(apr_has
  * Indicate in TARGET->SKIPPED whether the target should be skipped.
  * STRIP_COUNT specifies the number of leading path components
  * which should be stripped from target paths in the patch.
- * PROP_CHANGES_ONLY is used for determining if the target path is allowed
- * to be a dir.
+ * PROP_CHANGES_ONLY specifies whether the target path is allowed to have
+ * only property changes, and no content changes (in which case the target
+ * must be a directory).
  * Use RESULT_POOL for allocations of fields in TARGET.
  * Use SCRATCH_POOL for all other allocations. */
 static svn_error_t *
@@ -437,7 +438,7 @@ resolve_target_path(patch_target_t *targ
   SVN_ERR(svn_wc_read_kind(&target->db_kind, wc_ctx, target->local_abspath,
                            FALSE, scratch_pool));
 
-  /* If the target is a version directory not missing from disk,
+  /* 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)
@@ -510,14 +511,10 @@ init_prop_target(prop_patch_target_t **p
     }
 
   if (value)
-    {
-      /* We assume that a property is small enough to be kept in memory during
-       * the patch process. */
-      content_info->stream = svn_stream_from_string(value, result_pool);
-    }
+    content_info->stream = svn_stream_from_string(value, result_pool);
 
   /* Create a temporary file to write the patched result to. For properties,
-   * we don't have to worrry about different eol-style. */
+   * we don't have to worry about eol-style. ### Why not? */
   SVN_ERR(svn_stream_open_unique(&content_info->patched,
                                  &patched_path, NULL,
                                  remove_tempfiles ?
@@ -535,17 +532,22 @@ init_prop_target(prop_patch_target_t **p
  * described by PATCH. Use working copy context WC_CTX.
  * STRIP_COUNT specifies the number of leading path components
  * which should be stripped from target paths in the patch.
+ * OLD_PATCH_TARGET_NAMES indicates whether the old target's name parsed
+ * from the patch file should be preferred over the new target's name.
  * The patch target structure is allocated in RESULT_POOL, but if the target
  * should be skipped, PATCH_TARGET->SKIPPED is set and the target should be
  * treated as not fully initialized, e.g. the caller should not not do any
  * further operations on the target if it is marked to be skipped.
- * REMOVE_TEMPFILES as in svn_client_patch().
+ * If REMOVE_TEMPFILES is TRUE, set up temporary files to be removed as
+ * soon as they are no longer needed.
  * Use SCRATCH_POOL for all other allocations. */
 static svn_error_t *
 init_patch_target(patch_target_t **patch_target,
                   const svn_patch_t *patch,
                   const char *base_dir,
-                  svn_wc_context_t *wc_ctx, int strip_count,
+                  svn_wc_context_t *wc_ctx,
+                  int strip_count,
+                  svn_boolean_t old_patch_target_names,
                   svn_boolean_t remove_tempfiles,
                   apr_pool_t *result_pool, apr_pool_t *scratch_pool)
 {
@@ -557,7 +559,6 @@ init_patch_target(patch_target_t **patch
   {
     apr_hash_index_t *hi;
 
-    /* ### Should we use an iterpool here? */
     for (hi = apr_hash_first(scratch_pool, patch->prop_patches);
          hi;
          hi = apr_hash_next(hi))
@@ -592,7 +593,8 @@ init_patch_target(patch_target_t **patch
   target->prop_targets = apr_hash_make(result_pool);
   target->pool = result_pool;
 
-  SVN_ERR(resolve_target_path(target, patch->new_filename,
+  SVN_ERR(resolve_target_path(target, old_patch_target_names ?
+                                patch->old_filename : patch->new_filename,
                               base_dir, strip_count, prop_changes_only,
                               wc_ctx, result_pool, scratch_pool));
   if (! target->skipped)
@@ -602,18 +604,17 @@ init_patch_target(patch_target_t **patch
       apr_size_t len;
       svn_stream_t *patched_raw;
 
+      /* Create a temporary file, and associated streams,
+       * to write the patched result to. */
       if (target->kind_on_disk == svn_node_file)
         {
-          /* Open the file. */
           SVN_ERR(svn_io_file_open(&target->file, target->local_abspath,
                                    APR_READ | APR_BINARY | APR_BUFFERED,
                                    APR_OS_DEFAULT, result_pool));
 
-          /* Create a stream to read from the target. */
           content_info->stream = svn_stream_from_aprfile2(target->file,
                                                           FALSE, result_pool);
 
-          /* Also check the file for local mods and the Xbit. */
           SVN_ERR(svn_wc_text_modified_p2(&target->local_mods, wc_ctx,
                                           target->local_abspath, FALSE,
                                           scratch_pool));
@@ -630,7 +631,14 @@ init_patch_target(patch_target_t **patch
                                                    scratch_pool));
         }
 
-      /* Create a temporary file to write the patched result to. */
+      /* ### Is it ok to set target->added here? Isn't the target supposed to
+       * ### be marked as added after it's been proven that it can be added?
+       * ### One alternative is to include a git_added flag. Or maybe we
+       * ### should have kept the patch field in patch_target_t? Then we
+       * ### could have checked for target->patch->operation == added */
+      if (patch->operation == svn_diff_op_added)
+        target->added = TRUE;
+
       SVN_ERR(svn_stream_open_unique(&patched_raw,
                                      &target->patched_path, NULL,
                                      remove_tempfiles ?
@@ -638,16 +646,15 @@ init_patch_target(patch_target_t **patch
                                        svn_io_file_del_none,
                                      result_pool, scratch_pool));
 
-      /* Expand keywords in the patched file.
-       * Repair newlines if svn:eol-style dictates a particular style. */
+      /* We always expand keywords in the patched file, but repair newlines
+       * only if svn:eol-style dictates a particular style. */
       repair_eol = (content_info->eol_style == svn_subst_eol_style_fixed 
                     || content_info->eol_style == svn_subst_eol_style_native);
       content_info->patched = svn_subst_stream_translated(
                               patched_raw, content_info->eol_str, repair_eol,
                               content_info->keywords, TRUE, result_pool);
 
-      /* We'll also need a stream to write rejected hunks to.
-       * We don't expand keywords, nor normalise line-endings,
+      /* We don't expand keywords, nor normalise line-endings,
        * in reject files. */
       SVN_ERR(svn_stream_open_unique(&content_info->reject,
                                      &target->reject_path, NULL,
@@ -665,7 +672,7 @@ init_patch_target(patch_target_t **patch
       len = strlen(diff_header);
       SVN_ERR(svn_stream_write(content_info->reject, diff_header, &len));
 
-      /* Time for the properties */
+      /* Handle properties. */
       if (! target->skipped)
         {
           apr_hash_index_t *hi;
@@ -678,7 +685,6 @@ init_patch_target(patch_target_t **patch
               svn_prop_patch_t *prop_patch = svn__apr_hash_index_val(hi);
               prop_patch_target_t *prop_target;
 
-              /* Obtain info about this property */
               SVN_ERR(init_prop_target(&prop_target,
                                        prop_name,
                                        prop_patch->operation,
@@ -687,7 +693,6 @@ init_patch_target(patch_target_t **patch
                                        wc_ctx, target->local_abspath,
                                        result_pool, scratch_pool));
 
-              /* Store the info */
               apr_hash_set(target->prop_targets, prop_name,
                            APR_HASH_KEY_STRING, prop_target);
             }
@@ -800,7 +805,7 @@ seek_to_line(target_content_info_t *cont
  * Do temporary allocations in POOL. */
 static svn_error_t *
 match_hunk(svn_boolean_t *matched, target_content_info_t *content_info,
-           const svn_hunk_t *hunk, int fuzz, 
+           const svn_diff_hunk_t *hunk, int fuzz,
            svn_boolean_t ignore_whitespace,
            svn_boolean_t match_modified, apr_pool_t *pool)
 {
@@ -811,7 +816,7 @@ match_hunk(svn_boolean_t *matched, targe
   svn_boolean_t hunk_eof;
   svn_boolean_t lines_matched;
   apr_pool_t *iterpool;
-  svn_linenum_t original_length;
+  svn_linenum_t hunk_length;
   svn_linenum_t leading_context;
   svn_linenum_t trailing_context;
 
@@ -823,13 +828,18 @@ match_hunk(svn_boolean_t *matched, targe
   saved_line = content_info->current_line;
   lines_read = 0;
   lines_matched = FALSE;
-  original_length = svn_diff_hunk_get_original_length(hunk);
   leading_context = svn_diff_hunk_get_leading_context(hunk);
   trailing_context = svn_diff_hunk_get_trailing_context(hunk);
   if (match_modified)
-    SVN_ERR(svn_diff_hunk_reset_modified_text(hunk));
+    {
+      SVN_ERR(svn_diff_hunk_reset_modified_text(hunk));
+      hunk_length = svn_diff_hunk_get_modified_length(hunk);
+    }
   else
-    SVN_ERR(svn_diff_hunk_reset_original_text(hunk));
+    {
+      SVN_ERR(svn_diff_hunk_reset_original_text(hunk));
+      hunk_length = svn_diff_hunk_get_original_length(hunk);
+    }
   iterpool = svn_pool_create(pool);
   do
     {
@@ -852,59 +862,41 @@ match_hunk(svn_boolean_t *matched, targe
                                            NULL, FALSE,
                                            content_info->keywords, FALSE,
                                            iterpool));
-      lines_read++;
       SVN_ERR(read_line(content_info, &target_line, iterpool, iterpool));
-      if (! hunk_eof)
+
+      lines_read++;
+
+      /* If the last line doesn't have a newline, we get EOF but still
+       * have a non-empty line to compare. */
+      if ((hunk_eof && hunk_line->len == 0) ||
+          (content_info->eof && strlen(target_line) == 0))
+        break;
+
+      /* Leading/trailing fuzzy lines always match. */
+      if ((lines_read <= fuzz && leading_context > fuzz) ||
+          (lines_read > hunk_length - fuzz && trailing_context > fuzz))
+        lines_matched = TRUE;
+      else
         {
-          if (lines_read <= fuzz && leading_context > fuzz)
-            lines_matched = TRUE;
-          else if (lines_read > original_length - fuzz &&
-                   trailing_context > fuzz)
-            lines_matched = TRUE;
-          else
+          if (ignore_whitespace)
             {
-              if (ignore_whitespace)
-                {
-                  char *stripped_hunk_line = apr_pstrdup(pool,
-                                                         hunk_line_translated);
-                  char *stripped_target_line = apr_pstrdup(pool, target_line);
-
-                  apr_collapse_spaces(stripped_hunk_line,
-                                      hunk_line_translated);
-                  apr_collapse_spaces(stripped_target_line, target_line);
-                  lines_matched = ! strcmp(stripped_hunk_line,
-                                           stripped_target_line);
-                }
-              else 
-                lines_matched = ! strcmp(hunk_line_translated, target_line);
+              char *hunk_line_trimmed;
+              char *target_line_trimmed;
+
+              hunk_line_trimmed = apr_pstrdup(iterpool, hunk_line_translated);
+              target_line_trimmed = apr_pstrdup(iterpool, target_line);
+              apr_collapse_spaces(hunk_line_trimmed, hunk_line_trimmed);
+              apr_collapse_spaces(target_line_trimmed, target_line_trimmed);
+              lines_matched = ! strcmp(hunk_line_trimmed, target_line_trimmed);
             }
+          else
+            lines_matched = ! strcmp(hunk_line_translated, target_line);
         }
     }
-  while (lines_matched && ! (hunk_eof || content_info->eof));
+  while (lines_matched);
 
-  if (hunk_eof)
-    *matched = lines_matched;
-  else if (content_info->eof)
-    {
-      /* If the target has no newline at end-of-file, we get an EOF
-       * indication for the target earlier than we do get it for the hunk. */
-      if (match_modified)
-        SVN_ERR(svn_diff_hunk_readline_modified_text(hunk, &hunk_line,
-                                                     NULL, &hunk_eof,
-                                                     iterpool, iterpool));
-      else
-        SVN_ERR(svn_diff_hunk_readline_original_text(hunk, &hunk_line,
-                                                     NULL, &hunk_eof,
-                                                     iterpool, iterpool));
+  *matched = lines_matched && hunk_eof && hunk_line->len == 0;
 
-      /* When comparing modified text we require that all lines match, else
-       * a hunk that adds a newline at the end will be treated as already
-       * applied even if it isn't. */
-      if (! match_modified && hunk_line->len == 0 && hunk_eof)
-        *matched = lines_matched;
-      else
-        *matched = FALSE;
-    }
   SVN_ERR(seek_to_line(content_info, saved_line, iterpool));
 
   svn_pool_destroy(iterpool);
@@ -929,7 +921,7 @@ match_hunk(svn_boolean_t *matched, targe
 static svn_error_t *
 scan_for_match(svn_linenum_t *matched_line, 
                target_content_info_t *content_info,
-               const svn_hunk_t *hunk, svn_boolean_t match_first,
+               const svn_diff_hunk_t *hunk, svn_boolean_t match_first,
                svn_linenum_t upper_line, int fuzz, 
                svn_boolean_t ignore_whitespace,
                svn_boolean_t match_modified,
@@ -1001,7 +993,7 @@ scan_for_match(svn_linenum_t *matched_li
 static svn_error_t *
 match_existing_target(svn_boolean_t *match,
                       target_content_info_t *content_info,
-                      const svn_hunk_t *hunk,
+                      const svn_diff_hunk_t *hunk,
                       svn_stream_t *stream,
                       apr_pool_t *scratch_pool)
 {
@@ -1057,14 +1049,16 @@ match_existing_target(svn_boolean_t *mat
  * RESULT_POOL. Use fuzz factor FUZZ. Set HI->FUZZ to FUZZ. If no correct
  * line can be determined, set HI->REJECTED to TRUE.
  * IGNORE_WHITESPACE tells whether whitespace should be considered when
- * matching. When this function returns, neither CONTENT_INFO->CURRENT_LINE nor
+ * matching. IS_PROP_HUNK indicates whether the hunk patches file content
+ * or a property.
+ * When this function returns, neither CONTENT_INFO->CURRENT_LINE nor
  * the file offset in the target file will have changed.
  * Call cancel CANCEL_FUNC with baton CANCEL_BATON to trigger cancellation.
  * Do temporary allocations in POOL. */
 static svn_error_t *
 get_hunk_info(hunk_info_t **hi, patch_target_t *target,
               target_content_info_t *content_info,
-              const svn_hunk_t *hunk, int fuzz, 
+              const svn_diff_hunk_t *hunk, int fuzz,
               svn_boolean_t ignore_whitespace,
               svn_boolean_t is_prop_hunk,
               svn_cancel_func_t cancel_func, void *cancel_baton,
@@ -1100,7 +1094,7 @@ get_hunk_info(hunk_info_t **hi, patch_ta
 
               SVN_ERR(match_existing_target(&file_matches, content_info, hunk,
                                             stream, scratch_pool));
-              svn_stream_close(stream);
+              SVN_ERR(svn_stream_close(stream));
 
               if (file_matches)
                 {
@@ -1148,54 +1142,55 @@ get_hunk_info(hunk_info_t **hi, patch_ta
   else if (original_start > 0 && content_info->stream)
     {
       svn_linenum_t saved_line = content_info->current_line;
-      svn_linenum_t modified_start;
 
-      /* Check if the hunk is already applied.
-       * We only check for an exact match here, and don't bother checking
-       * for already applied patches with offset/fuzz, because such a
-       * check would be ambiguous. */
-      if (fuzz == 0)
+      /* Scan for a match at the line where the hunk thinks it
+       * should be going. */
+      SVN_ERR(seek_to_line(content_info, original_start, scratch_pool));
+      if (content_info->current_line != original_start)
         {
-          modified_start = svn_diff_hunk_get_modified_start(hunk);
-          if (modified_start == 0)
-            {
-              /* Patch wants to delete the file. */
-              already_applied = target->locally_deleted;
-            }
-          else
-            {
-              SVN_ERR(seek_to_line(content_info, modified_start,
-                                   scratch_pool));
-              SVN_ERR(scan_for_match(&matched_line, content_info,
-                                     hunk, TRUE,
-                                     modified_start + 1,
-                                     fuzz, ignore_whitespace, TRUE,
-                                     cancel_func, cancel_baton,
-                                     scratch_pool));
-              already_applied = (matched_line == modified_start);
-            }
+          /* Seek failed. */
+          matched_line = 0;
         }
       else
-        already_applied = FALSE;
+        SVN_ERR(scan_for_match(&matched_line, content_info, hunk, TRUE,
+                               original_start + 1, fuzz,
+                               ignore_whitespace, FALSE,
+                               cancel_func, cancel_baton,
+                               scratch_pool));
 
-      if (! already_applied)
+      if (matched_line != original_start)
         {
-          /* Scan for a match at the line where the hunk thinks it
-           * should be going. */
-          SVN_ERR(seek_to_line(content_info, original_start, scratch_pool));
-          if (content_info->current_line != original_start)
+          /* Check if the hunk is already applied.
+           * We only check for an exact match here, and don't bother checking
+           * for already applied patches with offset/fuzz, because such a
+           * check would be ambiguous. */
+          if (fuzz == 0)
             {
-              /* Seek failed. */
-              matched_line = 0;
+              svn_linenum_t modified_start;
+
+              modified_start = svn_diff_hunk_get_modified_start(hunk);
+              if (modified_start == 0)
+                {
+                  /* Patch wants to delete the file. */
+                  already_applied = target->locally_deleted;
+                }
+              else
+                {
+                  SVN_ERR(seek_to_line(content_info, modified_start,
+                                       scratch_pool));
+                  SVN_ERR(scan_for_match(&matched_line, content_info,
+                                         hunk, TRUE,
+                                         modified_start + 1,
+                                         fuzz, ignore_whitespace, TRUE,
+                                         cancel_func, cancel_baton,
+                                         scratch_pool));
+                  already_applied = (matched_line == modified_start);
+                }
             }
           else
-            SVN_ERR(scan_for_match(&matched_line, content_info, hunk, TRUE,
-                                   original_start + 1, fuzz,
-                                   ignore_whitespace, FALSE,
-                                   cancel_func, cancel_baton,
-                                   scratch_pool));
+            already_applied = FALSE;
 
-          if (matched_line != original_start)
+          if (! already_applied)
             {
               /* Scan the whole file again from the start. */
               SVN_ERR(seek_to_line(content_info, 1, scratch_pool));
@@ -1313,6 +1308,8 @@ reject_hunk(patch_target_t *target, targ
 
       SVN_ERR(svn_stream_write(content_info->reject, prop_header, &len));
 
+      /* ### What about just setting a variable to either "@@" or "##",
+       * ### and merging with the else clause below? */
       hunk_header = apr_psprintf(pool, "## -%lu,%lu +%lu,%lu ##%s",
                                  svn_diff_hunk_get_original_start(hi->hunk),
                                  svn_diff_hunk_get_original_length(hi->hunk),
@@ -1362,8 +1359,11 @@ reject_hunk(patch_target_t *target, targ
   return SVN_NO_ERROR;
 }
 
-/* Write the modified text of hunk described by HI to the patched
- * stream of CONTENT_INFO. Do temporary allocations in POOL. */
+/* Write the modified text of the hunk described by HI to the patched
+ * stream of CONTENT_INFO. TARGET is the patch target.
+ * If PROP_NAME is not NULL, the hunk is assumed to be targeted for
+ * a property with the given name.
+ * Do temporary allocations in POOL. */
 static svn_error_t *
 apply_hunk(patch_target_t *target, target_content_info_t *content_info,  
            hunk_info_t *hi, const char *prop_name, apr_pool_t *pool)
@@ -1449,7 +1449,8 @@ apply_hunk(patch_target_t *target, targe
 
 /* Use client context CTX to send a suitable notification for hunk HI,
  * using TARGET to determine the path. If the hunk is a property hunk,
- * PROP_NAME is set, else NULL. Use POOL for temporary allocations. */
+ * PROP_NAME must be the name of the property, else NULL.
+ * Use POOL for temporary allocations. */
 static svn_error_t *
 send_hunk_notification(const hunk_info_t *hi, 
                        const patch_target_t *target, 
@@ -1591,12 +1592,53 @@ send_patch_notification(const patch_targ
   return SVN_NO_ERROR;
 }
 
+/* Close the streams of the TARGET so that their content is flushed
+ * to disk. This will also close underlying streams and files. Use POOL for
+ * temporary allocations. */
+static svn_error_t *
+close_target_streams(const patch_target_t *target,
+                     apr_pool_t *pool)
+{
+  apr_hash_index_t *hi;
+  target_content_info_t *prop_content_info;
+
+   /* First the streams belonging to properties .. */
+      for (hi = apr_hash_first(pool, target->prop_targets);
+           hi;
+           hi = apr_hash_next(hi))
+        {
+          prop_patch_target_t *prop_target;
+          prop_target = svn__apr_hash_index_val(hi);
+          prop_content_info = prop_target->content_info;
+
+          /* ### If the prop did not exist pre-patching we'll not have a
+           * ### stream to read from. Find a better way to store info on
+           * ### the existence of the target prop. */
+          if (prop_content_info->stream)
+            SVN_ERR(svn_stream_close(prop_content_info->stream));
+
+          SVN_ERR(svn_stream_close(prop_content_info->patched));
+        }
+
+
+   /* .. And then streams associted with the file. The reject stream is
+    * shared between all target_content_info structures. */
+  if (target->kind_on_disk == svn_node_file)
+    SVN_ERR(svn_stream_close(target->content_info->stream));
+  SVN_ERR(svn_stream_close(target->content_info->patched));
+  SVN_ERR(svn_stream_close(target->content_info->reject));
+
+  return SVN_NO_ERROR;
+}
+
 /* Apply a PATCH to a working copy at ABS_WC_PATH and put the result
  * into temporary files, to be installed in the working copy later.
  * Return information about the patch target in *PATCH_TARGET, allocated
  * in RESULT_POOL. Use WC_CTX as the working copy context.
  * STRIP_COUNT specifies the number of leading path components
  * which should be stripped from target paths in the patch.
+ * OLD_PATCH_TARGET_NAMES indicates whether the old filename parsed
+ * from the patch file should be preferred over the new filename.
  * REMOVE_TEMPFILES, PATCH_FUNC, and PATCH_BATON as in svn_client_patch().
  * IGNORE_WHITESPACE tells whether whitespace should be considered when
  * doing the matching.
@@ -1606,6 +1648,7 @@ static svn_error_t *
 apply_one_patch(patch_target_t **patch_target, svn_patch_t *patch,
                 const char *abs_wc_path, svn_wc_context_t *wc_ctx,
                 int strip_count,
+                svn_boolean_t old_patch_target_names,
                 svn_boolean_t ignore_whitespace,
                 svn_boolean_t remove_tempfiles,
                 svn_client_patch_func_t patch_func,
@@ -1620,7 +1663,8 @@ apply_one_patch(patch_target_t **patch_t
   static const int MAX_FUZZ = 2;
   apr_hash_index_t *hash_index;
 
-  SVN_ERR(init_patch_target(&target, patch, abs_wc_path, wc_ctx, strip_count,
+  SVN_ERR(init_patch_target(&target, patch, abs_wc_path, wc_ctx,
+                            strip_count, old_patch_target_names,
                             remove_tempfiles, result_pool, scratch_pool));
   if (target->skipped)
     {
@@ -1645,7 +1689,7 @@ apply_one_patch(patch_target_t **patch_t
   /* Match hunks. */
   for (i = 0; i < patch->hunks->nelts; i++)
     {
-      svn_hunk_t *hunk;
+      svn_diff_hunk_t *hunk;
       hunk_info_t *hi;
       int fuzz = 0;
 
@@ -1654,7 +1698,7 @@ apply_one_patch(patch_target_t **patch_t
       if (cancel_func)
         SVN_ERR((cancel_func)(cancel_baton));
 
-      hunk = APR_ARRAY_IDX(patch->hunks, i, svn_hunk_t *);
+      hunk = APR_ARRAY_IDX(patch->hunks, i, svn_diff_hunk_t *);
 
       /* Determine the line the hunk should be applied at.
        * If no match is found initially, try with fuzz. */
@@ -1705,7 +1749,7 @@ apply_one_patch(patch_target_t **patch_t
         }
     }
 
-  /* Match property hunks. */
+  /* Match property hunks.   ### Can we use scratch_pool here? */
   for (hash_index = apr_hash_first(result_pool, patch->prop_patches);
        hash_index;
        hash_index = apr_hash_next(hash_index))
@@ -1713,21 +1757,17 @@ apply_one_patch(patch_target_t **patch_t
       svn_prop_patch_t *prop_patch;
       const char *prop_name;
       prop_patch_target_t *prop_target;
-      target_content_info_t *prop_content_info;
         
-      /* Fetching the parsed info for one property */
       prop_name = svn__apr_hash_index_key(hash_index);
       prop_patch = svn__apr_hash_index_val(hash_index);
 
-      /* Fetch the prop_content_info we'll use to store the matched hunks
-       * in. */
+      /* We'll store matched hunks in prop_content_info. */
       prop_target = apr_hash_get(target->prop_targets, prop_name, 
                                  APR_HASH_KEY_STRING);
-      prop_content_info = prop_target->content_info;
 
       for (i = 0; i < prop_patch->hunks->nelts; i++)
         {
-          svn_hunk_t *hunk;
+          svn_diff_hunk_t *hunk;
           hunk_info_t *hi;
           int fuzz = 0;
 
@@ -1736,13 +1776,14 @@ apply_one_patch(patch_target_t **patch_t
           if (cancel_func)
             SVN_ERR((cancel_func)(cancel_baton));
 
-          hunk = APR_ARRAY_IDX(prop_patch->hunks, i, svn_hunk_t *);
+          hunk = APR_ARRAY_IDX(prop_patch->hunks, i, svn_diff_hunk_t *);
 
           /* Determine the line the hunk should be applied at.
            * If no match is found initially, try with fuzz. */
           do
             {
-              SVN_ERR(get_hunk_info(&hi, target, prop_content_info, hunk, fuzz,
+              SVN_ERR(get_hunk_info(&hi, target, prop_target->content_info, 
+                                    hunk, fuzz,
                                     ignore_whitespace,
                                     TRUE /* is_prop_hunk */,
                                     cancel_func, cancel_baton,
@@ -1751,7 +1792,7 @@ apply_one_patch(patch_target_t **patch_t
             }
           while (hi->rejected && fuzz <= MAX_FUZZ && ! hi->already_applied);
 
-          APR_ARRAY_PUSH(prop_content_info->hunks, hunk_info_t *) = hi;
+          APR_ARRAY_PUSH(prop_target->content_info->hunks, hunk_info_t *) = hi;
         }
     }
 
@@ -1761,47 +1802,40 @@ apply_one_patch(patch_target_t **patch_t
        hash_index = apr_hash_next(hash_index))
     {
       prop_patch_target_t *prop_target;
-      target_content_info_t *prop_content_info;
-      const char *prop_patched_path;
 
       prop_target = svn__apr_hash_index_val(hash_index);
-      prop_content_info = prop_target->content_info;
-      prop_patched_path = prop_target->patched_path;
 
-      for (i = 0; i < prop_content_info->hunks->nelts; i++)
+      for (i = 0; i < prop_target->content_info->hunks->nelts; i++)
         {
           hunk_info_t *hi;
 
           svn_pool_clear(iterpool);
 
-          hi = APR_ARRAY_IDX(prop_content_info->hunks, i, hunk_info_t *);
+          hi = APR_ARRAY_IDX(prop_target->content_info->hunks, i, 
+                             hunk_info_t *);
           if (hi->already_applied)
             continue;
           else if (hi->rejected)
-            SVN_ERR(reject_hunk(target, prop_content_info, hi,
+            SVN_ERR(reject_hunk(target, prop_target->content_info, hi,
                                 prop_target->name,
                                 iterpool));
           else
-            SVN_ERR(apply_hunk(target, prop_content_info, hi, 
+            SVN_ERR(apply_hunk(target, prop_target->content_info, hi, 
                                prop_target->name,
                                iterpool));
         }
 
-        if (prop_content_info->stream)
+        if (prop_target->content_info->stream)
           {
             /* Copy any remaining lines to target. */
-            SVN_ERR(copy_lines_to_target(prop_content_info, 0,
-                                         prop_patched_path, scratch_pool));
-            if (! prop_content_info->eof)
+            SVN_ERR(copy_lines_to_target(prop_target->content_info, 0,
+                                         prop_target->patched_path, 
+                                         scratch_pool));
+            if (! prop_target->content_info->eof)
               {
                 /* We could not copy the entire target property to the
                  * temporary file, and would truncate the target if we
-                 * copied the temporary file on top of it. Skip this target. 
-                 *
-                 * ### dannas: Do we really want to skip an entire target
-                 * ### if one of the properties does not apply cleanly,
-                 * ### e.g. both text changes and all prop changes will not be
-                 * ### installed. */
+                 * copied the temporary file on top of it. Skip this target.  */
                 target->skipped = TRUE;
               }
           }
@@ -1809,38 +1843,7 @@ apply_one_patch(patch_target_t **patch_t
 
   svn_pool_destroy(iterpool);
 
-    {
-      apr_hash_index_t *hi;
-      target_content_info_t *prop_content_info;
-
-      /* Close the streams of the target so that their content is flushed
-       * to disk. This will also close underlying streams and files. 
-       * First the streams belonging to properties .. */
-          for (hi = apr_hash_first(result_pool, target->prop_targets);
-               hi;
-               hi = apr_hash_next(hi))
-            {
-              prop_patch_target_t *prop_target;
-              prop_target = svn__apr_hash_index_val(hi);
-              prop_content_info = prop_target->content_info;
-
-              /* ### If the prop did not exist pre-patching we'll not have a
-               * ### stream to read from. Find a better way to store info on
-               * ### the existence of the target prop. */
-              if (prop_content_info->stream)
-                svn_stream_close(prop_content_info->stream);
-
-              svn_stream_close(prop_content_info->patched);
-            }
-
-
-       /* .. And then streams associted with the file. The reject stream is
-        * shared between all target_content_info structures. */
-      if (target->kind_on_disk == svn_node_file)
-        SVN_ERR(svn_stream_close(target->content_info->stream));
-      SVN_ERR(svn_stream_close(target->content_info->patched));
-      SVN_ERR(svn_stream_close(target->content_info->reject));
-    }
+  SVN_ERR(close_target_streams(target, scratch_pool));
 
   if (! target->skipped)
     {
@@ -1871,9 +1874,13 @@ apply_one_patch(patch_target_t **patch_t
       else if (patched_file.size == 0 && working_file.size == 0)
         {
           /* The target was empty or non-existent to begin with
-           * and nothing has changed by patching.
-           * Report this as skipped if it didn't exist. */
-          if (target->kind_on_disk == svn_node_none)
+           * and no content was changed by patching.
+           * Report this as skipped if it didn't exist, unless in the special
+           * case of adding an empty file which has properties set on it or
+           * adding an empty file with a 'git diff' */
+          if (target->kind_on_disk == svn_node_none 
+              && ! target->has_prop_changes
+              && ! target->added)
             target->skipped = TRUE;
         }
       else if (patched_file.size > 0 && working_file.size == 0)
@@ -1966,7 +1973,7 @@ create_missing_parents(patch_target_t *t
         }
       else
         {
-          /* It's not a file, it's not a dir.. 
+          /* It's not a file, it's not a dir...
              Let's add a dir */
           break;
         }
@@ -2149,7 +2156,7 @@ write_out_rejected_hunks(patch_target_t 
 
 /* Install the patched properties for TARGET. Use client context CTX to
  * retrieve WC_CTX. If DRY_RUN is TRUE, don't modify the working copy.
- * Do tempoary allocations in SCRATCH_POOL. */
+ * Do temporary allocations in SCRATCH_POOL. */
 static svn_error_t *
 install_patched_prop_targets(patch_target_t *target,
                              svn_client_ctx_t *ctx, svn_boolean_t dry_run,
@@ -2159,7 +2166,12 @@ install_patched_prop_targets(patch_targe
   apr_pool_t *iterpool;
 
   if (dry_run)
-    return SVN_NO_ERROR;
+    {
+      if (! target->has_text_changes && target->kind_on_disk == svn_node_none)
+        target->added = TRUE;
+
+      return SVN_NO_ERROR;
+    }
 
   iterpool = svn_pool_create(scratch_pool);
 
@@ -2183,17 +2195,18 @@ install_patched_prop_targets(patch_targe
           SVN_ERR(svn_wc_prop_set4(ctx->wc_ctx, target->local_abspath,
                                    prop_target->name, NULL, 
                                    TRUE /* skip_checks */,
-                                   NULL, NULL,
+                                   NULL, NULL, /* suppress notification */
                                    iterpool));
           continue;
         }
 
-      /* A property is usually one line long.
-       * ### Is this the optimal size to allocate? */
+      /* A property is usually small, at most a couple of bytes.
+       * Start out assuming it won't be larger than a typical line of text. */
       prop_content = svn_stringbuf_create_ensure(80, scratch_pool);
 
       /* svn_wc_prop_set4() wants a svn_string_t for input so we need to
-       * open the tmp file for reading again. */
+       * open the tmp file for reading again.
+       * ### Just keep it open? */
       SVN_ERR(svn_io_file_open(&file, prop_target->patched_path,
                                APR_READ | APR_BINARY, APR_OS_DEFAULT,
                                scratch_pool));
@@ -2214,10 +2227,37 @@ install_patched_prop_targets(patch_targe
         }
       while (! eof);
 
-      svn_stream_close(patched_stream);
+      SVN_ERR(svn_stream_close(patched_stream));
+
+      /* If the patch target doesn't exist yet, the patch wants to add an
+       * empty file with properties set on it. So create an empty file and
+       * add it to version control. But if the patch was in the 'git format'
+       * then the file has already been added.
+       *
+       * ### How can we tell whether the patch really wanted to create
+       * ### an empty directory? */
+      if (! target->has_text_changes 
+          && target->kind_on_disk == svn_node_none
+          && ! target->added)
+        {
+          SVN_ERR(svn_io_file_create(target->local_abspath, "", scratch_pool));
+          SVN_ERR(svn_wc_add4(ctx->wc_ctx, target->local_abspath,
+                              svn_depth_infinity,
+                              NULL, SVN_INVALID_REVNUM,
+                              ctx->cancel_func,
+                              ctx->cancel_baton,
+                              NULL, NULL, /* suppress notification */
+                              iterpool));
+          target->added = TRUE;
+        }
 
       /* ### How should we handle SVN_ERR_ILLEGAL_TARGET and
-       * ### SVN_ERR_BAD_MIME_TYPE? */
+       * ### SVN_ERR_BAD_MIME_TYPE?
+       *
+       * ### stsp: I'd say reject the property hunk.
+       * ###       We should verify all modified prop hunk texts using
+       * ###       svn_wc_canonicalize_svn_prop() before starting the
+       * ###       patching process, to reject them as early as possible. */
       SVN_ERR(svn_wc_prop_set4(ctx->wc_ctx, target->local_abspath,
                                prop_target->name,
                                svn_string_create_from_buf(prop_content, 
@@ -2511,6 +2551,9 @@ typedef struct {
   /* Number of leading components to strip from patch target paths. */
   int strip_count;
 
+  /* Whether to use the old path from the patch file instead of the new one. */
+  svn_boolean_t old_patch_target_names;
+
   /* Whether to apply the patch in reverse. */
   svn_boolean_t reverse;
 
@@ -2576,6 +2619,7 @@ apply_patches(void *baton,
 
           SVN_ERR(apply_one_patch(&target, patch, btn->abs_wc_path,
                                   btn->ctx->wc_ctx, btn->strip_count,
+                                  btn->old_patch_target_names,
                                   btn->ignore_whitespace,
                                   btn->remove_tempfiles,
                                   btn->patch_func, btn->patch_baton,
@@ -2595,7 +2639,7 @@ apply_patches(void *baton,
 
               if (! target->skipped)
                 {
-                  if (target->has_text_changes)
+                  if (target->has_text_changes || target->added)
                     SVN_ERR(install_patched_target(target, btn->abs_wc_path,
                                                    btn->ctx, btn->dry_run,
                                                    iterpool));
@@ -2611,7 +2655,7 @@ apply_patches(void *baton,
               SVN_ERR(send_patch_notification(target, btn->ctx, iterpool));
             }
 
-          SVN_ERR(svn_diff_close_patch(patch));
+          SVN_ERR(svn_diff_close_patch(patch, iterpool));
         }
     }
   while (patch);
@@ -2631,6 +2675,7 @@ svn_client_patch(const char *patch_abspa
                  const char *local_abspath,
                  svn_boolean_t dry_run,
                  int strip_count,
+                 svn_boolean_t old_patch_target_names,
                  svn_boolean_t reverse,
                  svn_boolean_t ignore_whitespace,
                  svn_boolean_t remove_tempfiles,
@@ -2651,6 +2696,7 @@ svn_client_patch(const char *patch_abspa
   baton.dry_run = dry_run;
   baton.ctx = ctx;
   baton.strip_count = strip_count;
+  baton.old_patch_target_names = old_patch_target_names;
   baton.reverse = reverse;
   baton.ignore_whitespace = ignore_whitespace;
   baton.remove_tempfiles = remove_tempfiles;

Modified: subversion/branches/ignore-mergeinfo/subversion/libsvn_client/prop_commands.c
URL: http://svn.apache.org/viewvc/subversion/branches/ignore-mergeinfo/subversion/libsvn_client/prop_commands.c?rev=1044516&r1=1044515&r2=1044516&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_client/prop_commands.c (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_client/prop_commands.c Fri Dec 10 21:23:03 2010
@@ -196,6 +196,8 @@ propset_on_url(const char *propname,
                svn_boolean_t skip_checks,
                svn_revnum_t base_revision_for_url,
                const apr_hash_t *revprop_table,
+               svn_commit_callback2_t commit_callback,
+               void *commit_baton,
                svn_client_ctx_t *ctx,
                apr_pool_t *pool)
 {
@@ -270,8 +272,8 @@ propset_on_url(const char *propname,
   /* Fetch RA commit editor. */
   SVN_ERR(svn_ra_get_commit_editor3(ra_session, &editor, &edit_baton,
                                     commit_revprops,
-                                    ctx->commit_callback2,
-                                    ctx->commit_baton,
+                                    commit_callback,
+                                    commit_baton,
                                     NULL, TRUE, /* No lock tokens */
                                     pool));
 
@@ -346,6 +348,8 @@ svn_client_propset4(const char *propname
                     svn_revnum_t base_revision_for_url,
                     const apr_array_header_t *changelists,
                     const apr_hash_t *revprop_table,
+                    svn_commit_callback2_t commit_callback,
+                    void *commit_baton,
                     svn_client_ctx_t *ctx,
                     apr_pool_t *pool)
 {
@@ -397,7 +401,8 @@ svn_client_propset4(const char *propname
                                    "'%s' is not supported"), propname, target);
 
       return propset_on_url(propname, propval, target, skip_checks,
-                            base_revision_for_url, revprop_table, ctx, pool);
+                            base_revision_for_url, revprop_table,
+                            commit_callback, commit_baton, ctx, pool);
     }
   else
     {

Modified: subversion/branches/ignore-mergeinfo/subversion/libsvn_client/relocate.c
URL: http://svn.apache.org/viewvc/subversion/branches/ignore-mergeinfo/subversion/libsvn_client/relocate.c?rev=1044516&r1=1044515&r2=1044516&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_client/relocate.c (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_client/relocate.c Fri Dec 10 21:23:03 2010
@@ -126,24 +126,23 @@ validator_func(void *baton,
 }
 
 svn_error_t *
-svn_client_relocate(const char *path,
-                    const char *from,
-                    const char *to,
-                    svn_boolean_t recurse,
-                    svn_client_ctx_t *ctx,
-                    apr_pool_t *pool)
+svn_client_relocate2(const char *wcroot_dir,
+                     const char *from,
+                     const char *to,
+                     svn_client_ctx_t *ctx,
+                     apr_pool_t *pool)
 {
   struct validator_baton_t vb;
   const char *local_abspath;
 
-  /* Now, populate our validator callback baton, and call the relocate code. */
+  /* Populate our validator callback baton, and call the relocate code. */
   vb.ctx = ctx;
-  vb.path = path;
+  vb.path = wcroot_dir;
   vb.url_uuids = apr_array_make(pool, 1, sizeof(struct url_uuid_t));
   vb.pool = pool;
 
-  SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool));
-  SVN_ERR(svn_wc_relocate4(ctx->wc_ctx, local_abspath, from, to, recurse,
+  SVN_ERR(svn_dirent_get_absolute(&local_abspath, wcroot_dir, pool));
+  SVN_ERR(svn_wc_relocate4(ctx->wc_ctx, local_abspath, from, to,
                            validator_func, &vb, pool));
 
   return SVN_NO_ERROR;

Modified: subversion/branches/ignore-mergeinfo/subversion/libsvn_client/repos_diff.c
URL: http://svn.apache.org/viewvc/subversion/branches/ignore-mergeinfo/subversion/libsvn_client/repos_diff.c?rev=1044516&r1=1044515&r2=1044516&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_client/repos_diff.c (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_client/repos_diff.c Fri Dec 10 21:23:03 2010
@@ -241,11 +241,10 @@ make_dir_baton(const char *path,
 static struct file_baton *
 make_file_baton(const char *path,
                 svn_boolean_t added,
-                void *edit_baton,
+                struct edit_baton *edit_baton,
                 apr_pool_t *pool)
 {
   struct file_baton *file_baton = apr_pcalloc(pool, sizeof(*file_baton));
-  struct edit_baton *eb = edit_baton;
 
   file_baton->edit_baton = edit_baton;
   file_baton->added = added;
@@ -253,7 +252,7 @@ make_file_baton(const char *path,
   file_baton->skip = FALSE;
   file_baton->pool = pool;
   file_baton->path = apr_pstrdup(pool, path);
-  file_baton->wcpath = svn_dirent_join(eb->target, path, pool);
+  file_baton->wcpath = svn_dirent_join(edit_baton->target, path, pool);
   file_baton->propchanges  = apr_array_make(pool, 1, sizeof(svn_prop_t));
 
   return file_baton;
@@ -460,7 +459,7 @@ open_root(void *edit_baton,
  * reporting all files as deleted.  Part of a workaround for issue 2333.
  *
  * DIR is a repository path relative to the URL in RA_SESSION.  REVISION
- * may be NULL, in which case it defaults to HEAD.  EB is the
+ * must be a valid revision number, not SVN_INVALID_REVNUM.  EB is the
  * overall crawler editor baton.  If CANCEL_FUNC is not NULL, then it
  * should refer to a cancellation function (along with CANCEL_BATON).
  */
@@ -478,6 +477,8 @@ diff_deleted_dir(const char *dir,
   apr_pool_t *iterpool = svn_pool_create(pool);
   apr_hash_index_t *hi;
 
+  SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(revision));
+
   if (cancel_func)
     SVN_ERR(cancel_func(cancel_baton));
 

Modified: subversion/branches/ignore-mergeinfo/subversion/libsvn_client/repos_diff_summarize.c
URL: http://svn.apache.org/viewvc/subversion/branches/ignore-mergeinfo/subversion/libsvn_client/repos_diff_summarize.c?rev=1044516&r1=1044515&r2=1044516&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_client/repos_diff_summarize.c (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_client/repos_diff_summarize.c Fri Dec 10 21:23:03 2010
@@ -23,6 +23,7 @@
  */
 
 
+#include "svn_dirent_uri.h"
 #include "svn_props.h"
 #include "svn_pools.h"
 
@@ -45,6 +46,18 @@ struct edit_baton {
 
   /* The start revision for the comparison */
   svn_revnum_t revision;
+
+  /* TRUE if the operation needs to walk deleted dirs on the "old" side.
+     FALSE otherwise. */
+  svn_boolean_t walk_deleted_repos_dirs;
+
+  /* A callback used to see if the client wishes to cancel the running
+     operation. */
+  svn_cancel_func_t cancel_func;
+
+  /* A baton to pass to the cancellation callback. */
+  void *cancel_baton;
+
 };
 
 
@@ -97,7 +110,7 @@ create_item_baton(struct edit_baton *edi
 /* Make sure that this item baton contains a summarize struct.
  * If it doesn't before this call, allocate a new struct in the item's pool,
  * initializing the diff kind to normal.
- * All other fields are also initialized from IB to to NULL/invalid values. */
+ * All other fields are also initialized from IB or to NULL/invalid values. */
 static void
 ensure_summarize(struct item_baton *ib)
 {
@@ -129,6 +142,83 @@ open_root(void *edit_baton,
   return SVN_NO_ERROR;
 }
 
+/* Recursively walk the tree rooted at DIR (at REVISION) in the
+ * repository, reporting all files as deleted.  Part of a workaround
+ * for issue 2333.
+ *
+ * DIR is a repository path relative to the URL in RA_SESSION.  REVISION
+ * may be NULL, in which case it defaults to HEAD.  EDIT_BATON is the
+ * overall crawler editor baton.  If CANCEL_FUNC is not NULL, then it
+ * should refer to a cancellation function (along with CANCEL_BATON).
+ */
+/* ### TODO: Handle depth. */
+static svn_error_t *
+diff_deleted_dir(const char *dir,
+                 svn_revnum_t revision,
+                 svn_ra_session_t *ra_session,
+                 void *edit_baton,
+                 svn_cancel_func_t cancel_func,
+                 void *cancel_baton,
+                 apr_pool_t *pool)
+{
+  struct edit_baton *eb = edit_baton;
+  apr_hash_t *dirents;
+  apr_pool_t *iterpool = svn_pool_create(pool);
+  apr_hash_index_t *hi;
+
+  if (cancel_func)
+    SVN_ERR(cancel_func(cancel_baton));
+
+  SVN_ERR(svn_ra_get_dir2(ra_session,
+                          &dirents,
+                          NULL, NULL,
+                          dir,
+                          revision,
+                          SVN_DIRENT_KIND,
+                          pool));
+  
+  for (hi = apr_hash_first(pool, dirents); hi;
+       hi = apr_hash_next(hi))
+    {
+      const char *path;
+      const char *name = svn__apr_hash_index_key(hi);
+      svn_dirent_t *dirent = svn__apr_hash_index_val(hi);
+      svn_node_kind_t kind;
+      svn_client_diff_summarize_t *sum;
+
+      svn_pool_clear(iterpool);
+
+      path = svn_relpath_join(dir, name, iterpool);
+
+      SVN_ERR(svn_ra_check_path(eb->ra_session,
+                                path,
+                                eb->revision,
+                                &kind,
+                                iterpool));
+
+      sum = apr_pcalloc(pool, sizeof(*sum));
+      sum->summarize_kind = svn_client_diff_summarize_kind_deleted;
+      sum->path = path;
+      sum->node_kind = kind;
+
+      SVN_ERR(eb->summarize_func(sum,
+                                 eb->summarize_func_baton,
+                                 iterpool));
+
+      if (dirent->kind == svn_node_dir)
+        SVN_ERR(diff_deleted_dir(path,
+                                 revision,
+                                 ra_session,
+                                 eb,
+                                 cancel_func,
+                                 cancel_baton,
+                                 iterpool));
+    }
+
+  svn_pool_destroy(iterpool);
+  return SVN_NO_ERROR;
+}
+
 /* An editor function.  */
 static svn_error_t *
 delete_entry(const char *path,
@@ -153,7 +243,18 @@ delete_entry(const char *path,
   sum->path = path;
   sum->node_kind = kind;
 
-  return eb->summarize_func(sum, eb->summarize_func_baton, pool);
+  SVN_ERR(eb->summarize_func(sum, eb->summarize_func_baton, pool));
+
+  if (kind == svn_node_dir)
+        SVN_ERR(diff_deleted_dir(path,
+                                 eb->revision,
+                                 eb->ra_session,
+                                 eb,
+                                 eb->cancel_func,
+                                 eb->cancel_baton,
+                                 pool));
+
+  return SVN_NO_ERROR;
 }
 
 /* An editor function.  */
@@ -298,7 +399,9 @@ change_prop(void *entry_baton,
   if (svn_property_kind(NULL, name) == svn_prop_regular_kind)
     {
       ensure_summarize(ib);
-      ib->summarize->prop_changed = TRUE;
+
+      if (ib->summarize->summarize_kind != svn_client_diff_summarize_kind_added)
+        ib->summarize->prop_changed = TRUE;
     }
 
   return SVN_NO_ERROR;
@@ -309,7 +412,7 @@ svn_error_t *
 svn_client__get_diff_summarize_editor(const char *target,
                                       svn_client_diff_summarize_func_t
                                       summarize_func,
-                                      void *item_baton,
+                                      void *summarize_baton,
                                       svn_ra_session_t *ra_session,
                                       svn_revnum_t revision,
                                       svn_cancel_func_t cancel_func,
@@ -323,9 +426,12 @@ svn_client__get_diff_summarize_editor(co
 
   eb->target = target;
   eb->summarize_func = summarize_func;
-  eb->summarize_func_baton = item_baton;
+  eb->summarize_func_baton = summarize_baton;
   eb->ra_session = ra_session;
   eb->revision = revision;
+  eb->walk_deleted_repos_dirs = TRUE;
+  eb->cancel_func = cancel_func;
+  eb->cancel_baton = cancel_baton;
 
   tree_editor->open_root = open_root;
   tree_editor->delete_entry = delete_entry;

Modified: subversion/branches/ignore-mergeinfo/subversion/libsvn_client/status.c
URL: http://svn.apache.org/viewvc/subversion/branches/ignore-mergeinfo/subversion/libsvn_client/status.c?rev=1044516&r1=1044515&r2=1044516&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_client/status.c (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_client/status.c Fri Dec 10 21:23:03 2010
@@ -291,6 +291,7 @@ svn_client_status5(svn_revnum_t *result_
                    svn_boolean_t update,
                    svn_boolean_t no_ignore,
                    svn_boolean_t ignore_externals,
+                   svn_boolean_t depth_as_sticky,
                    svn_boolean_t ignore_mergeinfo,
                    const apr_array_header_t *changelists,
                    svn_client_status_func_t status_func,
@@ -496,6 +497,7 @@ svn_client_status5(svn_revnum_t *result_
         {
           svn_revnum_t revnum;
           report_baton_t rb;
+          svn_depth_t status_depth;
 
           if (revision->kind == svn_opt_revision_head)
             {
@@ -513,10 +515,15 @@ svn_client_status5(svn_revnum_t *result_
                                                       pool));
             }
 
+          if (depth_as_sticky)
+            status_depth = depth;
+          else
+            status_depth = svn_depth_unknown; /* Use depth from WC */
+
           /* Do the deed.  Let the RA layer drive the status editor. */
           SVN_ERR(svn_ra_do_status2(ra_session, &rb.wrapped_reporter,
                                     &rb.wrapped_report_baton,
-                                    target_basename, revnum, svn_depth_unknown,
+                                    target_basename, revnum, status_depth,
                                     editor, edit_baton, pool));
 
           /* Init the report baton. */

Modified: subversion/branches/ignore-mergeinfo/subversion/libsvn_client/switch.c
URL: http://svn.apache.org/viewvc/subversion/branches/ignore-mergeinfo/subversion/libsvn_client/switch.c?rev=1044516&r1=1044515&r2=1044516&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_client/switch.c (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_client/switch.c Fri Dec 10 21:23:03 2010
@@ -190,7 +190,6 @@ switch_internal(svn_revnum_t *result_rev
                                     depth,
                                     depth_is_sticky, allow_unver_obstructions,
                                     diff3_cmd, preserved_exts,
-                                    NULL, NULL,
                                     ctx->conflict_func, ctx->conflict_baton,
                                     svn_client__external_info_gatherer, &efb,
                                     ctx->cancel_func, ctx->cancel_baton,

Modified: subversion/branches/ignore-mergeinfo/subversion/libsvn_client/update.c
URL: http://svn.apache.org/viewvc/subversion/branches/ignore-mergeinfo/subversion/libsvn_client/update.c?rev=1044516&r1=1044515&r2=1044516&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_client/update.c (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_client/update.c Fri Dec 10 21:23:03 2010
@@ -45,49 +45,6 @@
 /*** Code. ***/
 
 
-/* Context baton for file_fetcher below. */
-struct ff_baton
-{
-  svn_client_ctx_t *ctx;       /* client context used to open ra session */
-  const char *repos_root;      /* repository root URL */
-  svn_ra_session_t *session;   /* the secondary ra session itself */
-  apr_pool_t *pool;            /* the pool where the ra session is allocated */
-};
-
-
-/* Implementation of svn_wc_get_file_t.  A feeble callback wrapper
-   around svn_ra_get_file(), so that the update_editor can use it to
-   fetch any file, any time. */
-static svn_error_t *
-file_fetcher(void *baton,
-             const char *path,
-             svn_revnum_t revision,
-             svn_stream_t *stream,
-             svn_revnum_t *fetched_rev,
-             apr_hash_t **props,
-             apr_pool_t *pool)
-{
-  struct ff_baton *ffb = (struct ff_baton *)baton;
-  const char *dirpath, *base_name, *session_url, *old_session_url;
-
-  svn_relpath_split(&dirpath, &base_name, path, pool);
-  session_url = svn_path_url_add_component2(ffb->repos_root, 
-                                            dirpath, pool);
-
-  if (ffb->session)
-    SVN_ERR(svn_client__ensure_ra_session_url(&old_session_url, ffb->session,
-                                              session_url, ffb->pool));
-  else
-    SVN_ERR(svn_client__open_ra_session_internal(&(ffb->session), NULL,
-                                                 session_url, NULL, NULL,
-                                                 FALSE, TRUE,
-                                                 ffb->ctx, ffb->pool));
-
-  return svn_ra_get_file(ffb->session, base_name, revision, stream,
-                         fetched_rev, props, pool);
-}
-
-
 static svn_error_t *
 update_internal(svn_revnum_t *result_rev,
                 const char *local_abspath,
@@ -98,7 +55,6 @@ update_internal(svn_revnum_t *result_rev
                 svn_boolean_t ignore_externals,
                 svn_boolean_t allow_unver_obstructions,
                 svn_boolean_t *timestamp_sleep,
-                svn_boolean_t send_copyfrom_args,
                 svn_boolean_t innerupdate,
                 svn_client_ctx_t *ctx,
                 apr_pool_t *pool)
@@ -120,7 +76,6 @@ update_internal(svn_revnum_t *result_rev
   svn_ra_session_t *ra_session;
   const char *preserved_exts_str;
   apr_array_header_t *preserved_exts;
-  struct ff_baton *ffb;
   svn_client__external_func_baton_t efb;
   svn_boolean_t server_supports_depth;
   svn_config_t *cfg = ctx->config ? apr_hash_get(ctx->config,
@@ -216,12 +171,6 @@ update_internal(svn_revnum_t *result_rev
      a strict sense, however.) */
   SVN_ERR(svn_ra_get_repos_root2(ra_session, &repos_root, pool));
 
-  /* Build a baton for the file-fetching callback. */
-  ffb = apr_pcalloc(pool, sizeof(*ffb));
-  ffb->ctx = ctx;
-  ffb->repos_root = repos_root;
-  ffb->pool = pool;
-
   /* Build a baton for the externals-info-gatherer callback. */
   efb.externals_new = apr_hash_make(pool);
   efb.externals_old = apr_hash_make(pool);
@@ -235,7 +184,6 @@ update_internal(svn_revnum_t *result_rev
                                     target, use_commit_times, depth,
                                     depth_is_sticky, allow_unver_obstructions,
                                     diff3_cmd, preserved_exts,
-                                    file_fetcher, ffb,
                                     ctx->conflict_func, ctx->conflict_baton,
                                     svn_client__external_info_gatherer, &efb,
                                     ctx->cancel_func, ctx->cancel_baton,
@@ -244,12 +192,8 @@ update_internal(svn_revnum_t *result_rev
 
   /* Tell RA to do an update of URL+TARGET to REVISION; if we pass an
      invalid revnum, that means RA will use the latest revision.  */
-  SVN_ERR(svn_ra_do_update2(ra_session,
-                            &reporter, &report_baton,
-                            revnum,
-                            target,
-                            depth,
-                            send_copyfrom_args,
+  SVN_ERR(svn_ra_do_update2(ra_session, &reporter, &report_baton,
+                            revnum, target, depth, FALSE,
                             update_editor, update_edit_baton, pool));
 
   SVN_ERR(svn_ra_has_capability(ra_session, &server_supports_depth,
@@ -321,7 +265,6 @@ svn_client__update_internal(svn_revnum_t
                             svn_boolean_t ignore_externals,
                             svn_boolean_t allow_unver_obstructions,
                             svn_boolean_t *timestamp_sleep,
-                            svn_boolean_t send_copyfrom_args,
                             svn_boolean_t innerupdate,
                             svn_client_ctx_t *ctx,
                             apr_pool_t *pool)
@@ -343,8 +286,7 @@ svn_client__update_internal(svn_revnum_t
   err = update_internal(result_rev, local_abspath, anchor_abspath,
                          revision, depth, depth_is_sticky,
                          ignore_externals, allow_unver_obstructions,
-                         timestamp_sleep, send_copyfrom_args,
-                         innerupdate, ctx, pool);
+                         timestamp_sleep, innerupdate, ctx, pool);
 
   err = svn_error_compose_create(
             err,
@@ -398,7 +340,7 @@ svn_client_update3(apr_array_header_t **
                                             revision, depth, depth_is_sticky,
                                             ignore_externals,
                                             allow_unver_obstructions,
-                                            &sleep, TRUE, FALSE, ctx, subpool);
+                                            &sleep, FALSE, ctx, subpool);
 
           if (err && err->apr_err != SVN_ERR_WC_NOT_WORKING_COPY)
             {

Modified: subversion/branches/ignore-mergeinfo/subversion/libsvn_delta/svndiff.c
URL: http://svn.apache.org/viewvc/subversion/branches/ignore-mergeinfo/subversion/libsvn_delta/svndiff.c?rev=1044516&r1=1044515&r2=1044516&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_delta/svndiff.c (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_delta/svndiff.c Fri Dec 10 21:23:03 2010
@@ -31,10 +31,12 @@
 #include "svn_private_config.h"
 #include <zlib.h>
 
-/* This macro is taken from zlib, and was originally the function
-   compressBound.  It shouldn't ever change, but once every millenium,
-   it may be useful for someone to make sure. */
+/* The zlib compressBound function was not exported until 1.2.0. */
+#if ZLIB_VERNUM >= 0x1200
+#define svnCompressBound(LEN) compressBound(LEN)
+#else
 #define svnCompressBound(LEN) ((LEN) + ((LEN) >> 12) + ((LEN) >> 14) + 11)
+#endif
 
 /* For svndiff1, address/instruction/new data under this size will not
    be compressed using zlib as a secondary compressor.  */

Modified: subversion/branches/ignore-mergeinfo/subversion/libsvn_diff/diff_file.c
URL: http://svn.apache.org/viewvc/subversion/branches/ignore-mergeinfo/subversion/libsvn_diff/diff_file.c?rev=1044516&r1=1044515&r2=1044516&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_diff/diff_file.c (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_diff/diff_file.c Fri Dec 10 21:23:03 2010
@@ -860,7 +860,7 @@ output_unified_line(svn_diff__file_outpu
             {
               if (type != svn_diff__file_output_unified_skip)
                 {
-                  svn_stringbuf_appendbytes(baton->hunk, curp, 1);
+                  svn_stringbuf_appendbyte(baton->hunk, *curp);
                 }
               /* We don't append the LF to extra_context, since it would
                * just be stripped anyway. */