subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From danie...@apache.org
Subject svn commit: r967221 [2/7] - in /subversion/branches/atomic-revprop: ./ build/generator/ notes/ notes/tree-conflicts/ subversion/bindings/javahl/tests/org/apache/subversion/javahl/ subversion/bindings/javahl/tests/org/tigris/subversion/javahl/ subversio...
Date Fri, 23 Jul 2010 19:37:24 GMT
Modified: subversion/branches/atomic-revprop/subversion/libsvn_client/copy.c
URL: http://svn.apache.org/viewvc/subversion/branches/atomic-revprop/subversion/libsvn_client/copy.c?rev=967221&r1=967220&r2=967221&view=diff
==============================================================================
--- subversion/branches/atomic-revprop/subversion/libsvn_client/copy.c (original)
+++ subversion/branches/atomic-revprop/subversion/libsvn_client/copy.c Fri Jul 23 19:37:19 2010
@@ -310,7 +310,7 @@ do_wc_to_wc_copies(const apr_array_heade
   baton.dst_parent = dst_parent;
   SVN_ERR(svn_wc__call_with_write_lock(do_wc_to_wc_copies_with_write_lock,
                                        &baton, ctx->wc_ctx, dst_parent_abspath,
-                                       pool, pool));
+                                       FALSE, pool, pool));
 
   return SVN_NO_ERROR;
 }
@@ -361,7 +361,7 @@ do_wc_to_wc_moves_with_locks1(void *bato
   if (b->lock_dst)
     SVN_ERR(svn_wc__call_with_write_lock(do_wc_to_wc_moves_with_locks2, b,
                                          b->ctx->wc_ctx, b->dst_parent_abspath,
-                                         result_pool, scratch_pool));
+                                         FALSE, result_pool, scratch_pool));
   else
     SVN_ERR(do_wc_to_wc_moves_with_locks2(b, result_pool, scratch_pool));
 
@@ -430,7 +430,7 @@ do_wc_to_wc_moves(const apr_array_header
         SVN_ERR(svn_wc__call_with_write_lock(do_wc_to_wc_moves_with_locks1,
                                              &baton,
                                              ctx->wc_ctx, src_parent_abspath,
-                                             iterpool, iterpool));
+                                             FALSE, iterpool, iterpool));
       else
         SVN_ERR(do_wc_to_wc_moves_with_locks1(&baton, iterpool, iterpool));
 
@@ -720,8 +720,7 @@ find_absent_parents2(svn_ra_session_t *r
 }
 
 static svn_error_t *
-repos_to_repos_copy(svn_commit_info_t **commit_info_p,
-                    const apr_array_header_t *copy_pairs,
+repos_to_repos_copy(const apr_array_header_t *copy_pairs,
                     svn_boolean_t make_parents,
                     const apr_hash_t *revprop_table,
                     svn_client_ctx_t *ctx,
@@ -739,7 +738,6 @@ repos_to_repos_copy(svn_commit_info_t **
   svn_ra_session_t *ra_session = NULL;
   const svn_delta_editor_t *editor;
   void *edit_baton;
-  void *commit_baton;
   struct path_driver_cb_baton cb_baton;
   apr_array_header_t *new_dirs = NULL;
   apr_hash_t *commit_revprops;
@@ -1115,11 +1113,10 @@ repos_to_repos_copy(svn_commit_info_t **
                                            message, ctx, pool));
 
   /* Fetch RA commit editor. */
-  SVN_ERR(svn_client__commit_get_baton(&commit_baton, commit_info_p, pool));
   SVN_ERR(svn_ra_get_commit_editor3(ra_session, &editor, &edit_baton,
                                     commit_revprops,
-                                    svn_client__commit_callback,
-                                    commit_baton,
+                                    ctx->commit_callback2,
+                                    ctx->commit_baton,
                                     NULL, TRUE, /* No lock tokens */
                                     pool));
 
@@ -1151,8 +1148,7 @@ repos_to_repos_copy(svn_commit_info_t **
  * REVPROP_TABLE is ...
  * CTX is ... */
 static svn_error_t *
-wc_to_repos_copy(svn_commit_info_t **commit_info_p,
-                 const apr_array_header_t *copy_pairs,
+wc_to_repos_copy(const apr_array_header_t *copy_pairs,
                  svn_boolean_t make_parents,
                  const apr_hash_t *revprop_table,
                  svn_client_ctx_t *ctx,
@@ -1164,7 +1160,6 @@ wc_to_repos_copy(svn_commit_info_t **com
   svn_ra_session_t *ra_session;
   const svn_delta_editor_t *editor;
   void *edit_baton;
-  void *commit_baton;
   apr_hash_t *committables;
   apr_array_header_t *commit_items;
   apr_pool_t *iterpool;
@@ -1392,11 +1387,10 @@ wc_to_repos_copy(svn_commit_info_t **com
                                                FALSE, FALSE, ctx, pool));
 
   /* Fetch RA commit editor. */
-  SVN_ERR(svn_client__commit_get_baton(&commit_baton, commit_info_p, pool));
   SVN_ERR(svn_ra_get_commit_editor3(ra_session, &editor, &edit_baton,
                                     commit_revprops,
-                                    svn_client__commit_callback,
-                                    commit_baton, NULL,
+                                    ctx->commit_callback2,
+                                    ctx->commit_baton, NULL,
                                     TRUE, /* No lock tokens */
                                     pool));
 
@@ -1404,7 +1398,7 @@ wc_to_repos_copy(svn_commit_info_t **com
   SVN_ERR_W(svn_client__do_commit(top_dst_url, commit_items,
                                   editor, edit_baton,
                                   0, /* ### any notify_path_offset needed? */
-                                  NULL, NULL, NULL, ctx, pool),
+                                  NULL, NULL, ctx, pool),
             _("Commit failed (details follow):"));
 
   /* Sleep to ensure timestamp integrity. */
@@ -1859,7 +1853,7 @@ repos_to_wc_copy(const apr_array_header_
 
   SVN_ERR(svn_wc__call_with_write_lock(repos_to_wc_copy_cb, &baton,
                                        ctx->wc_ctx, lock_abspath,
-                                       pool, pool));
+                                       FALSE, pool, pool));
   return SVN_NO_ERROR;
 }
 
@@ -1869,8 +1863,7 @@ repos_to_wc_copy(const apr_array_header_
 
 /* Perform all allocations in POOL. */
 static svn_error_t *
-try_copy(svn_commit_info_t **commit_info_p,
-         const apr_array_header_t *sources,
+try_copy(const apr_array_header_t *sources,
          const char *dst_path_in,
          svn_boolean_t is_move,
          svn_boolean_t force,
@@ -2154,7 +2147,6 @@ try_copy(svn_commit_info_t **commit_info
   /* Now, call the right handler for the operation. */
   if ((! srcs_are_urls) && (! dst_is_url))
     {
-      *commit_info_p = NULL;
       return svn_error_return(
         wc_to_wc_copy(copy_pairs, dst_path_in, is_move, make_parents, ctx,
                       pool));
@@ -2162,12 +2154,10 @@ try_copy(svn_commit_info_t **commit_info
   else if ((! srcs_are_urls) && (dst_is_url))
     {
       return svn_error_return(
-        wc_to_repos_copy(commit_info_p, copy_pairs, make_parents,
-                         revprop_table, ctx, pool));
+        wc_to_repos_copy(copy_pairs, make_parents, revprop_table, ctx, pool));
     }
   else if ((srcs_are_urls) && (! dst_is_url))
     {
-      *commit_info_p = NULL;
       return svn_error_return(
         repos_to_wc_copy(copy_pairs, make_parents, ignore_externals,
                          ctx, pool));
@@ -2175,7 +2165,7 @@ try_copy(svn_commit_info_t **commit_info
   else
     {
       return svn_error_return(
-        repos_to_repos_copy(commit_info_p, copy_pairs, make_parents,
+        repos_to_repos_copy(copy_pairs, make_parents,
                             revprop_table, ctx, is_move, pool));
     }
 }
@@ -2184,8 +2174,7 @@ try_copy(svn_commit_info_t **commit_info
 
 /* Public Interfaces */
 svn_error_t *
-svn_client_copy5(svn_commit_info_t **commit_info_p,
-                 const apr_array_header_t *sources,
+svn_client_copy6(const apr_array_header_t *sources,
                  const char *dst_path,
                  svn_boolean_t copy_as_child,
                  svn_boolean_t make_parents,
@@ -2195,15 +2184,13 @@ svn_client_copy5(svn_commit_info_t **com
                  apr_pool_t *pool)
 {
   svn_error_t *err;
-  svn_commit_info_t *commit_info = NULL;
   apr_pool_t *subpool = svn_pool_create(pool);
 
   if (sources->nelts > 1 && !copy_as_child)
     return svn_error_create(SVN_ERR_CLIENT_MULTIPLE_SOURCES_DISALLOWED,
                             NULL, NULL);
 
-  err = try_copy(&commit_info,
-                 sources, dst_path,
+  err = try_copy(sources, dst_path,
                  FALSE /* is_move */,
                  TRUE /* force, set to avoid deletion check */,
                  make_parents,
@@ -2232,8 +2219,7 @@ svn_client_copy5(svn_commit_info_t **com
       if (svn_path_is_url(src_path) && ! svn_path_is_url(dst_path))
         src_basename = svn_path_uri_decode(src_basename, subpool);
 
-      err = try_copy(&commit_info,
-                     sources,
+      err = try_copy(sources,
                      dst_is_uri
                          ? svn_uri_join(dst_path, src_basename, subpool)
                          : svn_dirent_join(dst_path, src_basename, subpool),
@@ -2246,22 +2232,13 @@ svn_client_copy5(svn_commit_info_t **com
                      subpool);
     }
 
-  if (commit_info_p != NULL)
-    {
-      if (commit_info)
-        *commit_info_p = svn_commit_info_dup(commit_info, pool);
-      else
-        *commit_info_p = NULL;
-    }
-
   svn_pool_destroy(subpool);
   return svn_error_return(err);
 }
 
 
 svn_error_t *
-svn_client_move5(svn_commit_info_t **commit_info_p,
-                 const apr_array_header_t *src_paths,
+svn_client_move6(const apr_array_header_t *src_paths,
                  const char *dst_path,
                  svn_boolean_t force,
                  svn_boolean_t move_as_child,
@@ -2270,7 +2247,6 @@ svn_client_move5(svn_commit_info_t **com
                  svn_client_ctx_t *ctx,
                  apr_pool_t *pool)
 {
-  svn_commit_info_t *commit_info = NULL;
   const svn_opt_revision_t head_revision
     = { svn_opt_revision_head, { 0 } };
   svn_error_t *err;
@@ -2296,7 +2272,7 @@ svn_client_move5(svn_commit_info_t **com
       APR_ARRAY_PUSH(sources, svn_client_copy_source_t *) = copy_source;
     }
 
-  err = try_copy(&commit_info, sources, dst_path,
+  err = try_copy(sources, dst_path,
                  TRUE /* is_move */,
                  force,
                  make_parents,
@@ -2322,7 +2298,7 @@ svn_client_move5(svn_commit_info_t **com
       src_basename = src_is_uri ? svn_uri_basename(src_path, pool)
                                 : svn_dirent_basename(src_path, pool);
 
-      err = try_copy(&commit_info, sources,
+      err = try_copy(sources,
                      dst_is_uri
                          ? svn_uri_join(dst_path, src_basename, pool)
                          : svn_dirent_join(dst_path, src_basename, pool),
@@ -2335,14 +2311,6 @@ svn_client_move5(svn_commit_info_t **com
                      subpool);
     }
 
-  if (commit_info_p != NULL)
-    {
-      if (commit_info)
-        *commit_info_p = svn_commit_info_dup(commit_info, pool);
-      else
-        *commit_info_p = commit_info;
-    }
-
   svn_pool_destroy(subpool);
   return svn_error_return(err);
 }

Modified: subversion/branches/atomic-revprop/subversion/libsvn_client/delete.c
URL: http://svn.apache.org/viewvc/subversion/branches/atomic-revprop/subversion/libsvn_client/delete.c?rev=967221&r1=967220&r2=967221&view=diff
==============================================================================
--- subversion/branches/atomic-revprop/subversion/libsvn_client/delete.c (original)
+++ subversion/branches/atomic-revprop/subversion/libsvn_client/delete.c Fri Jul 23 19:37:19 2010
@@ -136,8 +136,7 @@ path_driver_cb_func(void **dir_baton,
 
 
 static svn_error_t *
-delete_urls(svn_commit_info_t **commit_info_p,
-            const apr_array_header_t *paths,
+delete_urls(const apr_array_header_t *paths,
             const apr_hash_t *revprop_table,
             svn_client_ctx_t *ctx,
             apr_pool_t *pool)
@@ -145,7 +144,6 @@ delete_urls(svn_commit_info_t **commit_i
   svn_ra_session_t *ra_session = NULL;
   const svn_delta_editor_t *editor;
   void *edit_baton;
-  void *commit_baton;
   const char *log_msg;
   svn_node_kind_t kind;
   apr_array_header_t *targets;
@@ -237,11 +235,10 @@ delete_urls(svn_commit_info_t **commit_i
   SVN_ERR(svn_ra_reparent(ra_session, common, pool));
 
   /* Fetch RA commit editor */
-  SVN_ERR(svn_client__commit_get_baton(&commit_baton, commit_info_p, pool));
   SVN_ERR(svn_ra_get_commit_editor3(ra_session, &editor, &edit_baton,
                                     commit_revprops,
-                                    svn_client__commit_callback,
-                                    commit_baton,
+                                    ctx->commit_callback2,
+                                    ctx->commit_baton,
                                     NULL, TRUE, /* No lock tokens */
                                     pool));
 
@@ -314,8 +311,7 @@ delete_with_write_lock_func(void *baton,
 }
 
 svn_error_t *
-svn_client_delete3(svn_commit_info_t **commit_info_p,
-                   const apr_array_header_t *paths,
+svn_client_delete4(const apr_array_header_t *paths,
                    svn_boolean_t force,
                    svn_boolean_t keep_local,
                    const apr_hash_t *revprop_table,
@@ -327,7 +323,7 @@ svn_client_delete3(svn_commit_info_t **c
 
   if (svn_path_is_url(APR_ARRAY_IDX(paths, 0, const char *)))
     {
-      SVN_ERR(delete_urls(commit_info_p, paths, revprop_table, ctx, pool));
+      SVN_ERR(delete_urls(paths, revprop_table, ctx, pool));
     }
   else
     {
@@ -353,7 +349,8 @@ svn_client_delete3(svn_commit_info_t **c
           dwwlb.ctx = ctx;
           SVN_ERR(svn_wc__call_with_write_lock(delete_with_write_lock_func,
                                                &dwwlb, ctx->wc_ctx,
-                                               local_abspath, pool, subpool));
+                                               local_abspath, TRUE,
+                                               pool, subpool));
         }
       svn_pool_destroy(subpool);
     }

Modified: subversion/branches/atomic-revprop/subversion/libsvn_client/deprecated.c
URL: http://svn.apache.org/viewvc/subversion/branches/atomic-revprop/subversion/libsvn_client/deprecated.c?rev=967221&r1=967220&r2=967221&view=diff
==============================================================================
--- subversion/branches/atomic-revprop/subversion/libsvn_client/deprecated.c (original)
+++ subversion/branches/atomic-revprop/subversion/libsvn_client/deprecated.c Fri Jul 23 19:37:19 2010
@@ -50,6 +50,39 @@
 
 /*** Code. ***/
 
+
+/* Baton for capture_commit_info() */
+struct capture_baton_t {
+  svn_commit_callback2_t original_callback;
+  void *original_baton;
+
+  svn_commit_info_t **info;
+  apr_pool_t *pool;
+
+  svn_boolean_t saw_commit;
+};
+
+
+/* Callback which implements svn_commit_callback2_t for use with some
+   backward compat functions. */
+static svn_error_t *
+capture_commit_info(const svn_commit_info_t *commit_info,
+                    void *baton,
+                    apr_pool_t *pool)
+{
+  struct capture_baton_t *cb = baton;
+
+  *(cb->info) = svn_commit_info_dup(commit_info, cb->pool);
+
+  if (cb->original_callback)
+    SVN_ERR((cb->original_callback)(commit_info, cb->original_baton, pool));
+
+  cb->saw_commit = TRUE;
+
+  return SVN_NO_ERROR;
+}
+
+
 /*** From add.c ***/
 svn_error_t *
 svn_client_add3(const char *path,
@@ -83,7 +116,29 @@ svn_client_add(const char *path,
   return svn_client_add3(path, recursive, FALSE, FALSE, ctx, pool);
 }
 
+svn_error_t *
+svn_client_mkdir3(svn_commit_info_t **commit_info_p,
+                  const apr_array_header_t *paths,
+                  svn_boolean_t make_parents,
+                  const apr_hash_t *revprop_table,
+                  svn_client_ctx_t *ctx,
+                  apr_pool_t *pool)
+{
+  svn_client_ctx_t shadow_ctx;
+  struct capture_baton_t cb;
 
+  cb.info = commit_info_p;
+  cb.pool = pool;
+  cb.original_callback = ctx->commit_callback2;
+  cb.original_baton = ctx->commit_baton;
+
+  shadow_ctx = *ctx;
+  shadow_ctx.commit_callback2 = capture_commit_info;
+  shadow_ctx.commit_baton = &cb;
+
+  return svn_client_mkdir4(paths, make_parents, revprop_table, &shadow_ctx,
+                           pool);
+}
 
 svn_error_t *
 svn_client_mkdir2(svn_commit_info_t **commit_info_p,
@@ -333,6 +388,34 @@ svn_client_blame(const char *target,
 
 /*** From commit.c ***/
 svn_error_t *
+svn_client_import3(svn_commit_info_t **commit_info_p,
+                   const char *path,
+                   const char *url,
+                   svn_depth_t depth,
+                   svn_boolean_t no_ignore,
+                   svn_boolean_t ignore_unknown_node_types,
+                   const apr_hash_t *revprop_table,
+                   svn_client_ctx_t *ctx,
+                   apr_pool_t *pool)
+{
+  svn_client_ctx_t shadow_ctx;
+  struct capture_baton_t cb;
+
+  cb.info = commit_info_p;
+  cb.pool = pool;
+  cb.original_callback = ctx->commit_callback2;
+  cb.original_baton = ctx->commit_baton;
+
+  shadow_ctx = *ctx;
+  shadow_ctx.commit_callback2 = capture_commit_info;
+  shadow_ctx.commit_baton = &cb;
+
+  return svn_client_import4(path, url, depth, no_ignore,
+                            ignore_unknown_node_types, revprop_table,
+                            &shadow_ctx, pool);
+}
+
+svn_error_t *
 svn_client_import2(svn_commit_info_t **commit_info_p,
                    const char *path,
                    const char *url,
@@ -367,6 +450,39 @@ svn_client_import(svn_client_commit_info
 }
 
 svn_error_t *
+svn_client_commit4(svn_commit_info_t **commit_info_p,
+                   const apr_array_header_t *targets,
+                   svn_depth_t depth,
+                   svn_boolean_t keep_locks,
+                   svn_boolean_t keep_changelists,
+                   const apr_array_header_t *changelists,
+                   const apr_hash_t *revprop_table,
+                   svn_client_ctx_t *ctx,
+                   apr_pool_t *pool)
+{
+  svn_client_ctx_t shadow_ctx;
+  struct capture_baton_t cb;
+
+  cb.info = commit_info_p;
+  cb.pool = pool;
+  cb.original_callback = ctx->commit_callback2;
+  cb.original_baton = ctx->commit_baton;
+  cb.saw_commit = FALSE;
+
+  shadow_ctx = *ctx;
+  shadow_ctx.commit_callback2 = capture_commit_info;
+  shadow_ctx.commit_baton = &cb;
+
+  SVN_ERR(svn_client_commit5(targets, depth, keep_locks, keep_changelists,
+                             changelists, revprop_table, &shadow_ctx, pool));
+
+  if (!cb.saw_commit)
+    *commit_info_p = svn_create_commit_info(pool);
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
 svn_client_commit3(svn_commit_info_t **commit_info_p,
                    const apr_array_header_t *targets,
                    svn_boolean_t recurse,
@@ -412,6 +528,32 @@ svn_client_commit(svn_client_commit_info
 }
 
 /*** From copy.c ***/
+svn_error_t *
+svn_client_copy5(svn_commit_info_t **commit_info_p,
+                 const apr_array_header_t *sources,
+                 const char *dst_path,
+                 svn_boolean_t copy_as_child,
+                 svn_boolean_t make_parents,
+                 svn_boolean_t ignore_externals,
+                 const apr_hash_t *revprop_table,
+                 svn_client_ctx_t *ctx,
+                 apr_pool_t *pool)
+{
+  svn_client_ctx_t shadow_ctx;
+  struct capture_baton_t cb;
+
+  cb.info = commit_info_p;
+  cb.pool = pool;
+  cb.original_callback = ctx->commit_callback2;
+  cb.original_baton = ctx->commit_baton;
+
+  shadow_ctx = *ctx;
+  shadow_ctx.commit_callback2 = capture_commit_info;
+  shadow_ctx.commit_baton = &cb;
+
+  return svn_client_copy6(sources, dst_path, copy_as_child, make_parents,
+                          ignore_externals, revprop_table, &shadow_ctx, pool);
+}
 
 svn_error_t *
 svn_client_copy4(svn_commit_info_t **commit_info_p,
@@ -499,6 +641,33 @@ svn_client_copy(svn_client_commit_info_t
 }
 
 svn_error_t *
+svn_client_move5(svn_commit_info_t **commit_info_p,
+                 const apr_array_header_t *src_paths,
+                 const char *dst_path,
+                 svn_boolean_t force,
+                 svn_boolean_t move_as_child,
+                 svn_boolean_t make_parents,
+                 const apr_hash_t *revprop_table,
+                 svn_client_ctx_t *ctx,
+                 apr_pool_t *pool)
+{
+  svn_client_ctx_t shadow_ctx;
+  struct capture_baton_t cb;
+
+  cb.info = commit_info_p;
+  cb.pool = pool;
+  cb.original_callback = ctx->commit_callback2;
+  cb.original_baton = ctx->commit_baton;
+
+  shadow_ctx = *ctx;
+  shadow_ctx.commit_callback2 = capture_commit_info;
+  shadow_ctx.commit_baton = &cb;
+
+  return svn_client_move6(src_paths, dst_path, force, move_as_child,
+                          make_parents, revprop_table, &shadow_ctx, pool);
+}
+
+svn_error_t *
 svn_client_move4(svn_commit_info_t **commit_info_p,
                  const char *src_path,
                  const char *dst_path,
@@ -591,6 +760,31 @@ svn_client_move(svn_client_commit_info_t
 
 /*** From delete.c ***/
 svn_error_t *
+svn_client_delete3(svn_commit_info_t **commit_info_p,
+                   const apr_array_header_t *paths,
+                   svn_boolean_t force,
+                   svn_boolean_t keep_local,
+                   const apr_hash_t *revprop_table,
+                   svn_client_ctx_t *ctx,
+                   apr_pool_t *pool)
+{
+  svn_client_ctx_t shadow_ctx;
+  struct capture_baton_t cb;
+
+  cb.info = commit_info_p;
+  cb.pool = pool;
+  cb.original_callback = ctx->commit_callback2;
+  cb.original_baton = ctx->commit_baton;
+
+  shadow_ctx = *ctx;
+  shadow_ctx.commit_callback2 = capture_commit_info;
+  shadow_ctx.commit_baton = &cb;
+
+  return svn_client_delete4(paths, force, keep_local, revprop_table,
+                            &shadow_ctx, pool);
+}
+
+svn_error_t *
 svn_client_delete2(svn_commit_info_t **commit_info_p,
                    const apr_array_header_t *paths,
                    svn_boolean_t force,
@@ -1281,6 +1475,36 @@ svn_client_merge_peg(const char *source,
 
 /*** From prop_commands.c ***/
 svn_error_t *
+svn_client_propset3(svn_commit_info_t **commit_info_p,
+                    const char *propname,
+                    const svn_string_t *propval,
+                    const char *target,
+                    svn_depth_t depth,
+                    svn_boolean_t skip_checks,
+                    svn_revnum_t base_revision_for_url,
+                    const apr_array_header_t *changelists,
+                    const apr_hash_t *revprop_table,
+                    svn_client_ctx_t *ctx,
+                    apr_pool_t *pool)
+{
+  svn_client_ctx_t shadow_ctx;
+  struct capture_baton_t cb;
+
+  cb.info = commit_info_p;
+  cb.pool = pool;
+  cb.original_callback = ctx->commit_callback2;
+  cb.original_baton = ctx->commit_baton;
+
+  shadow_ctx = *ctx;
+  shadow_ctx.commit_callback2 = capture_commit_info;
+  shadow_ctx.commit_baton = &cb;
+
+  return svn_client_propset4(propname, propval, target, depth, skip_checks,
+                             base_revision_for_url, changelists, revprop_table,
+                             &shadow_ctx, pool);
+}
+
+svn_error_t *
 svn_client_propset2(const char *propname,
                     const svn_string_t *propval,
                     const char *target,

Modified: subversion/branches/atomic-revprop/subversion/libsvn_client/diff.c
URL: http://svn.apache.org/viewvc/subversion/branches/atomic-revprop/subversion/libsvn_client/diff.c?rev=967221&r1=967220&r2=967221&view=diff
==============================================================================
--- subversion/branches/atomic-revprop/subversion/libsvn_client/diff.c (original)
+++ subversion/branches/atomic-revprop/subversion/libsvn_client/diff.c Fri Jul 23 19:37:19 2010
@@ -190,22 +190,22 @@ maybe_append_eol(const svn_string_t *tok
     }
 }
 
-/* Adjust PATH, PATH1 and PATH2, representing the changed file and the two
- * original targets passed to the diff command, to handle the case when
- * we're dealing with different anchors. RELATIVE_TO_DIR is the directory
- * the diff target should be considered relative to. All allocations are done
- * in POOL. */
+/* Adjust PATH, ORIG_PATH_1 and ORIG_PATH_2, representing the changed file
+ * and the two original targets passed to the diff command, to handle the
+ * case when we're dealing with different anchors. RELATIVE_TO_DIR is the
+ * directory the diff target should be considered relative to. All
+ * allocations are done in POOL. */
 static svn_error_t *
 adjust_paths_for_diff_labels(const char **path,
-                             const char **path1,
-                             const char **path2,
+                             const char **orig_path_1,
+                             const char **orig_path_2,
                              const char *relative_to_dir,
                              apr_pool_t *pool)
 {
   apr_size_t len;
   const char *new_path = *path;
-  const char *new_path1 = *path1;
-  const char *new_path2 = *path2;
+  const char *new_path1 = *orig_path_1;
+  const char *new_path2 = *orig_path_2;
 
   /* ### Holy cow.  Due to anchor/target weirdness, we can't
      simply join diff_cmd_baton->orig_path_1 with path, ditto for
@@ -274,8 +274,8 @@ adjust_paths_for_diff_labels(const char 
         return MAKE_ERR_BAD_RELATIVE_PATH(new_path2, relative_to_dir);
     }
   *path = new_path;
-  *path1 = new_path1;
-  *path2 = new_path2;
+  *orig_path_1 = new_path1;
+  *orig_path_2 = new_path2;
 
   return SVN_NO_ERROR;
 }
@@ -321,20 +321,6 @@ display_prop_diffs(const apr_array_heade
 {
   int i;
 
-  if (relative_to_dir)
-    {
-      /* Possibly adjust the path shown in the output (see issue #2723). */
-      const char *child_path = svn_dirent_is_child(relative_to_dir, path,
-                                                   pool);
-
-      if (child_path)
-        path = child_path;
-      else if (!svn_path_compare_paths(relative_to_dir, path))
-        path = ".";
-      else
-        return MAKE_ERR_BAD_RELATIVE_PATH(path, relative_to_dir);
-    }
-
   /* If we're creating a diff on the wc root, path would be empty. */
   if (path[0] == '\0')
     path = apr_psprintf(pool, ".");

Modified: subversion/branches/atomic-revprop/subversion/libsvn_client/export.c
URL: http://svn.apache.org/viewvc/subversion/branches/atomic-revprop/subversion/libsvn_client/export.c?rev=967221&r1=967220&r2=967221&view=diff
==============================================================================
--- subversion/branches/atomic-revprop/subversion/libsvn_client/export.c (original)
+++ subversion/branches/atomic-revprop/subversion/libsvn_client/export.c Fri Jul 23 19:37:19 2010
@@ -1083,7 +1083,8 @@ svn_client_export5(svn_revnum_t *result_
               SVN_ERR(svn_client__fetch_externals(eb->externals,
                                                   from, to_abspath,
                                                   repos_root_url, depth, TRUE,
-                                                  &use_sleep, ctx, pool));
+                                                  native_eol, &use_sleep,
+                                                  ctx, pool));
             }
         }
       else if (kind == svn_node_none)

Modified: subversion/branches/atomic-revprop/subversion/libsvn_client/externals.c
URL: http://svn.apache.org/viewvc/subversion/branches/atomic-revprop/subversion/libsvn_client/externals.c?rev=967221&r1=967220&r2=967221&view=diff
==============================================================================
--- subversion/branches/atomic-revprop/subversion/libsvn_client/externals.c (original)
+++ subversion/branches/atomic-revprop/subversion/libsvn_client/externals.c Fri Jul 23 19:37:19 2010
@@ -62,6 +62,9 @@ struct handle_external_item_change_baton
   /* Passed through to svn_client_* functions. */
   svn_client_ctx_t *ctx;
 
+  /* Passed to svn_client_exportX() */
+  const char *native_eol;
+
   svn_boolean_t *timestamp_sleep;
   svn_boolean_t is_export;
 
@@ -274,9 +277,10 @@ switch_dir_external(const char *path,
       baton.cancel_baton = ctx->cancel_baton;
 
       /* Buh-bye, old and busted ... */
-      SVN_ERR(svn_wc__call_with_write_lock(relegate_dir_external, &baton,
-                                           ctx->wc_ctx, local_abspath,
-                                           pool, pool));
+      SVN_ERR(svn_wc__acquire_write_lock(NULL, ctx->wc_ctx, local_abspath,
+                                         FALSE, pool, pool));
+      
+      SVN_ERR(relegate_dir_external(&baton, pool, pool));
     }
   else
     {
@@ -362,7 +366,7 @@ switch_file_external(const char *path,
            url, dest_wc_repos_root_url);
 
       SVN_ERR(svn_wc__acquire_write_lock(NULL, ctx->wc_ctx, anchor_abspath,
-                                         subpool, subpool));
+                                         FALSE, subpool, subpool));
     }
 
   err = svn_wc_read_kind(&kind, ctx->wc_ctx, local_abspath, FALSE, subpool);
@@ -854,7 +858,8 @@ handle_external_item_change(const void *
             SVN_ERR(svn_client_export4(NULL, new_item->url, local_abspath,
                                        &(new_item->peg_revision),
                                        &(new_item->revision),
-                                       TRUE, FALSE, svn_depth_infinity, NULL,
+                                       TRUE, FALSE, svn_depth_infinity, 
+                                       ib->native_eol,
                                        ib->ctx, ib->iter_pool));
           else
             SVN_ERR(svn_client__checkout_internal
@@ -909,7 +914,7 @@ handle_external_item_change(const void *
       if (! lock_existed)
         {
           SVN_ERR(svn_wc__acquire_write_lock(NULL, ib->ctx->wc_ctx,
-                                             local_abspath,
+                                             local_abspath, FALSE,
                                              ib->iter_pool,
                                              ib->iter_pool));
         }
@@ -1067,6 +1072,9 @@ struct handle_externals_desc_change_bato
   svn_boolean_t *timestamp_sleep;
   svn_boolean_t is_export;
 
+  /* Passed to svn_client_exportX() */
+  const char *native_eol;
+
   apr_pool_t *pool;
 };
 
@@ -1157,6 +1165,7 @@ handle_externals_desc_change(const void 
   ib.repos_root_url    = cb->repos_root_url;
   ib.ctx               = cb->ctx;
   ib.is_export         = cb->is_export;
+  ib.native_eol        = cb->native_eol;
   ib.timestamp_sleep   = cb->timestamp_sleep;
   ib.pool              = cb->pool;
   ib.iter_pool         = svn_pool_create(cb->pool);
@@ -1261,6 +1270,7 @@ svn_client__handle_externals(apr_hash_t 
   cb.ctx               = ctx;
   cb.timestamp_sleep   = timestamp_sleep;
   cb.is_export         = FALSE;
+  cb.native_eol        = NULL;
   cb.pool              = pool;
 
   return svn_hash_diff(cb.externals_old, cb.externals_new,
@@ -1275,6 +1285,7 @@ svn_client__fetch_externals(apr_hash_t *
                             const char *repos_root_url,
                             svn_depth_t requested_depth,
                             svn_boolean_t is_export,
+                            const char *native_eol,
                             svn_boolean_t *timestamp_sleep,
                             svn_client_ctx_t *ctx,
                             apr_pool_t *pool)
@@ -1292,6 +1303,7 @@ svn_client__fetch_externals(apr_hash_t *
   cb.to_abspath        = to_abspath;
   cb.repos_root_url    = repos_root_url;
   cb.timestamp_sleep   = timestamp_sleep;
+  cb.native_eol        = native_eol;
   cb.is_export         = is_export;
   cb.pool              = pool;
 

Modified: subversion/branches/atomic-revprop/subversion/libsvn_client/merge.c
URL: http://svn.apache.org/viewvc/subversion/branches/atomic-revprop/subversion/libsvn_client/merge.c?rev=967221&r1=967220&r2=967221&view=diff
==============================================================================
--- subversion/branches/atomic-revprop/subversion/libsvn_client/merge.c (original)
+++ subversion/branches/atomic-revprop/subversion/libsvn_client/merge.c Fri Jul 23 19:37:19 2010
@@ -8974,8 +8974,9 @@ svn_client_merge3(const char *source1,
   baton.ctx = ctx;
 
   if (!dry_run)
-    SVN_ERR(svn_wc__call_with_write_lock(merge_cb, &baton, ctx->wc_ctx,
-                                         lock_abspath, pool, pool));
+    SVN_ERR(svn_wc__call_with_write_lock(merge_cb, &baton,
+                                         ctx->wc_ctx, lock_abspath, FALSE,
+                                         pool, pool));
   else
     SVN_ERR(merge_cb(&baton, pool, pool));
 
@@ -10158,7 +10159,7 @@ svn_client_merge_reintegrate(const char 
 
   if (!dry_run)
     SVN_ERR(svn_wc__call_with_write_lock(merge_reintegrate_cb, &baton,
-                                         ctx->wc_ctx, lock_abspath,
+                                         ctx->wc_ctx, lock_abspath, FALSE,
                                          pool, pool));
   else
     SVN_ERR(merge_reintegrate_cb(&baton, pool, pool));
@@ -10317,8 +10318,9 @@ svn_client_merge_peg3(const char *source
   baton.ctx = ctx;
 
   if (!dry_run)
-    SVN_ERR(svn_wc__call_with_write_lock(merge_peg_cb, &baton, ctx->wc_ctx,
-                                         lock_abspath, pool, pool));
+    SVN_ERR(svn_wc__call_with_write_lock(merge_peg_cb, &baton,
+                                         ctx->wc_ctx, lock_abspath, FALSE,
+                                         pool, pool));
   else
     SVN_ERR(merge_peg_cb(&baton, pool, pool));
 

Modified: subversion/branches/atomic-revprop/subversion/libsvn_client/patch.c
URL: http://svn.apache.org/viewvc/subversion/branches/atomic-revprop/subversion/libsvn_client/patch.c?rev=967221&r1=967220&r2=967221&view=diff
==============================================================================
--- subversion/branches/atomic-revprop/subversion/libsvn_client/patch.c (original)
+++ subversion/branches/atomic-revprop/subversion/libsvn_client/patch.c Fri Jul 23 19:37:19 2010
@@ -65,28 +65,9 @@ typedef struct hunk_info_t {
   int fuzz;
 } hunk_info_t;
 
-typedef struct patch_target_t {
-  /* The patch being applied. */
-  const svn_patch_t *patch;
-
-  /* The target path as it appeared in the patch file,
-   * but in canonicalised form. */
-  const char *canon_path_from_patchfile;
-
-  /* The target path, relative to the working copy directory the
-   * patch is being applied to. A patch strip count applies to this
-   * and only this path. This is never NULL. */
-  const char *local_relpath;
-
-  /* The absolute path of the target on the filesystem.
-   * Any symlinks the path from the patch file may contain are resolved.
-   * Is not always known, so it may be NULL. */
-  char *local_abspath;
-
-  /* The target file, read-only, seekable. This is NULL in case the target
-   * file did not exist prior to patch application. */
-  apr_file_t *file;
-
+/* A struct carrying the information related to the content of a target, be it
+ * a property or the the text of a file. */
+typedef struct target_content_info_t {
   /* A stream to read lines form the target file. This is NULL in case
    * the target file did not exist prior to patch application. */
   svn_stream_t *stream;
@@ -98,16 +79,10 @@ typedef struct patch_target_t {
    * so EOL transformation and keyword contraction is done transparently. */
   svn_stream_t *patched;
 
-  /* Path to the temporary file underlying the result stream. */
-  const char *patched_path;
-
   /* The reject stream, write-only, not seekable.
    * Hunks that are rejected will be written to this stream. */
   svn_stream_t *reject;
 
-  /* Path to the temporary file underlying the reject stream. */
-  const char *reject_path;
-
   /* The line last read from the target file. */
   svn_linenum_t current_line;
 
@@ -127,6 +102,53 @@ typedef struct patch_target_t {
   /* An array containing hunk_info_t structures for hunks already matched. */
   apr_array_header_t *hunks;
 
+  /* True if end-of-file was reached while reading from the target. */
+  svn_boolean_t eof;
+
+  /* The keywords of the target. */
+  apr_hash_t *keywords;
+
+  /* The pool the target_info is allocated in. */
+  apr_pool_t *pool;
+} target_content_info_t;
+
+typedef struct prop_patch_target_t {
+  const char *name;
+  target_content_info_t *content_info;
+  const char *patched_path;
+
+  /* ### Here we'll add flags telling if the prop was added, deleted,
+   * ### had_rejects, had_local_mods prior to patching and so on. */
+} prop_patch_target_t;
+
+typedef struct patch_target_t {
+  /* The patch being applied. */
+  const svn_patch_t *patch;
+
+  /* The target path as it appeared in the patch file,
+   * but in canonicalised form. */
+  const char *canon_path_from_patchfile;
+
+  /* The target path, relative to the working copy directory the
+   * patch is being applied to. A patch strip count applies to this
+   * and only this path. This is never NULL. */
+  const char *local_relpath;
+
+  /* The absolute path of the target on the filesystem.
+   * Any symlinks the path from the patch file may contain are resolved.
+   * Is not always known, so it may be NULL. */
+  char *local_abspath;
+
+  /* The target file, read-only, seekable. This is NULL in case the target
+   * file did not exist prior to patch application. */
+  apr_file_t *file;
+
+  /* Path to the temporary file underlying the result stream. */
+  const char *patched_path;
+
+  /* Path to the temporary file underlying the reject stream. */
+  const char *reject_path;
+
   /* The node kind of the target as found in WC-DB prior
    * to patch application. */
   svn_node_kind_t db_kind;
@@ -137,9 +159,6 @@ typedef struct patch_target_t {
   /* True if the target was locally deleted prior to patching. */
   svn_boolean_t locally_deleted;
 
-  /* True if end-of-file was reached while reading from the target. */
-  svn_boolean_t eof;
-
   /* True if the target had to be skipped for some reason. */
   svn_boolean_t skipped;
 
@@ -167,8 +186,11 @@ typedef struct patch_target_t {
   /* True if the target has the executable bit set. */
   svn_boolean_t executable;
 
-  /* The keywords of the target. */
-  apr_hash_t *keywords;
+  /* All the information that is specifict to the content of the target. */
+  target_content_info_t *content_info;
+
+  /* A hash table of prop_patch_target_t objects keyed by property names. */
+  apr_hash_t *prop_targets;
 
   /* The pool the target is allocated in. */
   apr_pool_t *pool;
@@ -217,16 +239,17 @@ strip_path(const char **result, const ch
   return SVN_NO_ERROR;
 }
 
-/* Obtain eol and keywords information for LOCAL_ABSPATH, from WC_CTX and
- * store the obtained information in *TARGET.
+/* Obtain KEYWORDS, EOL_STYLE and EOL_STR for LOCAL_ABSPATH, from WC_CTX.
  * Use RESULT_POOL for allocations of fields in TARGET.
  * Use SCRATCH_POOL for all other allocations. */
 static svn_error_t *
-resolve_target_wc_file_info(svn_wc_context_t *wc_ctx,
-                            const char *local_abspath,
-                            patch_target_t *target,
-                            apr_pool_t *result_pool,
-                            apr_pool_t *scratch_pool)
+obtain_eol_and_keywords_for_file(apr_hash_t **keywords,
+                                 svn_subst_eol_style_t *eol_style,
+                                 const char **eol_str,
+                                 svn_wc_context_t *wc_ctx,
+                                 const char *local_abspath,
+                                 apr_pool_t *result_pool,
+                                 apr_pool_t *scratch_pool)
 {
   apr_hash_t *props;
   svn_string_t *keywords_val, *eol_style_val;
@@ -252,9 +275,9 @@ resolve_target_wc_file_info(svn_wc_conte
                                             scratch_pool));
       rev_str = apr_psprintf(scratch_pool, "%ld", changed_rev);
       SVN_ERR(svn_wc__node_get_url(&url, wc_ctx,
-                                   target->local_abspath,
+                                   local_abspath,
                                    scratch_pool, scratch_pool));
-      SVN_ERR(svn_subst_build_keywords2(&target->keywords,
+      SVN_ERR(svn_subst_build_keywords2(keywords,
                                         keywords_val->data,
                                         rev_str, url, changed_date,
                                         author, result_pool));
@@ -264,8 +287,8 @@ resolve_target_wc_file_info(svn_wc_conte
                                APR_HASH_KEY_STRING);
   if (eol_style_val)
     {
-      svn_subst_eol_style_from_value(&target->eol_style,
-                                     &target->eol_str,
+      svn_subst_eol_style_from_value(eol_style,
+                                     eol_str,
                                      eol_style_val->data);
     }
 
@@ -282,8 +305,6 @@ resolve_target_wc_file_info(svn_wc_conte
  * 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.
- * If the path is not skipped also obtain eol-style and keywords
- * information and store this in *TARGET.
  * Use RESULT_POOL for allocations of fields in TARGET.
  * Use SCRATCH_POOL for all other allocations. */
 static svn_error_t *
@@ -348,7 +369,7 @@ resolve_target_path(patch_target_t *targ
 
   /* Skip things we should not be messing with. */
   err = svn_wc_status3(&status, wc_ctx, target->local_abspath,
-                         result_pool, scratch_pool);
+                       result_pool, scratch_pool);
   if (err)
     {
       if (err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
@@ -397,9 +418,66 @@ resolve_target_path(patch_target_t *targ
       return SVN_NO_ERROR;
     }
 
-  if (target->kind_on_disk == svn_node_file)
-    SVN_ERR(resolve_target_wc_file_info(wc_ctx, target->local_abspath,
-                                        target, result_pool, scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+/* Initialize a PROP_TARGET structure for PROP_NAME. Use working copy
+ * context WC_CTX. Use the REJECT stream that is shared with all content
+ * info structures.
+ * REMOVE_TEMPFILES as in svn_client_patch().
+ */
+static svn_error_t *
+init_prop_target(prop_patch_target_t **prop_target,
+                 const char *prop_name,
+                 svn_stream_t *reject,
+                 svn_boolean_t remove_tempfiles,
+                 svn_wc_context_t *wc_ctx,
+                 const char *local_abspath,
+                 apr_pool_t *result_pool, apr_pool_t *scratch_pool)
+{
+  prop_patch_target_t *new_prop_target;
+  target_content_info_t *content_info; 
+  const svn_string_t *value;
+  const char *patched_path;
+
+
+  content_info = apr_pcalloc(result_pool, sizeof(*content_info));
+
+  /* All other fields in are FALSE or NULL due to apr_pcalloc().*/
+  content_info->current_line = 1;
+  content_info->eol_style = svn_subst_eol_style_none;
+  content_info->lines = apr_array_make(result_pool, 0,
+                                       sizeof(svn_stream_mark_t *));
+  content_info->hunks = apr_array_make(result_pool, 0, sizeof(hunk_info_t *));
+  content_info->keywords = apr_hash_make(result_pool);
+  content_info->reject = reject;
+  content_info->pool = result_pool;
+
+  new_prop_target = apr_palloc(result_pool, sizeof(*new_prop_target));
+  new_prop_target->name = apr_pstrdup(result_pool, prop_name);
+  new_prop_target->content_info = content_info;
+
+  SVN_ERR(svn_wc_prop_get2(&value, wc_ctx, local_abspath, prop_name, 
+                           result_pool, scratch_pool));
+
+  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);
+    }
+
+  /* Create a temporary file to write the patched result to. For properties,
+   * we don't have to worrry about different eol-style. */
+  SVN_ERR(svn_stream_open_unique(&content_info->patched,
+                                 &patched_path, NULL,
+                                 remove_tempfiles ?
+                                   svn_io_file_del_on_pool_cleanup :
+                                   svn_io_file_del_none,
+                                 result_pool, scratch_pool));
+
+  new_prop_target->patched_path = patched_path;
+  *prop_target = new_prop_target;
 
   return SVN_NO_ERROR;
 }
@@ -408,8 +486,10 @@ resolve_target_path(patch_target_t *targ
  * 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.
- * Upon success, allocate the patch target structure in RESULT_POOL.
- * Else, set *target to NULL.
+ * 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().
  * Use SCRATCH_POOL for all other allocations. */
 static svn_error_t *
@@ -421,18 +501,27 @@ init_patch_target(patch_target_t **patch
                   apr_pool_t *result_pool, apr_pool_t *scratch_pool)
 {
   patch_target_t *target;
+  target_content_info_t *content_info; 
+
+  content_info = apr_pcalloc(result_pool, sizeof(*content_info));
+
+  /* All other fields in content_info are FALSE or NULL due to apr_pcalloc().*/
+  content_info->current_line = 1;
+  content_info->eol_style = svn_subst_eol_style_none;
+  content_info->lines = apr_array_make(result_pool, 0,
+                                       sizeof(svn_stream_mark_t *));
+  content_info->hunks = apr_array_make(result_pool, 0, sizeof(hunk_info_t *));
+  content_info->keywords = apr_hash_make(result_pool);
+  content_info->pool = result_pool;
 
   target = apr_pcalloc(result_pool, sizeof(*target));
 
-  /* All other fields are FALSE or NULL due to apr_pcalloc(). */
+  /* All other fields in target are FALSE or NULL due to apr_pcalloc(). */
   target->patch = patch;
-  target->current_line = 1;
-  target->eol_style = svn_subst_eol_style_none;
-  target->lines = apr_array_make(result_pool, 0,
-                                 sizeof(svn_stream_mark_t *));
-  target->hunks = apr_array_make(result_pool, 0, sizeof(hunk_info_t *));
   target->db_kind = svn_node_none;
   target->kind_on_disk = svn_node_none;
+  target->content_info = content_info;
+  target->prop_targets = apr_hash_make(result_pool);
   target->pool = result_pool;
 
   SVN_ERR(resolve_target_path(target, patch->new_filename,
@@ -453,8 +542,8 @@ init_patch_target(patch_target_t **patch
                                    APR_OS_DEFAULT, result_pool));
 
           /* Create a stream to read from the target. */
-          target->stream = svn_stream_from_aprfile2(target->file,
-                                                    FALSE, result_pool);
+          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,
@@ -463,6 +552,14 @@ init_patch_target(patch_target_t **patch
           SVN_ERR(svn_io_is_file_executable(&target->executable,
                                             target->local_abspath,
                                             scratch_pool));
+
+          SVN_ERR(obtain_eol_and_keywords_for_file(&content_info->keywords,
+                                                   &content_info->eol_style,
+                                                   &content_info->eol_str,
+                                                   wc_ctx,
+                                                   target->local_abspath,
+                                                   result_pool,
+                                                   scratch_pool));
         }
 
       /* Create a temporary file to write the patched result to. */
@@ -475,16 +572,16 @@ init_patch_target(patch_target_t **patch
 
       /* Expand keywords in the patched file.
        * Repair newlines if svn:eol-style dictates a particular style. */
-      repair_eol = (target->eol_style == svn_subst_eol_style_fixed ||
-                    target->eol_style == svn_subst_eol_style_native);
-      target->patched = svn_subst_stream_translated(
-                              patched_raw, target->eol_str, repair_eol,
-                              target->keywords, TRUE, result_pool);
+      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,
        * in reject files. */
-      SVN_ERR(svn_stream_open_unique(&target->reject,
+      SVN_ERR(svn_stream_open_unique(&content_info->reject,
                                      &target->reject_path, NULL,
                                      remove_tempfiles ?
                                        svn_io_file_del_on_pool_cleanup :
@@ -498,19 +595,45 @@ init_patch_target(patch_target_t **patch
                                  target->canon_path_from_patchfile,
                                  APR_EOL_STR);
       len = strlen(diff_header);
-      SVN_ERR(svn_stream_write(target->reject, diff_header, &len));
+      SVN_ERR(svn_stream_write(content_info->reject, diff_header, &len));
+
+      /* Time for the properties */
+      if (! target->skipped)
+        {
+          apr_hash_index_t *hi;
+
+          for (hi = apr_hash_first(result_pool, patch->prop_patches);
+               hi;
+               hi = apr_hash_next(hi))
+            {
+              const char *prop_name = svn__apr_hash_index_key(hi);
+              prop_patch_target_t *prop_target;
+
+              /* Obtain info about this property */
+              SVN_ERR(init_prop_target(&prop_target,
+                                       prop_name,
+                                       content_info->reject,
+                                       remove_tempfiles,
+                                       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);
+            }
+        }
     }
 
   *patch_target = target;
   return SVN_NO_ERROR;
 }
 
-/* Read a *LINE from TARGET. If the line has not been read before
- * mark the line in TARGET->LINES. Allocate *LINE in RESULT_POOL.
+/* Read a *LINE from CONTENT_INFO. If the line has not been read before
+ * mark the line in CONTENT_INFO->LINES. Allocate *LINE in RESULT_POOL.
  * Do temporary allocations in SCRATCH_POOL.
  */
 static svn_error_t *
-read_line(patch_target_t *target,
+read_line(target_content_info_t *content_info,
           const char **line,
           apr_pool_t *scratch_pool,
           apr_pool_t *result_pool)
@@ -518,43 +641,44 @@ read_line(patch_target_t *target,
   svn_stringbuf_t *line_raw;
   const char *eol_str;
 
-  if (target->eof)
+  if (content_info->eof)
     {
       *line = "";
       return SVN_NO_ERROR;
     }
 
-  SVN_ERR_ASSERT(target->current_line <= target->lines->nelts + 1);
-  if (target->current_line == target->lines->nelts + 1)
+  SVN_ERR_ASSERT(content_info->current_line <= content_info->lines->nelts + 1);
+  if (content_info->current_line == content_info->lines->nelts + 1)
     {
       svn_stream_mark_t *mark;
-      SVN_ERR(svn_stream_mark(target->stream, &mark, target->pool));
-      APR_ARRAY_PUSH(target->lines, svn_stream_mark_t *) = mark;
+      SVN_ERR(svn_stream_mark(content_info->stream, &mark,
+                              content_info->pool));
+      APR_ARRAY_PUSH(content_info->lines, svn_stream_mark_t *) = mark;
     }
 
-  SVN_ERR(svn_stream_readline_detect_eol(target->stream, &line_raw,
-                                         &eol_str, &target->eof,
+  SVN_ERR(svn_stream_readline_detect_eol(content_info->stream, &line_raw,
+                                         &eol_str, &content_info->eof,
                                          scratch_pool));
-  if (target->eol_style == svn_subst_eol_style_none)
-    target->eol_str = eol_str;
+  if (content_info->eol_style == svn_subst_eol_style_none)
+    content_info->eol_str = eol_str;
 
   /* Contract keywords. */
   SVN_ERR(svn_subst_translate_cstring2(line_raw->data, line,
                                        NULL, FALSE,
-                                       target->keywords, FALSE,
+                                       content_info->keywords, FALSE,
                                        result_pool));
-  if (! target->eof)
-    target->current_line++;
+  if (! content_info->eof)
+    content_info->current_line++;
 
   return SVN_NO_ERROR;
 }
 
-/* Seek to the specified LINE in TARGET.
- * Mark any lines not read before in TARGET->LINES.
+/* Seek to the specified LINE in CONTENT_INFO.
+ * Mark any lines not read before in CONTENT_INFO->LINES.
  * Do temporary allocations in SCRATCH_POOL.
  */
 static svn_error_t *
-seek_to_line(patch_target_t *target, svn_linenum_t line,
+seek_to_line(target_content_info_t *content_info, svn_linenum_t line,
              apr_pool_t *scratch_pool)
 {
   svn_linenum_t saved_line;
@@ -562,50 +686,50 @@ seek_to_line(patch_target_t *target, svn
 
   SVN_ERR_ASSERT(line > 0);
 
-  if (line == target->current_line)
+  if (line == content_info->current_line)
     return SVN_NO_ERROR;
 
-  saved_line = target->current_line;
-  saved_eof = target->eof;
+  saved_line = content_info->current_line;
+  saved_eof = content_info->eof;
 
-  if (line <= target->lines->nelts)
+  if (line <= content_info->lines->nelts)
     {
       svn_stream_mark_t *mark;
 
-      mark = APR_ARRAY_IDX(target->lines, line - 1, svn_stream_mark_t *);
-      SVN_ERR(svn_stream_seek(target->stream, mark));
-      target->current_line = line;
+      mark = APR_ARRAY_IDX(content_info->lines, line - 1, svn_stream_mark_t *);
+      SVN_ERR(svn_stream_seek(content_info->stream, mark));
+      content_info->current_line = line;
     }
   else
     {
       const char *dummy;
       apr_pool_t *iterpool = svn_pool_create(scratch_pool);
 
-      while (! target->eof && target->current_line < line)
+      while (! content_info->eof && content_info->current_line < line)
         {
           svn_pool_clear(iterpool);
-          SVN_ERR(read_line(target, &dummy, iterpool, iterpool));
+          SVN_ERR(read_line(content_info, &dummy, iterpool, iterpool));
         }
       svn_pool_destroy(iterpool);
     }
 
   /* After seeking backwards from EOF position clear EOF indicator. */
-  if (saved_eof && saved_line > target->current_line)
-    target->eof = FALSE;
+  if (saved_eof && saved_line > content_info->current_line)
+    content_info->eof = FALSE;
 
   return SVN_NO_ERROR;
 }
 
 /* Indicate in *MATCHED whether the original text of HUNK matches the patch
- * TARGET at its current line. Lines within FUZZ lines of the start or end
- * of HUNK will always match. If IGNORE_WHITESPACE is set, we ignore
+ * CONTENT_INFO at its current line. Lines within FUZZ lines of the start or
+ * end of HUNK will always match. If IGNORE_WHITESPACE is set, we ignore
  * whitespace when doing the matching. When this function returns, neither
- * TARGET->CURRENT_LINE nor the file offset in the target file will have
- * changed. If MATCH_MODIFIED is TRUE, match the modified hunk text,
+ * CONTENT_INFO->CURRENT_LINE nor the file offset in the target file will 
+ * have changed. If MATCH_MODIFIED is TRUE, match the modified hunk text,
  * rather than the original hunk text.
  * Do temporary allocations in POOL. */
 static svn_error_t *
-match_hunk(svn_boolean_t *matched, patch_target_t *target,
+match_hunk(svn_boolean_t *matched, target_content_info_t *content_info,
            const svn_hunk_t *hunk, int fuzz, 
            svn_boolean_t ignore_whitespace,
            svn_boolean_t match_modified, apr_pool_t *pool)
@@ -623,10 +747,10 @@ match_hunk(svn_boolean_t *matched, patch
 
   *matched = FALSE;
 
-  if (target->eof)
+  if (content_info->eof)
     return SVN_NO_ERROR;
 
-  saved_line = target->current_line;
+  saved_line = content_info->current_line;
   lines_read = 0;
   lines_matched = FALSE;
   original_length = svn_diff_hunk_get_original_length(hunk);
@@ -656,10 +780,10 @@ match_hunk(svn_boolean_t *matched, patch
       SVN_ERR(svn_subst_translate_cstring2(hunk_line->data,
                                            &hunk_line_translated,
                                            NULL, FALSE,
-                                           target->keywords, FALSE,
+                                           content_info->keywords, FALSE,
                                            iterpool));
       lines_read++;
-      SVN_ERR(read_line(target, &target_line, iterpool, iterpool));
+      SVN_ERR(read_line(content_info, &target_line, iterpool, iterpool));
       if (! hunk_eof)
         {
           if (lines_read <= fuzz && leading_context > fuzz)
@@ -686,11 +810,11 @@ match_hunk(svn_boolean_t *matched, patch
             }
         }
     }
-  while (lines_matched && ! (hunk_eof || target->eof));
+  while (lines_matched && ! (hunk_eof || content_info->eof));
 
   if (hunk_eof)
     *matched = lines_matched;
-  else if (target->eof)
+  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. */
@@ -711,14 +835,14 @@ match_hunk(svn_boolean_t *matched, patch
       else
         *matched = FALSE;
     }
-  SVN_ERR(seek_to_line(target, saved_line, iterpool));
+  SVN_ERR(seek_to_line(content_info, saved_line, iterpool));
 
   svn_pool_destroy(iterpool);
 
   return SVN_NO_ERROR;
 }
 
-/* Scan lines of TARGET for a match of the original text of HUNK,
+/* Scan lines of CONTENT_INFO for a match of the original text of HUNK,
  * up to but not including the specified UPPER_LINE. Use fuzz factor FUZZ.
  * If UPPER_LINE is zero scan until EOF occurs when reading from TARGET.
  * Return the line at which HUNK was matched in *MATCHED_LINE.
@@ -733,7 +857,8 @@ match_hunk(svn_boolean_t *matched, patch
  * Call cancel CANCEL_FUNC with baton CANCEL_BATON to trigger cancellation.
  * Do all allocations in POOL. */
 static svn_error_t *
-scan_for_match(svn_linenum_t *matched_line, patch_target_t *target,
+scan_for_match(svn_linenum_t *matched_line, 
+               target_content_info_t *content_info,
                const svn_hunk_t *hunk, svn_boolean_t match_first,
                svn_linenum_t upper_line, int fuzz, 
                svn_boolean_t ignore_whitespace,
@@ -745,8 +870,8 @@ scan_for_match(svn_linenum_t *matched_li
 
   *matched_line = 0;
   iterpool = svn_pool_create(pool);
-  while ((target->current_line < upper_line || upper_line == 0) &&
-         ! target->eof)
+  while ((content_info->current_line < upper_line || upper_line == 0) &&
+         ! content_info->eof)
     {
       svn_boolean_t matched;
       int i;
@@ -756,19 +881,19 @@ scan_for_match(svn_linenum_t *matched_li
       if (cancel_func)
         SVN_ERR((cancel_func)(cancel_baton));
 
-      SVN_ERR(match_hunk(&matched, target, hunk, fuzz, ignore_whitespace,
+      SVN_ERR(match_hunk(&matched, content_info, hunk, fuzz, ignore_whitespace,
                          match_modified, iterpool));
       if (matched)
         {
           svn_boolean_t taken = FALSE;
 
           /* Don't allow hunks to match at overlapping locations. */
-          for (i = 0; i < target->hunks->nelts; i++)
+          for (i = 0; i < content_info->hunks->nelts; i++)
             {
               const hunk_info_t *hi;
               svn_linenum_t length;
 
-              hi = APR_ARRAY_IDX(target->hunks, i, const hunk_info_t *);
+              hi = APR_ARRAY_IDX(content_info->hunks, i, const hunk_info_t *);
 
               if (match_modified)
                 length = svn_diff_hunk_get_modified_length(hi->hunk);
@@ -776,49 +901,45 @@ scan_for_match(svn_linenum_t *matched_li
                 length = svn_diff_hunk_get_original_length(hi->hunk);
 
               taken = (! hi->rejected &&
-                       target->current_line >= hi->matched_line &&
-                       target->current_line < (hi->matched_line + length));
+                       content_info->current_line >= hi->matched_line &&
+                       content_info->current_line < (hi->matched_line + length));
               if (taken)
                 break;
             }
 
           if (! taken)
             {
-              *matched_line = target->current_line;
+              *matched_line = content_info->current_line;
               if (match_first)
                 break;
             }
         }
 
-      if (! target->eof)
-        SVN_ERR(seek_to_line(target, target->current_line + 1, iterpool));
+      if (! content_info->eof)
+        SVN_ERR(seek_to_line(content_info, content_info->current_line + 1,
+                             iterpool));
     }
   svn_pool_destroy(iterpool);
 
   return SVN_NO_ERROR;
 }
 
-/* Indicate in *MATCH whether the file at TARGET->abspath matches the
- * modified text of HUNK. Use SCRATCH_POOL for temporary allocations. */
+/* Indicate in *MATCH whether the STREAM matches the modified text of HUNK.
+ * Use CONTENT_INFO for retrieving information on eol and keywords that is
+ * needed for the comparison.
+ * Use SCRATCH_POOL for temporary allocations. */
 static svn_error_t *
-match_existing_file(svn_boolean_t *match,
-                    patch_target_t *target,
-                    const svn_hunk_t *hunk,
-                    apr_pool_t *scratch_pool)
+match_existing_target(svn_boolean_t *match,
+                      target_content_info_t *content_info,
+                      const svn_hunk_t *hunk,
+                      svn_stream_t *stream,
+                      apr_pool_t *scratch_pool)
 {
-  apr_file_t *file;
-  svn_stream_t *stream;
   svn_boolean_t lines_matched;
   apr_pool_t *iterpool;
   svn_boolean_t eof;
   svn_boolean_t hunk_eof;
 
-  SVN_ERR(svn_io_file_open(&file, target->local_abspath,
-                           APR_READ | APR_BINARY, APR_OS_DEFAULT,
-                           scratch_pool));
-  stream = svn_stream_from_aprfile2(file, FALSE, scratch_pool);
-
-
   SVN_ERR(svn_diff_hunk_reset_modified_text(hunk));
 
   iterpool = svn_pool_create(scratch_pool);
@@ -838,18 +959,19 @@ match_existing_file(svn_boolean_t *match
                                                    iterpool, iterpool));
       /* Contract keywords. */
       SVN_ERR(svn_subst_translate_cstring2(line->data, &line_translated,
-                                           NULL, FALSE, target->keywords,
+                                           NULL, FALSE, 
+                                           content_info->keywords,
                                            FALSE, iterpool));
       SVN_ERR(svn_subst_translate_cstring2(hunk_line->data,
                                            &hunk_line_translated,
-                                           NULL, FALSE, target->keywords,
+                                           NULL, FALSE,
+                                           content_info->keywords,
                                            FALSE, iterpool));
       lines_matched = ! strcmp(line_translated, hunk_line_translated);
       if (eof != hunk_eof)
         {
           svn_pool_destroy(iterpool);
           *match = FALSE;
-          svn_stream_close(stream);
           return SVN_NO_ERROR;
         }
       }
@@ -857,23 +979,24 @@ match_existing_file(svn_boolean_t *match
     svn_pool_destroy(iterpool);
 
     *match = (lines_matched && eof == hunk_eof);
-    svn_stream_close(stream);
     return SVN_NO_ERROR;
 }
 
-/* Determine the line at which a HUNK applies to the TARGET file,
- * and return an appropriate hunk_info object in *HI, allocated from
+/* Determine the line at which a HUNK applies to the CONTENT_INFO of TARGET
+ * file, and return an appropriate hunk_info object in *HI, allocated from
  * 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 TARGET->CURRENT_LINE nor
+ * matching. 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, 
               svn_boolean_t ignore_whitespace,
+              svn_boolean_t is_prop_hunk,
               svn_cancel_func_t cancel_func, void *cancel_baton,
               apr_pool_t *result_pool, apr_pool_t *scratch_pool)
 {
@@ -888,17 +1011,27 @@ get_hunk_info(hunk_info_t **hi, patch_ta
    * a new file. Don't bother matching hunks in that case, since
    * the hunk applies at line 1. If the file already exists, the hunk
    * is rejected, unless the file is versioned and its content matches
-   * the file the patch wants to create. */
-  if (original_start == 0)
+   * the file the patch wants to create.  */
+  if (original_start == 0 && ! is_prop_hunk)
     {
       if (target->kind_on_disk == svn_node_file)
         {
           if (target->db_kind == svn_node_file)
             {
               svn_boolean_t file_matches;
+              apr_file_t *file;
+              svn_stream_t *stream;
+
+              /* ### dannas: Why not use content_info-stream here? */
+              SVN_ERR(svn_io_file_open(&file, target->local_abspath,
+                                       APR_READ | APR_BINARY, APR_OS_DEFAULT,
+                                       scratch_pool));
+              stream = svn_stream_from_aprfile2(file, FALSE, scratch_pool);
+
+              SVN_ERR(match_existing_target(&file_matches, content_info, hunk,
+                                            stream, scratch_pool));
+              svn_stream_close(stream);
 
-              SVN_ERR(match_existing_file(&file_matches, target, hunk,
-                                          scratch_pool));
               if (file_matches)
                 {
                   matched_line = 1;
@@ -913,9 +1046,38 @@ get_hunk_info(hunk_info_t **hi, patch_ta
       else
         matched_line = 1;
     }
-  else if (original_start > 0 && target->kind_on_disk == svn_node_file)
+  /* Same conditions apply as for the file case above. 
+   *
+   * ### Since the hunk says the prop should be added we just assume so for
+   * ### now and don't bother with storing the previous lines and such. When
+   * ### we have the diff operation available we can just check for adds. */
+  else if (original_start == 0 && is_prop_hunk)
     {
-      svn_linenum_t saved_line = target->current_line;
+      if (content_info->stream)
+        {
+          svn_boolean_t prop_matches;
+
+          SVN_ERR(match_existing_target(&prop_matches, content_info, hunk,
+                                        content_info->stream, scratch_pool));
+
+          if (prop_matches)
+            {
+              matched_line = 1;
+              already_applied = TRUE;
+            }
+          else
+            matched_line = 0; /* reject */
+        }
+      else
+        matched_line = 1;
+    }
+  /* ### We previously checked for target->kind_on_disk == svn_node_file
+   * ### here. But that wasn't generic enough to cope with properties. How
+   * ### better describe that content_info->stream is only set if we have an
+   * ### existing target? */
+  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.
@@ -932,8 +1094,10 @@ get_hunk_info(hunk_info_t **hi, patch_ta
             }
           else
             {
-              SVN_ERR(seek_to_line(target, modified_start, scratch_pool));
-              SVN_ERR(scan_for_match(&matched_line, target, hunk, TRUE,
+              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,
@@ -948,14 +1112,14 @@ get_hunk_info(hunk_info_t **hi, patch_ta
         {
           /* Scan for a match at the line where the hunk thinks it
            * should be going. */
-          SVN_ERR(seek_to_line(target, original_start, scratch_pool));
-          if (target->current_line != original_start)
+          SVN_ERR(seek_to_line(content_info, original_start, scratch_pool));
+          if (content_info->current_line != original_start)
             {
               /* Seek failed. */
               matched_line = 0;
             }
           else
-            SVN_ERR(scan_for_match(&matched_line, target, hunk, TRUE,
+            SVN_ERR(scan_for_match(&matched_line, content_info, hunk, TRUE,
                                    original_start + 1, fuzz,
                                    ignore_whitespace, FALSE,
                                    cancel_func, cancel_baton,
@@ -964,11 +1128,11 @@ get_hunk_info(hunk_info_t **hi, patch_ta
           if (matched_line != original_start)
             {
               /* Scan the whole file again from the start. */
-              SVN_ERR(seek_to_line(target, 1, scratch_pool));
+              SVN_ERR(seek_to_line(content_info, 1, scratch_pool));
 
               /* Scan forward towards the hunk's line and look for a line
                * where the hunk matches. */
-              SVN_ERR(scan_for_match(&matched_line, target, hunk, FALSE,
+              SVN_ERR(scan_for_match(&matched_line, content_info, hunk, FALSE,
                                      original_start, fuzz,
                                      ignore_whitespace, FALSE,
                                      cancel_func, cancel_baton,
@@ -980,15 +1144,15 @@ get_hunk_info(hunk_info_t **hi, patch_ta
                 {
                   /* Scan forward towards the end of the file and look
                    * for a line where the hunk matches. */
-                  SVN_ERR(scan_for_match(&matched_line, target, hunk, TRUE, 0,
-                                         fuzz, ignore_whitespace, FALSE,
-                                         cancel_func, cancel_baton,
+                  SVN_ERR(scan_for_match(&matched_line, content_info, hunk,
+                                         TRUE, 0, fuzz, ignore_whitespace,
+                                         FALSE, cancel_func, cancel_baton,
                                          scratch_pool));
                 }
             }
         }
 
-      SVN_ERR(seek_to_line(target, saved_line, scratch_pool));
+      SVN_ERR(seek_to_line(content_info, saved_line, scratch_pool));
     }
   else
     {
@@ -1030,23 +1194,25 @@ try_stream_write(svn_stream_t *stream, c
  * If LINE is zero, copy lines until end-of-file has been reached.
  * Do all allocations in POOL. */
 static svn_error_t *
-copy_lines_to_target(patch_target_t *target, svn_linenum_t line,
-                     apr_pool_t *pool)
+copy_lines_to_target(target_content_info_t *content_info, svn_linenum_t line,
+                     const char *patched_path, apr_pool_t *pool)
 {
   apr_pool_t *iterpool;
 
   iterpool = svn_pool_create(pool);
-  while ((target->current_line < line || line == 0) && ! target->eof)
+  while ((content_info->current_line < line || line == 0) 
+         && ! content_info->eof)
     {
       const char *target_line;
 
       svn_pool_clear(iterpool);
 
-      SVN_ERR(read_line(target, &target_line, iterpool, iterpool));
-      if (! target->eof)
-        target_line = apr_pstrcat(iterpool, target_line, target->eol_str, NULL);
+      SVN_ERR(read_line(content_info, &target_line, iterpool, iterpool));
+      if (! content_info->eof)
+        target_line = apr_pstrcat(iterpool, target_line, content_info->eol_str,
+                                  NULL);
 
-      SVN_ERR(try_stream_write(target->patched, target->patched_path,
+      SVN_ERR(try_stream_write(content_info->patched, patched_path,
                                target_line, strlen(target_line), iterpool));
     }
   svn_pool_destroy(iterpool);
@@ -1055,10 +1221,11 @@ copy_lines_to_target(patch_target_t *tar
 }
 
 /* Write the diff text of the hunk described by HI to the
- * reject stream of TARGET, and mark TARGET as having had rejects.
+ * reject stream of CONTENT_INFO, and mark TARGET as having had rejects.
  * Do temporary allocations in POOL. */
 static svn_error_t *
-reject_hunk(patch_target_t *target, hunk_info_t *hi, apr_pool_t *pool)
+reject_hunk(patch_target_t *target, target_content_info_t *content_info, 
+            hunk_info_t *hi, svn_boolean_t is_prop_hunk,  apr_pool_t *pool)
 {
   const char *hunk_header;
   apr_size_t len;
@@ -1072,7 +1239,7 @@ reject_hunk(patch_target_t *target, hunk
                              svn_diff_hunk_get_modified_length(hi->hunk),
                              APR_EOL_STR);
   len = strlen(hunk_header);
-  SVN_ERR(svn_stream_write(target->reject, hunk_header, &len));
+  SVN_ERR(svn_stream_write(content_info->reject, hunk_header, &len));
 
   iterpool = svn_pool_create(pool);
   do
@@ -1087,32 +1254,38 @@ reject_hunk(patch_target_t *target, hunk
       if (! eof)
         {
           if (hunk_line->len >= 1)
-            SVN_ERR(try_stream_write(target->reject, target->reject_path,
+            SVN_ERR(try_stream_write(content_info->reject, target->reject_path,
                                      hunk_line->data, hunk_line->len,
                                      iterpool));
           if (eol_str)
-            SVN_ERR(try_stream_write(target->reject, target->reject_path,
+            SVN_ERR(try_stream_write(content_info->reject, target->reject_path,
                                      eol_str, strlen(eol_str), iterpool));
         }
     }
   while (! eof);
   svn_pool_destroy(iterpool);
 
-  target->had_rejects = TRUE;
+  /* ### had_rejects is used for notification. We haven't yet turned on
+   * ### notification for properties. */
+  if (! is_prop_hunk)
+    target->had_rejects = TRUE;
 
   return SVN_NO_ERROR;
 }
 
 /* Write the modified text of hunk described by HI to the patched
- * stream of TARGET. Do temporary allocations in POOL. */
+ * stream of CONTENT_INFO. Do temporary allocations in POOL. */
 static svn_error_t *
-apply_hunk(patch_target_t *target, hunk_info_t *hi, apr_pool_t *pool)
+apply_hunk(patch_target_t *target, target_content_info_t *content_info,  
+           hunk_info_t *hi, svn_boolean_t is_prop_hunk, apr_pool_t *pool)
 {
   svn_linenum_t lines_read;
   svn_boolean_t eof;
   apr_pool_t *iterpool;
 
-  if (target->kind_on_disk == svn_node_file)
+  /* ### Is there a cleaner way to describe if we have an existing target?
+   */
+  if (target->kind_on_disk == svn_node_file || is_prop_hunk)
     {
       svn_linenum_t line;
 
@@ -1120,19 +1293,19 @@ apply_hunk(patch_target_t *target, hunk_
        * Also copy leading lines of context which matched with fuzz.
        * The target has changed on the fuzzy-matched lines,
        * so we should retain the target's version of those lines. */
-      SVN_ERR(copy_lines_to_target(target, hi->matched_line + hi->fuzz,
-                                   pool));
+      SVN_ERR(copy_lines_to_target(content_info, hi->matched_line + hi->fuzz,
+                                   target->patched_path, pool));
 
       /* Skip the target's version of the hunk.
        * Don't skip trailing lines which matched with fuzz. */
-      line = target->current_line +
+      line = content_info->current_line +
              svn_diff_hunk_get_original_length(hi->hunk) - (2 * hi->fuzz);
-      SVN_ERR(seek_to_line(target, line, pool));
-      if (target->current_line != line && ! target->eof)
+      SVN_ERR(seek_to_line(content_info, line, pool));
+      if (content_info->current_line != line && ! content_info->eof)
         {
           /* Seek failed, reject this hunk. */
           hi->rejected = TRUE;
-          SVN_ERR(reject_hunk(target, hi, pool));
+          SVN_ERR(reject_hunk(target, content_info, hi, is_prop_hunk, pool));
           return SVN_NO_ERROR;
         }
     }
@@ -1157,18 +1330,20 @@ apply_hunk(patch_target_t *target, hunk_
           lines_read <= svn_diff_hunk_get_modified_length(hi->hunk) - hi->fuzz)
         {
           if (hunk_line->len >= 1)
-            SVN_ERR(try_stream_write(target->patched, target->patched_path,
+            SVN_ERR(try_stream_write(content_info->patched, 
+                                     target->patched_path,
                                      hunk_line->data, hunk_line->len,
                                      iterpool));
           if (eol_str)
             {
               /* Use the EOL as it was read from the patch file,
                * unless the target's EOL style is set by svn:eol-style */
-              if (target->eol_style != svn_subst_eol_style_none)
-                eol_str = target->eol_str;
+              if (content_info->eol_style != svn_subst_eol_style_none)
+                eol_str = content_info->eol_str;
 
-              SVN_ERR(try_stream_write(target->patched, target->patched_path,
-                                       eol_str, strlen(eol_str), iterpool));
+              SVN_ERR(try_stream_write(content_info->patched,
+                                       target->patched_path, eol_str,
+                                       strlen(eol_str), iterpool));
             }
         }
     }
@@ -1233,13 +1408,13 @@ send_patch_notification(const patch_targ
       apr_pool_t *iterpool;
 
       iterpool = svn_pool_create(pool);
-      for (i = 0; i < target->hunks->nelts; i++)
+      for (i = 0; i < target->content_info->hunks->nelts; i++)
         {
           hunk_info_t *hi;
 
           svn_pool_clear(iterpool);
 
-          hi = APR_ARRAY_IDX(target->hunks, i, hunk_info_t *);
+          hi = APR_ARRAY_IDX(target->content_info->hunks, i, hunk_info_t *);
 
           if (hi->already_applied)
             action = svn_wc_notify_patch_hunk_already_applied;
@@ -1298,6 +1473,7 @@ apply_one_patch(patch_target_t **patch_t
   apr_pool_t *iterpool;
   int i;
   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,
                             remove_tempfiles, result_pool, scratch_pool));
@@ -1339,39 +1515,43 @@ apply_one_patch(patch_target_t **patch_t
        * If no match is found initially, try with fuzz. */
       do
         {
-          SVN_ERR(get_hunk_info(&hi, target, hunk, fuzz,
+          SVN_ERR(get_hunk_info(&hi, target, target->content_info, hunk, fuzz,
                                 ignore_whitespace,
+                                FALSE /* is_prop_hunk */,
                                 cancel_func, cancel_baton,
                                 result_pool, iterpool));
           fuzz++;
         }
       while (hi->rejected && fuzz <= MAX_FUZZ && ! hi->already_applied);
 
-      APR_ARRAY_PUSH(target->hunks, hunk_info_t *) = hi;
+      APR_ARRAY_PUSH(target->content_info->hunks, hunk_info_t *) = hi;
     }
 
   /* Apply or reject hunks. */
-  for (i = 0; i < target->hunks->nelts; i++)
+  for (i = 0; i < target->content_info->hunks->nelts; i++)
     {
       hunk_info_t *hi;
 
       svn_pool_clear(iterpool);
 
-      hi = APR_ARRAY_IDX(target->hunks, i, hunk_info_t *);
+      hi = APR_ARRAY_IDX(target->content_info->hunks, i, hunk_info_t *);
       if (hi->already_applied)
         continue;
       else if (hi->rejected)
-        SVN_ERR(reject_hunk(target, hi, iterpool));
+        SVN_ERR(reject_hunk(target, target->content_info, hi,
+                            FALSE /* is_prop_hunk */, 
+                            iterpool));
       else
-        SVN_ERR(apply_hunk(target, hi, iterpool));
+        SVN_ERR(apply_hunk(target, target->content_info, hi,
+                           FALSE /* is_prop_hunk */, iterpool));
     }
-  svn_pool_destroy(iterpool);
 
   if (target->kind_on_disk == svn_node_file)
     {
       /* Copy any remaining lines to target. */
-      SVN_ERR(copy_lines_to_target(target, 0, scratch_pool));
-      if (! target->eof)
+      SVN_ERR(copy_lines_to_target(target->content_info, 0,
+                                   target->patched_path, scratch_pool));
+      if (! target->content_info->eof)
         {
           /* We could not copy the entire target file to the temporary file,
            * and would truncate the target if we copied the temporary file
@@ -1380,12 +1560,142 @@ apply_one_patch(patch_target_t **patch_t
         }
     }
 
-  /* Close the streams of the target so that their content is flushed
-   * to disk. This will also close underlying streams and files. */
-  if (target->kind_on_disk == svn_node_file)
-    SVN_ERR(svn_stream_close(target->stream));
-  SVN_ERR(svn_stream_close(target->patched));
-  SVN_ERR(svn_stream_close(target->reject));
+  /* Match property hunks. */
+  for (hash_index = apr_hash_first(result_pool, patch->prop_patches);
+       hash_index;
+       hash_index = apr_hash_next(hash_index))
+    {
+      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. */
+      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;
+          hunk_info_t *hi;
+          int fuzz = 0;
+
+          svn_pool_clear(iterpool);
+
+          if (cancel_func)
+            SVN_ERR((cancel_func)(cancel_baton));
+
+          hunk = APR_ARRAY_IDX(prop_patch->hunks, i, svn_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,
+                                    ignore_whitespace,
+                                    TRUE /* is_prop_hunk */,
+                                    cancel_func, cancel_baton,
+                                    result_pool, iterpool));
+              fuzz++;
+            }
+          while (hi->rejected && fuzz <= MAX_FUZZ && ! hi->already_applied);
+
+          APR_ARRAY_PUSH(prop_content_info->hunks, hunk_info_t *) = hi;
+        }
+    }
+
+  /* Apply or reject property hunks. */
+  for (hash_index = apr_hash_first(result_pool, target->prop_targets);
+       hash_index;
+       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++)
+        {
+          hunk_info_t *hi;
+
+          svn_pool_clear(iterpool);
+
+          hi = APR_ARRAY_IDX(prop_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,
+                                TRUE /* is_prop_hunk */, 
+                                iterpool));
+          else
+            SVN_ERR(apply_hunk(target, prop_content_info, hi, 
+                               TRUE /* is_prop_hunk */,
+                               iterpool));
+        }
+
+        if (prop_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)
+              {
+                /* 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. */
+                target->skipped = TRUE;
+              }
+          }
+      }
+
+  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));
+    }
 
   if (! target->skipped)
     {
@@ -2070,7 +2380,8 @@ svn_client_patch(const char *patch_abspa
   baton.patch_func = patch_func;
   baton.patch_baton = patch_baton;
 
-  return svn_error_return(svn_wc__call_with_write_lock(apply_patches, &baton,
-                                       ctx->wc_ctx, local_abspath,
-                                       result_pool, scratch_pool));
+  return svn_error_return(
+           svn_wc__call_with_write_lock(apply_patches, &baton,
+                                        ctx->wc_ctx, local_abspath, FALSE,
+                                        result_pool, scratch_pool));
 }



Mime
View raw message