Author: rhuijben
Date: Wed Oct 17 13:15:39 2012
New Revision: 1399220

URL: http://svn.apache.org/viewvc?rev=1399220&view=rev
Log:
Resolve a recently introduced regression in the 'svn cp PATH PATH' code
and move the wc check code to a single place to avoid fixing two cases.

* subversion/libsvn_client/copy.c
  (verify_wc_dsts): New function with extra filestat, extracted from ...
  (verify_wc_srcs_and_dsts): ... this function. Split pool handling.

  (repos_to_wc_copy_locked): Remove duplicated code and call verify_wc_dsts
    instead.

  (try_copy): Update caller.

* subversion/tests/cmdline/copy_tests.py
  (mv_unversioned_file,
  (copy_deleted_dir): Expect more detailed error messages.

Modified:
    subversion/trunk/subversion/libsvn_client/copy.c
    subversion/trunk/subversion/tests/cmdline/copy_tests.py

Modified: subversion/trunk/subversion/libsvn_client/copy.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/copy.c?rev=1399220&r1=1399219&r2=1399220&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/copy.c (original)
+++ subversion/trunk/subversion/libsvn_client/copy.c Wed Oct 17 13:15:39 2012
@@ -365,18 +365,21 @@ do_wc_to_wc_moves(const apr_array_header
   return svn_error_trace(err);
 }
 
-
+/* Verify that the destinations stored in COPY_PAIRS are valid working copy
+   destinations and set pair->dst_parent_abspath and pair->base_name for each
+   item to the resulting location if they do */
 static svn_error_t *
-verify_wc_srcs_and_dsts(const apr_array_header_t *copy_pairs,
-                        svn_boolean_t make_parents,
-                        svn_boolean_t is_move,
-                        svn_client_ctx_t *ctx,
-                        apr_pool_t *pool)
+verify_wc_dsts(const apr_array_header_t *copy_pairs,
+               svn_boolean_t make_parents,
+               svn_boolean_t is_move,
+               svn_client_ctx_t *ctx,
+               apr_pool_t *result_pool,
+               apr_pool_t *scratch_pool)
 {
   int i;
-  apr_pool_t *iterpool = svn_pool_create(pool);
+  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
 
-  /* Check that all of our SRCs exist, and all the DSTs don't. */
+  /* Check that DST does not exist, but its parent does */
   for (i = 0; i < copy_pairs->nelts; i++)
     {
       svn_client__copy_pair_t *pair = APR_ARRAY_IDX(copy_pairs, i,
@@ -385,15 +388,6 @@ verify_wc_srcs_and_dsts(const apr_array_
 
       svn_pool_clear(iterpool);
 
-      /* Verify that SRC_PATH exists. */
-      SVN_ERR(svn_io_check_path(pair->src_abspath_or_url, &pair->src_kind,
-                                iterpool));
-      if (pair->src_kind == svn_node_none)
-        return svn_error_createf(
-          SVN_ERR_NODE_UNKNOWN_KIND, NULL,
-          _("Path '%s' does not exist"),
-          svn_dirent_local_style(pair->src_abspath_or_url, pool));
-
       /* If DST_PATH does not exist, then its basename will become a new
          file or dir added to its parent (possibly an implicit '.').
          Else, just error out. */
@@ -419,8 +413,30 @@ verify_wc_srcs_and_dsts(const apr_array_
                   svn_dirent_local_style(pair->dst_abspath_or_url, iterpool));
             }
 
-          if ((! is_not_present)
-              && is_move
+          if (! is_not_present)
+            {
+              svn_boolean_t is_deleted;
+
+              SVN_ERR(svn_wc__node_is_status_deleted(&is_deleted, ctx->wc_ctx,
+                                                     pair->dst_abspath_or_url,
+                                                     scratch_pool));
+
+              if (! is_deleted)
+                return svn_error_createf(
+                            SVN_ERR_ENTRY_EXISTS, NULL,
+                            _("Path '%s' already exists"),
+                            svn_dirent_local_style(pair->dst_abspath_or_url,
+                                                   scratch_pool));
+            }
+        }
+
+      /* Check that there is no unversioned obstruction */
+      SVN_ERR(svn_io_check_path(pair->dst_abspath_or_url, &dst_kind,
+                                iterpool));
+
+      if (dst_kind != svn_node_none)
+        {
+          if (is_move
               && copy_pairs->nelts == 1
               && strcmp(svn_dirent_dirname(pair->src_abspath_or_url, iterpool),
                         svn_dirent_dirname(pair->dst_abspath_or_url,
@@ -435,7 +451,7 @@ verify_wc_srcs_and_dsts(const apr_array_
 
               SVN_ERR(svn_path_cstring_from_utf8(&dst,
                                                  pair->dst_abspath_or_url,
-                                                 pool));
+                                                 scratch_pool));
 
               apr_err = apr_filepath_merge(&dst_apr, NULL, dst,
                                            APR_FILEPATH_TRUENAME, iterpool);
@@ -452,31 +468,22 @@ verify_wc_srcs_and_dsts(const apr_array_
                 {
                   /* Ok, we have a single case only rename. Get out of here */
                   svn_dirent_split(&pair->dst_parent_abspath, &pair->base_name,
-                                   pair->dst_abspath_or_url, pool);
+                                   pair->dst_abspath_or_url, result_pool);
 
                   svn_pool_destroy(iterpool);
                   return SVN_NO_ERROR;
                 }
             }
 
-          if (! is_not_present)
-            {
-              svn_boolean_t is_deleted;
-
-              SVN_ERR(svn_wc__node_is_status_deleted(&is_deleted, ctx->wc_ctx,
-                                                     pair->dst_abspath_or_url, 
pool));
-
-              if (! is_deleted)
-                return svn_error_createf(
+          return svn_error_createf(
                             SVN_ERR_ENTRY_EXISTS, NULL,
-                            _("Path '%s' already exists"),
+                            _("Path '%s' already exists as unversioned node"),
                             svn_dirent_local_style(pair->dst_abspath_or_url,
-                                                   pool));
-            }
+                                                   scratch_pool));
         }
 
       svn_dirent_split(&pair->dst_parent_abspath, &pair->base_name,
-                       pair->dst_abspath_or_url, pool);
+                       pair->dst_abspath_or_url, result_pool);
 
       /* Make sure the destination parent is a directory and produce a clear
          error message if it is not. */
@@ -502,7 +509,7 @@ verify_wc_srcs_and_dsts(const apr_array_
           return svn_error_createf(SVN_ERR_WC_NOT_WORKING_COPY, NULL,
                                    _("Path '%s' is not a directory"),
                                    svn_dirent_local_style(
-                                     pair->dst_parent_abspath, pool));
+                                     pair->dst_parent_abspath, scratch_pool));
         }
     }
 
@@ -511,6 +518,43 @@ verify_wc_srcs_and_dsts(const apr_array_
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *
+verify_wc_srcs_and_dsts(const apr_array_header_t *copy_pairs,
+                        svn_boolean_t make_parents,
+                        svn_boolean_t is_move,
+                        svn_client_ctx_t *ctx,
+                        apr_pool_t *result_pool,
+                        apr_pool_t *scratch_pool)
+{
+  int i;
+  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+
+  /* Check that all of our SRCs exist. */
+  for (i = 0; i < copy_pairs->nelts; i++)
+    {
+      svn_client__copy_pair_t *pair = APR_ARRAY_IDX(copy_pairs, i,
+                                                    svn_client__copy_pair_t *);
+      svn_pool_clear(iterpool);
+
+      /* Verify that SRC_PATH exists. */
+      SVN_ERR(svn_wc_read_kind(&pair->src_kind, ctx->wc_ctx,
+                               pair->src_abspath_or_url, FALSE, iterpool));
+      if (pair->src_kind == svn_node_none)
+        return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
+                                 _("Path '%s' does not exist"),
+                                 svn_dirent_local_style(
+                                        pair->src_abspath_or_url,
+                                        scratch_pool));
+    }
+
+  SVN_ERR(verify_wc_dsts(copy_pairs, make_parents, is_move, ctx,
+                         result_pool, iterpool));
+
+  svn_pool_destroy(iterpool);
+
+  return SVN_NO_ERROR;
+}
+
 
 /* Path-specific state used as part of path_driver_cb_baton. */
 typedef struct path_driver_info_t
@@ -1638,74 +1682,24 @@ repos_to_wc_copy_locked(const apr_array_
                         apr_pool_t *scratch_pool)
 {
   int i;
-  const char *src_uuid = NULL, *dst_uuid = NULL;
   svn_boolean_t same_repositories;
   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
 
   /* We've already checked for physical obstruction by a working file.
      But there could also be logical obstruction by an entry whose
      working file happens to be missing.*/
-  for (i = 0; i < copy_pairs->nelts; i++)
-    {
-      svn_client__copy_pair_t *pair = APR_ARRAY_IDX(copy_pairs, i,
-                                                    svn_client__copy_pair_t *);
-      svn_node_kind_t kind;
-      svn_boolean_t is_not_present;
-      svn_boolean_t is_excluded;
-      svn_boolean_t is_server_excluded;
-      svn_boolean_t is_deleted;
-
-      svn_pool_clear(iterpool);
-
-      SVN_ERR(svn_wc_read_kind(&kind, ctx->wc_ctx, pair->dst_abspath_or_url,
-                               TRUE /* show_hidden */, iterpool));
-      if (kind == svn_node_none)
-        continue;
-
-      /* ### TODO(#2843): Rework these error report. Maybe we can
-         ### simplify the conditions? */
-
-      /* Hidden by client exclusion */
-      SVN_ERR(svn_wc__node_is_not_present(&is_not_present, &is_excluded,
-                                          &is_server_excluded, ctx->wc_ctx,
-                                          pair->dst_abspath_or_url,
-                                          iterpool));
-
-      if (is_not_present)
-        continue;
-
-      if (is_excluded || is_server_excluded)
-        {
-          return svn_error_createf(
-             SVN_ERR_WC_OBSTRUCTED_UPDATE,
-             NULL, _("Path '%s' exists, but is excluded"),
-             svn_dirent_local_style(pair->dst_abspath_or_url, iterpool));
-        }
-
-      /* Working file missing to something other than being scheduled
-         for addition or in "deleted" state. */
-
-      SVN_ERR(svn_wc__node_is_status_deleted(&is_deleted, ctx->wc_ctx,
-                                             pair->dst_abspath_or_url,
-                                             iterpool));
-
-      if (! is_deleted)
-        {
-          return svn_error_createf(
-               SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL,
-               _("Path '%s' exists, but the working file is missing"),
-               svn_dirent_local_style(pair->dst_abspath_or_url, iterpool));
-        }
-    }
+  SVN_ERR(verify_wc_dsts(copy_pairs, FALSE, FALSE, ctx,
+                         scratch_pool, iterpool));
 
   /* Decide whether the two repositories are the same or not. */
   {
     svn_error_t *src_err, *dst_err;
     const char *parent;
     const char *parent_abspath;
+    const char *src_uuid, *dst_uuid;
 
     /* Get the repository uuid of SRC_URL */
-    src_err = svn_ra_get_uuid2(ra_session, &src_uuid, scratch_pool);
+    src_err = svn_ra_get_uuid2(ra_session, &src_uuid, iterpool);
     if (src_err && src_err->apr_err != SVN_ERR_RA_NO_REPOS_UUID)
       return svn_error_trace(src_err);
 
@@ -1720,7 +1714,7 @@ repos_to_wc_copy_locked(const apr_array_
     SVN_ERR(svn_dirent_get_absolute(&parent_abspath, parent, scratch_pool));
     dst_err = svn_client_get_repos_root(NULL /* root_url */, &dst_uuid,
                                         parent_abspath, ctx,
-                                        scratch_pool, scratch_pool);
+                                        iterpool, iterpool);
     if (dst_err && dst_err->apr_err != SVN_ERR_RA_NO_REPOS_UUID)
       return dst_err;
 
@@ -1730,7 +1724,6 @@ repos_to_wc_copy_locked(const apr_array_
        copy-history is attempted. */
     if (src_err || dst_err || (! src_uuid) || (! dst_uuid))
       same_repositories = FALSE;
-
     else
       same_repositories = (strcmp(src_uuid, dst_uuid) == 0);
   }
@@ -2167,7 +2160,7 @@ try_copy(const apr_array_header_t *sourc
   if ((! srcs_are_urls) && (! dst_is_url))
     {
       SVN_ERR(verify_wc_srcs_and_dsts(copy_pairs, make_parents, is_move,
-                                      ctx, pool));
+                                      ctx, pool, pool));
 
       /* Copy or move all targets. */
       if (is_move)

Modified: subversion/trunk/subversion/tests/cmdline/copy_tests.py
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/copy_tests.py?rev=1399220&r1=1399219&r2=1399220&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/copy_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/copy_tests.py Wed Oct 17 13:15:39 
2012
@@ -1878,12 +1878,14 @@ def mv_unversioned_file(sbox):
 
   # Try to move an unversioned file.
   svntest.actions.run_and_verify_svn(None, None,
-                                     ".*unversioned1.* is not under version 
control.*",
+                                     ".*unversioned1' " +
+                                       "(does not exist|is not under version 
control)",
                                      'mv', unver_path_1, dest_path_1)
 
   # Try to forcibly move an unversioned file.
   svntest.actions.run_and_verify_svn(None, None,
-                                     ".*unversioned2.* is not under version 
control.*",
+                                     ".*unversioned2.* " +
+                                       "(does not exist|is not under version 
control)",
                                      'mv',
                                      unver_path_2, dest_path_2)
 
@@ -5457,11 +5459,13 @@ def copy_deleted_dir(sbox):
   sbox.simple_rm('A')
 
   svntest.actions.run_and_verify_svn(None, None,
-                                     'svn: E145000: Path.* does not exist',
+                                     '(svn: E145000: Path.* does not exist)|' +
+                                      "(svn: E155035: Deleted node .* copied)",
                                      'cp', sbox.ospath('iota'),
                                      sbox.ospath('new_iota'))
   svntest.actions.run_and_verify_svn(None, None,
-                                     'svn: E145000: Path.* does not exist',
+                                     '(svn: E145000: Path.* does not exist)|' +
+                                      "(svn: E155035: Deleted node .* copied)",
                                      'cp', sbox.ospath('A/D'),
                                      sbox.ospath('new_D'))
 


Reply via email to