You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by cm...@apache.org on 2010/07/30 21:10:15 UTC

svn commit: r980929 [1/2] - in /subversion/branches/issue-2779-dev: ./ subversion/libsvn_client/ subversion/libsvn_diff/ subversion/libsvn_fs_fs/ subversion/libsvn_ra_serf/ subversion/libsvn_wc/ subversion/svnrdump/ subversion/tests/cmdline/ subversion...

Author: cmpilato
Date: Fri Jul 30 19:10:14 2010
New Revision: 980929

URL: http://svn.apache.org/viewvc?rev=980929&view=rev
Log:
Sync with trunk changes.  (Merged /subversion/trunk:r980618-980924)

Modified:
    subversion/branches/issue-2779-dev/   (props changed)
    subversion/branches/issue-2779-dev/subversion/libsvn_client/export.c
    subversion/branches/issue-2779-dev/subversion/libsvn_client/patch.c
    subversion/branches/issue-2779-dev/subversion/libsvn_diff/diff_memory.c
    subversion/branches/issue-2779-dev/subversion/libsvn_fs_fs/fs.h
    subversion/branches/issue-2779-dev/subversion/libsvn_fs_fs/fs_fs.c
    subversion/branches/issue-2779-dev/subversion/libsvn_ra_serf/blame.c
    subversion/branches/issue-2779-dev/subversion/libsvn_ra_serf/commit.c
    subversion/branches/issue-2779-dev/subversion/libsvn_ra_serf/getlocations.c
    subversion/branches/issue-2779-dev/subversion/libsvn_ra_serf/getlocationsegments.c
    subversion/branches/issue-2779-dev/subversion/libsvn_ra_serf/mergeinfo.c
    subversion/branches/issue-2779-dev/subversion/libsvn_ra_serf/options.c
    subversion/branches/issue-2779-dev/subversion/libsvn_ra_serf/property.c
    subversion/branches/issue-2779-dev/subversion/libsvn_ra_serf/ra_serf.h
    subversion/branches/issue-2779-dev/subversion/libsvn_ra_serf/update.c
    subversion/branches/issue-2779-dev/subversion/libsvn_ra_serf/util.c
    subversion/branches/issue-2779-dev/subversion/libsvn_wc/adm_files.c
    subversion/branches/issue-2779-dev/subversion/libsvn_wc/node.c
    subversion/branches/issue-2779-dev/subversion/libsvn_wc/status.c
    subversion/branches/issue-2779-dev/subversion/libsvn_wc/wc_db.c
    subversion/branches/issue-2779-dev/subversion/libsvn_wc/wc_db.h
    subversion/branches/issue-2779-dev/subversion/svnrdump/dumpfile_parser.c
    subversion/branches/issue-2779-dev/subversion/svnrdump/load_editor.c
    subversion/branches/issue-2779-dev/subversion/svnrdump/load_editor.h
    subversion/branches/issue-2779-dev/subversion/svnrdump/svnrdump.c
    subversion/branches/issue-2779-dev/subversion/tests/cmdline/basic_tests.py
    subversion/branches/issue-2779-dev/subversion/tests/cmdline/diff_tests.py
    subversion/branches/issue-2779-dev/subversion/tests/cmdline/patch_tests.py
    subversion/branches/issue-2779-dev/subversion/tests/cmdline/stat_tests.py
    subversion/branches/issue-2779-dev/subversion/tests/cmdline/svntest/wc.py

Propchange: subversion/branches/issue-2779-dev/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Fri Jul 30 19:10:14 2010
@@ -34,4 +34,4 @@
 /subversion/branches/tc_url_rev:874351-874483
 /subversion/branches/tree-conflicts:868291-873154
 /subversion/branches/tree-conflicts-notify:873926-874008
-/subversion/trunk:965496-980617
+/subversion/trunk:965496-980924

Modified: subversion/branches/issue-2779-dev/subversion/libsvn_client/export.c
URL: http://svn.apache.org/viewvc/subversion/branches/issue-2779-dev/subversion/libsvn_client/export.c?rev=980929&r1=980928&r2=980929&view=diff
==============================================================================
--- subversion/branches/issue-2779-dev/subversion/libsvn_client/export.c (original)
+++ subversion/branches/issue-2779-dev/subversion/libsvn_client/export.c Fri Jul 30 19:10:14 2010
@@ -349,21 +349,26 @@ copy_versioned_files(const char *from,
 
   if (from_kind == svn_node_dir)
     {
+      apr_fileperms_t perm = APR_OS_DEFAULT;
+
       /* Try to make the new directory.  If this fails because the
          directory already exists, check our FORCE flag to see if we
          care. */
 
-      /* Skip retrieving the umask on windows. Apr does not implement setting
+      /* Keep the source directory's permissions if applicable.
+         Skip retrieving the umask on windows. Apr does not implement setting
          filesystem privileges on Windows.
          Retrieving the file permissions with APR_FINFO_PROT | APR_FINFO_OWNER
          is documented to be 'incredibly expensive' */
-#ifdef WIN32
-      err = svn_io_dir_make(to, APR_OS_DEFAULT, pool);
-#else
-      apr_finfo_t finfo;
-      SVN_ERR(svn_io_stat(&finfo, from, APR_FINFO_PROT, pool));
-      err = svn_io_dir_make(to, finfo.protection, pool);
+#ifndef WIN32
+      if (revision->kind == svn_opt_revision_working)
+        {
+          apr_finfo_t finfo;
+          SVN_ERR(svn_io_stat(&finfo, from, APR_FINFO_PROT, pool));
+          perm = finfo.protection;
+        }
 #endif
+      err = svn_io_dir_make(to, perm, pool);
       if (err)
         {
           if (! APR_STATUS_IS_EEXIST(err->apr_err))

Modified: subversion/branches/issue-2779-dev/subversion/libsvn_client/patch.c
URL: http://svn.apache.org/viewvc/subversion/branches/issue-2779-dev/subversion/libsvn_client/patch.c?rev=980929&r1=980928&r2=980929&view=diff
==============================================================================
--- subversion/branches/issue-2779-dev/subversion/libsvn_client/patch.c (original)
+++ subversion/branches/issue-2779-dev/subversion/libsvn_client/patch.c Fri Jul 30 19:10:14 2010
@@ -1426,6 +1426,47 @@ apply_hunk(patch_target_t *target, targe
   return SVN_NO_ERROR;
 }
 
+/* Use client context CTX to send a suitable notification for hunk HI,
+ * using TARGET to determine the path. If the hunk is a property hunk,
+ * PROP_NAME is set, else NULL. Use POOL for temporary allocations. */
+static svn_error_t *
+send_hunk_notification(const hunk_info_t *hi, 
+                       const patch_target_t *target, 
+                       const char *prop_name, 
+                       const svn_client_ctx_t *ctx,
+                       apr_pool_t *pool)
+{
+  svn_wc_notify_t *notify;
+  svn_wc_notify_action_t action;
+
+  if (hi->already_applied)
+    action = svn_wc_notify_patch_hunk_already_applied;
+  else if (hi->rejected)
+    action = svn_wc_notify_patch_rejected_hunk;
+  else
+    action = svn_wc_notify_patch_applied_hunk;
+
+  notify = svn_wc_create_notify(target->local_abspath
+                                    ? target->local_abspath
+                                    : target->local_relpath,
+                                action, pool);
+  notify->hunk_original_start =
+    svn_diff_hunk_get_original_start(hi->hunk);
+  notify->hunk_original_length =
+    svn_diff_hunk_get_original_length(hi->hunk);
+  notify->hunk_modified_start =
+    svn_diff_hunk_get_modified_start(hi->hunk);
+  notify->hunk_modified_length =
+    svn_diff_hunk_get_modified_length(hi->hunk);
+  notify->hunk_matched_line = hi->matched_line;
+  notify->hunk_fuzz = hi->fuzz;
+  notify->prop_name = prop_name;
+
+  (*ctx->notify_func2)(ctx->notify_baton2, notify, pool);
+
+  return SVN_NO_ERROR;
+}
+
 /* Use client context CTX to send a suitable notification for a patch TARGET.
  * Use POOL for temporary allocations. */
 static svn_error_t *
@@ -1472,9 +1513,6 @@ send_patch_notification(const patch_targ
       else if (target->has_text_changes)
         notify->content_state = svn_wc_notify_state_changed;
 
-      /* ### We need to decide on how we want prop notifications to work. 
-       * ### At the moment we're not reporting property hunks and what about
-       * ### added paths with props and paths scheduled for deletion? */
       if (target->had_prop_rejects)
         notify->prop_state = svn_wc_notify_state_conflicted;
       else if (target->has_prop_changes)
@@ -1492,36 +1530,14 @@ send_patch_notification(const patch_targ
       iterpool = svn_pool_create(pool);
       for (i = 0; i < target->content_info->hunks->nelts; i++)
         {
-          hunk_info_t *hi;
+          const hunk_info_t *hi;
 
           svn_pool_clear(iterpool);
 
           hi = APR_ARRAY_IDX(target->content_info->hunks, i, hunk_info_t *);
 
-          if (hi->already_applied)
-            action = svn_wc_notify_patch_hunk_already_applied;
-          else if (hi->rejected)
-            action = svn_wc_notify_patch_rejected_hunk;
-          else
-            action = svn_wc_notify_patch_applied_hunk;
-
-          notify = svn_wc_create_notify(target->local_abspath
-                                            ? target->local_abspath
-                                            : target->local_relpath,
-                                        action, pool);
-          notify->hunk_original_start =
-            svn_diff_hunk_get_original_start(hi->hunk);
-          notify->hunk_original_length =
-            svn_diff_hunk_get_original_length(hi->hunk);
-          notify->hunk_modified_start =
-            svn_diff_hunk_get_modified_start(hi->hunk);
-          notify->hunk_modified_length =
-            svn_diff_hunk_get_modified_length(hi->hunk);
-          notify->hunk_matched_line = hi->matched_line;
-          notify->hunk_fuzz = hi->fuzz;
-          notify->prop_name = NULL;
-
-          (*ctx->notify_func2)(ctx->notify_baton2, notify, pool);
+          SVN_ERR(send_hunk_notification(hi, target, NULL /* prop_name */, 
+                                         ctx, iterpool));
         }
 
       for (hash_index = apr_hash_first(pool, target->prop_targets);
@@ -1534,37 +1550,14 @@ send_patch_notification(const patch_targ
 
           for (i = 0; i < prop_target->content_info->hunks->nelts; i++)
             {
-              hunk_info_t *hi;
+              const hunk_info_t *hi;
 
               svn_pool_clear(iterpool);
 
               hi = APR_ARRAY_IDX(prop_target->content_info->hunks, i,
                                  hunk_info_t *);
-
-              if (hi->already_applied)
-                action = svn_wc_notify_patch_hunk_already_applied;
-              else if (hi->rejected)
-                action = svn_wc_notify_patch_rejected_hunk;
-              else
-                action = svn_wc_notify_patch_applied_hunk;
-
-              notify = svn_wc_create_notify(target->local_abspath
-                                                ? target->local_abspath
-                                                : target->local_relpath,
-                                            action, pool);
-              notify->hunk_original_start =
-                svn_diff_hunk_get_original_start(hi->hunk);
-              notify->hunk_original_length =
-                svn_diff_hunk_get_original_length(hi->hunk);
-              notify->hunk_modified_start =
-                svn_diff_hunk_get_modified_start(hi->hunk);
-              notify->hunk_modified_length =
-                svn_diff_hunk_get_modified_length(hi->hunk);
-              notify->hunk_matched_line = hi->matched_line;
-              notify->hunk_fuzz = hi->fuzz;
-              notify->prop_name = apr_pstrdup(pool, prop_target->name);
-
-              (*ctx->notify_func2)(ctx->notify_baton2, notify, pool);
+              SVN_ERR(send_hunk_notification(hi, target, prop_target->name, 
+                                             ctx, iterpool));
             }
         }
       svn_pool_destroy(iterpool);

Modified: subversion/branches/issue-2779-dev/subversion/libsvn_diff/diff_memory.c
URL: http://svn.apache.org/viewvc/subversion/branches/issue-2779-dev/subversion/libsvn_diff/diff_memory.c?rev=980929&r1=980928&r2=980929&view=diff
==============================================================================
--- subversion/branches/issue-2779-dev/subversion/libsvn_diff/diff_memory.c (original)
+++ subversion/branches/issue-2779-dev/subversion/libsvn_diff/diff_memory.c Fri Jul 30 19:10:14 2010
@@ -353,6 +353,10 @@ typedef struct unified_output_baton_t
   apr_off_t hunk_length[2]; /* 0 == original; 1 == modified */
   apr_off_t hunk_start[2];  /* 0 == original; 1 == modified */
 
+  /* The delimiters of the hunk header, '@@' for text hunks and '##' for
+   * property hunks. */
+  const char *hunk_delimiter;
+
   /* Pool for allocation of temporary memory in the callbacks
      Should be cleared on entry of each iteration of a callback */
   apr_pool_t *pool;
@@ -516,7 +520,7 @@ output_unified_diff_modified(void *baton
   targ_mod = modified_start;
 
   if (btn->next_token + SVN_DIFF__UNIFIED_CONTEXT_SIZE < targ_orig)
-    SVN_ERR(output_unified_flush_hunk(btn, NULL));
+    SVN_ERR(output_unified_flush_hunk(btn, btn->hunk_delimiter));
 
   if (btn->hunk_length[0] == 0
       && btn->hunk_length[1] == 0)
@@ -569,6 +573,7 @@ svn_diff_mem_string_output_unified2(svn_
       baton.pool = svn_pool_create(pool);
       baton.header_encoding = header_encoding;
       baton.hunk = svn_stringbuf_create("", pool);
+      baton.hunk_delimiter = hunk_delimiter;
 
       SVN_ERR(svn_utf_cstring_from_utf8_ex2
               (&(baton.prefix_str[unified_output_context]), " ",

Modified: subversion/branches/issue-2779-dev/subversion/libsvn_fs_fs/fs.h
URL: http://svn.apache.org/viewvc/subversion/branches/issue-2779-dev/subversion/libsvn_fs_fs/fs.h?rev=980929&r1=980928&r2=980929&view=diff
==============================================================================
--- subversion/branches/issue-2779-dev/subversion/libsvn_fs_fs/fs.h (original)
+++ subversion/branches/issue-2779-dev/subversion/libsvn_fs_fs/fs.h Fri Jul 30 19:10:14 2010
@@ -125,6 +125,9 @@ extern "C" {
 /* The minimum format number that supports packed revprop shards. */
 #define SVN_FS_FS__MIN_PACKED_REVPROP_FORMAT 5
 
+/* The minimum format number that supports a configuration file (fsfs.conf) */
+#define SVN_FS_FS__MIN_CONFIG_FILE 4
+
 /* Private FSFS-specific data shared between all svn_txn_t objects that
    relate to a particular transaction in a filesystem (as identified
    by transaction id and filesystem UUID).  Objects of this type are

Modified: subversion/branches/issue-2779-dev/subversion/libsvn_fs_fs/fs_fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/issue-2779-dev/subversion/libsvn_fs_fs/fs_fs.c?rev=980929&r1=980928&r2=980929&view=diff
==============================================================================
--- subversion/branches/issue-2779-dev/subversion/libsvn_fs_fs/fs_fs.c (original)
+++ subversion/branches/issue-2779-dev/subversion/libsvn_fs_fs/fs_fs.c Fri Jul 30 19:10:14 2010
@@ -1275,11 +1275,32 @@ upgrade_body(void *baton, apr_pool_t *po
   fs_fs_data_t *ffd = fs->fsap_data;
   int format, max_files_per_dir;
   const char *format_path = path_format(fs, pool);
+  svn_node_kind_t kind;
 
   /* Read the FS format number and max-files-per-dir setting. */
   SVN_ERR(read_format(&format, &max_files_per_dir, format_path, pool));
 
-  /* If we're already up-to-date, there's nothing to be done here. */
+  /* If the config file does not exist, create one. */
+  SVN_ERR(svn_io_check_path(svn_dirent_join(fs->path, PATH_CONFIG, pool),
+                            &kind, pool));
+  switch (kind)
+    {
+    case svn_node_none:
+      SVN_ERR(write_config(fs, pool));
+      break;
+    case svn_node_dir:
+      return svn_error_return(svn_error_createf(SVN_ERR_FS_GENERAL, NULL,
+                                                _("'%s' is a directory. "
+                                                  "Please move it out of "
+                                                  "the way and try again"),
+                                                svn_dirent_join(fs->path,
+                                                                PATH_CONFIG,
+                                                                pool)));
+    default:
+      break;
+    }
+
+  /* If we're already up-to-date, there's nothing else to be done here. */
   if (format == SVN_FS_FS__FORMAT_NUMBER)
     return SVN_NO_ERROR;
 
@@ -1496,15 +1517,64 @@ svn_fs_fs__hotcopy(const char *src_path,
                       pool));
   SVN_ERR(check_format(format));
 
+  /* Try to copy the config.
+   *
+   * ### We try copying the config file before doing anything else,
+   * ### because higher layers will abort the hotcopy if we throw
+   * ### an error from this function, and that renders the hotcopy
+   * ### unusable anyway. */
+  if (format >= SVN_FS_FS__MIN_CONFIG_FILE)
+    {
+      svn_error_t *err;
+
+      err = svn_io_dir_file_copy(src_path, dst_path, PATH_CONFIG, pool);
+      if (err)
+        {
+          if (APR_STATUS_IS_ENOENT(err->apr_err))
+            {
+              /* 1.6.0 to 1.6.11 did not copy the configuration file during
+               * hotcopy. So if we're hotcopying a repository which has been
+               * created as a hotcopy itself, it's possible that fsfs.conf
+               * does not exist. Ask the user to re-create it.
+               *
+               * ### It would be nice to make this a non-fatal error,
+               * ### but this function does not get an svn_fs_t object
+               * ### so we have no way of just printing a warning via
+               * ### the fs->warning() callback. */
+
+              const char *msg;
+              const char *src_abspath;
+              const char *dst_abspath;
+              const char *config_relpath;
+
+              config_relpath = svn_dirent_join(src_path, PATH_CONFIG, pool);
+              SVN_ERR(svn_dirent_get_absolute(&src_abspath, src_path, pool));
+              SVN_ERR(svn_dirent_get_absolute(&dst_abspath, dst_path, pool));
+              
+              /* ### hack: strip off the 'db/' directory from paths so
+               * ### they make sense to the user */
+              src_abspath = svn_dirent_dirname(src_abspath, pool);
+              dst_abspath = svn_dirent_dirname(dst_abspath, pool);
+
+              msg = apr_psprintf(pool,
+                                 _("Failed to create hotcopy at '%s'. "
+                                   "The file '%s' is missing from the source "
+                                   "repository. Please create this file, for "
+                                   "instance by running 'svnadmin upgrade %s'"),
+                                 dst_abspath, config_relpath, src_abspath);
+              return svn_error_return(svn_error_quick_wrap(err, msg));
+            }
+          else
+            return svn_error_return(err);
+        }
+    }
+
   /* Copy the 'current' file. */
   SVN_ERR(svn_io_dir_file_copy(src_path, dst_path, PATH_CURRENT, pool));
 
   /* Copy the uuid. */
   SVN_ERR(svn_io_dir_file_copy(src_path, dst_path, PATH_UUID, pool));
 
-  /* Copy the config. */
-  SVN_ERR(svn_io_dir_file_copy(src_path, dst_path, PATH_CONFIG, pool));
-
   /* Copy the rep cache before copying the rev files to make sure all
      cached references will be present in the copy. */
   src_subdir = svn_dirent_join(src_path, REP_CACHE_DB_NAME, pool);

Modified: subversion/branches/issue-2779-dev/subversion/libsvn_ra_serf/blame.c
URL: http://svn.apache.org/viewvc/subversion/branches/issue-2779-dev/subversion/libsvn_ra_serf/blame.c?rev=980929&r1=980928&r2=980929&view=diff
==============================================================================
--- subversion/branches/issue-2779-dev/subversion/libsvn_ra_serf/blame.c (original)
+++ subversion/branches/issue-2779-dev/subversion/libsvn_ra_serf/blame.c Fri Jul 30 19:10:14 2010
@@ -483,8 +483,10 @@ svn_ra_serf__get_file_revs(svn_ra_sessio
   err = svn_ra_serf__context_run_wait(&blame_ctx->done, session, pool);
 
   err = svn_error_compose_create(
-                svn_ra_serf__error_on_status(status_code, handler->path),
-                err);
+            svn_ra_serf__error_on_status(status_code,
+                                         handler->path,
+                                         parser_ctx->location),
+            err);
 
   return svn_error_return(err);
 }

Modified: subversion/branches/issue-2779-dev/subversion/libsvn_ra_serf/commit.c
URL: http://svn.apache.org/viewvc/subversion/branches/issue-2779-dev/subversion/libsvn_ra_serf/commit.c?rev=980929&r1=980928&r2=980929&view=diff
==============================================================================
--- subversion/branches/issue-2779-dev/subversion/libsvn_ra_serf/commit.c (original)
+++ subversion/branches/issue-2779-dev/subversion/libsvn_ra_serf/commit.c Fri Jul 30 19:10:14 2010
@@ -220,16 +220,22 @@ static svn_error_t *
 return_response_err(svn_ra_serf__handler_t *handler,
                     svn_ra_serf__simple_request_context_t *ctx)
 {
+  svn_error_t *err;
+
+  /* Ye Olde Fallback Error */
+  err = svn_error_compose_create(
+            ctx->server_error.error,
+            svn_error_createf(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL,
+                              "%s of '%s': %d %s",
+                              handler->method, handler->path,
+                              ctx->status, ctx->reason));
+
   /* Try to return one of the standard errors for 301, 404, etc.,
      then look for an error embedded in the response.  */
-  return svn_error_compose_create(
-    svn_ra_serf__error_on_status(ctx->status, handler->path),
-    svn_error_compose_create(
-      ctx->server_error.error,
-      svn_error_createf(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL,
-                        "%s of '%s': %d %s",
-                        handler->method, handler->path,
-                        ctx->status, ctx->reason)));
+  return svn_error_compose_create(svn_ra_serf__error_on_status(ctx->status,
+                                                               handler->path,
+                                                               ctx->location),
+                                  err);
 }
 
 static serf_bucket_t *

Modified: subversion/branches/issue-2779-dev/subversion/libsvn_ra_serf/getlocations.c
URL: http://svn.apache.org/viewvc/subversion/branches/issue-2779-dev/subversion/libsvn_ra_serf/getlocations.c?rev=980929&r1=980928&r2=980929&view=diff
==============================================================================
--- subversion/branches/issue-2779-dev/subversion/libsvn_ra_serf/getlocations.c (original)
+++ subversion/branches/issue-2779-dev/subversion/libsvn_ra_serf/getlocations.c Fri Jul 30 19:10:14 2010
@@ -277,7 +277,9 @@ svn_ra_serf__get_locations(svn_ra_sessio
   err = svn_ra_serf__context_run_wait(&loc_ctx->done, session, pool);
 
   SVN_ERR(svn_error_compose_create(
-              svn_ra_serf__error_on_status(loc_ctx->status_code, req_url),
+              svn_ra_serf__error_on_status(loc_ctx->status_code,
+                                           req_url,
+                                           parser_ctx->location),
               err));
 
   return SVN_NO_ERROR;

Modified: subversion/branches/issue-2779-dev/subversion/libsvn_ra_serf/getlocationsegments.c
URL: http://svn.apache.org/viewvc/subversion/branches/issue-2779-dev/subversion/libsvn_ra_serf/getlocationsegments.c?rev=980929&r1=980928&r2=980929&view=diff
==============================================================================
--- subversion/branches/issue-2779-dev/subversion/libsvn_ra_serf/getlocationsegments.c (original)
+++ subversion/branches/issue-2779-dev/subversion/libsvn_ra_serf/getlocationsegments.c Fri Jul 30 19:10:14 2010
@@ -181,7 +181,7 @@ svn_ra_serf__get_location_segments(svn_r
   svn_ra_serf__handler_t *handler;
   svn_ra_serf__xml_parser_t *parser_ctx;
   const char *relative_url, *basecoll_url, *req_url;
-  svn_error_t *err;
+  svn_error_t *err, *err2;
 
   gls_ctx = apr_pcalloc(pool, sizeof(*gls_ctx));
   gls_ctx->path = path;
@@ -230,8 +230,15 @@ svn_ra_serf__get_location_segments(svn_r
                             _("Location segment report failed on '%s'@'%ld'"),
                               path, peg_revision);
 
-  /* ### Leaks err */
-  SVN_ERR(svn_ra_serf__error_on_status(gls_ctx->status_code, handler->path));
+  err2 = svn_ra_serf__error_on_status(gls_ctx->status_code,
+                                      handler->path,
+                                      parser_ctx->location);
+  if (err2)
+    {
+      /* Prefer err2 to err. */
+      svn_error_clear(err);
+      return err2;
+    }
 
   svn_pool_destroy(gls_ctx->subpool);
 

Modified: subversion/branches/issue-2779-dev/subversion/libsvn_ra_serf/mergeinfo.c
URL: http://svn.apache.org/viewvc/subversion/branches/issue-2779-dev/subversion/libsvn_ra_serf/mergeinfo.c?rev=980929&r1=980928&r2=980929&view=diff
==============================================================================
--- subversion/branches/issue-2779-dev/subversion/libsvn_ra_serf/mergeinfo.c (original)
+++ subversion/branches/issue-2779-dev/subversion/libsvn_ra_serf/mergeinfo.c Fri Jul 30 19:10:14 2010
@@ -290,12 +290,12 @@ svn_ra_serf__get_mergeinfo(svn_ra_sessio
 
   err = svn_ra_serf__context_run_wait(&mergeinfo_ctx->done, session, pool);
 
-  err2 = svn_ra_serf__error_on_status(status_code, handler->path);
-
+  err2 = svn_ra_serf__error_on_status(status_code, handler->path,
+                                      parser_ctx->location);
   if (err2)
     {
       svn_error_clear(err);
-      SVN_ERR(err2);
+      return err2;
     }
 
   SVN_ERR(err);

Modified: subversion/branches/issue-2779-dev/subversion/libsvn_ra_serf/options.c
URL: http://svn.apache.org/viewvc/subversion/branches/issue-2779-dev/subversion/libsvn_ra_serf/options.c?rev=980929&r1=980928&r2=980929&view=diff
==============================================================================
--- subversion/branches/issue-2779-dev/subversion/libsvn_ra_serf/options.c (original)
+++ subversion/branches/issue-2779-dev/subversion/libsvn_ra_serf/options.c Fri Jul 30 19:10:14 2010
@@ -481,15 +481,20 @@ svn_ra_serf__exchange_capabilities(svn_r
                                    apr_pool_t *pool)
 {
   svn_ra_serf__options_context_t *opt_ctx;
+  svn_error_t *err;
 
   /* This routine automatically fills in serf_sess->capabilities */
   svn_ra_serf__create_options_req(&opt_ctx, serf_sess, serf_sess->conns[0],
                                   serf_sess->repos_url.path, pool);
 
-  SVN_ERR(svn_ra_serf__context_run_wait(
-    svn_ra_serf__get_options_done_ptr(opt_ctx), serf_sess, pool));
+  err = svn_ra_serf__context_run_wait(
+            svn_ra_serf__get_options_done_ptr(opt_ctx), serf_sess, pool);
 
-  return SVN_NO_ERROR;
+  return svn_error_compose_create(
+             svn_ra_serf__error_on_status(opt_ctx->status_code,
+                                          serf_sess->repos_url.path,
+                                          opt_ctx->parser_ctx->location),
+             err);
 }
 
 

Modified: subversion/branches/issue-2779-dev/subversion/libsvn_ra_serf/property.c
URL: http://svn.apache.org/viewvc/subversion/branches/issue-2779-dev/subversion/libsvn_ra_serf/property.c?rev=980929&r1=980928&r2=980929&view=diff
==============================================================================
--- subversion/branches/issue-2779-dev/subversion/libsvn_ra_serf/property.c (original)
+++ subversion/branches/issue-2779-dev/subversion/libsvn_ra_serf/property.c Fri Jul 30 19:10:14 2010
@@ -700,7 +700,8 @@ svn_ra_serf__wait_for_props(svn_ra_serf_
 
   err = svn_ra_serf__context_run_wait(&prop_ctx->done, sess, pool);
 
-  err2 = svn_ra_serf__error_on_status(prop_ctx->status_code, prop_ctx->path);
+  err2 = svn_ra_serf__error_on_status(prop_ctx->status_code,
+                                      prop_ctx->path, NULL);
   if (err2)
     {
       svn_error_clear(err);

Modified: subversion/branches/issue-2779-dev/subversion/libsvn_ra_serf/ra_serf.h
URL: http://svn.apache.org/viewvc/subversion/branches/issue-2779-dev/subversion/libsvn_ra_serf/ra_serf.h?rev=980929&r1=980928&r2=980929&view=diff
==============================================================================
--- subversion/branches/issue-2779-dev/subversion/libsvn_ra_serf/ra_serf.h (original)
+++ subversion/branches/issue-2779-dev/subversion/libsvn_ra_serf/ra_serf.h Fri Jul 30 19:10:14 2010
@@ -623,6 +623,10 @@ struct svn_ra_serf__xml_parser_t {
    */
   int *status_code;
 
+  /* If non-NULL, this is the value of the response's Location header.
+   */
+  const char *location;
+
   /* If non-NULL, this value will be set to TRUE when the response is
    * completed.
    */
@@ -686,6 +690,10 @@ typedef struct svn_ra_serf__simple_reque
   /* The HTTP status line of the response */
   const char *reason;
 
+  /* The Location header value of the response, or NULL if there
+     wasn't one. */
+  const char *location;
+
   /* This value is set to TRUE when the response is completed. */
   svn_boolean_t done;
 
@@ -775,6 +783,13 @@ svn_ra_serf__response_discard_handler(se
                                       void *baton,
                                       apr_pool_t *pool);
 
+/* Return the value of the RESPONSE's Location header if any, or NULL
+ * otherwise.  All allocations will be made in POOL.
+ */
+const char *
+svn_ra_serf__response_get_location(serf_bucket_t *response,
+                                   apr_pool_t *pool);
+
 /** XML helper functions. **/
 
 /*
@@ -1498,11 +1513,14 @@ svn_ra_serf__encode_auth_header(const ch
 /*** General utility functions ***/
 
 /**
- * Convert an HTTP status code resulting from a WebDAV request to the relevant
- * error code.
+ * Convert an HTTP STATUS_CODE resulting from a WebDAV request against
+ * PATH to the relevant error code.  Use the response-supplied LOCATION
+ * where it necessary.
  */
 svn_error_t *
-svn_ra_serf__error_on_status(int status_code, const char *path);
+svn_ra_serf__error_on_status(int status_code,
+                             const char *path,
+                             const char *location);
 
 #ifdef __cplusplus
 }

Modified: subversion/branches/issue-2779-dev/subversion/libsvn_ra_serf/update.c
URL: http://svn.apache.org/viewvc/subversion/branches/issue-2779-dev/subversion/libsvn_ra_serf/update.c?rev=980929&r1=980928&r2=980929&view=diff
==============================================================================
--- subversion/branches/issue-2779-dev/subversion/libsvn_ra_serf/update.c (original)
+++ subversion/branches/issue-2779-dev/subversion/libsvn_ra_serf/update.c Fri Jul 30 19:10:14 2010
@@ -995,11 +995,15 @@ handle_stream(serf_request_t *request,
 {
   report_fetch_t *fetch_ctx = handler_baton;
   serf_status_line sl;
+  const char *location;
 
   serf_bucket_response_status(response, &sl);
 
   /* Woo-hoo.  Nothing here to see.  */
-  fetch_ctx->err = svn_ra_serf__error_on_status(sl.code, fetch_ctx->info->name);
+  location = svn_ra_serf__response_get_location(response, pool);
+  fetch_ctx->err = svn_ra_serf__error_on_status(sl.code,
+                                                fetch_ctx->info->name,
+                                                location);
   if (fetch_ctx->err)
     {
       fetch_ctx->done = TRUE;

Modified: subversion/branches/issue-2779-dev/subversion/libsvn_ra_serf/util.c
URL: http://svn.apache.org/viewvc/subversion/branches/issue-2779-dev/subversion/libsvn_ra_serf/util.c?rev=980929&r1=980928&r2=980929&view=diff
==============================================================================
--- subversion/branches/issue-2779-dev/subversion/libsvn_ra_serf/util.c (original)
+++ subversion/branches/issue-2779-dev/subversion/libsvn_ra_serf/util.c Fri Jul 30 19:10:14 2010
@@ -804,6 +804,18 @@ svn_ra_serf__response_discard_handler(se
     }
 }
 
+const char *
+svn_ra_serf__response_get_location(serf_bucket_t *response,
+                                   apr_pool_t *pool)
+{
+  serf_bucket_t *headers;
+  const char *val;
+
+  headers = serf_bucket_response_get_headers(response);
+  val = serf_bucket_headers_get(headers, "Location");
+  return val ? svn_uri_canonicalize(val, pool) : NULL;
+}
+
 /* Implements svn_ra_serf__response_handler_t */
 svn_error_t *
 svn_ra_serf__handle_status_only(serf_request_t *request,
@@ -826,7 +838,7 @@ svn_ra_serf__handle_status_only(serf_req
 
       ctx->status = sl.code;
       ctx->reason = sl.reason;
-
+      ctx->location = svn_ra_serf__response_get_location(response, pool);
       ctx->done = TRUE;
     }
 
@@ -986,6 +998,7 @@ svn_ra_serf__handle_multistatus_only(ser
 
       ctx->status = sl.code;
       ctx->reason = sl.reason;
+      ctx->location = svn_ra_serf__response_get_location(response, pool);
     }
 
   return svn_error_return(err);
@@ -1060,6 +1073,11 @@ svn_ra_serf__handle_xml_parser(serf_requ
       *ctx->status_code = sl.code;
     }
 
+  if (sl.code == 301 || sl.code == 302)
+    {
+      ctx->location = svn_ra_serf__response_get_location(response, pool);
+    }
+
   /* Woo-hoo.  Nothing here to see.  */
   if (sl.code == 404 && ctx->ignore_errors == FALSE)
     {
@@ -1702,18 +1720,20 @@ svn_ra_serf__report_resource(const char 
 }
 
 svn_error_t *
-svn_ra_serf__error_on_status(int status_code, const char *path)
+svn_ra_serf__error_on_status(int status_code,
+                             const char *path,
+                             const char *location)
 {
   switch(status_code)
     {
       case 301:
       case 302:
         return svn_error_createf(SVN_ERR_RA_DAV_RELOCATED, NULL,
-                        (status_code == 301)
-                        ? _("Repository moved permanently to '%s';"
-                            " please relocate")
-                        : _("Repository moved temporarily to '%s';"
-                            " please relocate"), path);
+                                 (status_code == 301)
+                                 ? _("Repository moved permanently to '%s';"
+                                     " please relocate")
+                                 : _("Repository moved temporarily to '%s';"
+                                     " please relocate"), location);
       case 404:
         return svn_error_createf(SVN_ERR_FS_NOT_FOUND, NULL,
                                  _("'%s' path not found"), path);

Modified: subversion/branches/issue-2779-dev/subversion/libsvn_wc/adm_files.c
URL: http://svn.apache.org/viewvc/subversion/branches/issue-2779-dev/subversion/libsvn_wc/adm_files.c?rev=980929&r1=980928&r2=980929&view=diff
==============================================================================
--- subversion/branches/issue-2779-dev/subversion/libsvn_wc/adm_files.c (original)
+++ subversion/branches/issue-2779-dev/subversion/libsvn_wc/adm_files.c Fri Jul 30 19:10:14 2010
@@ -597,9 +597,11 @@ svn_wc__internal_ensure_adm(svn_wc__db_t
                             svn_depth_t depth,
                             apr_pool_t *scratch_pool)
 {
-  const svn_wc_entry_t *entry;
   int format;
   const char *repos_relpath;
+  svn_wc__db_status_t status;
+  const char *db_repos_relpath, *db_repos_root_url, *db_repos_uuid;
+  svn_revnum_t db_revision;
 
   SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
   SVN_ERR_ASSERT(url != NULL);
@@ -622,40 +624,60 @@ svn_wc__internal_ensure_adm(svn_wc__db_t
                                      repos_relpath, repos_root_url, repos_uuid,
                                      revision, depth, scratch_pool));
 
-  /* Now, get the existing url and repos for PATH. */
-  SVN_ERR(svn_wc__get_entry(&entry, db, local_abspath, FALSE, svn_node_unknown,
-                            FALSE, scratch_pool, scratch_pool));
+  SVN_ERR(svn_wc__db_read_info(&status, NULL,
+                               &db_revision, &db_repos_relpath,
+                               &db_repos_root_url, &db_repos_uuid,
+                               NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+                               NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+                               NULL, NULL, NULL, NULL,
+                               db, local_abspath, scratch_pool, scratch_pool));
 
-  /* When the directory exists and is scheduled for deletion do not
-   * check the revision or the URL.  The revision can be any
+  /* When the directory exists and is scheduled for deletion or is not-present
+   * do not check the revision or the URL.  The revision can be any
    * arbitrary revision and the URL may differ if the add is
    * being driven from a merge which will have a different URL. */
-  if (entry->schedule != svn_wc_schedule_delete)
+  if (status != svn_wc__db_status_deleted
+      && status != svn_wc__db_status_obstructed_delete
+      && status != svn_wc__db_status_not_present)
     {
-      if (entry->revision != revision)
+      /* ### Should we match copyfrom_revision? */
+      if (db_revision != revision)
         return
           svn_error_createf(SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL,
                             _("Revision %ld doesn't match existing "
                               "revision %ld in '%s'"),
-                            revision, entry->revision, local_abspath);
+                            revision, db_revision, local_abspath);
 
       /* The caller gives us a URL which should match the entry. However,
          some callers compensate for an old problem in entry->url and pass
          the copyfrom_url instead. See ^/notes/api-errata/wc002.txt. As
          a result, we allow the passed URL to match copyfrom_url if it
-         does match the entry's primary URL.  */
-      /** ### comparing URLs, should they be canonicalized first? */
-      if (strcmp(entry->url, url) != 0
-          && (entry->copyfrom_url == NULL
-              || strcmp(entry->copyfrom_url, url) != 0)
-          && (!svn_uri_is_ancestor(repos_root_url, entry->url)
-              || strcmp(entry->uuid, repos_uuid) != 0))
+         does not match the entry's primary URL.  */
+      /* ### comparing URLs, should they be canonicalized first? */
+      if (strcmp(db_repos_uuid, repos_uuid)
+          || strcmp(db_repos_root_url, repos_root_url)
+          || !svn_relpath_is_ancestor(db_repos_relpath, repos_relpath))
         {
-          return
-            svn_error_createf(SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL,
-                              _("URL '%s' doesn't match existing "
-                                "URL '%s' in '%s'"),
-                              url, entry->url, local_abspath);
+          const char *copyfrom_root_url, *copyfrom_repos_relpath;
+
+          SVN_ERR(svn_wc__internal_get_copyfrom_info(&copyfrom_root_url,
+                                                     &copyfrom_repos_relpath,
+                                                     NULL, NULL, NULL,
+                                                     db, local_abspath,
+                                                     scratch_pool,
+                                                     scratch_pool));
+
+          if (copyfrom_root_url == NULL
+              || strcmp(copyfrom_root_url, repos_root_url)
+              || strcmp(copyfrom_repos_relpath, repos_relpath))
+            return
+              svn_error_createf(SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL,
+                                _("URL '%s' doesn't match existing "
+                                  "URL '%s' in '%s'"),
+                                url,
+                                svn_uri_join(db_repos_root_url,
+                                             db_repos_relpath, scratch_pool),
+                                local_abspath);
         }
     }
 

Modified: subversion/branches/issue-2779-dev/subversion/libsvn_wc/node.c
URL: http://svn.apache.org/viewvc/subversion/branches/issue-2779-dev/subversion/libsvn_wc/node.c?rev=980929&r1=980928&r2=980929&view=diff
==============================================================================
--- subversion/branches/issue-2779-dev/subversion/libsvn_wc/node.c (original)
+++ subversion/branches/issue-2779-dev/subversion/libsvn_wc/node.c Fri Jul 30 19:10:14 2010
@@ -467,17 +467,16 @@ svn_wc__node_get_repos_relpath(const cha
 }
 
 svn_error_t *
-svn_wc__node_get_copyfrom_info(const char **copyfrom_root_url,
-                               const char **copyfrom_repos_relpath,
-                               const char **copyfrom_url,
-                               svn_revnum_t *copyfrom_rev,
-                               svn_boolean_t *is_copy_target,
-                               svn_wc_context_t *wc_ctx,
-                               const char *local_abspath,
-                               apr_pool_t *result_pool,
-                               apr_pool_t *scratch_pool)
+svn_wc__internal_get_copyfrom_info(const char **copyfrom_root_url,
+                                   const char **copyfrom_repos_relpath,
+                                   const char **copyfrom_url,
+                                   svn_revnum_t *copyfrom_rev,
+                                   svn_boolean_t *is_copy_target,
+                                   svn_wc__db_t *db,
+                                   const char *local_abspath,
+                                   apr_pool_t *result_pool,
+                                   apr_pool_t *scratch_pool)
 {
-  svn_wc__db_t *db = wc_ctx->db;
   const char *original_root_url;
   const char *original_repos_relpath;
   svn_revnum_t original_revision;
@@ -544,11 +543,12 @@ svn_wc__node_get_copyfrom_info(const cha
 
           /* This is a copied node, so we should never fall off the top of a
            * working copy here. */
-          SVN_ERR(svn_wc__node_get_copyfrom_info(NULL, NULL,
-                                                 &parent_copyfrom_url,
-                                                 NULL, NULL,
-                                                 wc_ctx, parent_abspath,
-                                                 scratch_pool, scratch_pool));
+          SVN_ERR(svn_wc__internal_get_copyfrom_info(NULL, NULL,
+                                                     &parent_copyfrom_url,
+                                                     NULL, NULL,
+                                                     db, parent_abspath,
+                                                     scratch_pool,
+                                                     scratch_pool));
 
           /* So, count this as a separate copy target only if the URLs
            * don't match up, or if the parent isn't copied at all. */
@@ -607,8 +607,39 @@ svn_wc__node_get_copyfrom_info(const cha
   return SVN_NO_ERROR;
 }
 
+svn_error_t *
+svn_wc__node_get_copyfrom_info(const char **copyfrom_root_url,
+                               const char **copyfrom_repos_relpath,
+                               const char **copyfrom_url,
+                               svn_revnum_t *copyfrom_rev,
+                               svn_boolean_t *is_copy_target,
+                               svn_wc_context_t *wc_ctx,
+                               const char *local_abspath,
+                               apr_pool_t *result_pool,
+                               apr_pool_t *scratch_pool)
+{
+  return
+    svn_error_return(svn_wc__internal_get_copyfrom_info(copyfrom_root_url,
+                                                        copyfrom_repos_relpath,
+                                                        copyfrom_url,
+                                                        copyfrom_rev,
+                                                        is_copy_target,
+                                                        wc_ctx->db,
+                                                        local_abspath,
+                                                        scratch_pool,
+                                                        scratch_pool));
+}
 
-/* A recursive node-walker, helper for svn_wc__node_walk_children(). */
+/* A recursive node-walker, helper for svn_wc__node_walk_children().
+ *
+ * Call WALK_CALLBACK with WALK_BATON on all children (recursively) of
+ * DIR_ABSPATH in DB, but not on DIR_ABSPATH itself. DIR_ABSPATH must be a
+ * versioned directory. If SHOW_HIDDEN is true, visit hidden nodes, else
+ * ignore them. Restrict the depth of the walk to DEPTH.
+ *
+ * ### Is it possible for a subdirectory to be hidden and known to be a
+ *     directory?  If so, and if show_hidden is true, this will try to
+ *     recurse into it.  */
 static svn_error_t *
 walker_helper(svn_wc__db_t *db,
               const char *dir_abspath,

Modified: subversion/branches/issue-2779-dev/subversion/libsvn_wc/status.c
URL: http://svn.apache.org/viewvc/subversion/branches/issue-2779-dev/subversion/libsvn_wc/status.c?rev=980929&r1=980928&r2=980929&view=diff
==============================================================================
--- subversion/branches/issue-2779-dev/subversion/libsvn_wc/status.c (original)
+++ subversion/branches/issue-2779-dev/subversion/libsvn_wc/status.c Fri Jul 30 19:10:14 2010
@@ -1786,7 +1786,6 @@ mark_deleted(void *baton,
    a deletion.  Use POOL for all allocations. */
 static svn_error_t *
 handle_statii(struct edit_baton *eb,
-              const char *local_abspath,
               const char *dir_repos_root_url,
               const char *dir_repos_relpath,
               apr_hash_t *statii,
@@ -1809,7 +1808,7 @@ handle_statii(struct edit_baton *eb,
       status_baton = &sb;
     }
 
-  /* Loop over all the statuses still in our hash, handling each one. */
+  /* Loop over all the statii still in our hash, handling each one. */
   for (hi = apr_hash_first(pool, statii); hi; hi = apr_hash_next(hi))
     {
       const char *local_abspath = svn__apr_hash_index_key(hi);
@@ -2070,7 +2069,7 @@ close_directory(void *dir_baton,
         was_deleted = TRUE;
 
       /* Now do the status reporting. */
-      SVN_ERR(handle_statii(eb, db->local_abspath,
+      SVN_ERR(handle_statii(eb,
                             dir_status ? dir_status->repos_root_url : NULL,
                             dir_status ? dir_status->repos_relpath : NULL,
                             db->statii, was_deleted, db->depth, pool));
@@ -2116,7 +2115,7 @@ close_directory(void *dir_baton,
           /* Otherwise, we report on all our children and ourself.
              Note that our directory couldn't have been deleted,
              because it is the root of the edit drive. */
-          SVN_ERR(handle_statii(eb, eb->anchor_abspath,
+          SVN_ERR(handle_statii(eb,
                                 eb->anchor_status->repos_root_url,
                                 eb->anchor_status->repos_relpath,
                                 db->statii, FALSE, eb->default_depth, pool));
@@ -2430,7 +2429,7 @@ svn_wc_walk_status(svn_wc_context_t *wc_
 {
   svn_node_kind_t kind;
   struct walk_status_baton wb;
-  svn_io_dirent2_t *dirent;
+  const svn_io_dirent2_t *dirent;
   const char *anchor_abspath, *target_name;
   svn_boolean_t skip_root;
 

Modified: subversion/branches/issue-2779-dev/subversion/libsvn_wc/wc_db.c
URL: http://svn.apache.org/viewvc/subversion/branches/issue-2779-dev/subversion/libsvn_wc/wc_db.c?rev=980929&r1=980928&r2=980929&view=diff
==============================================================================
--- subversion/branches/issue-2779-dev/subversion/libsvn_wc/wc_db.c (original)
+++ subversion/branches/issue-2779-dev/subversion/libsvn_wc/wc_db.c Fri Jul 30 19:10:14 2010
@@ -2676,6 +2676,32 @@ svn_wc__db_pristine_get_sha1(const svn_c
 }
 
 
+/* Delete the pristine text referenced by SHA1_CHECKSUM in the database
+ * referenced by PDH. */
+static svn_error_t *
+pristine_remove(svn_wc__db_pdh_t *pdh,
+                const svn_checksum_t *sha1_checksum,
+                apr_pool_t *scratch_pool)
+{
+  svn_sqlite__stmt_t *stmt;
+  const char *pristine_abspath;
+
+  /* Remove the DB row. */
+  SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+                                    STMT_DELETE_PRISTINE));
+  SVN_ERR(svn_sqlite__bind_checksum(stmt, 1, sha1_checksum, scratch_pool));
+  SVN_ERR(svn_sqlite__update(NULL, stmt));
+
+  /* Remove the file */
+  SVN_ERR(get_pristine_fname(&pristine_abspath, pdh->wcroot->abspath,
+                             sha1_checksum, TRUE /* create_subdir */,
+                             scratch_pool, scratch_pool));
+  SVN_ERR(svn_io_remove_file2(pristine_abspath, TRUE /* ignore_enoent */,
+                              scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
 svn_error_t *
 svn_wc__db_pristine_remove(svn_wc__db_t *db,
                            const char *wri_abspath,
@@ -2701,6 +2727,21 @@ svn_wc__db_pristine_remove(svn_wc__db_t 
                               scratch_pool, scratch_pool));
   VERIFY_USABLE_PDH(pdh);
 
+  /* If the work queue is not empty, don't delete any pristine text because
+   * the work queue may contain a reference to it. */
+  {
+    svn_sqlite__stmt_t *stmt;
+    svn_boolean_t have_row;
+
+    SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+                                      STMT_LOOK_FOR_WORK));
+    SVN_ERR(svn_sqlite__step(&have_row, stmt));
+    SVN_ERR(svn_sqlite__reset(stmt));
+
+    if (have_row)
+      return SVN_NO_ERROR;
+  }
+
   /* Find whether the SHA-1 (or the MD-5) is referenced; set IS_REFERENCED. */
   {
     const svn_checksum_t *md5_checksum;
@@ -2720,24 +2761,10 @@ svn_wc__db_pristine_remove(svn_wc__db_t 
     SVN_ERR(svn_sqlite__reset(stmt));
   }
 
-  /* If not referenced, remove first the PRISTINE table row, then the file. */
+  /* If not referenced, remove the PRISTINE table row and the file. */
   if (! is_referenced)
     {
-      svn_sqlite__stmt_t *stmt;
-      const char *pristine_abspath;
-
-      /* Remove the DB row. */
-      SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
-                                        STMT_DELETE_PRISTINE));
-      SVN_ERR(svn_sqlite__bind_checksum(stmt, 1, sha1_checksum, scratch_pool));
-      SVN_ERR(svn_sqlite__update(NULL, stmt));
-
-      /* Remove the file */
-      SVN_ERR(get_pristine_fname(&pristine_abspath, pdh->wcroot->abspath,
-                                 sha1_checksum,
-                                 TRUE /* create_subdir */,
-                                 scratch_pool, scratch_pool));
-      SVN_ERR(svn_io_remove_file2(pristine_abspath, TRUE, scratch_pool));
+      SVN_ERR(pristine_remove(pdh, sha1_checksum, scratch_pool));
     }
 
   return SVN_NO_ERROR;
@@ -8348,6 +8375,8 @@ svn_wc__db_wclock_release(svn_wc__db_t *
             case svn_wc__db_status_obstructed_delete:
               return SVN_NO_ERROR; /* Administrative area missing
                                       -> Lock gone */
+            default:
+              break;
           }
       SVN_ERR_ASSERT(*local_relpath == '\0');
     }

Modified: subversion/branches/issue-2779-dev/subversion/libsvn_wc/wc_db.h
URL: http://svn.apache.org/viewvc/subversion/branches/issue-2779-dev/subversion/libsvn_wc/wc_db.h?rev=980929&r1=980928&r2=980929&view=diff
==============================================================================
--- subversion/branches/issue-2779-dev/subversion/libsvn_wc/wc_db.h (original)
+++ subversion/branches/issue-2779-dev/subversion/libsvn_wc/wc_db.h Fri Jul 30 19:10:14 2010
@@ -2536,6 +2536,17 @@ svn_wc__db_drop_root(svn_wc__db_t *db,
                      const char *local_abspath,
                      apr_pool_t *scratch_pool);
 
+/* Internal version of svn_wc__node_get_copyfrom_info */
+svn_error_t *
+svn_wc__internal_get_copyfrom_info(const char **copyfrom_root_url,
+                                   const char **copyfrom_repos_relpath,
+                                   const char **copyfrom_url,
+                                   svn_revnum_t *copyfrom_rev,
+                                   svn_boolean_t *is_copy_target,
+                                   svn_wc__db_t *db,
+                                   const char *local_abspath,
+                                   apr_pool_t *result_pool,
+                                   apr_pool_t *scratch_pool);
 /* @} */
 
 

Modified: subversion/branches/issue-2779-dev/subversion/svnrdump/dumpfile_parser.c
URL: http://svn.apache.org/viewvc/subversion/branches/issue-2779-dev/subversion/svnrdump/dumpfile_parser.c?rev=980929&r1=980928&r2=980929&view=diff
==============================================================================
--- subversion/branches/issue-2779-dev/subversion/svnrdump/dumpfile_parser.c (original)
+++ subversion/branches/issue-2779-dev/subversion/svnrdump/dumpfile_parser.c Fri Jul 30 19:10:14 2010
@@ -13,10 +13,31 @@ new_revision_record(void **revision_bato
 		    apr_pool_t *pool)
 {
   struct revision_baton *rb;
+  apr_hash_index_t *hi;
+  const struct svn_delta_editor_t *commit_editor;
+  void *root_baton;
+
   rb = apr_pcalloc(pool, sizeof(*rb));
   rb->pb = parse_baton;
+  commit_editor = rb->pb->commit_editor;
 
-  fprintf(stderr, "new_revision_record called\n");
+  for (hi = apr_hash_first(pool, headers); hi; hi = apr_hash_next(hi))
+    {
+      const void *key;
+      void *val;
+      const char *hname, *hval;
+
+      apr_hash_this(hi, &key, NULL, &val);
+      hname = key;
+      hval = val;
+
+      if (strcmp(hname, SVN_REPOS_DUMPFILE_REVISION_NUMBER) == 0)
+        rb->rev = atoi(hval);
+    }
+
+  SVN_ERR(commit_editor->open_root(rb->pb->commit_edit_baton, rb->rev,
+                                   pool, &root_baton));
+  rb->dir_baton = root_baton;
 
   *revision_baton = rb;
   return SVN_NO_ERROR;
@@ -37,10 +58,65 @@ new_node_record(void **node_baton,
                 apr_pool_t *pool)
 {
   struct node_baton *nb;
+  apr_hash_index_t *hi;
+  void *file_baton;
+  void *child_baton;
+  const struct svn_delta_editor_t *commit_editor;
   nb = apr_pcalloc(pool, sizeof(*nb));
   nb->rb = revision_baton;
 
-  fprintf(stderr, "new_node_record called\n");
+  commit_editor = nb->rb->pb->commit_editor;
+
+  for (hi = apr_hash_first(pool, headers); hi; hi = apr_hash_next(hi))
+    {
+      const void *key;
+      void *val;
+      const char *hname, *hval;
+
+      apr_hash_this(hi, &key, NULL, &val);
+      hname = key;
+      hval = val;
+
+      /* Parse the different kinds of headers we can encounter and
+         stuff them into the node_baton for writing later */
+      if (strcmp(hname, SVN_REPOS_DUMPFILE_NODE_PATH) == 0)
+        nb->path = apr_pstrdup(pool, hval);
+      if (strcmp(hname, SVN_REPOS_DUMPFILE_NODE_KIND) == 0)
+        nb->kind = strcmp(hval, "file") == 0 ? svn_node_file : svn_node_dir;
+      if (strcmp(hname, SVN_REPOS_DUMPFILE_NODE_ACTION) == 0)
+        {
+          if (strcmp(hval, "add") == 0)
+            nb->action = svn_node_action_add;
+          if (strcmp(hval, "change") == 0)
+            nb->action = svn_node_action_change;
+          if (strcmp(hval, "delete") == 0)
+            nb->action = svn_node_action_delete;
+          if (strcmp(hval, "replace") == 0)
+            nb->action = svn_node_action_replace;
+        }
+      if (strcmp(hname, SVN_REPOS_DUMPFILE_NODE_COPYFROM_REV) == 0)
+        nb->copyfrom_rev = atoi(hval);
+      if (strcmp(hname, SVN_REPOS_DUMPFILE_NODE_COPYFROM_PATH) == 0)
+        nb->copyfrom_path = apr_pstrdup(pool, hval);
+    }
+
+  if (nb->action == svn_node_action_add)
+    {
+      if (nb->kind == svn_node_file)
+        {
+          SVN_ERR(commit_editor->add_file(nb->path, nb->rb->dir_baton, NULL,
+                                          SVN_INVALID_REVNUM, pool,
+                                          &file_baton));
+          nb->file_baton = file_baton;
+        }
+      else if(nb->kind == svn_node_dir)
+        {
+          SVN_ERR(commit_editor->add_directory(nb->path, nb->rb->dir_baton,
+                                               NULL, SVN_INVALID_REVNUM,
+                                               pool, &child_baton));
+          nb->rb->dir_baton = child_baton;
+        }
+    }
 
   *node_baton = nb;
   return SVN_NO_ERROR;
@@ -80,30 +156,7 @@ static svn_error_t *
 set_fulltext(svn_stream_t **stream,
              void *node_baton)
 {
-  return SVN_NO_ERROR;
-}
-
-#if 0
-static svn_error_t *
-apply_window(svn_txdelta_window_t *window, void *baton)
-{
-  struct apply_baton *apply_baton;
-  apr_size_t tlen;
-  apply_baton = baton;
-  if (window == NULL)
-    return SVN_NO_ERROR;
-
-  tlen = window->tview_len;
-  apply_baton->target = apr_pcalloc(apply_baton->pool, tlen);
-  svn_txdelta_apply_instructions(window, apply_baton->source,
-                                 apply_baton->target, &tlen);
-  return SVN_NO_ERROR;
-}
-#endif
-
-static svn_error_t *
-apply_window(svn_txdelta_window_t *window, void *baton)
-{
+  /* ### Not implemented */
   return SVN_NO_ERROR;
 }
 
@@ -113,32 +166,52 @@ apply_textdelta(svn_txdelta_window_handl
                 void *node_baton)
 {
   struct node_baton *nb;
+  const struct svn_delta_editor_t *commit_editor;
+  apr_pool_t *pool;
   nb = node_baton;
-  *handler = apply_window;
-  *handler_baton = nb->rb->pb->ab;
-  return SVN_NO_ERROR;
+  commit_editor = nb->rb->pb->commit_editor;
+  pool = nb->rb->pb->pool;
+  return commit_editor->apply_textdelta(nb->file_baton, NULL, pool,
+                                        handler, handler_baton);
 }
 
 static svn_error_t *
 close_node(void *baton)
 {
+  struct node_baton *nb;
+  const struct svn_delta_editor_t *commit_editor;  
+  nb = baton;
+  commit_editor = nb->rb->pb->commit_editor;
+  if (nb->kind == svn_node_file)
+    SVN_ERR(commit_editor->close_file(nb->file_baton, NULL,
+                                      nb->rb->pb->pool));
+  else if(nb->kind == svn_node_dir)
+    SVN_ERR(commit_editor->close_directory(nb->rb->dir_baton,
+                                           nb->rb->pb->pool));
+
   return SVN_NO_ERROR;
 }
 
 static svn_error_t *
 close_revision(void *baton)
 {
+  struct revision_baton *rb;
+  const struct svn_delta_editor_t *commit_editor;    
+  rb = baton;
+  commit_editor = rb->pb->commit_editor;
+  SVN_ERR(commit_editor->close_edit(rb->pb->commit_edit_baton, rb->pb->pool));
   return SVN_NO_ERROR;
 }
 
 svn_error_t *
 build_dumpfile_parser(const svn_repos_parse_fns2_t **parser,
                       void **parse_baton,
+                      const struct svn_delta_editor_t *editor,
+                      void *edit_baton,
                       apr_pool_t *pool)
 {
   svn_repos_parse_fns2_t *pf;
   struct parse_baton *pb;
-  struct apply_baton *ab;
 
   pf = apr_pcalloc(pool, sizeof(*pf));
   pf->new_revision_record = new_revision_record;
@@ -154,9 +227,9 @@ build_dumpfile_parser(const svn_repos_pa
   pf->close_revision = close_revision;
 
   pb = apr_pcalloc(pool, sizeof(*pb));
-  ab = apr_pcalloc(pool, sizeof(struct apply_baton));
-  ab->source = apr_pstrmemdup(pool, " ", sizeof(" "));
-  pb->ab = ab;
+  pb->commit_editor = editor;
+  pb->commit_edit_baton = edit_baton;
+  pb->pool = pool;
 
   *parser = pf;
   *parse_baton = pb;

Modified: subversion/branches/issue-2779-dev/subversion/svnrdump/load_editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/issue-2779-dev/subversion/svnrdump/load_editor.c?rev=980929&r1=980928&r2=980929&view=diff
==============================================================================
--- subversion/branches/issue-2779-dev/subversion/svnrdump/load_editor.c (original)
+++ subversion/branches/issue-2779-dev/subversion/svnrdump/load_editor.c Fri Jul 30 19:10:14 2010
@@ -46,13 +46,13 @@ commit_callback(const svn_commit_info_t 
 svn_error_t *
 drive_load_editor(const svn_delta_editor_t *editor,
                   void *edit_baton,
-                  struct operation *operation,
                   svn_stream_t *stream,
                   apr_pool_t *pool)
 {
   const svn_repos_parse_fns2_t *parser;
   void *pb;
-  SVN_ERR(build_dumpfile_parser(&parser, &pb, pool));
+
+  SVN_ERR(build_dumpfile_parser(&parser, &pb, editor, edit_baton, pool));
   SVN_ERR(svn_repos_parse_dumpstream2(stream, parser, pb,
                                       NULL, NULL, pool));
 
@@ -64,32 +64,21 @@ drive_load_editor(const svn_delta_editor
 svn_error_t *
 get_load_editor(const svn_delta_editor_t **editor,
                 void **edit_baton,
-                struct operation **root_operation,
                 svn_ra_session_t *session,
                 apr_pool_t *pool)
 {
-  const svn_delta_editor_t *de;
-  struct operation *root;
-  struct commit_dir_baton *db;
+  const svn_delta_editor_t *delta_editor;
   apr_hash_t *revprop_table;
-  void *cb;
+  void *delta_edit_baton;
 
-  root = apr_pcalloc(pool, sizeof(*root));
-  db = apr_pcalloc(pool, sizeof(*db));
-  root->baton = db;
   revprop_table = apr_hash_make(pool);
-
-  SVN_ERR(svn_ra_get_latest_revnum(session, &(root->revision), pool));
  
-  /* Call the commit editor and get back a delta_editor and
-     commit_baton to use for performing the actual commit */
-  SVN_ERR(svn_ra_get_commit_editor3(session, &de, &cb, revprop_table,
-                                    commit_callback, NULL, NULL, FALSE, pool));
-  SVN_ERR(de->open_root(cb, root->revision, pool, root->baton));
-
-  *editor = de;
-  *edit_baton = cb;
-  *root_operation = root;
+  /* Call the commit editor and get back a delta_editor and delta_editor_baton */
+  SVN_ERR(svn_ra_get_commit_editor3(session, &delta_editor, &delta_edit_baton,
+                                    revprop_table, commit_callback,
+                                    NULL, NULL, FALSE, pool));
+  *editor = delta_editor;
+  *edit_baton = delta_edit_baton;
 
   return SVN_NO_ERROR;
 }

Modified: subversion/branches/issue-2779-dev/subversion/svnrdump/load_editor.h
URL: http://svn.apache.org/viewvc/subversion/branches/issue-2779-dev/subversion/svnrdump/load_editor.h?rev=980929&r1=980928&r2=980929&view=diff
==============================================================================
--- subversion/branches/issue-2779-dev/subversion/svnrdump/load_editor.h (original)
+++ subversion/branches/issue-2779-dev/subversion/svnrdump/load_editor.h Fri Jul 30 19:10:14 2010
@@ -29,22 +29,13 @@
 #define LOAD_EDITOR_H_
 
 /**
- * Baton used by the txdelta applier.
- */
-struct apply_baton
-{
-  const char *source;
-  char *target;
-  apr_pool_t *pool;
-};
-
-/**
- * General baton used by the parser functions. Contains a link to
- * apply baton.
+ * General baton used by the parser functions.
  */
 struct parse_baton
 {
-  struct apply_baton *ab;
+  const svn_delta_editor_t *commit_editor;
+  void *commit_edit_baton;
+  apr_pool_t *pool;
 };
 
 /**
@@ -55,12 +46,13 @@ struct node_baton
 {
   const char *path;
   svn_node_kind_t kind;
+  enum svn_node_action action;
 
   svn_revnum_t copyfrom_rev;
   const char *copyfrom_path;
 
+  void *file_baton;
   struct revision_baton *rb;
-  apr_pool_t *pool;
 };
 
 /**
@@ -71,55 +63,25 @@ struct revision_baton
 {
   svn_revnum_t rev;
 
-  svn_fs_txn_t *txn;
-  svn_fs_root_t *txn_root;
-
   const svn_string_t *datestamp;
 
-  apr_int32_t rev_offset;
-
   struct parse_baton *pb;
   apr_pool_t *pool;
-};
-
-/**
- * Used to represent an operation to perform while driving the load
- * editor.
- */
-struct operation {
-  enum {
-    OP_OPEN,
-    OP_DELETE,
-    OP_ADD,
-    OP_REPLACE,
-    OP_PROPSET
-  } operation;
-
-  svn_revnum_t revision;        /* The revision on which the operation is being performed */
-  void *baton;                  /* Represents a commit_dir_baton object */
-};
-
-/**
- * A directory baton from commit.c.
- */
-struct commit_dir_baton
-{
-  struct commit_baton *edit_baton;
-  struct commit_dir_baton *parent;
-  const char *path; /* the -absolute- path to this dir in the fs */
-  svn_revnum_t base_rev;        /* the revision I'm based on  */
-  svn_boolean_t was_copied; /* was this directory added with history? */
-  apr_pool_t *pool; /* my personal pool, in which I am allocated. */
+  void *dir_baton;                    /* Keep track of dirs */
 };
 
 /**
  * Build up a @a parser for parsing a dumpfile stream from @a stream
  * set to fire the appropriate callbacks in load editor along with a
- * @a parser_baton, using @a pool for all memory allocations.
+ * @a parser_baton, using @a pool for all memory allocations. The
+ * @a editor/ @a edit_baton are central to the functionality of the
+ *  parser.
  */
 svn_error_t *
 build_dumpfile_parser(const svn_repos_parse_fns2_t **parser,
                       void **parse_baton,
+                      const struct svn_delta_editor_t *editor,
+                      void *edit_baton,
                       apr_pool_t *pool);
 
 /**
@@ -129,20 +91,17 @@ build_dumpfile_parser(const svn_repos_pa
 svn_error_t *
 drive_load_editor(const svn_delta_editor_t *editor,
                   void *edit_baton,
-                  struct operation *operation,
                   svn_stream_t *stream,
                   apr_pool_t *pool);
 
 /**
- * Get a load editor @a editor along with an @a edit_baton and an
- * operation @a root_operation corresponding to open_root, all
- * allocated in @a pool. The load editor will commit revisions to @a
- * session when driven using drive_load_editor().
+ * Get a load editor @a editor along with an @a edit_baton allocated
+ * in @a pool. The load editor will commit revisions to @a session
+ * when driven using drive_load_editor().
  */
 svn_error_t *
 get_load_editor(const svn_delta_editor_t **editor,
                 void **edit_baton,
-                struct operation **root_operation,
                 svn_ra_session_t *session,
                 apr_pool_t *pool);
 

Modified: subversion/branches/issue-2779-dev/subversion/svnrdump/svnrdump.c
URL: http://svn.apache.org/viewvc/subversion/branches/issue-2779-dev/subversion/svnrdump/svnrdump.c?rev=980929&r1=980928&r2=980929&view=diff
==============================================================================
--- subversion/branches/issue-2779-dev/subversion/svnrdump/svnrdump.c (original)
+++ subversion/branches/issue-2779-dev/subversion/svnrdump/svnrdump.c Fri Jul 30 19:10:14 2010
@@ -293,15 +293,12 @@ load_revisions(svn_ra_session_t *session
   void *load_baton;
   apr_file_t *stdin_file;
   svn_stream_t *stdin_stream;
-  struct operation *root_operation;
 
   apr_file_open_stdin(&stdin_file, pool);
   stdin_stream = svn_stream_from_aprfile2(stdin_file, FALSE, pool);
 
-  SVN_ERR(get_load_editor(&load_editor, &load_baton, &root_operation,
-                          session, pool));
-  SVN_ERR(drive_load_editor(load_editor, load_baton, root_operation,
-                            stdin_stream, pool));
+  SVN_ERR(get_load_editor(&load_editor, &load_baton, session, pool));
+  SVN_ERR(drive_load_editor(load_editor, load_baton, stdin_stream, pool));
 
   svn_stream_close(stdin_stream);
 

Modified: subversion/branches/issue-2779-dev/subversion/tests/cmdline/basic_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/issue-2779-dev/subversion/tests/cmdline/basic_tests.py?rev=980929&r1=980928&r2=980929&view=diff
==============================================================================
--- subversion/branches/issue-2779-dev/subversion/tests/cmdline/basic_tests.py (original)
+++ subversion/branches/issue-2779-dev/subversion/tests/cmdline/basic_tests.py Fri Jul 30 19:10:14 2010
@@ -2520,6 +2520,37 @@ def meta_correct_library_being_used(sbox
   svntest.actions.run_and_verify_svn("is $http_library available",
                                      expected_output, [], '--version')
 
+def delete_and_add_same_file(sbox):
+  "commit deletes a file and adds one with same text"
+  sbox.build()
+
+  wc_dir = sbox.wc_dir
+
+  iota = os.path.join(wc_dir, 'iota')
+  iota2 = os.path.join(wc_dir, 'iota2')
+
+  shutil.copyfile(iota, iota2)
+
+  svntest.main.run_svn(None, 'rm', iota)
+  svntest.main.run_svn(None, 'add', iota2)
+
+  expected_output = wc.State(wc_dir, {
+    'iota' : Item(verb='Deleting'),
+    'iota2' : Item(verb='Adding'),
+    })
+
+  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+  expected_status.remove('iota')
+  expected_status.add({ 'iota2':  Item(status='  ', wc_rev='2')})
+
+  # At one time the commit post-processing used to fail with "Pristine text
+  # not found".
+  svntest.actions.run_and_verify_commit(wc_dir,
+                                        expected_output,
+                                        expected_status,
+                                        None,
+                                        wc_dir)
+
 #----------------------------------------------------------------------
 
 ########################################################################
@@ -2579,6 +2610,7 @@ test_list = [ None,
               delete_from_url_with_spaces,
               SkipUnless(meta_correct_library_being_used,
                          svntest.main.is_ra_type_dav),
+              delete_and_add_same_file,
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/issue-2779-dev/subversion/tests/cmdline/diff_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/issue-2779-dev/subversion/tests/cmdline/diff_tests.py?rev=980929&r1=980928&r2=980929&view=diff
==============================================================================
--- subversion/branches/issue-2779-dev/subversion/tests/cmdline/diff_tests.py (original)
+++ subversion/branches/issue-2779-dev/subversion/tests/cmdline/diff_tests.py Fri Jul 30 19:10:14 2010
@@ -3474,13 +3474,10 @@ def diff_prop_multiple_hunks(sbox):
              ])
   svntest.main.run_svn(None,
                        "propset", "prop", prop_val, iota_path)
-  expected_output = [
-    "Index: iota\n",
-    "===================================================================\n",
-    "--- iota\t(revision 2)\n",
-    "+++ iota\t(working copy)\n",
+  expected_output = make_diff_header(iota_path, 'revision 2', 
+                                     'working copy') + [
     "\n",
-    "Property changes on: iota\n",
+    "Property changes on: %s\n" % iota_path.replace('\\', '/'),
     "___________________________________________________________________\n",
     "Modified: prop\n",
     "## -1,6 +1,7 ##\n",
@@ -3564,7 +3561,7 @@ test_list = [ None,
               diff_git_format_url_wc,
               diff_git_format_url_url,
               XFail(diff_prop_missing_context),
-              XFail(diff_prop_multiple_hunks),
+              diff_prop_multiple_hunks,
               ]
 
 if __name__ == '__main__':

Modified: subversion/branches/issue-2779-dev/subversion/tests/cmdline/patch_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/issue-2779-dev/subversion/tests/cmdline/patch_tests.py?rev=980929&r1=980928&r2=980929&view=diff
==============================================================================
--- subversion/branches/issue-2779-dev/subversion/tests/cmdline/patch_tests.py (original)
+++ subversion/branches/issue-2779-dev/subversion/tests/cmdline/patch_tests.py Fri Jul 30 19:10:14 2010
@@ -2598,6 +2598,362 @@ def patch_add_path_with_props(sbox):
                                        1, # check-props
                                        1) # dry-run
 
+def patch_prop_offset(sbox):
+  "property patch with offset searching"
+
+  sbox.build()
+  wc_dir = sbox.wc_dir
+
+  patch_file_path = make_patch_path(sbox)
+  iota_path = os.path.join(wc_dir, 'iota')
+
+  prop1_content = ''.join([
+    "Dear internet user,\n",
+    # The missing line here will cause the first hunk to match early
+    "We wish to congratulate you over your email success in our computer\n",
+    "Balloting. This is a Millennium Scientific Electronic Computer Draw\n",
+    "in which email addresses were used. All participants were selected\n",
+    "through a computer ballot system drawn from over 100,000 company\n",
+    "and 50,000,000 individual email addresses from all over the world.\n",
+    "\n",
+    "Your email address drew and have won the sum of  750,000 Euros\n",
+    "( Seven Hundred and Fifty Thousand Euros) in cash credited to\n",
+    "file with\n",
+    "    REFERENCE NUMBER: ESP/WIN/008/05/10/MA;\n",
+    "These extra lines will cause the second hunk to match late\n",
+    "These extra lines will cause the second hunk to match late\n",
+    "These extra lines will cause the second hunk to match late\n",
+    "These extra lines will cause the second hunk to match late\n",
+    "These extra lines will cause the second hunk to match late\n",
+    "    WINNING NUMBER : 14-17-24-34-37-45-16\n",
+    "    BATCH NUMBERS :\n",
+    "    EULO/1007/444/606/08;\n",
+    "    SERIAL NUMBER: 45327\n",
+    "and PROMOTION DATE: 13th June. 2009\n",
+    "\n",
+    "To claim your winning prize, you are to contact the appointed\n",
+    "agent below as soon as possible for the immediate release of your\n",
+    "winnings with the below details.\n",
+    "\n",
+    "Again, we wish to congratulate you over your email success in our\n"
+    "computer Balloting.\n",
+  ])
+
+  # prop2's content will make both a late and early match possible.
+  # The hunk to be applied is replicated here for reference:
+  # ## -5,6 +5,7 ##
+  #  property
+  #  property
+  #  property
+  # +x
+  #  property
+  #  property
+  #  property
+  #
+  # This hunk wants to be applied at line 5, but that isn't
+  # possible because line 8 ("zzz") does not match "property".
+  # The early match happens at line 2 (offset 3 = 5 - 2).
+  # The late match happens at line 9 (offset 4 = 9 - 5).
+  # Subversion will pick the early match in this case because it
+  # is closer to line 5.
+  prop2_content = ''.join([
+    "property\n",
+    "property\n",
+    "property\n",
+    "property\n",
+    "property\n",
+    "property\n",
+    "property\n",
+    "zzz\n",
+    "property\n",
+    "property\n",
+    "property\n",
+    "property\n",
+    "property\n",
+    "property\n",
+    "property\n"
+  ])
+
+  # Set iota prop contents
+  svntest.main.run_svn(None, 'propset', 'prop1', prop1_content,
+                       iota_path)
+  svntest.main.run_svn(None, 'propset', 'prop2', prop2_content,
+                       iota_path)
+  expected_output = svntest.wc.State(wc_dir, {
+    'iota'       : Item(verb='Sending'),
+    })
+  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+  expected_status.tweak('iota', wc_rev=2)
+  svntest.actions.run_and_verify_commit(wc_dir, expected_output,
+                                        expected_status, None, wc_dir)
+
+  # Apply patch
+
+  unidiff_patch = [
+    "Index: iota\n",
+    "===================================================================\n",
+    "--- iota	(revision XYZ)\n",
+    "+++ iota	(working copy)\n",
+    "\n",
+    "Property changes on: iota\n",
+    "-------------------------------------------------------------------\n",
+    "Modified: prop1\n",
+    "## -6,6 +6,9 ##\n",
+    " through a computer ballot system drawn from over 100,000 company\n",
+    " and 50,000,000 individual email addresses from all over the world.\n",
+    " \n",
+    "+It is a promotional program aimed at encouraging internet users;\n",
+    "+therefore you do not need to buy ticket to enter for it.\n",
+    "+\n",
+    " Your email address drew and have won the sum of  750,000 Euros\n",
+    " ( Seven Hundred and Fifty Thousand Euros) in cash credited to\n",
+    " file with\n",
+    "## -14,11 +17,8 ##\n",
+    "     BATCH NUMBERS :\n",
+    "     EULO/1007/444/606/08;\n",
+    "     SERIAL NUMBER: 45327\n",
+    "-and PROMOTION DATE: 13th June. 2009\n",
+    "+and PROMOTION DATE: 14th June. 2009\n",
+    " \n",
+    " To claim your winning prize, you are to contact the appointed\n",
+    " agent below as soon as possible for the immediate release of your\n",
+    " winnings with the below details.\n",
+    "-\n",
+    "-Again, we wish to congratulate you over your email success in our\n",
+    "-computer Balloting.\n",
+    "Modified: prop2\n",
+    "## -5,6 +5,7 ##\n",
+    " property\n",
+    " property\n",
+    " property\n",
+    "+x\n",
+    " property\n",
+    " property\n",
+    " property\n",
+  ]
+
+  svntest.main.file_write(patch_file_path, ''.join(unidiff_patch))
+
+  prop1_content = ''.join([
+    "Dear internet user,\n",
+    "We wish to congratulate you over your email success in our computer\n",
+    "Balloting. This is a Millennium Scientific Electronic Computer Draw\n",
+    "in which email addresses were used. All participants were selected\n",
+    "through a computer ballot system drawn from over 100,000 company\n",
+    "and 50,000,000 individual email addresses from all over the world.\n",
+    "\n",
+    "It is a promotional program aimed at encouraging internet users;\n",
+    "therefore you do not need to buy ticket to enter for it.\n",
+    "\n",
+    "Your email address drew and have won the sum of  750,000 Euros\n",
+    "( Seven Hundred and Fifty Thousand Euros) in cash credited to\n",
+    "file with\n",
+    "    REFERENCE NUMBER: ESP/WIN/008/05/10/MA;\n",
+    "These extra lines will cause the second hunk to match late\n",
+    "These extra lines will cause the second hunk to match late\n",
+    "These extra lines will cause the second hunk to match late\n",
+    "These extra lines will cause the second hunk to match late\n",
+    "These extra lines will cause the second hunk to match late\n",
+    "    WINNING NUMBER : 14-17-24-34-37-45-16\n",
+    "    BATCH NUMBERS :\n",
+    "    EULO/1007/444/606/08;\n",
+    "    SERIAL NUMBER: 45327\n",
+    "and PROMOTION DATE: 14th June. 2009\n",
+    "\n",
+    "To claim your winning prize, you are to contact the appointed\n",
+    "agent below as soon as possible for the immediate release of your\n",
+    "winnings with the below details.\n",
+  ])
+
+  prop2_content = ''.join([
+    "property\n",
+    "property\n",
+    "property\n",
+    "property\n",
+    "x\n",
+    "property\n",
+    "property\n",
+    "property\n",
+    "zzz\n",
+    "property\n",
+    "property\n",
+    "property\n",
+    "property\n",
+    "property\n",
+    "property\n",
+    "property\n",
+  ])
+
+  os.chdir(wc_dir)
+
+  expected_output = [
+    ' U        iota\n',
+    '>         applied hunk ## -6,6 +6,9 ## with offset -1 (prop1)\n',
+    '>         applied hunk ## -14,11 +17,8 ## with offset 4 (prop1)\n',
+    '>         applied hunk ## -5,6 +5,7 ## with offset -3 (prop2)\n',
+  ]
+
+  expected_disk = svntest.main.greek_state.copy()
+  expected_disk.tweak('iota', props = {'prop1' : prop1_content,
+                                       'prop2' : prop2_content})
+
+  expected_status = svntest.actions.get_virginal_state('.', 1)
+  expected_status.tweak('iota', status=' M', wc_rev=2)
+
+  expected_skip = wc.State('', { })
+
+  svntest.actions.run_and_verify_patch('.', os.path.abspath(patch_file_path),
+                                       expected_output,
+                                       expected_disk,
+                                       expected_status,
+                                       expected_skip,
+                                       None, # expected err
+                                       1, # check-props
+                                       1) # dry-run
+
+def patch_prop_with_fuzz(sbox):
+  "property patch with fuzz"
+
+  sbox.build()
+  wc_dir = sbox.wc_dir
+  patch_file_path = make_patch_path(sbox)
+
+  mu_path = os.path.join(wc_dir, 'A', 'mu')
+
+  # We have replaced a couple of lines to cause fuzz. Those lines contains
+  # the word fuzz
+  prop_contents = ''.join([
+    "Line replaced for fuzz = 1\n",
+    "\n",
+    "We wish to congratulate you over your email success in our computer\n",
+    "Balloting. This is a Millennium Scientific Electronic Computer Draw\n",
+    "in which email addresses were used. All participants were selected\n",
+    "through a computer ballot system drawn from over 100,000 company\n",
+    "and 50,000,000 individual email addresses from all over the world.\n",
+    "Line replaced for fuzz = 2 with only the second context line changed\n",
+    "Your email address drew and have won the sum of  750,000 Euros\n",
+    "( Seven Hundred and Fifty Thousand Euros) in cash credited to\n",
+    "file with\n",
+    "    REFERENCE NUMBER: ESP/WIN/008/05/10/MA;\n",
+    "    WINNING NUMBER : 14-17-24-34-37-45-16\n",
+    "    BATCH NUMBERS :\n",
+    "    EULO/1007/444/606/08;\n",
+    "    SERIAL NUMBER: 45327\n",
+    "and PROMOTION DATE: 13th June. 2009\n",
+    "\n",
+    "This line is inserted to cause an offset of +1\n",
+    "To claim your winning prize, you are to contact the appointed\n",
+    "agent below as soon as possible for the immediate release of your\n",
+    "winnings with the below details.\n",
+    "\n",
+    "Line replaced for fuzz = 2\n",
+    "Line replaced for fuzz = 2\n",
+  ])
+
+  # Set mu prop contents
+  svntest.main.run_svn(None, 'propset', 'prop', prop_contents,
+                       mu_path)
+  expected_output = svntest.wc.State(wc_dir, {
+    'A/mu'       : Item(verb='Sending'),
+    })
+  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+  expected_status.tweak('A/mu', wc_rev=2)
+  svntest.actions.run_and_verify_commit(wc_dir, expected_output,
+                                      expected_status, None, wc_dir)
+
+  unidiff_patch = [
+    "Index: mu\n",
+    "===================================================================\n",
+    "--- A/mu\t(revision 0)\n",
+    "+++ A/mu\t(revision 0)\n",
+    "\n",
+    "Property changes on: mu\n",
+    "Modified: prop\n",
+    "## -1,6 +1,7 ##\n",
+    " Dear internet user,\n",
+    " \n",
+    " We wish to congratulate you over your email success in our computer\n",
+    "+A new line here\n",
+    " Balloting. This is a Millennium Scientific Electronic Computer Draw\n",
+    " in which email addresses were used. All participants were selected\n",
+    " through a computer ballot system drawn from over 100,000 company\n",
+    "## -7,7 +8,9 ##\n",
+    " and 50,000,000 individual email addresses from all over the world.\n",
+    " \n",
+    " Your email address drew and have won the sum of  750,000 Euros\n",
+    "+Another new line\n",
+    " ( Seven Hundred and Fifty Thousand Euros) in cash credited to\n",
+    "+A third new line\n",
+    " file with\n",
+    "    REFERENCE NUMBER: ESP/WIN/008/05/10/MA;\n",
+    "    WINNING NUMBER : 14-17-24-34-37-45-16\n",
+    "## -19,6 +20,7 ##\n",
+    " To claim your winning prize, you are to contact the appointed\n",
+    " agent below as soon as possible for the immediate release of your\n",
+    " winnings with the below details.\n",
+    "+A fourth new line\n",
+    " \n",
+    " Again, we wish to congratulate you over your email success in our\n"
+    " computer Balloting. [No trailing newline here]"
+  ]
+
+  svntest.main.file_write(patch_file_path, ''.join(unidiff_patch))
+
+  prop_contents = ''.join([
+    "Line replaced for fuzz = 1\n",
+    "\n",
+    "We wish to congratulate you over your email success in our computer\n",
+    "A new line here\n",
+    "Balloting. This is a Millennium Scientific Electronic Computer Draw\n",
+    "in which email addresses were used. All participants were selected\n",
+    "through a computer ballot system drawn from over 100,000 company\n",
+    "and 50,000,000 individual email addresses from all over the world.\n",
+    "Line replaced for fuzz = 2 with only the second context line changed\n",
+    "Your email address drew and have won the sum of  750,000 Euros\n",
+    "Another new line\n",
+    "( Seven Hundred and Fifty Thousand Euros) in cash credited to\n",
+    "A third new line\n",
+    "file with\n",
+    "    REFERENCE NUMBER: ESP/WIN/008/05/10/MA;\n",
+    "    WINNING NUMBER : 14-17-24-34-37-45-16\n",
+    "    BATCH NUMBERS :\n",
+    "    EULO/1007/444/606/08;\n",
+    "    SERIAL NUMBER: 45327\n",
+    "and PROMOTION DATE: 13th June. 2009\n",
+    "\n",
+    "This line is inserted to cause an offset of +1\n",
+    "To claim your winning prize, you are to contact the appointed\n",
+    "agent below as soon as possible for the immediate release of your\n",
+    "winnings with the below details.\n",
+    "A fourth new line\n",
+    "\n",
+    "Line replaced for fuzz = 2\n",
+    "Line replaced for fuzz = 2\n",
+  ])
+
+  expected_output = [
+    ' U        %s\n' % os.path.join(wc_dir, 'A', 'mu'),
+    '>         applied hunk ## -1,6 +1,7 ## with fuzz 1 (prop)\n',
+    '>         applied hunk ## -7,7 +8,9 ## with fuzz 2 (prop)\n',
+    '>         applied hunk ## -19,6 +20,7 ## with offset 1 and fuzz 2 (prop)\n',
+  ]
+  expected_disk = svntest.main.greek_state.copy()
+  expected_disk.tweak('A/mu', props = {'prop' : prop_contents})
+
+  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+  expected_status.tweak('A/mu', status=' M', wc_rev=2)
+
+  expected_skip = wc.State('', { })
+
+  svntest.actions.run_and_verify_patch(wc_dir, os.path.abspath(patch_file_path),
+                                       expected_output,
+                                       expected_disk,
+                                       expected_status,
+                                       expected_skip,
+                                       None, # expected err
+                                       1, # check-props
+                                       1) # dry-run
+
 ########################################################################
 #Run the tests
 
@@ -2625,6 +2981,8 @@ test_list = [ None,
               patch_same_twice,
               XFail(patch_dir_properties),
               XFail(patch_add_path_with_props),
+              patch_prop_offset,
+              patch_prop_with_fuzz,
             ]
 
 if __name__ == '__main__':