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

svn commit: r984234 [5/20] - in /subversion/branches/ignore-mergeinfo: ./ build/ build/ac-macros/ build/generator/ notes/ notes/api-errata/ notes/obliterate/ notes/obliterate/fspec-cc1/ notes/rename-tracking/ notes/svnpatch/ notes/tree-conflicts/ notes...

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=984234&r1=984233&r2=984234&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_client/merge.c (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_client/merge.c Tue Aug 10 22:07:24 2010
@@ -368,7 +368,7 @@ is_path_conflicted_by_merge(merge_cmd_ba
 }
 
 /* Return a state indicating whether the WC metadata matches the
- * node kind on disk of the local path PATH.
+ * node kind on disk of the local path LOCAL_ABSPATH.
  * Use MERGE_B to determine the dry-run details; particularly, if a dry run
  * noted that it deleted this path, assume matching node kinds (as if both
  * kinds were svn_node_none).
@@ -379,26 +379,25 @@ is_path_conflicted_by_merge(merge_cmd_ba
  *   - Return 'missing' if there is no node on disk but one is expected.
  *     Also return 'missing' for absent nodes (not here due to authz).*/
 static svn_wc_notify_state_t
-obstructed_or_missing(const char *path,
+obstructed_or_missing(const char *local_abspath,
                       const char *local_dir_abspath,
                       const merge_cmd_baton_t *merge_b,
                       apr_pool_t *pool)
 {
   svn_error_t *err;
   svn_node_kind_t kind_expected, kind_on_disk;
-  const char *local_abspath;
+
+  SVN_ERR_ASSERT_NO_RETURN(svn_dirent_is_absolute(local_abspath));
 
   /* In a dry run, make as if nodes "deleted" by the dry run appear so. */
-  if (merge_b->dry_run && dry_run_deleted_p(merge_b, path))
+  if (merge_b->dry_run && dry_run_deleted_p(merge_b, local_abspath))
     return svn_wc_notify_state_inapplicable;
 
   /* Since this function returns no svn_error_t, we make all errors look like
    * no node found in the wc. */
-  err = svn_dirent_get_absolute(&local_abspath, path, pool);
 
-  if (!err)
-    err = svn_wc_read_kind(&kind_expected, merge_b->ctx->wc_ctx,
-                           local_abspath, FALSE, pool);
+  err = svn_wc_read_kind(&kind_expected, merge_b->ctx->wc_ctx,
+                         local_abspath, FALSE, pool);
 
   if (err)
     {
@@ -1063,7 +1062,7 @@ static svn_error_t *
 merge_props_changed(const char *local_dir_abspath,
                     svn_wc_notify_state_t *state,
                     svn_boolean_t *tree_conflicted,
-                    const char *path,
+                    const char *local_abspath,
                     const apr_array_header_t *propchanges,
                     apr_hash_t *original_props,
                     void *baton,
@@ -1074,9 +1073,8 @@ merge_props_changed(const char *local_di
   svn_client_ctx_t *ctx = merge_b->ctx;
   apr_pool_t *subpool = svn_pool_create(merge_b->pool);
   svn_error_t *err;
-  const char *local_abspath;
 
-  SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, subpool));
+  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
 
   if (tree_conflicted)
     *tree_conflicted = FALSE;
@@ -1085,8 +1083,8 @@ merge_props_changed(const char *local_di
   {
     svn_wc_notify_state_t obstr_state;
 
-    obstr_state = obstructed_or_missing(path, local_dir_abspath, merge_b,
-                                        subpool);
+    obstr_state = obstructed_or_missing(local_abspath, local_dir_abspath,
+                                        merge_b, subpool);
     if (obstr_state != svn_wc_notify_state_inapplicable)
       {
         if (state)
@@ -1274,9 +1272,9 @@ merge_file_changed(const char *local_dir
                    svn_wc_notify_state_t *content_state,
                    svn_wc_notify_state_t *prop_state,
                    svn_boolean_t *tree_conflicted,
-                   const char *mine,
-                   const char *older,
-                   const char *yours,
+                   const char *mine_abspath,
+                   const char *older_abspath,
+                   const char *yours_abspath,
                    svn_revnum_t older_rev,
                    svn_revnum_t yours_rev,
                    const char *mimetype1,
@@ -1290,19 +1288,10 @@ merge_file_changed(const char *local_dir
   apr_pool_t *subpool = svn_pool_create(merge_b->pool);
   svn_boolean_t merge_required = TRUE;
   enum svn_wc_merge_outcome_t merge_outcome;
-  const char *older_abspath;
-  const char *yours_abspath;
-  const char *mine_abspath;
 
-  if (older)
-    SVN_ERR(svn_dirent_get_absolute(&older_abspath, older, merge_b->pool));
-  else
-    older_abspath = NULL;
-  if (yours)
-    SVN_ERR(svn_dirent_get_absolute(&yours_abspath, yours, merge_b->pool));
-  else
-    yours_abspath = NULL;
-  SVN_ERR(svn_dirent_get_absolute(&mine_abspath, mine, merge_b->pool));
+  SVN_ERR_ASSERT(mine_abspath && svn_dirent_is_absolute(mine_abspath));
+  SVN_ERR_ASSERT(!older_abspath || svn_dirent_is_absolute(older_abspath));
+  SVN_ERR_ASSERT(!yours_abspath || svn_dirent_is_absolute(yours_abspath));
 
   if (tree_conflicted)
     *tree_conflicted = FALSE;
@@ -1326,8 +1315,8 @@ merge_file_changed(const char *local_dir
   {
     svn_wc_notify_state_t obstr_state;
 
-    obstr_state = obstructed_or_missing(mine, local_dir_abspath, merge_b,
-                                        subpool);
+    obstr_state = obstructed_or_missing(mine_abspath, local_dir_abspath,
+                                        merge_b, subpool);
     if (obstr_state != svn_wc_notify_state_inapplicable)
       {
         if (content_state)
@@ -1347,7 +1336,7 @@ merge_file_changed(const char *local_dir
 
     SVN_ERR(svn_wc_read_kind(&wc_kind, merge_b->ctx->wc_ctx, mine_abspath,
                              FALSE, subpool));
-    SVN_ERR(svn_io_check_path(mine, &kind, subpool));
+    SVN_ERR(svn_io_check_path(mine_abspath, &kind, subpool));
 
     /* If the file isn't there due to depth restrictions, do not flag
      * a conflict. Non-inheritable mergeinfo will be recorded, allowing
@@ -1415,7 +1404,7 @@ merge_file_changed(const char *local_dir
 
       SVN_ERR(merge_props_changed(local_dir_abspath, prop_state,
                                   &tree_conflicted2,
-                                  mine, prop_changes, original_props,
+                                  mine_abspath, prop_changes, original_props,
                                   baton, scratch_pool));
 
       /* If the prop change caused a tree-conflict, just bail. */
@@ -1440,7 +1429,7 @@ merge_file_changed(const char *local_dir
       return SVN_NO_ERROR;
     }
 
-  if (older)
+  if (older_abspath)
     {
       svn_boolean_t has_local_mods;
       SVN_ERR(svn_wc_text_modified_p2(&has_local_mods, merge_b->ctx->wc_ctx,
@@ -1466,14 +1455,14 @@ merge_file_changed(const char *local_dir
           svn_boolean_t same_contents;
           SVN_ERR(svn_io_files_contents_same_p(&same_contents,
                                                (older_revision_exists ?
-                                                older : yours),
-                                               mine, subpool));
+                                                older_abspath : yours_abspath),
+                                               mine_abspath, subpool));
           if (same_contents)
             {
               if (older_revision_exists && !merge_b->dry_run)
                 {
-                  SVN_ERR(svn_io_copy_file(yours, mine, FALSE, subpool));
-                  SVN_ERR(svn_io_remove_file2(yours, TRUE, subpool));
+                  SVN_ERR(svn_io_file_move(yours_abspath, mine_abspath,
+                                           subpool));
                 }
               merge_outcome = svn_wc_merge_merged;
               merge_required = FALSE;
@@ -1541,9 +1530,9 @@ merge_file_added(const char *local_dir_a
                  svn_wc_notify_state_t *content_state,
                  svn_wc_notify_state_t *prop_state,
                  svn_boolean_t *tree_conflicted,
-                 const char *mine,
-                 const char *older,
-                 const char *yours,
+                 const char *mine_abspath,
+                 const char *older_abspath,
+                 const char *yours_abspath,
                  svn_revnum_t rev1,
                  svn_revnum_t rev2,
                  const char *mimetype1,
@@ -1561,7 +1550,8 @@ merge_file_added(const char *local_dir_a
   svn_node_kind_t kind;
   int i;
   apr_hash_t *file_props;
-  const char *mine_abspath;
+
+  SVN_ERR_ASSERT(svn_dirent_is_absolute(mine_abspath));
 
   /* Easy out: We are only applying mergeinfo differences. */
   if (merge_b->record_only)
@@ -1576,8 +1566,6 @@ merge_file_added(const char *local_dir_a
       return SVN_NO_ERROR;
     }
 
-  SVN_ERR(svn_dirent_get_absolute(&mine_abspath, mine, subpool));
-
   /* In most cases, we just leave prop_state as unknown, and let the
      content_state what happened, so we set prop_state here to avoid that
      below. */
@@ -1622,7 +1610,7 @@ merge_file_added(const char *local_dir_a
   if (! local_dir_abspath)
     {
       if (merge_b->dry_run && merge_b->added_path
-          && svn_dirent_is_child(merge_b->added_path, mine, subpool))
+          && svn_dirent_is_child(merge_b->added_path, mine_abspath, NULL))
         {
           if (content_state)
             *content_state = svn_wc_notify_state_changed;
@@ -1643,8 +1631,8 @@ merge_file_added(const char *local_dir_a
   {
     svn_wc_notify_state_t obstr_state;
 
-    obstr_state = obstructed_or_missing(mine, local_dir_abspath, merge_b,
-                                        subpool);
+    obstr_state = obstructed_or_missing(mine_abspath, local_dir_abspath,
+                                        merge_b, subpool);
     if (obstr_state != svn_wc_notify_state_inapplicable)
       {
         if (content_state)
@@ -1656,7 +1644,7 @@ merge_file_added(const char *local_dir_a
 
   parent_abspath = local_dir_abspath;
 
-  SVN_ERR(svn_io_check_path(mine, &kind, subpool));
+  SVN_ERR(svn_io_check_path(mine_abspath, &kind, subpool));
   switch (kind)
     {
     case svn_node_none:
@@ -1675,7 +1663,7 @@ merge_file_added(const char *local_dir_a
             if (merge_b->same_repos)
               {
                 const char *child = svn_dirent_is_child(merge_b->target_abspath,
-                                                        mine, subpool);
+                                                        mine_abspath, subpool);
                 if (child != NULL)
                   copyfrom_url = svn_path_url_add_component2(
                                                merge_b->merge_source.url2,
@@ -1688,7 +1676,8 @@ merge_file_added(const char *local_dir_a
                                            copyfrom_url, subpool));
                 new_base_props = file_props;
                 new_props = NULL; /* inherit from new_base_props */
-                SVN_ERR(svn_stream_open_readonly(&new_base_contents, yours,
+                SVN_ERR(svn_stream_open_readonly(&new_base_contents,
+                                                 yours_abspath,
                                                  subpool, subpool));
                 new_contents = NULL; /* inherit from new_base_contents */
               }
@@ -1699,7 +1688,7 @@ merge_file_added(const char *local_dir_a
                 new_base_props = apr_hash_make(subpool);
                 new_props = file_props;
                 new_base_contents = svn_stream_empty(subpool);
-                SVN_ERR(svn_stream_open_readonly(&new_contents, yours,
+                SVN_ERR(svn_stream_open_readonly(&new_contents, yours_abspath,
                                                  subpool, subpool));
               }
 
@@ -1763,7 +1752,8 @@ merge_file_added(const char *local_dir_a
           SVN_ERR(svn_wc_read_kind(&wc_kind, merge_b->ctx->wc_ctx,
                                    mine_abspath, FALSE, subpool));
 
-          if ((wc_kind != svn_node_none) && dry_run_deleted_p(merge_b, mine))
+          if ((wc_kind != svn_node_none) 
+              && dry_run_deleted_p(merge_b, mine_abspath))
             *content_state = svn_wc_notify_state_changed;
           else
             /* this will make the repos_editor send a 'skipped' message */
@@ -1772,7 +1762,7 @@ merge_file_added(const char *local_dir_a
       break;
     case svn_node_file:
       {
-            if (dry_run_deleted_p(merge_b, mine))
+            if (dry_run_deleted_p(merge_b, mine_abspath))
               {
                 if (content_state)
                   *content_state = svn_wc_notify_state_changed;
@@ -1872,9 +1862,9 @@ static svn_error_t *
 merge_file_deleted(const char *local_dir_abspath,
                    svn_wc_notify_state_t *state,
                    svn_boolean_t *tree_conflicted,
-                   const char *mine,
-                   const char *older,
-                   const char *yours,
+                   const char *mine_abspath,
+                   const char *older_abspath,
+                   const char *yours_abspath,
                    const char *mimetype1,
                    const char *mimetype2,
                    apr_hash_t *original_props,
@@ -1884,7 +1874,6 @@ merge_file_deleted(const char *local_dir
   merge_cmd_baton_t *merge_b = baton;
   apr_pool_t *subpool = svn_pool_create(merge_b->pool);
   svn_node_kind_t kind;
-  const char *mine_abspath;
 
   /* Easy out: We are only applying mergeinfo differences. */
   if (merge_b->record_only)
@@ -1897,8 +1886,6 @@ merge_file_deleted(const char *local_dir
       return SVN_NO_ERROR;
     }
 
-  SVN_ERR(svn_dirent_get_absolute(&mine_abspath, mine, subpool));
-
   if (tree_conflicted)
     *tree_conflicted = FALSE;
 
@@ -1918,8 +1905,8 @@ merge_file_deleted(const char *local_dir
   {
     svn_wc_notify_state_t obstr_state;
 
-    obstr_state = obstructed_or_missing(mine, local_dir_abspath, merge_b,
-                                        subpool);
+    obstr_state = obstructed_or_missing(mine_abspath, local_dir_abspath,
+                                        merge_b, subpool);
     if (obstr_state != svn_wc_notify_state_inapplicable)
       {
         if (state)
@@ -1929,15 +1916,12 @@ merge_file_deleted(const char *local_dir
       }
   }
 
-  SVN_ERR(svn_io_check_path(mine, &kind, subpool));
+  SVN_ERR(svn_io_check_path(mine_abspath, &kind, subpool));
   switch (kind)
     {
     case svn_node_file:
       {
         svn_boolean_t same;
-        const char *older_abspath;
-
-        SVN_ERR(svn_dirent_get_absolute(&older_abspath, older, subpool));
 
         /* If the files are identical, attempt deletion */
         SVN_ERR(files_same_p(&same, older_abspath, original_props,
@@ -1946,7 +1930,7 @@ merge_file_deleted(const char *local_dir
           {
             /* Passing NULL for the notify_func and notify_baton because
                repos_diff.c:delete_entry() will do it for us. */
-            SVN_ERR(svn_client__wc_delete(mine, TRUE,
+            SVN_ERR(svn_client__wc_delete(mine_abspath, TRUE,
                                           merge_b->dry_run, FALSE, NULL, NULL,
                                           merge_b->ctx, subpool));
             if (state)
@@ -2013,7 +1997,7 @@ static svn_error_t *
 merge_dir_added(const char *local_dir_abspath,
                 svn_wc_notify_state_t *state,
                 svn_boolean_t *tree_conflicted,
-                const char *path,
+                const char *local_abspath,
                 svn_revnum_t rev,
                 const char *copyfrom_path,
                 svn_revnum_t copyfrom_revision,
@@ -2026,7 +2010,6 @@ merge_dir_added(const char *local_dir_ab
   const char *copyfrom_url = NULL, *child;
   svn_revnum_t copyfrom_rev = SVN_INVALID_REVNUM;
   const char *parent_abspath;
-  const char *local_abspath;
   svn_boolean_t is_versioned;
   svn_boolean_t is_deleted;
   svn_error_t *err;
@@ -2042,7 +2025,6 @@ merge_dir_added(const char *local_dir_ab
       return SVN_NO_ERROR;
     }
 
-  SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, subpool));
   parent_abspath = local_dir_abspath;
 
   if (tree_conflicted)
@@ -2057,7 +2039,7 @@ merge_dir_added(const char *local_dir_ab
       if (state)
         {
           if (merge_b->dry_run && merge_b->added_path
-              && svn_dirent_is_child(merge_b->added_path, path, subpool))
+              && svn_dirent_is_child(merge_b->added_path, local_abspath, NULL))
             *state = svn_wc_notify_state_changed;
           else
             *state = svn_wc_notify_state_missing;
@@ -2070,7 +2052,7 @@ merge_dir_added(const char *local_dir_ab
       return SVN_NO_ERROR;
     }
 
-  child = svn_dirent_is_child(merge_b->target_abspath, path, subpool);
+  child = svn_dirent_is_child(merge_b->target_abspath, local_abspath, NULL);
   SVN_ERR_ASSERT(child != NULL);
 
   /* If this is a merge from the same repository as our working copy,
@@ -2105,14 +2087,14 @@ merge_dir_added(const char *local_dir_ab
       is_versioned = TRUE;
     }
 
-  SVN_ERR(svn_io_check_path(path, &kind, subpool));
+  SVN_ERR(svn_io_check_path(local_abspath, &kind, subpool));
 
   /* Check for an obstructed or missing node on disk. */
   {
     svn_wc_notify_state_t obstr_state;
 
-    obstr_state = obstructed_or_missing(path, local_dir_abspath, merge_b,
-                                        subpool);
+    obstr_state = obstructed_or_missing(local_abspath, local_dir_abspath,
+                                        merge_b, subpool);
 
     /* In this case of adding a directory, we have an exception to the usual
      * "skip if it's inconsistent" rule. If the directory exists on disk
@@ -2137,10 +2119,10 @@ merge_dir_added(const char *local_dir_ab
     case svn_node_none:
       /* Unversioned or schedule-delete */
       if (merge_b->dry_run)
-        merge_b->added_path = apr_pstrdup(merge_b->pool, path);
+        merge_b->added_path = apr_pstrdup(merge_b->pool, local_abspath);
       else
         {
-          SVN_ERR(svn_io_make_dir_recursively(path, subpool));
+          SVN_ERR(svn_io_make_dir_recursively(local_abspath, subpool));
           SVN_ERR(svn_wc_add4(merge_b->ctx->wc_ctx, local_abspath,
                               svn_depth_infinity,
                               copyfrom_url, copyfrom_rev,
@@ -2168,14 +2150,14 @@ merge_dir_added(const char *local_dir_ab
                                 NULL, NULL, /* no notification func! */
                                 subpool));
           else
-            merge_b->added_path = apr_pstrdup(merge_b->pool, path);
+            merge_b->added_path = apr_pstrdup(merge_b->pool, local_abspath);
           if (state)
             *state = svn_wc_notify_state_changed;
         }
       else
         {
           /* The dir is known to Subversion as already existing. */
-          if (dry_run_deleted_p(merge_b, path))
+          if (dry_run_deleted_p(merge_b, local_abspath))
             {
               if (state)
                 *state = svn_wc_notify_state_changed;
@@ -2198,7 +2180,7 @@ merge_dir_added(const char *local_dir_ab
       if (merge_b->dry_run)
         merge_b->added_path = NULL;
 
-      if (is_versioned && dry_run_deleted_p(merge_b, path))
+      if (is_versioned && dry_run_deleted_p(merge_b, local_abspath))
         {
           /* ### TODO: Retain record of this dir being added to
              ### avoid problems from subsequent edits which try to
@@ -2235,7 +2217,7 @@ static svn_error_t *
 merge_dir_deleted(const char *local_dir_abspath,
                   svn_wc_notify_state_t *state,
                   svn_boolean_t *tree_conflicted,
-                  const char *path,
+                  const char *local_abspath,
                   void *baton,
                   apr_pool_t *scratch_pool)
 {
@@ -2243,7 +2225,6 @@ merge_dir_deleted(const char *local_dir_
   apr_pool_t *subpool = svn_pool_create(merge_b->pool);
   svn_node_kind_t kind;
   svn_error_t *err;
-  const char *local_abspath;
   svn_boolean_t is_versioned;
   svn_boolean_t is_deleted;
 
@@ -2258,8 +2239,6 @@ merge_dir_deleted(const char *local_dir_
       return SVN_NO_ERROR;
     }
 
-  SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, subpool));
-
   if (tree_conflicted)
     *tree_conflicted = FALSE;
 
@@ -2303,8 +2282,8 @@ merge_dir_deleted(const char *local_dir_
   {
     svn_wc_notify_state_t obstr_state;
 
-    obstr_state = obstructed_or_missing(path, local_dir_abspath, merge_b,
-                                        subpool);
+    obstr_state = obstructed_or_missing(local_abspath, local_dir_abspath,
+                                        merge_b, subpool);
     if (obstr_state != svn_wc_notify_state_inapplicable)
       {
         if (state)
@@ -2315,7 +2294,7 @@ merge_dir_deleted(const char *local_dir_
   }
 
   /* Switch on the on-disk state of this path */
-  SVN_ERR(svn_io_check_path(path, &kind, subpool));
+  SVN_ERR(svn_io_check_path(local_abspath, &kind, subpool));
   switch (kind)
     {
     case svn_node_dir:
@@ -2331,7 +2310,7 @@ merge_dir_deleted(const char *local_dir_
 
             /* Passing NULL for the notify_func and notify_baton because
                repos_diff.c:delete_entry() will do it for us. */
-            err = svn_client__wc_delete(path, merge_b->force,
+            err = svn_client__wc_delete(local_abspath, merge_b->force,
                                         merge_b->dry_run, FALSE,
                                         NULL, NULL,
                                         merge_b->ctx, subpool);
@@ -4571,8 +4550,8 @@ record_skips(const char *mergeinfo_path,
          might be an unversioned obstruction. */
       SVN_ERR(svn_wc_status3(&status, merge_b->ctx->wc_ctx,
                              skipped_abspath, pool, pool));
-      if (status->text_status == svn_wc_status_none
-          || status->text_status == svn_wc_status_unversioned)
+      if (status->node_status == svn_wc_status_none
+          || status->node_status == svn_wc_status_unversioned)
         continue;
 
       /* Add an empty range list for this path.
@@ -9636,10 +9615,12 @@ calculate_left_hand_side(const char **ur
        hi = apr_hash_next(hi))
     {
       const char *path = svn__apr_hash_index_key(hi);
+      const char *path_rel_to_session =
+        svn_relpath_skip_ancestor(target_repos_rel_path, path);
 
       SVN_ERR(svn_client__repos_location_segments(&segments,
                                                   target_ra_session,
-                                                  "",
+                                                  path_rel_to_session,
                                                   target_rev, target_rev,
                                                   SVN_INVALID_REVNUM,
                                                   ctx, subpool));

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=984234&r1=984233&r2=984234&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_client/patch.c (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_client/patch.c Tue Aug 10 22:07:24 2010
@@ -297,10 +297,10 @@ resolve_target_path(patch_target_t *targ
       else
         return svn_error_return(err);
     }
-  else if (status->text_status == svn_wc_status_ignored ||
-           status->text_status == svn_wc_status_unversioned ||
-           status->text_status == svn_wc_status_missing ||
-           status->text_status == svn_wc_status_obstructed)
+  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)
     {
       target->skipped = TRUE;
       return SVN_NO_ERROR;
@@ -1483,8 +1483,8 @@ find_existing_children(void *baton,
 {
   struct status_baton *btn = baton;
 
-  if (status->text_status != svn_wc_status_none
-      && status->text_status != svn_wc_status_deleted
+  if (status->node_status != svn_wc_status_none
+      && status->node_status != svn_wc_status_deleted
       && strcmp(abspath, btn->parent_path))
     {
       APR_ARRAY_PUSH(btn->existing_targets, 

Modified: subversion/branches/ignore-mergeinfo/subversion/libsvn_client/ra.c
URL: http://svn.apache.org/viewvc/subversion/branches/ignore-mergeinfo/subversion/libsvn_client/ra.c?rev=984234&r1=984233&r2=984234&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_client/ra.c (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_client/ra.c Tue Aug 10 22:07:24 2010
@@ -588,7 +588,8 @@ svn_client__repos_locations(const char *
       SVN_ERR(svn_dirent_get_absolute(&local_abspath_or_url, path, subpool));
       SVN_ERR(svn_wc__node_get_url(&node_url, ctx->wc_ctx,
                                    local_abspath_or_url, pool, subpool));
-      SVN_ERR(svn_wc__node_get_copyfrom_info(&copyfrom_url, &copyfrom_rev,
+      SVN_ERR(svn_wc__node_get_copyfrom_info(NULL, NULL,
+                                             &copyfrom_url, &copyfrom_rev,
                                              NULL, ctx->wc_ctx,
                                              local_abspath_or_url,
                                              pool, subpool));

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=984234&r1=984233&r2=984234&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_client/status.c (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_client/status.c Tue Aug 10 22:07:24 2010
@@ -51,19 +51,28 @@
    accordingly. */
 struct status_baton
 {
-  svn_boolean_t deleted_in_repos;          /* target is deleted in repos */
-  apr_hash_t *changelist_hash;             /* keys are changelist names */
-  svn_wc_status_func4_t real_status_func;  /* real status function */
-  void *real_status_baton;                 /* real status baton */
-  const char *anchor_abspath;              /* Absolute path of anchor */
-  const char *anchor_relpath;              /* Relative path of anchor */
-  apr_hash_t *ignored_props;               /* props to ignore mods to */
-  svn_wc_context_t *wc_ctx;                /* working copy context */
-  svn_boolean_t no_ignore;            /* Same as svn_client_status5() */
-  svn_boolean_t get_all;              /* Same as svn_client_status5() */
+  svn_boolean_t deleted_in_repos;             /* target is deleted in repos */
+  apr_hash_t *changelist_hash;                /* keys are changelist names */
+  svn_client_status_func_t real_status_func;  /* real status function */
+  void *real_status_baton;                    /* real status baton */
+  const char *anchor_abspath;                 /* Absolute path of anchor */
+  const char *anchor_relpath;                 /* Relative path of anchor */
+  apr_hash_t *ignored_props;                  /* props to ignore mods to */
+  svn_wc_context_t *wc_ctx;                   /* working copy context */
+  svn_boolean_t no_ignore;                    /* Same as svn_client_status5() */
+  svn_boolean_t get_all;                      /* Same as svn_client_status5() */
 };
 
 
+/* Create svn_client_status_t from svn_wc_satus3_t */
+static svn_error_t *
+create_client_status(svn_client_status_t **cst,
+                     svn_wc_context_t *wc_ctx,
+                     const char *local_abspath,
+                     const svn_wc_status3_t *status,
+                     apr_pool_t *result_pool,
+                     apr_pool_t *scratch_pool);
+
 /* A status callback function which wraps the *real* status
    function/baton.   This sucker takes care of any status tweaks we
    need to make (such as noting that the target of the status is
@@ -78,6 +87,7 @@ tweak_status(void *baton,
 {
   struct status_baton *sb = baton;
   const char *path = local_abspath;
+  svn_client_status_t *cst;
 
   /* If we know that the target was deleted in HEAD of the repository,
      we need to note that fact in all the status structures that come
@@ -134,8 +144,11 @@ tweak_status(void *baton,
         }
     }
 
+  SVN_ERR(create_client_status(&cst, sb->wc_ctx, local_abspath, status,
+                               scratch_pool, scratch_pool));
+
   /* Call the real status function/baton. */
-  return sb->real_status_func(sb->real_status_baton, path, status,
+  return sb->real_status_func(sb->real_status_baton, path, cst,
                               scratch_pool);
 }
 
@@ -146,6 +159,7 @@ typedef struct report_baton_t {
   /* The common ancestor URL of all paths included in the report. */
   char *ancestor;
   void *set_locks_baton;
+  svn_depth_t depth;
   svn_client_ctx_t *ctx;
   /* Pool to store locks in. */
   apr_pool_t *pool;
@@ -186,14 +200,17 @@ reporter_link_path(void *report_baton, c
   const char *ancestor;
   apr_size_t len;
 
-  ancestor = svn_dirent_get_longest_ancestor(url, rb->ancestor, pool);
+  ancestor = svn_uri_get_longest_ancestor(url, rb->ancestor, pool);
 
   /* If we got a shorter ancestor, truncate our current ancestor.
      Note that svn_dirent_get_longest_ancestor will allocate its return
      value even if it identical to one of its arguments. */
   len = strlen(ancestor);
   if (len < strlen(rb->ancestor))
-    rb->ancestor[len] = '\0';
+    {
+      rb->ancestor[len] = '\0';
+      rb->depth = svn_depth_infinity;
+    }
 
   return rb->wrapped_reporter->link_path(rb->wrapped_report_baton, path, url,
                                          revision, depth, start_empty,
@@ -220,7 +237,7 @@ reporter_finish_report(void *report_bato
   /* The locks need to live throughout the edit.  Note that if the
      server doesn't support lock discovery, we'll just not do locky
      stuff. */
-  err = svn_ra_get_locks(ras, &locks, "", rb->pool);
+  err = svn_ra_get_locks2(ras, &locks, "", rb->depth, rb->pool);
   if (err && ((err->apr_err == SVN_ERR_RA_NOT_IMPLEMENTED)
               || (err->apr_err == SVN_ERR_UNSUPPORTED_FEATURE)))
     {
@@ -266,10 +283,9 @@ static svn_ra_reporter3_t lock_fetch_rep
 
 svn_error_t *
 svn_client_status5(svn_revnum_t *result_rev,
+                   svn_client_ctx_t *ctx,
                    const char *path,
                    const svn_opt_revision_t *revision,
-                   svn_wc_status_func4_t status_func,
-                   void *status_baton,
                    svn_depth_t depth,
                    svn_boolean_t get_all,
                    svn_boolean_t update,
@@ -277,7 +293,8 @@ svn_client_status5(svn_revnum_t *result_
                    svn_boolean_t ignore_externals,
                    svn_boolean_t ignore_mergeinfo,
                    const apr_array_header_t *changelists,
-                   svn_client_ctx_t *ctx,
+                   svn_client_status_func_t status_func,
+                   void *status_baton,
                    apr_pool_t *pool)  /* ### aka scratch_pool */
 {
   struct status_baton sb;
@@ -499,8 +516,8 @@ svn_client_status5(svn_revnum_t *result_
           /* 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, depth, editor,
-                                    edit_baton, pool));
+                                    target_basename, revnum, svn_depth_unknown,
+                                    editor, edit_baton, pool));
 
           /* Init the report baton. */
           rb.ancestor = apr_pstrdup(pool, URL); /* Edited later */
@@ -508,6 +525,11 @@ svn_client_status5(svn_revnum_t *result_
           rb.ctx = ctx;
           rb.pool = pool;
 
+          if (depth == svn_depth_unknown)
+            rb.depth = svn_depth_infinity;
+          else
+            rb.depth = depth;
+
           SVN_ERR(svn_ra_has_capability(ra_session, &server_supports_depth,
                                         SVN_RA_CAPABILITY_DEPTH, pool));
 
@@ -573,11 +595,155 @@ svn_client_status5(svn_revnum_t *result_
      in the future.
   */
   if (SVN_DEPTH_IS_RECURSIVE(depth) && (! ignore_externals))
-    SVN_ERR(svn_client__do_external_status(externals_store.externals_new,
-                                           status_func, status_baton,
+    SVN_ERR(svn_client__do_external_status(ctx, externals_store.externals_new,
                                            depth, get_all,
                                            update, no_ignore, ignored_props,
-                                           ctx, pool));
+                                           status_func, status_baton, pool));
+
+  return SVN_NO_ERROR;
+}
+
+svn_client_status_t *
+svn_client_status_dup(const svn_client_status_t *status,
+                      apr_pool_t *result_pool)
+{
+  svn_client_status_t *st = apr_palloc(result_pool, sizeof(*st));
+
+  *st = *status;
+
+  if (status->local_abspath)
+    st->local_abspath = apr_pstrdup(result_pool, status->local_abspath);
+
+  if (status->repos_root_url)
+    st->repos_root_url = apr_pstrdup(result_pool, status->repos_root_url);
+
+  if (status->repos_relpath)
+    st->repos_relpath = apr_pstrdup(result_pool, status->repos_relpath);
+
+  if (status->changed_author)
+    st->changed_author = apr_pstrdup(result_pool, status->changed_author);
+
+  if (status->lock)
+    st->lock = svn_lock_dup(status->lock, result_pool);
+
+  if (status->changelist)
+    st->changelist = apr_pstrdup(result_pool, status->changelist);
+
+  if (status->repos_lock)
+    st->repos_lock = svn_lock_dup(status->repos_lock, result_pool);
+
+  if (status->backwards_compatibility_baton)
+    {
+      const svn_wc_status3_t *wc_st = status->backwards_compatibility_baton;
+
+      st->backwards_compatibility_baton = svn_wc_dup_status3(wc_st,
+                                                             result_pool);
+    }
+
+  return st;
+}
+
+/* Create a svn_client_status_t structure *CST for LOCAL_ABSPATH, shallow
+ * copying data from *STATUS wherever possible and retrieving the other values
+ * where needed. Peform temporary allocations in SCRATCH_POOL and allocate the
+ * result in RESULT_POOL
+ */
+static svn_error_t *
+create_client_status(svn_client_status_t **cst,
+                     svn_wc_context_t *wc_ctx,
+                     const char *local_abspath,
+                     const svn_wc_status3_t *status,
+                     apr_pool_t *result_pool,
+                     apr_pool_t *scratch_pool)
+{
+  *cst = apr_pcalloc(result_pool, sizeof(**cst));
+
+  (*cst)->kind = status->kind;
+  (*cst)->local_abspath = local_abspath;
+  (*cst)->versioned = status->versioned;
+
+  (*cst)->conflicted = status->conflicted;
+
+  (*cst)->node_status = status->node_status;
+  (*cst)->text_status = status->text_status;
+  (*cst)->prop_status = status->prop_status;
+
+  (*cst)->switched = status->switched;
+
+  if (status->kind == svn_node_dir)
+    SVN_ERR(svn_wc_locked2(NULL, &(*cst)->locked, wc_ctx, local_abspath,
+                           scratch_pool));
+
+  (*cst)->copied = status->copied;
+  (*cst)->revision = status->revision;
+
+  (*cst)->changed_rev = status->changed_rev;
+  (*cst)->changed_date = status->changed_date;
+  (*cst)->changed_author = status->changed_author;
+
+  (*cst)->repos_root_url = status->repos_root_url;
+  (*cst)->repos_relpath = status->repos_relpath;
+
+  (*cst)->switched = status->switched;
+  (*cst)->file_external = FALSE;
+
+  if (status->versioned
+      && status->switched
+      && status->kind == svn_node_file)
+    {
+      svn_boolean_t is_file_external;
+      SVN_ERR(svn_wc__node_is_file_external(&is_file_external, wc_ctx,
+                                            local_abspath, scratch_pool));
+
+      if (is_file_external)
+        {
+          (*cst)->file_external = is_file_external;
+          (*cst)->switched = FALSE; /* ### Keep switched true now? */
+        }
+    }
+
+  (*cst)->lock = status->lock;
+
+  (*cst)->changelist = status->changelist;
+  (*cst)->depth = status->depth;
+
+  /* Out of date information */
+  (*cst)->ood_kind = status->ood_kind;
+  (*cst)->repos_node_status = status->repos_node_status;
+  (*cst)->repos_text_status = status->repos_text_status;
+  (*cst)->repos_prop_status = status->repos_prop_status;
+  (*cst)->repos_lock = status->repos_lock;
+
+  (*cst)->ood_changed_rev = status->ood_changed_rev;
+  (*cst)->ood_changed_date = status->ood_changed_date;
+  (*cst)->ood_changed_author = status->ood_changed_author;
+
+  /* When changing the value of backwards_compatibility_baton, also
+     change its use in status4_wrapper_func in deprecated.c */
+  (*cst)->backwards_compatibility_baton = status;
+
+  if (status->versioned && status->conflicted)
+    {
+      svn_boolean_t text_conflicted, prop_conflicted, tree_conflicted;
+
+      /* Note: This checks the on disk markers to automatically hide
+               text/property conflicts that are hidden by removing their
+               markers */
+      SVN_ERR(svn_wc_conflicted_p3(&text_conflicted, &prop_conflicted,
+                                   &tree_conflicted, wc_ctx, local_abspath,
+                                   scratch_pool));
+
+      if (text_conflicted)
+        (*cst)->text_status = svn_wc_status_conflicted;
+
+      if (prop_conflicted)
+        (*cst)->prop_status = svn_wc_status_conflicted;
+
+      /* ### Also set this for tree_conflicts? */
+      if (text_conflicted || prop_conflicted)
+        (*cst)->node_status = svn_wc_status_conflicted;
+    }
 
   return SVN_NO_ERROR;
 }
+

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=984234&r1=984233&r2=984234&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_client/update.c (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_client/update.c Tue Aug 10 22:07:24 2010
@@ -70,7 +70,7 @@ file_fetcher(void *baton,
   struct ff_baton *ffb = (struct ff_baton *)baton;
   const char *dirpath, *base_name, *session_url, *old_session_url;
 
-  svn_relpath_split(path, &dirpath, &base_name, pool);
+  svn_relpath_split(&dirpath, &base_name, path, pool);
   session_url = svn_path_url_add_component2(ffb->repos_root, 
                                             dirpath, pool);
 

Modified: subversion/branches/ignore-mergeinfo/subversion/libsvn_client/url.c
URL: http://svn.apache.org/viewvc/subversion/branches/ignore-mergeinfo/subversion/libsvn_client/url.c?rev=984234&r1=984233&r2=984234&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_client/url.c (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_client/url.c Tue Aug 10 22:07:24 2010
@@ -146,7 +146,8 @@ svn_client__entry_location(const char **
       || peg_rev_kind == svn_opt_revision_head)
     return svn_error_create(SVN_ERR_CLIENT_BAD_REVISION, NULL, NULL);
 
-  SVN_ERR(svn_wc__node_get_copyfrom_info(&copyfrom_url, &copyfrom_rev,
+  SVN_ERR(svn_wc__node_get_copyfrom_info(NULL, NULL,
+                                         &copyfrom_url, &copyfrom_rev,
                                          NULL, wc_ctx, local_abspath,
                                          result_pool, scratch_pool));
 

Modified: subversion/branches/ignore-mergeinfo/subversion/libsvn_delta/path_driver.c
URL: http://svn.apache.org/viewvc/subversion/branches/ignore-mergeinfo/subversion/libsvn_delta/path_driver.c?rev=984234&r1=984233&r2=984234&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_delta/path_driver.c (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_delta/path_driver.c Tue Aug 10 22:07:24 2010
@@ -215,9 +215,9 @@ svn_delta_path_driver(const svn_delta_ed
       /*** Step C - Open any directories between the common ancestor
            and the parent of the current path. ***/
       if (*path == '/')
-        svn_uri_split(path, &pdir, &bname, iterpool);
+        svn_uri_split(&pdir, &bname, path, iterpool);
       else
-        svn_relpath_split(path, &pdir, &bname, iterpool);
+        svn_relpath_split(&pdir, &bname, path, iterpool);
       if (strlen(pdir) > common_len)
         {
           const char *piece = pdir + common_len + 1;

Modified: subversion/branches/ignore-mergeinfo/subversion/libsvn_delta/text_delta.c
URL: http://svn.apache.org/viewvc/subversion/branches/ignore-mergeinfo/subversion/libsvn_delta/text_delta.c?rev=984234&r1=984233&r2=984234&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_delta/text_delta.c (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_delta/text_delta.c Tue Aug 10 22:07:24 2010
@@ -564,6 +564,73 @@ size_buffer(char **buf, apr_size_t *buf_
   return SVN_NO_ERROR;
 }
 
+/* Copy LEN bytes from SOURCE to TARGET, optimizing for the case where LEN
+ * is often very small.  Return a pointer to the first byte after the copied
+ * target range, unlike standard memcpy(), as a potential further
+ * optimization for the caller.
+ *
+ * memcpy() is hard to tune for a wide range of buffer lengths.  Therefore,
+ * it is often tuned for high throughput on large buffers and relatively
+ * low latency for mid-sized buffers (tens of bytes).  However, the overhead
+ * for very small buffers (<10 bytes) is still high.  Even passing the
+ * parameters, for instance, may take as long as copying 3 bytes.
+ *
+ * Because short copy sequences seem to be a common case, at least in
+ * "format 2" FSFS repositories, we copy them directly.  Larger buffer sizes
+ * aren't hurt measurably by the exta 'if' clause.  */
+static APR_INLINE char *
+fast_memcpy(char *target, const char *source, apr_size_t len)
+{
+  if (len > 7)
+    {
+      memcpy(target, source, len);
+      target += len;
+    }
+  else
+    {
+      /* memcpy is not exactly fast for small block sizes.
+       * Since they are common, let's run optimized code for them. */
+      const char *end = source + len;
+      for (; source != end; source++)
+        *(target++) = *source;
+    }
+
+  return target;
+}
+
+/* Copy LEN bytes from SOURCE to TARGET.  Unlike memmove() or memcpy(),
+ * create repeating patterns if the source and target ranges overlap.
+ * Return a pointer to the first byte after the copied target range.  */
+static APR_INLINE char *
+patterning_copy(char *target, const char *source, apr_size_t len)
+{
+  const char *end = source + len;
+
+  /* On the majority of machines (x86 / x64), unaligned access is much
+   * cheaper than repeated aligned access.  Therefore, use chunky copies on
+   * these machines when feasible.
+   * For those machines, GCC, ICC and MSC will define one of the following: */
+#if defined(_M_IX86) || defined(_M_X64) || defined(i386) || defined(__x86_64)
+
+  if (end + sizeof(apr_uint32_t) <= target)
+    {
+      /* Source and target are at least 4 bytes apart, so we can copy in
+       * 4-byte chunks.  */
+      for (; source + sizeof(apr_uint32_t) <= end;
+           source += sizeof(apr_uint32_t),
+           target += sizeof(apr_uint32_t))
+      *(apr_uint32_t *)(target) = *(apr_uint32_t *)(source);
+    }
+
+#endif
+
+  /* fall through to byte-wise copy (either for the below-chunk-size tail
+   * or the whole copy) */
+  for (; source != end; source++)
+    *(target++) = *source;
+
+  return target;
+}
 
 void
 svn_txdelta_apply_instructions(svn_txdelta_window_t *window,
@@ -571,7 +638,7 @@ svn_txdelta_apply_instructions(svn_txdel
                                apr_size_t *tlen)
 {
   const svn_txdelta_op_t *op;
-  apr_size_t i, j, tpos = 0;
+  apr_size_t tpos = 0;
 
   for (op = window->ops; op < window->ops + window->num_ops; op++)
     {
@@ -586,25 +653,26 @@ svn_txdelta_apply_instructions(svn_txdel
         case svn_txdelta_source:
           /* Copy from source area.  */
           assert(op->offset + op->length <= window->sview_len);
-          memcpy(tbuf + tpos, sbuf + op->offset, buf_len);
+          fast_memcpy(tbuf + tpos, sbuf + op->offset, buf_len);
           break;
 
         case svn_txdelta_target:
-          /* Copy from target area.  Don't use memcpy() since its
-             semantics aren't guaranteed for overlapping memory areas,
-             and target copies are allowed to overlap to generate
-             repeated data.  */
+          /* Copy from target area.  We can't use memcpy() or the like
+           * since we need a specific semantics for overlapping copies:
+           * they must result in repeating patterns.
+           * Note that most copies won't have overlapping source and
+           * target ranges (they are just a result of self-compressed
+           * data) but a small percentage will.  */
           assert(op->offset < tpos);
-          for (i = op->offset, j = tpos; i < op->offset + buf_len; i++)
-            tbuf[j++] = tbuf[i];
+          patterning_copy(tbuf + tpos, tbuf + op->offset, buf_len);
           break;
 
         case svn_txdelta_new:
           /* Copy from window new area.  */
           assert(op->offset + op->length <= window->new_data->len);
-          memcpy(tbuf + tpos,
-                 window->new_data->data + op->offset,
-                 buf_len);
+          fast_memcpy(tbuf + tpos,
+                      window->new_data->data + op->offset,
+                      buf_len);
           break;
 
         default:

Modified: subversion/branches/ignore-mergeinfo/subversion/libsvn_diff/parse-diff.c
URL: http://svn.apache.org/viewvc/subversion/branches/ignore-mergeinfo/subversion/libsvn_diff/parse-diff.c?rev=984234&r1=984233&r2=984234&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_diff/parse-diff.c (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_diff/parse-diff.c Tue Aug 10 22:07:24 2010
@@ -100,14 +100,14 @@ parse_range(svn_linenum_t *start, svn_li
 }
 
 /* Try to parse a hunk header in string HEADER, putting parsed information
- * into HUNK. Return TRUE if the header parsed correctly.
+ * into HUNK. Return TRUE if the header parsed correctly. ATAT is the
+ * character string used to delimit the hunk header.
  * If REVERSE is TRUE, invert the hunk header while parsing it.
  * Do all allocations in POOL. */
 static svn_boolean_t
 parse_hunk_header(const char *header, svn_hunk_t *hunk,
-                  svn_boolean_t reverse, apr_pool_t *pool)
+                  const char *atat, svn_boolean_t reverse, apr_pool_t *pool)
 {
-  static const char * const atat = "@@";
   const char *p;
   svn_stringbuf_t *range;
 
@@ -233,7 +233,7 @@ reverse_diff_transformer(svn_stringbuf_t
   /* ### Pass the already parsed hunk via the baton?
    * ### Maybe we should really make svn_stream_readline() a proper stream
    * ### method and override it instead of adding special callbacks? */
-  if (parse_hunk_header(line, &hunk, FALSE, scratch_pool))
+  if (parse_hunk_header(line, &hunk, "@@", FALSE, scratch_pool))
     {
       *buf = svn_stringbuf_createf(result_pool,
                                    "@@ -%lu,%lu +%lu,%lu @@",
@@ -242,6 +242,15 @@ reverse_diff_transformer(svn_stringbuf_t
                                    hunk.original_start,
                                    hunk.original_length);
     }
+  else if (parse_hunk_header(line, &hunk, "##", FALSE, scratch_pool))
+    {
+      *buf = svn_stringbuf_createf(result_pool,
+                                   "## -%lu,%lu +%lu,%lu ##",
+                                   hunk.modified_start,
+                                   hunk.modified_length,
+                                   hunk.original_start,
+                                   hunk.original_length);
+    }
   else if (line[0] == '+')
     {
       *buf = svn_stringbuf_create(line, result_pool);
@@ -258,14 +267,31 @@ reverse_diff_transformer(svn_stringbuf_t
   return SVN_NO_ERROR;
 }
 
+/* Parse PROP_NAME from HEADER as the part after the INDICATOR line. */
+static svn_error_t *
+parse_prop_name(const char **prop_name, const char *header, 
+                const char *indicator, apr_pool_t *result_pool)
+{
+  SVN_ERR(svn_utf_cstring_to_utf8(prop_name,
+                                  header + strlen(indicator),
+                                  result_pool));
+
+  /* ### Are we guarenteed that there are no trailing or leading
+   * ### whitespaces in the name? */
+
+  return SVN_NO_ERROR;
+}
+
 /* Return the next *HUNK from a PATCH, using STREAM to read data
- * from the patch file. If no hunk can be found, set *HUNK to NULL.
- * If REVERSE is TRUE, invert the hunk while parsing it. If
- * IGNORE_WHiTESPACES is TRUE, let lines without leading spaces be
- * recognized as context lines.  Allocate results in RESULT_POOL.  Use
- * SCRATCH_POOL for all other allocations. */
+ * from the patch file. If no hunk can be found, set *HUNK to NULL. If we
+ * have a property hunk, PROP_NAME will be set. If we have a text hunk,
+ * PROP_NAME will be NULL. If REVERSE is TRUE, invert the hunk while
+ * parsing it. If IGNORE_WHiTESPACES is TRUE, let lines without leading
+ * spaces be recognized as context lines.  Allocate results in RESULT_POOL.
+ * Use SCRATCH_POOL for all other allocations. */
 static svn_error_t *
 parse_next_hunk(svn_hunk_t **hunk,
+                const char **prop_name,
                 svn_patch_t *patch,
                 svn_stream_t *stream,
                 svn_boolean_t reverse,
@@ -274,7 +300,8 @@ parse_next_hunk(svn_hunk_t **hunk,
                 apr_pool_t *scratch_pool)
 {
   static const char * const minus = "--- ";
-  static const char * const atat = "@@";
+  static const char * const text_atat = "@@";
+  static const char * const prop_atat = "##";
   svn_stringbuf_t *line;
   svn_boolean_t eof, in_hunk, hunk_seen;
   apr_off_t pos, last_line;
@@ -289,6 +316,12 @@ parse_next_hunk(svn_hunk_t **hunk,
   svn_boolean_t changed_line_seen;
   apr_pool_t *iterpool;
 
+  /* We only set this if we have a property hunk. 
+   * ### prop_name acts as both a state flag inside this function and a
+   * ### qualifier to discriminate between props and text hunks. Is that
+   * ### kind of overloading ok? */
+  *prop_name = NULL;
+
   if (apr_file_eof(patch->patch_file) == APR_EOF)
     {
       /* No more hunks here. */
@@ -407,18 +440,47 @@ parse_next_hunk(svn_hunk_t **hunk,
         }
       else
         {
-          if (starts_with(line->data, atat))
+          if (starts_with(line->data, text_atat))
             {
               /* Looks like we have a hunk header, try to rip it apart. */
-              in_hunk = parse_hunk_header(line->data, *hunk, reverse,
-                                          iterpool);
+              in_hunk = parse_hunk_header(line->data, *hunk, text_atat,
+                                          reverse, iterpool);
               if (in_hunk)
                 {
                   original_lines = (*hunk)->original_length;
                   modified_lines = (*hunk)->modified_length;
+                  *prop_name = NULL;
                 }
+              }
+          else if (starts_with(line->data, prop_atat) && *prop_name)
+            {
+              /* Looks like we have a property hunk header, try to rip it
+               * apart. */
+              in_hunk = parse_hunk_header(line->data, *hunk, prop_atat,
+                                          reverse, iterpool);
+              if (in_hunk)
+                {
+                  original_lines = (*hunk)->original_length;
+                  modified_lines = (*hunk)->modified_length;
+                }
+            }
+          else if (starts_with(line->data, "Added: "))
+            {
+              SVN_ERR(parse_prop_name(prop_name, line->data, "Added: ",
+                                      result_pool));
             }
-          else if (starts_with(line->data, minus))
+          else if (starts_with(line->data, "Deleted: "))
+            {
+              SVN_ERR(parse_prop_name(prop_name, line->data, "Deleted: ",
+                                      result_pool));
+            }
+          else if (starts_with(line->data, "Modified: "))
+            {
+              SVN_ERR(parse_prop_name(prop_name, line->data, "Modified: ",
+                                      result_pool));
+            }
+          else if (starts_with(line->data, minus)
+                   || starts_with(line->data, "git --diff "))
             /* This could be a header of another patch. Bail out. */
             break;
         }
@@ -517,6 +579,268 @@ close_hunk(const svn_hunk_t *hunk)
   return SVN_NO_ERROR;
 }
 
+enum parse_state
+{
+   state_start,
+   state_git_diff_seen,
+  /* if we have an add || del || cp src+dst || mv src+dst */
+   state_git_tree_seen, 
+   state_git_minus_seen,
+   state_git_plus_seen,
+   state_move_from_seen,
+   state_copy_from_seen,
+   state_minus_seen,
+   state_unidiff_found,
+   state_add_seen,
+   state_del_seen,
+   state_git_header_found
+};
+
+struct transition
+{
+  const char *line;
+  enum parse_state state;
+  svn_error_t *(*fn)(enum parse_state *state, const char *line, 
+                     svn_patch_t *patch, apr_pool_t *result_pool,
+                     apr_pool_t *scratch_pool);
+};
+
+/* UTF-8 encode and canonicalize the content of LINE as FILE_NAME. */
+static svn_error_t *
+grab_filename(const char **file_name, const char *line, apr_pool_t *result_pool,
+              apr_pool_t *scratch_pool)
+{
+  const char *utf8_path;
+  const char *canon_path;
+
+  /* Grab the filename and encode it in UTF-8. */
+  /* TODO: Allow specifying the patch file's encoding.
+   *       For now, we assume its encoding is native. */
+  SVN_ERR(svn_utf_cstring_to_utf8(&utf8_path,
+                                  line,
+                                  scratch_pool));
+
+  /* Canonicalize the path name. */
+  canon_path = svn_dirent_canonicalize(utf8_path, scratch_pool);
+
+  *file_name = apr_pstrdup(result_pool, canon_path);
+
+  return SVN_NO_ERROR;
+}
+
+/* Parse the '--- ' line of a regular unidiff. */
+static svn_error_t *
+diff_minus(enum parse_state *state, const char *line, svn_patch_t *patch,
+           apr_pool_t *result_pool, apr_pool_t *scratch_pool)
+{
+  /* If we can find a tab, it separates the filename from
+   * the rest of the line which we can discard. */
+  char *tab = strchr(line, '\t');
+  if (tab)
+    *tab = '\0';
+
+  SVN_ERR(grab_filename(&patch->old_filename, line + strlen("--- "),
+                        result_pool, scratch_pool));
+
+  *state = state_minus_seen;
+
+  return SVN_NO_ERROR;
+}
+
+/* Parse the '+++ ' line of a regular unidiff. */
+static svn_error_t *
+diff_plus(enum parse_state *state, const char *line, svn_patch_t *patch,
+           apr_pool_t *result_pool, apr_pool_t *scratch_pool)
+{
+  /* If we can find a tab, it separates the filename from
+   * the rest of the line which we can discard. */
+  char *tab = strchr(line, '\t');
+  if (tab)
+    *tab = '\0';
+
+  SVN_ERR(grab_filename(&patch->new_filename, line + strlen("+++ "),
+                        result_pool, scratch_pool));
+
+  *state = state_unidiff_found;
+
+  return SVN_NO_ERROR;
+}
+
+/* Parse the first line of a git extended unidiff. */
+static svn_error_t *
+git_start(enum parse_state *state, const char *line, svn_patch_t *patch,
+          apr_pool_t *result_pool, apr_pool_t *scratch_pool)
+{
+  const char *old_path;
+  const char *new_path;
+  char *end_old_path;
+  char *slash;
+
+  /* ### Add handling of escaped paths
+   * http://www.kernel.org/pub/software/scm/git/docs/git-diff.html: 
+   *
+   * TAB, LF, double quote and backslash characters in pathnames are
+   * represented as \t, \n, \" and \\, respectively. If there is need for
+   * such substitution then the whole pathname is put in double quotes.
+   */
+
+  /* Our line should look like this: 'git --diff a/path b/path'. 
+   * If we find any deviations from that format, we return with state reset
+   * to start.
+   *
+   * ### We can't handle paths with spaces!
+   */
+  slash = strchr(line, '/');
+
+  if (! slash)
+    {
+      *state = state_start;
+      return SVN_NO_ERROR;
+    }
+
+  old_path = slash + 1;
+
+  if (! *old_path)
+    {
+      *state = state_start;
+      return SVN_NO_ERROR;
+    }
+
+  end_old_path = strchr(old_path, ' ');
+
+  if (end_old_path)
+    *end_old_path = '\0';
+  else
+    {
+      *state = state_start;
+      return SVN_NO_ERROR;
+    }
+
+  /* The new path begins after the first slash after the old path. */
+  slash = strchr(end_old_path + 1, '/');
+
+  if (! slash)
+    {
+      *state = state_start;
+      return SVN_NO_ERROR;
+    }
+
+  /* The path starts after the slash */
+  new_path = slash + 1;
+
+  if (! *new_path)
+    {
+      *state = state_start;
+      return SVN_NO_ERROR;
+    }
+
+  SVN_ERR(grab_filename(&patch->old_filename, old_path,
+                        result_pool, scratch_pool));
+
+  SVN_ERR(grab_filename(&patch->new_filename, new_path,
+                        result_pool, scratch_pool));
+
+  /* We assume that the path is only modified until we've found a 'tree'
+   * header */
+  patch->operation = svn_diff_op_modified;
+
+  *state = state_git_diff_seen;
+  return SVN_NO_ERROR;
+}
+
+/* Parse the '--- ' line of a git extended unidiff. */
+static svn_error_t *
+git_minus(enum parse_state *state, const char *line, svn_patch_t *patch,
+          apr_pool_t *result_pool, apr_pool_t *scratch_pool)
+{
+  /* ### Check that the path is consistent with the 'git --diff ' line. */
+
+  *state = state_git_minus_seen;
+  return SVN_NO_ERROR;
+}
+
+/* Parse the '+++ ' line of a git extended unidiff. */
+static svn_error_t *
+git_plus(enum parse_state *state, const char *line, svn_patch_t *patch,
+          apr_pool_t *result_pool, apr_pool_t *scratch_pool)
+{
+  /* ### Check that the path is consistent with the 'git --diff ' line. */
+
+  *state = state_git_header_found;
+  return SVN_NO_ERROR;
+}
+
+/* Parse the 'move from ' line of a git extended unidiff. */
+static svn_error_t *
+git_move_from(enum parse_state *state, const char *line, svn_patch_t *patch,
+              apr_pool_t *result_pool, apr_pool_t *scratch_pool)
+{
+  /* ### Check that the path is consistent with the 'git --diff ' line. */
+
+  *state = state_move_from_seen;
+  return SVN_NO_ERROR;
+}
+
+/* Parse the 'move to ' line fo a git extended unidiff. */
+static svn_error_t *
+git_move_to(enum parse_state *state, const char *line, svn_patch_t *patch,
+            apr_pool_t *result_pool, apr_pool_t *scratch_pool)
+{
+  /* ### Check that the path is consistent with the 'git --diff ' line. */
+
+  patch->operation = svn_diff_op_moved;
+
+  *state = state_git_tree_seen;
+  return SVN_NO_ERROR;
+}
+
+/* Parse the 'copy from ' line of a git extended unidiff. */
+static svn_error_t *
+git_copy_from(enum parse_state *state, const char *line, svn_patch_t *patch,
+              apr_pool_t *result_pool, apr_pool_t *scratch_pool)
+{
+  /* ### Check that the path is consistent with the 'git --diff ' line. */
+
+  *state = state_copy_from_seen; 
+  return SVN_NO_ERROR;
+}
+
+/* Parse the 'copy to ' line of a git extended unidiff. */
+static svn_error_t *
+git_copy_to(enum parse_state *state, const char *line, svn_patch_t *patch,
+            apr_pool_t *result_pool, apr_pool_t *scratch_pool)
+{
+  /* ### Check that the path is consistent with the 'git --diff ' line. */
+
+  patch->operation = svn_diff_op_copied;
+
+  *state = state_git_tree_seen;
+  return SVN_NO_ERROR;
+}
+
+/* Parse the 'new file ' line of a git extended unidiff. */
+static svn_error_t *
+git_new_file(enum parse_state *state, const char *line, svn_patch_t *patch,
+             apr_pool_t *result_pool, apr_pool_t *scratch_pool)
+{
+  patch->operation = svn_diff_op_added;
+
+  *state = state_git_header_found;
+  return SVN_NO_ERROR;
+}
+
+/* Parse the 'deleted file ' line of a git extended unidiff. */
+static svn_error_t *
+git_deleted_file(enum parse_state *state, const char *line, svn_patch_t *patch,
+                 apr_pool_t *result_pool, apr_pool_t *scratch_pool)
+{
+  patch->operation = svn_diff_op_deleted;
+
+  *state = state_git_header_found;
+  return SVN_NO_ERROR;
+}
+
+
 svn_error_t *
 svn_diff_parse_next_patch(svn_patch_t **patch,
                           apr_file_t *patch_file,
@@ -525,15 +849,39 @@ svn_diff_parse_next_patch(svn_patch_t **
                           apr_pool_t *result_pool,
                           apr_pool_t *scratch_pool)
 {
-  static const char * const minus = "--- ";
-  static const char * const plus = "+++ ";
-  const char *indicator;
   const char *fname;
   svn_stream_t *stream;
-  svn_boolean_t eof, in_header;
-  svn_hunk_t *hunk;
+  apr_off_t pos, last_line;
+  svn_boolean_t eof;
+  svn_boolean_t line_after_tree_header_read = FALSE;
+
   apr_pool_t *iterpool;
 
+  enum parse_state state = state_start;
+
+  /* ### dannas: As I've understood the git diff format, the first line
+   * ### contains both paths and the paths in the headers that follow are only
+   * ### there to ensure that the path is valid. Not sure though, the
+   * ### research continues... */
+
+  /* Our table consisting of:
+   * Input             Required state           function to call */
+  struct transition transitions[] = 
+    {
+      {"--- ",          state_start,            diff_minus},
+      {"+++ ",          state_minus_seen,       diff_plus},
+      {"git --diff",    state_start,            git_start},
+      {"--- a/",        state_git_diff_seen,    git_minus},
+      {"--- a/",        state_git_tree_seen,    git_minus},
+      {"+++ b/",        state_git_minus_seen,   git_plus},
+      {"move from ",    state_git_diff_seen,    git_move_from},
+      {"move to ",      state_move_from_seen,   git_move_to},
+      {"copy from ",    state_git_diff_seen,    git_copy_from},
+      {"copy to ",      state_copy_from_seen,   git_copy_to},
+      {"new file ",     state_git_diff_seen,    git_new_file},
+      {"deleted file ", state_git_diff_seen,    git_deleted_file},
+    };
+
   if (apr_file_eof(patch_file) == APR_EOF)
     {
       /* No more patches here. */
@@ -554,66 +902,74 @@ svn_diff_parse_next_patch(svn_patch_t **
    * make sure it is disowned. */
   stream = svn_stream_from_aprfile2(patch_file, TRUE, scratch_pool);
 
-  indicator = minus;
-  in_header = FALSE;
+  /* Get current seek position -- APR has no ftell() :( */
+  pos = 0;
+  SVN_ERR(svn_io_file_seek((*patch)->patch_file, APR_CUR, &pos, scratch_pool));
+
   iterpool = svn_pool_create(scratch_pool);
+
   do
     {
       svn_stringbuf_t *line;
+      int i;
 
       svn_pool_clear(iterpool);
 
-      /* Read a line from the stream. */
+      /* Remember the current line's offset, and read the line. */
+      last_line = pos;
       SVN_ERR(svn_stream_readline_detect_eol(stream, &line, NULL, &eof,
                                              iterpool));
 
-      /* See if we have a diff header. */
-      if (line->len > strlen(indicator) && starts_with(line->data, indicator))
+      if (! eof)
         {
-          const char *utf8_path;
-          const char *canon_path;
+          /* Update line offset for next iteration.
+           * APR has no ftell() :( */
+          pos = 0;
+          SVN_ERR(svn_io_file_seek((*patch)->patch_file, APR_CUR, &pos, iterpool));
+        }
 
-          /* If we can find a tab, it separates the filename from
-           * the rest of the line which we can discard. */
-          char *tab = strchr(line->data, '\t');
-          if (tab)
-            *tab = '\0';
-
-          /* Grab the filename and encode it in UTF-8. */
-          /* TODO: Allow specifying the patch file's encoding.
-           *       For now, we assume its encoding is native. */
-          SVN_ERR(svn_utf_cstring_to_utf8(&utf8_path,
-                                          line->data + strlen(indicator),
-                                          iterpool));
-
-          /* Canonicalize the path name. */
-          canon_path = svn_dirent_canonicalize(utf8_path, iterpool);
-
-          if ((! in_header) && strcmp(indicator, minus) == 0)
-            {
-              /* First line of header contains old filename. */
-              if (reverse)
-                (*patch)->new_filename = apr_pstrdup(result_pool, canon_path);
-              else
-                (*patch)->old_filename = apr_pstrdup(result_pool, canon_path);
-              indicator = plus;
-              in_header = TRUE;
-            }
-          else if (in_header && strcmp(indicator, plus) == 0)
-            {
-              /* Second line of header contains new filename. */
-              if (reverse)
-                (*patch)->old_filename = apr_pstrdup(result_pool, canon_path);
-              else
-                (*patch)->new_filename = apr_pstrdup(result_pool, canon_path);
-              in_header = FALSE;
-              break; /* All good! */
+      /* Run the state machine. */
+      for (i = 0; i < sizeof(transitions)/sizeof(transitions[0]); i++)
+        {
+          if (line->len > strlen(transitions[i].line) 
+              && starts_with(line->data, transitions[i].line)
+              && state == transitions[i].state)
+            {
+              SVN_ERR(transitions[i].fn(&state, line->data, *patch,
+                                        result_pool, iterpool));
+              break;
             }
-          else
-            in_header = FALSE;
         }
+
+      if (state == state_unidiff_found
+          || state == state_git_header_found)
+        {
+          /* We have a valid diff header, yay! */
+          break; 
+        }
+      else if (state == state_git_tree_seen 
+               && line_after_tree_header_read)
+        {
+          /* We have a valid diff header for a patch with only tree changes.
+           * Rewind to the start of the line just read, so subsequent calls
+           * to this function don't end up skipping the line -- it may
+           * contain a patch. */
+          SVN_ERR(svn_io_file_seek((*patch)->patch_file, APR_SET, &last_line,
+                                   scratch_pool));
+          break;
+        }
+      else if (state == state_git_tree_seen)
+          line_after_tree_header_read = TRUE;
+
+    } while (! eof);
+
+  if (reverse)
+    {
+      const char *temp;
+      temp = (*patch)->old_filename;
+      (*patch)->old_filename = (*patch)->new_filename;
+      (*patch)->new_filename = temp;
     }
-  while (! eof);
 
   if ((*patch)->old_filename == NULL || (*patch)->new_filename == NULL)
     {
@@ -622,16 +978,38 @@ svn_diff_parse_next_patch(svn_patch_t **
     }
   else
     {
+      svn_hunk_t *hunk;
+      const char *prop_name;
+
       /* Parse hunks. */
       (*patch)->hunks = apr_array_make(result_pool, 10, sizeof(svn_hunk_t *));
+      (*patch)->property_hunks = apr_hash_make(result_pool);
       do
         {
           svn_pool_clear(iterpool);
 
-          SVN_ERR(parse_next_hunk(&hunk, *patch, stream, reverse,
-                                  ignore_whitespace, result_pool, iterpool));
-          if (hunk)
+          SVN_ERR(parse_next_hunk(&hunk, &prop_name, *patch, stream,
+                                  reverse, ignore_whitespace,
+                                  result_pool, iterpool));
+          if (hunk && prop_name)
+            {
+              apr_array_header_t *hunks;
+
+              hunks = apr_hash_get((*patch)->property_hunks, prop_name,
+                                    APR_HASH_KEY_STRING);
+              if (! hunks)
+                {
+                  hunks = apr_array_make(result_pool, 1, 
+                                          sizeof(svn_hunk_t *));
+                  apr_hash_set((*patch)->property_hunks, prop_name,
+                                       APR_HASH_KEY_STRING, hunks);
+                }
+
+              APR_ARRAY_PUSH(hunks, svn_hunk_t *) = hunk;
+            }
+          else if (hunk)
             APR_ARRAY_PUSH((*patch)->hunks, svn_hunk_t *) = hunk;
+
         }
       while (hunk);
     }

Modified: subversion/branches/ignore-mergeinfo/subversion/libsvn_fs/fs-loader.c
URL: http://svn.apache.org/viewvc/subversion/branches/ignore-mergeinfo/subversion/libsvn_fs/fs-loader.c?rev=984234&r1=984233&r2=984234&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_fs/fs-loader.c (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_fs/fs-loader.c Tue Aug 10 22:07:24 2010
@@ -1199,11 +1199,21 @@ svn_fs_revision_proplist(apr_hash_t **ta
 }
 
 svn_error_t *
+svn_fs_change_rev_prop2(svn_fs_t *fs, svn_revnum_t rev, const char *name,
+                        const svn_string_t *const *old_value_p,
+                        const svn_string_t *value, apr_pool_t *pool)
+{
+  return svn_error_return(fs->vtable->change_rev_prop(fs, rev, name,
+                                                      old_value_p,
+                                                      value, pool));
+}
+
+svn_error_t *
 svn_fs_change_rev_prop(svn_fs_t *fs, svn_revnum_t rev, const char *name,
                        const svn_string_t *value, apr_pool_t *pool)
 {
-  return svn_error_return(fs->vtable->change_rev_prop(fs, rev, name, value,
-                                                      pool));
+  return svn_error_return(
+           svn_fs_change_rev_prop2(fs, rev, name, NULL, value, pool));
 }
 
 svn_error_t *
@@ -1291,16 +1301,29 @@ svn_fs_get_lock(svn_lock_t **lock, svn_f
 }
 
 svn_error_t *
+svn_fs_get_locks2(svn_fs_t *fs, const char *path, svn_depth_t depth,
+                  svn_fs_get_locks_callback_t get_locks_func,
+                  void *get_locks_baton, apr_pool_t *pool)
+{
+  SVN_ERR_ASSERT((depth == svn_depth_empty) ||
+                 (depth == svn_depth_files) ||
+                 (depth == svn_depth_immediates) ||
+                 (depth == svn_depth_infinity));
+  return svn_error_return(fs->vtable->get_locks(fs, path, depth,
+                                                get_locks_func,
+                                                get_locks_baton, pool));
+}
+
+svn_error_t *
 svn_fs_get_locks(svn_fs_t *fs, const char *path,
                  svn_fs_get_locks_callback_t get_locks_func,
-                 void *get_locks_baton,
-                 apr_pool_t *pool)
+                 void *get_locks_baton, apr_pool_t *pool)
 {
-  return svn_error_return(fs->vtable->get_locks(fs, path, get_locks_func,
-                                                get_locks_baton, pool));
+  return svn_error_return(svn_fs_get_locks2(fs, path, svn_depth_infinity,
+                                            get_locks_func, get_locks_baton,
+                                            pool));
 }
 
-
 
 /* --- History functions --- */
 

Modified: subversion/branches/ignore-mergeinfo/subversion/libsvn_fs/fs-loader.h
URL: http://svn.apache.org/viewvc/subversion/branches/ignore-mergeinfo/subversion/libsvn_fs/fs-loader.h?rev=984234&r1=984233&r2=984234&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_fs/fs-loader.h (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_fs/fs-loader.h Tue Aug 10 22:07:24 2010
@@ -158,6 +158,7 @@ typedef struct fs_vtable_t
                                     svn_revnum_t rev, apr_pool_t *pool);
   svn_error_t *(*change_rev_prop)(svn_fs_t *fs, svn_revnum_t rev,
                                   const char *name,
+                                  const svn_string_t *const *old_value_p,
                                   const svn_string_t *value,
                                   apr_pool_t *pool);
   svn_error_t *(*get_uuid)(svn_fs_t *fs, const char **uuid, apr_pool_t *pool);
@@ -189,7 +190,7 @@ typedef struct fs_vtable_t
                          svn_boolean_t break_lock, apr_pool_t *pool);
   svn_error_t *(*get_lock)(svn_lock_t **lock, svn_fs_t *fs,
                            const char *path, apr_pool_t *pool);
-  svn_error_t *(*get_locks)(svn_fs_t *fs, const char *path,
+  svn_error_t *(*get_locks)(svn_fs_t *fs, const char *path, svn_depth_t depth,
                             svn_fs_get_locks_callback_t get_locks_func,
                             void *get_locks_baton,
                             apr_pool_t *pool);

Modified: subversion/branches/ignore-mergeinfo/subversion/libsvn_fs_base/bdb/locks-table.c
URL: http://svn.apache.org/viewvc/subversion/branches/ignore-mergeinfo/subversion/libsvn_fs_base/bdb/locks-table.c?rev=984234&r1=984233&r2=984234&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_fs_base/bdb/locks-table.c (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_fs_base/bdb/locks-table.c Tue Aug 10 22:07:24 2010
@@ -191,6 +191,7 @@ get_lock(svn_lock_t **lock_p,
 svn_error_t *
 svn_fs_bdb__locks_get(svn_fs_t *fs,
                       const char *path,
+                      svn_depth_t depth,
                       svn_fs_get_locks_callback_t get_locks_func,
                       void *get_locks_baton,
                       trail_t *trail,
@@ -225,9 +226,11 @@ svn_fs_bdb__locks_get(svn_fs_t *fs,
         SVN_ERR(get_locks_func(get_locks_baton, lock, pool));
     }
 
+  /* If we're only looking at PATH itself (depth = empty), stop here. */
+  if (depth == svn_depth_empty)
+    return SVN_NO_ERROR;
+
   /* Now go hunt for possible children of PATH. */
-  if (strcmp(path, "/") != 0)
-    lookup_path = apr_pstrcat(pool, path, "/", NULL);
 
   svn_fs_base__trail_debug(trail, "lock-tokens", "cursor");
   db_err = bfd->lock_tokens->cursor(bfd->lock_tokens, trail->db_txn,
@@ -246,6 +249,8 @@ svn_fs_bdb__locks_get(svn_fs_t *fs,
 
   /* As long as the prefix of the returned KEY matches LOOKUP_PATH we
      know it is either LOOKUP_PATH or a decendant thereof.  */
+  if (strcmp(path, "/") != 0)
+    lookup_path = apr_pstrcat(pool, path, "/", NULL);
   while ((! db_err)
          && strncmp(lookup_path, key.data, strlen(lookup_path)) == 0)
     {
@@ -260,6 +265,18 @@ svn_fs_bdb__locks_get(svn_fs_t *fs,
       child_path = apr_pstrmemdup(subpool, key.data, key.size);
       lock_token = apr_pstrmemdup(subpool, value.data, value.size);
 
+      if ((depth == svn_depth_files) || (depth == svn_depth_immediates))
+        {
+          /* On the assumption that we only store locks for files,
+             depth=files and depth=immediates should boil down to the
+             same set of results.  So just see if CHILD_PATH is an
+             immediate child of PATH.  If not, we don't care about
+             this item.   */
+          const char *rel_uri = svn_uri_is_child(path, child_path, subpool);
+          if (!rel_uri || (svn_path_component_count(rel_uri) != 1))
+            goto loop_it;
+        }
+
       /* Get the lock for CHILD_PATH.  */
       err = get_lock(&lock, fs, child_path, lock_token, trail, subpool);
       if (err)
@@ -279,6 +296,7 @@ svn_fs_bdb__locks_get(svn_fs_t *fs,
             }
         }
 
+    loop_it:
       svn_fs_base__result_dbt(&key);
       svn_fs_base__result_dbt(&value);
       db_err = svn_bdb_dbc_get(cursor, &key, &value, DB_NEXT);

Modified: subversion/branches/ignore-mergeinfo/subversion/libsvn_fs_base/bdb/locks-table.h
URL: http://svn.apache.org/viewvc/subversion/branches/ignore-mergeinfo/subversion/libsvn_fs_base/bdb/locks-table.h?rev=984234&r1=984233&r2=984234&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_fs_base/bdb/locks-table.h (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_fs_base/bdb/locks-table.h Tue Aug 10 22:07:24 2010
@@ -86,12 +86,16 @@ svn_error_t *svn_fs_bdb__lock_get(svn_lo
    in FS. Pass each lock to GET_LOCKS_FUNC callback along with
    GET_LOCKS_BATON.
 
+   Use DEPTH to filter the reported locks to only those within the
+   requested depth of PATH.
+
    This function promises to auto-expire any locks encountered while
    building the hash.  That means that the caller can trust that each
    returned lock hasn't yet expired.
 */
 svn_error_t *svn_fs_bdb__locks_get(svn_fs_t *fs,
                                    const char *path,
+                                   svn_depth_t depth,
                                    svn_fs_get_locks_callback_t get_locks_func,
                                    void *get_locks_baton,
                                    trail_t *trail,

Modified: subversion/branches/ignore-mergeinfo/subversion/libsvn_fs_base/dag.c
URL: http://svn.apache.org/viewvc/subversion/branches/ignore-mergeinfo/subversion/libsvn_fs_base/dag.c?rev=984234&r1=984233&r2=984234&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_fs_base/dag.c (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_fs_base/dag.c Tue Aug 10 22:07:24 2010
@@ -251,7 +251,7 @@ txn_body_dag_init_fs(void *baton,
   /* Set a date on revision 0. */
   date.data = svn_time_to_cstring(apr_time_now(), trail->pool);
   date.len = strlen(date.data);
-  return svn_fs_base__set_rev_prop(fs, 0, SVN_PROP_REVISION_DATE, &date,
+  return svn_fs_base__set_rev_prop(fs, 0, SVN_PROP_REVISION_DATE, NULL, &date,
                                    trail, trail->pool);
 }
 
@@ -1644,7 +1644,7 @@ svn_fs_base__dag_commit_txn(svn_revnum_t
   date.data = svn_time_to_cstring(apr_time_now(), pool);
   date.len = strlen(date.data);
   return svn_fs_base__set_rev_prop(fs, *new_rev, SVN_PROP_REVISION_DATE,
-                                   &date, trail, pool);
+                                   NULL, &date, trail, pool);
 }
 
 /* Modify all entries in the "node-origins" table that have a txn-id of

Modified: subversion/branches/ignore-mergeinfo/subversion/libsvn_fs_base/lock.c
URL: http://svn.apache.org/viewvc/subversion/branches/ignore-mergeinfo/subversion/libsvn_fs_base/lock.c?rev=984234&r1=984233&r2=984234&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_fs_base/lock.c (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_fs_base/lock.c Tue Aug 10 22:07:24 2010
@@ -396,6 +396,7 @@ svn_fs_base__get_lock(svn_lock_t **lock,
 struct locks_get_args
 {
   const char *path;
+  svn_depth_t depth;
   svn_fs_get_locks_callback_t get_locks_func;
   void *get_locks_baton;
 };
@@ -405,7 +406,7 @@ static svn_error_t *
 txn_body_get_locks(void *baton, trail_t *trail)
 {
   struct locks_get_args *args = baton;
-  return svn_fs_bdb__locks_get(trail->fs, args->path,
+  return svn_fs_bdb__locks_get(trail->fs, args->path, args->depth,
                                args->get_locks_func, args->get_locks_baton,
                                trail, trail->pool);
 }
@@ -414,6 +415,7 @@ txn_body_get_locks(void *baton, trail_t 
 svn_error_t *
 svn_fs_base__get_locks(svn_fs_t *fs,
                        const char *path,
+                       svn_depth_t depth,
                        svn_fs_get_locks_callback_t get_locks_func,
                        void *get_locks_baton,
                        apr_pool_t *pool)
@@ -422,6 +424,7 @@ svn_fs_base__get_locks(svn_fs_t *fs,
 
   SVN_ERR(svn_fs__check_fs(fs, TRUE));
   args.path = svn_fs__canonicalize_abspath(path, pool);
+  args.depth = depth;
   args.get_locks_func = get_locks_func;
   args.get_locks_baton = get_locks_baton;
   return svn_fs_base__retry_txn(fs, txn_body_get_locks, &args, FALSE, pool);
@@ -490,7 +493,8 @@ svn_fs_base__allow_locked_operation(cons
   if (recurse)
     {
       /* Discover all locks at or below the path. */
-      SVN_ERR(svn_fs_bdb__locks_get(trail->fs, path, get_locks_callback,
+      SVN_ERR(svn_fs_bdb__locks_get(trail->fs, path, svn_depth_infinity,
+                                    get_locks_callback,
                                     trail->fs, trail, pool));
     }
   else

Modified: subversion/branches/ignore-mergeinfo/subversion/libsvn_fs_base/lock.h
URL: http://svn.apache.org/viewvc/subversion/branches/ignore-mergeinfo/subversion/libsvn_fs_base/lock.h?rev=984234&r1=984233&r2=984234&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_fs_base/lock.h (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_fs_base/lock.h Tue Aug 10 22:07:24 2010
@@ -64,6 +64,7 @@ svn_error_t *svn_fs_base__get_lock(svn_l
 svn_error_t *
 svn_fs_base__get_locks(svn_fs_t *fs,
                        const char *path,
+                       svn_depth_t depth,
                        svn_fs_get_locks_callback_t get_locks_func,
                        void *get_locks_baton,
                        apr_pool_t *pool);

Modified: subversion/branches/ignore-mergeinfo/subversion/libsvn_fs_base/revs-txns.c
URL: http://svn.apache.org/viewvc/subversion/branches/ignore-mergeinfo/subversion/libsvn_fs_base/revs-txns.c?rev=984234&r1=984233&r2=984234&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_fs_base/revs-txns.c (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_fs_base/revs-txns.c Tue Aug 10 22:07:24 2010
@@ -241,6 +241,7 @@ svn_error_t *
 svn_fs_base__set_rev_prop(svn_fs_t *fs,
                           svn_revnum_t rev,
                           const char *name,
+                          const svn_string_t *const *old_value_p,
                           const svn_string_t *value,
                           trail_t *trail,
                           apr_pool_t *pool)
@@ -259,6 +260,23 @@ svn_fs_base__set_rev_prop(svn_fs_t *fs,
     txn->proplist = apr_hash_make(pool);
 
   /* Set the property. */
+  if (old_value_p)
+    {
+      const svn_string_t *wanted_value = *old_value_p;
+      const svn_string_t *present_value = apr_hash_get(txn->proplist, name,
+                                                       APR_HASH_KEY_STRING);
+      if ((!wanted_value != !present_value)
+          || (wanted_value && present_value
+              && !svn_string_compare(wanted_value, present_value)))
+        {
+          /* What we expected isn't what we found. */
+          return svn_error_createf(SVN_ERR_BAD_PROPERTY_VALUE, NULL,
+                                   _("revprop '%s' has unexpected value in "
+                                     "filesystem"),
+                                   name);
+        }
+      /* Fall through. */
+    }
   apr_hash_set(txn->proplist, name, APR_HASH_KEY_STRING, value);
 
   /* Overwrite the revision. */
@@ -269,6 +287,7 @@ svn_fs_base__set_rev_prop(svn_fs_t *fs,
 struct change_rev_prop_args {
   svn_revnum_t rev;
   const char *name;
+  const svn_string_t *const *old_value_p;
   const svn_string_t *value;
 };
 
@@ -279,7 +298,7 @@ txn_body_change_rev_prop(void *baton, tr
   struct change_rev_prop_args *args = baton;
 
   return svn_fs_base__set_rev_prop(trail->fs, args->rev,
-                                   args->name, args->value,
+                                   args->name, args->old_value_p, args->value,
                                    trail, trail->pool);
 }
 
@@ -288,6 +307,7 @@ svn_error_t *
 svn_fs_base__change_rev_prop(svn_fs_t *fs,
                              svn_revnum_t rev,
                              const char *name,
+                             const svn_string_t *const *old_value_p,
                              const svn_string_t *value,
                              apr_pool_t *pool)
 {
@@ -297,6 +317,7 @@ svn_fs_base__change_rev_prop(svn_fs_t *f
 
   args.rev = rev;
   args.name = name;
+  args.old_value_p = old_value_p;
   args.value = value;
   return svn_fs_base__retry_txn(fs, txn_body_change_rev_prop, &args,
                                 TRUE, pool);

Modified: subversion/branches/ignore-mergeinfo/subversion/libsvn_fs_base/revs-txns.h
URL: http://svn.apache.org/viewvc/subversion/branches/ignore-mergeinfo/subversion/libsvn_fs_base/revs-txns.h?rev=984234&r1=984233&r2=984234&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_fs_base/revs-txns.h (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_fs_base/revs-txns.h Tue Aug 10 22:07:24 2010
@@ -61,6 +61,7 @@ svn_error_t *svn_fs_base__rev_get_txn_id
 svn_error_t *svn_fs_base__set_rev_prop(svn_fs_t *fs,
                                        svn_revnum_t rev,
                                        const char *name,
+                                       const svn_string_t *const *old_value_p,
                                        const svn_string_t *value,
                                        trail_t *trail,
                                        apr_pool_t *pool);
@@ -180,6 +181,7 @@ svn_error_t *svn_fs_base__revision_propl
 
 svn_error_t *svn_fs_base__change_rev_prop(svn_fs_t *fs, svn_revnum_t rev,
                                           const char *name,
+                                          const svn_string_t *const *old_value_p,
                                           const svn_string_t *value,
                                           apr_pool_t *pool);