Return-Path: Delivered-To: apmail-subversion-commits-archive@minotaur.apache.org Received: (qmail 56335 invoked from network); 2 Feb 2011 13:05:38 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.3) by minotaur.apache.org with SMTP; 2 Feb 2011 13:05:38 -0000 Received: (qmail 67766 invoked by uid 500); 2 Feb 2011 13:05:38 -0000 Delivered-To: apmail-subversion-commits-archive@subversion.apache.org Received: (qmail 67711 invoked by uid 500); 2 Feb 2011 13:05:37 -0000 Mailing-List: contact commits-help@subversion.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@subversion.apache.org Delivered-To: mailing list commits@subversion.apache.org Received: (qmail 67698 invoked by uid 99); 2 Feb 2011 13:05:36 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 02 Feb 2011 13:05:36 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 02 Feb 2011 13:05:27 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id 967592388A68; Wed, 2 Feb 2011 13:05:04 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1066452 [3/11] - in /subversion/branches/performance: ./ build/ build/ac-macros/ build/generator/ contrib/hook-scripts/ notes/ notes/api-errata/1.7/ subversion/bindings/javahl/tests/org/apache/subversion/javahl/ subversion/include/ subvers... Date: Wed, 02 Feb 2011 13:04:59 -0000 To: commits@subversion.apache.org From: stefan2@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20110202130504.967592388A68@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Modified: subversion/branches/performance/subversion/libsvn_client/export.c URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_client/export.c?rev=1066452&r1=1066451&r2=1066452&view=diff ============================================================================== --- subversion/branches/performance/subversion/libsvn_client/export.c (original) +++ subversion/branches/performance/subversion/libsvn_client/export.c Wed Feb 2 13:04:51 2011 @@ -110,16 +110,15 @@ append_basename_if_dir(const char **appe SVN_ERR(svn_io_check_resolved_path(*appendable_dirent_p, &local_kind, pool)); if (local_kind == svn_node_dir) { - const char *basename2; /* _2 because it shadows basename() */ + const char *base_name; if (is_uri) - basename2 = svn_path_uri_decode(svn_uri_basename(basename_of, NULL), pool); + base_name = svn_uri_basename(basename_of, pool); else - basename2 = svn_dirent_basename(basename_of, NULL); + base_name = svn_dirent_basename(basename_of, NULL); *appendable_dirent_p = svn_dirent_join(*appendable_dirent_p, - basename2, - pool); + base_name, pool); } return SVN_NO_ERROR; @@ -882,11 +881,13 @@ change_dir_prop(void *dir_baton, /* Move the tmpfile to file, and send feedback. */ static svn_error_t * close_file(void *file_baton, - const char *text_checksum, + const char *text_digest, apr_pool_t *pool) { struct file_baton *fb = file_baton; struct edit_baton *eb = fb->edit_baton; + svn_checksum_t *text_checksum; + svn_checksum_t *actual_checksum; /* Was a txdelta even sent? */ if (! fb->tmppath) @@ -894,22 +895,21 @@ close_file(void *file_baton, SVN_ERR(svn_stream_close(fb->tmp_stream)); - if (text_checksum) - { - const char *actual_checksum = - svn_checksum_to_cstring(svn_checksum__from_digest(fb->text_digest, - svn_checksum_md5, - pool), pool); + SVN_ERR(svn_checksum_parse_hex(&text_checksum, svn_checksum_md5, text_digest, + pool)); + actual_checksum = svn_checksum__from_digest(fb->text_digest, + svn_checksum_md5, pool); - if (actual_checksum && (strcmp(text_checksum, actual_checksum) != 0)) - { - return svn_error_createf(SVN_ERR_CHECKSUM_MISMATCH, NULL, + if (!svn_checksum_match(text_checksum, actual_checksum)) + { + return svn_error_createf(SVN_ERR_CHECKSUM_MISMATCH, NULL, _("Checksum mismatch for '%s':\n" " expected: %s\n" " actual: %s\n"), svn_dirent_local_style(fb->path, pool), - text_checksum, actual_checksum); - } + svn_checksum_to_cstring_display(text_checksum, pool), + svn_checksum_to_cstring_display(actual_checksum, + pool)); } if ((! fb->eol_style_val) && (! fb->keywords_val) && (! fb->special)) @@ -984,6 +984,7 @@ svn_client_export5(svn_revnum_t *result_ { svn_revnum_t edit_revision = SVN_INVALID_REVNUM; const char *url; + svn_boolean_t from_is_url = svn_path_is_url(from_path_or_url); SVN_ERR_ASSERT(peg_revision != NULL); SVN_ERR_ASSERT(revision != NULL); @@ -996,8 +997,7 @@ svn_client_export5(svn_revnum_t *result_ from_path_or_url); revision = svn_cl__rev_default_to_peg(revision, peg_revision); - if (svn_path_is_url(from_path_or_url) || - ! SVN_CLIENT__REVKIND_IS_LOCAL_TO_WC(revision->kind)) + if (from_is_url || ! SVN_CLIENT__REVKIND_IS_LOCAL_TO_WC(revision->kind)) { svn_revnum_t revnum; svn_ra_session_t *ra_session; @@ -1036,14 +1036,16 @@ svn_client_export5(svn_revnum_t *result_ if (svn_path_is_empty(to_path)) { - to_path = svn_path_uri_decode(svn_uri_basename(from_path_or_url, - NULL), pool); + if (from_is_url) + to_path = svn_uri_basename(from_path_or_url, pool); + else + to_path = svn_dirent_basename(from_path_or_url, NULL); eb->root_path = to_path; } else { SVN_ERR(append_basename_if_dir(&to_path, from_path_or_url, - TRUE, pool)); + from_is_url, pool)); eb->root_path = to_path; } Modified: subversion/branches/performance/subversion/libsvn_client/externals.c URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_client/externals.c?rev=1066452&r1=1066451&r2=1066452&view=diff ============================================================================== --- subversion/branches/performance/subversion/libsvn_client/externals.c (original) +++ subversion/branches/performance/subversion/libsvn_client/externals.c Wed Feb 2 13:04:51 2011 @@ -565,23 +565,35 @@ resolve_relative_external_url(svn_wc_ext apr_pool_t *pool) { const char *url = item->url; - apr_uri_t parent_dir_parsed_uri; + apr_uri_t parent_dir_uri; apr_status_t status; - if ((url[0] == '/') && (url[1] == '/')) + /* If the URL is already absolute, there is nothing to do. */ + if (svn_path_is_url(url)) { - /* "//schema-relative" and in some cases "///schema-relative". - This last format is supported on file:// schema relative. */ - url = apr_pstrcat( - pool, - url[2] == '/' ? "///" : "//", - svn_relpath_canonicalize(url+2, pool), - (char *)NULL); + /* "http://server/path" */ + item->url = svn_uri_canonicalize(url, pool); + return SVN_NO_ERROR; } - else if (svn_path_is_url(url) || *url == '/') + + if (url[0] == '/') { - /* "http://server/path" and "/path" */ - url = svn_uri_canonicalize(url, pool); + /* "/path", "//path", and "///path" */ + int num_leading_slashes = 1; + if (url[1] == '/') + { + num_leading_slashes++; + if (url[2] == '/') + num_leading_slashes++; + } + + /* "//schema-relative" and in some cases "///schema-relative". + This last format is supported on file:// schema relative. */ + url = apr_pstrcat(pool, + apr_pstrndup(pool, url, num_leading_slashes), + svn_relpath_canonicalize(url + num_leading_slashes, + pool), + NULL); } else { @@ -589,15 +601,8 @@ resolve_relative_external_url(svn_wc_ext url = svn_relpath_canonicalize(url, pool); } - /* If the URL is already absolute, there is nothing to do. */ - if (svn_path_is_url(url)) - { - item->url = url; - return SVN_NO_ERROR; - } - /* Parse the parent directory URL into its parts. */ - status = apr_uri_parse(pool, parent_dir_url, &parent_dir_parsed_uri); + status = apr_uri_parse(pool, parent_dir_url, &parent_dir_uri); if (status) return svn_error_createf(SVN_ERR_BAD_URL, 0, _("Illegal parent directory URL '%s'"), @@ -606,8 +611,10 @@ resolve_relative_external_url(svn_wc_ext /* If the parent directory URL is at the server root, then the URL may have no / after the hostname so apr_uri_parse() will leave the URL's path as NULL. */ - if (! parent_dir_parsed_uri.path) - parent_dir_parsed_uri.path = apr_pstrmemdup(pool, "/", 1); + if (! parent_dir_uri.path) + parent_dir_uri.path = apr_pstrmemdup(pool, "/", 1); + parent_dir_uri.query = NULL; + parent_dir_uri.fragment = NULL; /* Handle URLs relative to the current directory or to the repository root. The backpaths may only remove path elements, @@ -625,15 +632,14 @@ resolve_relative_external_url(svn_wc_ext repository root's URL path into components. */ if (0 == strncmp("../", url, 3)) { - base_components = svn_path_decompose(parent_dir_parsed_uri.path, - pool); + base_components = svn_path_decompose(parent_dir_uri.path, pool); relative_components = svn_path_decompose(url, pool); } else { - apr_uri_t repos_root_parsed_uri; + apr_uri_t repos_root_uri; - status = apr_uri_parse(pool, repos_root_url, &repos_root_parsed_uri); + status = apr_uri_parse(pool, repos_root_url, &repos_root_uri); if (status) return svn_error_createf(SVN_ERR_BAD_URL, 0, _("Illegal repository root URL '%s'"), @@ -642,10 +648,10 @@ resolve_relative_external_url(svn_wc_ext /* If the repository root URL is at the server root, then the URL may have no / after the hostname so apr_uri_parse() will leave the URL's path as NULL. */ - if (! repos_root_parsed_uri.path) - repos_root_parsed_uri.path = apr_pstrmemdup(pool, "/", 1); + if (! repos_root_uri.path) + repos_root_uri.path = apr_pstrmemdup(pool, "/", 1); - base_components = svn_path_decompose(repos_root_parsed_uri.path, + base_components = svn_path_decompose(repos_root_uri.path, pool); relative_components = svn_path_decompose(url + 2, pool); } @@ -668,13 +674,9 @@ resolve_relative_external_url(svn_wc_ext APR_ARRAY_PUSH(base_components, const char *) = component; } - parent_dir_parsed_uri.path = (char *)svn_path_compose(base_components, - pool); - parent_dir_parsed_uri.query = NULL; - parent_dir_parsed_uri.fragment = NULL; - - item->url = apr_uri_unparse(pool, &parent_dir_parsed_uri, 0); - + parent_dir_uri.path = (char *)svn_path_compose(base_components, pool); + item->url = svn_uri_canonicalize(apr_uri_unparse(pool, &parent_dir_uri, + 0), pool); return SVN_NO_ERROR; } @@ -687,26 +689,24 @@ resolve_relative_external_url(svn_wc_ext "backpaths, i.e. '..'"), item->url); - /* Relative to the scheme. */ + /* Relative to the scheme: Build a new URL from the parts we know. */ if (0 == strncmp("//", url, 2)) { const char *scheme; SVN_ERR(uri_scheme(&scheme, repos_root_url, pool)); - item->url = svn_uri_canonicalize(apr_pstrcat(pool, - scheme, - ":", - url, - (char *)NULL), - pool); + item->url = svn_uri_canonicalize(apr_pstrcat(pool, scheme, ":", + url, NULL), pool); return SVN_NO_ERROR; } - /* Relative to the server root. */ + /* Relative to the server root: Just replace the path portion of the + parent's URL. */ if (url[0] == '/') { - item->url = svn_uri_join(parent_dir_url, url, pool); - + parent_dir_uri.path = (char *)url; + item->url = svn_uri_canonicalize(apr_uri_unparse(pool, &parent_dir_uri, + 0), pool); return SVN_NO_ERROR; } Modified: subversion/branches/performance/subversion/libsvn_client/info.c URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_client/info.c?rev=1066452&r1=1066451&r2=1066452&view=diff ============================================================================== --- subversion/branches/performance/subversion/libsvn_client/info.c (original) +++ subversion/branches/performance/subversion/libsvn_client/info.c Wed Feb 2 13:04:51 2011 @@ -34,6 +34,7 @@ #include "svn_wc.h" #include "svn_private_config.h" +#include "private/svn_fspath.h" #include "private/svn_wc_private.h" @@ -289,11 +290,9 @@ push_dir_info(svn_ra_session_t *ra_sessi SVN_ERR(ctx->cancel_func(ctx->cancel_baton)); path = svn_relpath_join(dir, name, subpool); - URL = svn_path_url_add_component2(session_URL, name, subpool); - - fs_path = svn_uri_is_child(repos_root, URL, subpool); - fs_path = apr_pstrcat(subpool, "/", fs_path, (char *)NULL); - fs_path = svn_path_uri_decode(fs_path, subpool); + URL = svn_path_url_add_component2(session_URL, name, subpool); + fs_path = svn_fspath__canonicalize(svn_uri_is_child(repos_root, URL, + subpool), subpool); lock = apr_hash_get(locks, fs_path, APR_HASH_KEY_STRING); @@ -537,7 +536,6 @@ svn_client_info3(const char *abspath_or_ SVN_ERR(svn_ra_get_uuid2(ra_session, &repos_UUID, pool)); svn_uri_split(&parent_url, &base_name, url, pool); - base_name = svn_path_uri_decode(base_name, pool); /* Get the dirent for the URL itself. */ err = svn_ra_stat(ra_session, "", rev, &the_ent, pool); Modified: subversion/branches/performance/subversion/libsvn_client/list.c URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_client/list.c?rev=1066452&r1=1066451&r2=1066452&view=diff ============================================================================== --- subversion/branches/performance/subversion/libsvn_client/list.c (original) +++ subversion/branches/performance/subversion/libsvn_client/list.c Wed Feb 2 13:04:51 2011 @@ -31,6 +31,7 @@ #include "client.h" +#include "private/svn_fspath.h" #include "svn_private_config.h" /* Get the directory entries of DIR at REV (relative to the root of @@ -181,11 +182,6 @@ svn_client_list2(const char *path_or_url doesn't support svn_ra_reparent anyway, so don't try it. */ svn_uri_split(&parent_url, &base_name, url, pool); - /* 'base_name' is now the last component of an URL, but we want - to use it as a plain file name. Therefore, we must URI-decode - it. */ - base_name = svn_path_uri_decode(base_name, pool); - SVN_ERR(svn_client__open_ra_session_internal(&parent_session, NULL, parent_url, NULL, NULL, FALSE, Modified: subversion/branches/performance/subversion/libsvn_client/locking_commands.c URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_client/locking_commands.c?rev=1066452&r1=1066451&r2=1066452&view=diff ============================================================================== --- subversion/branches/performance/subversion/libsvn_client/locking_commands.c (original) +++ subversion/branches/performance/subversion/libsvn_client/locking_commands.c Wed Feb 2 13:04:51 2011 @@ -138,6 +138,58 @@ store_locks_callback(void *baton, } +/* This is a wrapper around svn_uri_condense_targets() and + * svn_dirent_condense_targets() (the choice of which is made based on + * the value of TARGETS_ARE_URIS) which takes care of the + * single-target special case. + * + * Callers are expected to check for an empty *COMMON_PARENT (which + * means, "there was nothing common") for themselves. + */ +static svn_error_t * +condense_targets(const char **common_parent, + apr_array_header_t **target_relpaths, + const apr_array_header_t *targets, + svn_boolean_t targets_are_uris, + svn_boolean_t remove_redundancies, + apr_pool_t *scratch_pool, + apr_pool_t *result_pool) +{ + if (targets_are_uris) + { + SVN_ERR(svn_uri_condense_targets(common_parent, target_relpaths, + targets, remove_redundancies, + result_pool, scratch_pool)); + } + else + { + SVN_ERR(svn_dirent_condense_targets(common_parent, target_relpaths, + targets, remove_redundancies, + result_pool, scratch_pool)); + } + + /* svn_*_condense_targets leaves *TARGET_RELPATHS empty if TARGETS only + had 1 member, so we special case that. */ + if (apr_is_empty_array(*target_relpaths)) + { + const char *base_name; + + if (targets_are_uris) + { + svn_uri_split(common_parent, &base_name, + *common_parent, result_pool); + } + else + { + svn_dirent_split(common_parent, &base_name, + *common_parent, result_pool); + } + APR_ARRAY_PUSH(*target_relpaths, const char *) = base_name; + } + + return SVN_NO_ERROR; +} + /* Set *COMMON_PARENT_URL to the nearest common parent URL of all TARGETS. * If TARGETS are local paths, then the entry for each path is examined * and *COMMON_PARENT is set to the common parent URL for all the @@ -175,176 +227,160 @@ organize_lock_targets(const char **commo svn_boolean_t do_lock, svn_boolean_t force, svn_client_ctx_t *ctx, - apr_pool_t *pool) + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) { - int i; - apr_array_header_t *rel_targets = apr_array_make(pool, 1, - sizeof(const char *)); - apr_hash_t *rel_targets_ret = apr_hash_make(pool); - apr_pool_t *subpool = svn_pool_create(pool); + const char *common_url = NULL; + const char *common_dirent = NULL; + apr_hash_t *rel_targets_ret = apr_hash_make(result_pool); + apr_hash_t *rel_fs_paths = NULL; + apr_array_header_t *rel_targets; svn_boolean_t url_mode; + int i; + SVN_ERR_ASSERT(targets->nelts); SVN_ERR(svn_client__assert_homogeneous_target_type(targets)); - url_mode = ((targets->nelts >= 1) && - svn_path_is_url(APR_ARRAY_IDX(targets, 0, const char *))); + url_mode = svn_path_is_url(APR_ARRAY_IDX(targets, 0, const char *)); - /* Get the common parent and all paths */ if (url_mode) - SVN_ERR(svn_uri_condense_targets(common_parent_url, &rel_targets, - targets, TRUE, pool, pool)); - else - SVN_ERR(svn_dirent_condense_targets(common_parent_url, &rel_targets, - targets, TRUE, pool, pool)); - - /* svn_uri_condense_targets and svn_dirent_condense_targets leaves - URLs/paths empty if TARGETS only had 1 member, so we special case - that. */ - if (apr_is_empty_array(rel_targets)) { - const char *parent, *base; - if (url_mode) - svn_uri_split(&parent, &base, *common_parent_url, pool); - else - svn_dirent_split(&parent, &base, *common_parent_url, pool); - - *common_parent_url = parent; - APR_ARRAY_PUSH(rel_targets, const char *) = base; - } - - if (*common_parent_url == NULL || (*common_parent_url)[0] == '\0') - return svn_error_create - (SVN_ERR_UNSUPPORTED_FEATURE, NULL, - _("No common parent found, unable to operate on disjoint arguments")); + svn_revnum_t *invalid_revnum = + apr_palloc(result_pool, sizeof(*invalid_revnum)); - if (url_mode) - { - svn_revnum_t *invalid_revnum; - invalid_revnum = apr_palloc(pool, sizeof(*invalid_revnum)); *invalid_revnum = SVN_INVALID_REVNUM; - *base_dir = NULL; + /* Get the common parent URL and a bunch of relpaths, one per target. */ + SVN_ERR(condense_targets(&common_url, &rel_targets, targets, + TRUE, TRUE, scratch_pool, result_pool)); + if (! (common_url && *common_url)) + return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL, + _("No common parent found, unable to operate " + "on disjoint arguments")); + + /* Create mapping of the target relpaths to either + SVN_INVALID_REVNUM (if our caller is locking) or to an empty + lock token string (if the caller is unlocking). */ for (i = 0; i < rel_targets->nelts; i++) { - const char *target = APR_ARRAY_IDX(rel_targets, i, const char *); - apr_hash_set(rel_targets_ret, svn_path_uri_decode(target, pool), + apr_hash_set(rel_targets_ret, + APR_ARRAY_IDX(rel_targets, i, const char *), APR_HASH_KEY_STRING, - do_lock ? (const void *) invalid_revnum - : (const void *) ""); + do_lock ? (const void *)invalid_revnum + : (const void *)""); } - *rel_fs_paths_p = NULL; } - else /* common parent is a local path */ + else { - apr_array_header_t *rel_urls; - apr_array_header_t *urls = apr_array_make(pool, 1, - sizeof(const char *)); - apr_hash_t *urls_hash = apr_hash_make(pool); - const char *common_url; - - *base_dir = *common_parent_url; - - /* Get the url for each target and verify all paths. */ + apr_array_header_t *rel_urls, *target_urls; + apr_pool_t *iterpool = svn_pool_create(scratch_pool); + + /* Get the common parent dirent and a bunch of relpaths, one per + target. */ + SVN_ERR(condense_targets(&common_dirent, &rel_targets, targets, + FALSE, TRUE, scratch_pool, result_pool)); + if (! (common_dirent && *common_dirent)) + return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL, + _("No common parent found, unable to operate " + "on disjoint arguments")); + + /* Get the URL for each target (which also serves to verify that + the dirent targets are sane). */ + target_urls = apr_array_make(scratch_pool, rel_targets->nelts, + sizeof(const char *)); for (i = 0; i < rel_targets->nelts; i++) { - const char *target = APR_ARRAY_IDX(rel_targets, i, const char *); - const char *local_abspath; - const char *url; - - svn_pool_clear(subpool); - - local_abspath = svn_dirent_join(*common_parent_url, target, subpool); + const char *rel_target, *local_abspath, *target_url; - SVN_ERR(svn_wc__node_get_url(&url, ctx->wc_ctx, local_abspath, - pool, subpool)); + svn_pool_clear(iterpool); - if (! url) + rel_target = APR_ARRAY_IDX(rel_targets, i, const char *); + local_abspath = svn_dirent_join(common_dirent, rel_target, iterpool); + SVN_ERR(svn_wc__node_get_url(&target_url, ctx->wc_ctx, local_abspath, + scratch_pool, iterpool)); + if (! target_url) return svn_error_createf(SVN_ERR_ENTRY_MISSING_URL, NULL, _("'%s' has no URL"), - svn_dirent_local_style(target, pool)); + svn_dirent_local_style(local_abspath, + iterpool)); - APR_ARRAY_PUSH(urls, const char *) = url; + APR_ARRAY_PUSH(target_urls, const char *) = target_url; } - /* Condense our absolute urls and get the relative urls. */ - SVN_ERR(svn_uri_condense_targets(&common_url, &rel_urls, urls, - FALSE, pool, pool)); - - /* svn_uri_condense_targets leaves URLs empty if TARGETS only - had 1 member, so we special case that (again). */ - if (apr_is_empty_array(rel_urls)) - { - const char *base_name = svn_uri_basename(common_url, pool); - common_url = svn_uri_dirname(common_url, pool); - APR_ARRAY_PUSH(rel_urls, const char *) = base_name; - } - - /* If we have no common URL parent, bail (cross-repos lock attempt) */ - if (common_url == NULL || (common_url)[0] == '\0') - return svn_error_create - (SVN_ERR_UNSUPPORTED_FEATURE, NULL, - _("Unable to lock/unlock across multiple repositories")); + /* Now that we have a bunch of URLs for our dirent targets, + condense those into a single common parent URL and a bunch of + paths relative to that. */ + SVN_ERR(condense_targets(&common_url, &rel_urls, target_urls, + TRUE, FALSE, scratch_pool, result_pool)); + if (! (common_url && *common_url)) + return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL, + _("Unable to lock/unlock across multiple " + "repositories")); - /* Now that we've got the relative URLs, gather our targets and - store the mapping between relative repository path and WC path. */ + /* Now we need to create a couple of different hash mappings. */ + rel_fs_paths = apr_hash_make(result_pool); for (i = 0; i < rel_targets->nelts; i++) { - const char *target = APR_ARRAY_IDX(rel_targets, i, const char *); - const char *url = APR_ARRAY_IDX(rel_urls, i, const char *); - const char *abs_path; - const char *decoded_url = svn_path_uri_decode(url, pool); - - svn_pool_clear(subpool); + const char *rel_target, *rel_url, *abs_path; - apr_hash_set(urls_hash, decoded_url, - APR_HASH_KEY_STRING, - apr_pstrdup(pool, target)); + svn_pool_clear(iterpool); - abs_path = svn_dirent_join(*common_parent_url, target, subpool); + /* First, we need to map our REL_URL (which is relative to + COMMON_URL) to our REL_TARGET (which is relative to + COMMON_DIRENT). */ + rel_target = APR_ARRAY_IDX(rel_targets, i, const char *); + rel_url = APR_ARRAY_IDX(rel_urls, i, const char *); + apr_hash_set(rel_fs_paths, rel_url, APR_HASH_KEY_STRING, + apr_pstrdup(result_pool, rel_target)); + + /* Then, we map our REL_URL (again) to either the base + revision of the dirent target with which it is associated + (if our caller is locking) or to a (possible empty) lock + token string (if the caller is unlocking). */ + abs_path = svn_dirent_join(common_dirent, rel_target, iterpool); if (do_lock) /* Lock. */ { svn_revnum_t *revnum; - revnum = apr_palloc(pool, sizeof(* revnum)); + revnum = apr_palloc(result_pool, sizeof(* revnum)); SVN_ERR(svn_wc__node_get_base_rev(revnum, ctx->wc_ctx, - abs_path, subpool)); - apr_hash_set(rel_targets_ret, decoded_url, + abs_path, result_pool)); + apr_hash_set(rel_targets_ret, rel_url, APR_HASH_KEY_STRING, revnum); } else /* Unlock. */ { - /* If not force, get the lock token. */ + const char *lock_token = NULL; + + /* If not forcing the unlock, get the lock token. */ if (! force) { - const char *lock_token; - SVN_ERR(svn_wc__node_get_lock_info(&lock_token, NULL, NULL, NULL, ctx->wc_ctx, - abs_path, pool, subpool)); + abs_path, result_pool, + iterpool)); if (! lock_token) - return svn_error_createf - (SVN_ERR_CLIENT_MISSING_LOCK_TOKEN, NULL, - _("'%s' is not locked in this working copy"), target); - - apr_hash_set(rel_targets_ret, decoded_url, - APR_HASH_KEY_STRING, - lock_token); - } - else - { - /* If breaking a lock, we shouldn't pass any lock token. */ - apr_hash_set(rel_targets_ret, decoded_url, - APR_HASH_KEY_STRING, ""); + return svn_error_createf( + SVN_ERR_CLIENT_MISSING_LOCK_TOKEN, NULL, + _("'%s' is not locked in this working copy"), + abs_path); } + + /* If breaking a lock, we shouldn't pass any lock token. */ + apr_hash_set(rel_targets_ret, rel_url, APR_HASH_KEY_STRING, + lock_token ? lock_token : ""); } } - *rel_fs_paths_p = urls_hash; - *common_parent_url = common_url; + svn_pool_destroy(iterpool); } + /* Set our return variables. */ + *common_parent_url = common_url; + *base_dir = common_dirent; *rel_targets_p = rel_targets_ret; - svn_pool_destroy(subpool); + *rel_fs_paths_p = rel_fs_paths; + return SVN_NO_ERROR; } @@ -408,7 +444,7 @@ svn_client_lock(const apr_array_header_t SVN_ERR(organize_lock_targets(&common_parent_url, &base_dir, &path_revs, &urls_to_paths, targets, TRUE, steal_lock, - ctx, pool)); + ctx, pool, pool)); /* Open an RA session to the common parent of TARGETS. */ if (base_dir) @@ -448,7 +484,7 @@ svn_client_unlock(const apr_array_header SVN_ERR(organize_lock_targets(&common_parent_url, &base_dir, &path_tokens, &urls_to_paths, targets, FALSE, break_lock, - ctx, pool)); + ctx, pool, pool)); /* Open an RA session. */ if (base_dir) Modified: subversion/branches/performance/subversion/libsvn_client/merge.c URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_client/merge.c?rev=1066452&r1=1066451&r2=1066452&view=diff ============================================================================== --- subversion/branches/performance/subversion/libsvn_client/merge.c (original) +++ subversion/branches/performance/subversion/libsvn_client/merge.c Wed Feb 2 13:04:51 2011 @@ -54,6 +54,7 @@ #include "private/svn_wc_private.h" #include "private/svn_mergeinfo_private.h" +#include "private/svn_fspath.h" #include "svn_private_config.h" @@ -529,7 +530,9 @@ make_tree_conflict(svn_wc_conflict_descr } /* Record a tree conflict in the WC, unless this is a dry run or a record- - * only merge. + * only merge, or if a tree conflict is already flagged for the VICTIM_PATH. + * (The latter can happen if a merge-tracking-aware merge is doing multiple + * editor drives because of a gap in the range of eligible revisions.) * * The tree conflict, with its victim specified by VICTIM_PATH, is * assumed to have happened during a merge using merge baton MERGE_B. @@ -546,16 +549,25 @@ tree_conflict(merge_cmd_baton_t *merge_b svn_wc_conflict_action_t action, svn_wc_conflict_reason_t reason) { + const svn_wc_conflict_description2_t *existing_conflict; svn_wc_conflict_description2_t *conflict; if (merge_b->record_only || merge_b->dry_run) return SVN_NO_ERROR; - SVN_ERR(make_tree_conflict(&conflict, merge_b, victim_abspath, - node_kind, action, reason)); + SVN_ERR(svn_wc__get_tree_conflict(&existing_conflict, merge_b->ctx->wc_ctx, + victim_abspath, merge_b->pool, + merge_b->pool)); + if (existing_conflict == NULL) + { + /* There is no existing tree conflict so it is safe to add one. */ + SVN_ERR(make_tree_conflict(&conflict, merge_b, victim_abspath, + node_kind, action, reason)); + SVN_ERR(svn_wc__add_tree_conflict(merge_b->ctx->wc_ctx, conflict, + merge_b->pool)); + } - return svn_error_return( - svn_wc__add_tree_conflict(merge_b->ctx->wc_ctx, conflict, merge_b->pool)); + return SVN_NO_ERROR; } /* Similar to tree_conflict(), but if this is an "add" action and there Modified: subversion/branches/performance/subversion/libsvn_client/mergeinfo.c URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_client/mergeinfo.c?rev=1066452&r1=1066451&r2=1066452&view=diff ============================================================================== --- subversion/branches/performance/subversion/libsvn_client/mergeinfo.c (original) +++ subversion/branches/performance/subversion/libsvn_client/mergeinfo.c Wed Feb 2 13:04:51 2011 @@ -41,6 +41,7 @@ #include "private/svn_mergeinfo_private.h" #include "private/svn_wc_private.h" #include "private/svn_ra_private.h" +#include "private/svn_fspath.h" #include "client.h" #include "mergeinfo.h" #include "svn_private_config.h" @@ -1667,11 +1668,9 @@ svn_client_mergeinfo_get_merged(apr_hash { const char *key = svn__apr_hash_index_key(hi); void *val = svn__apr_hash_index_val(hi); - const char *source_url; - - source_url = svn_path_uri_encode(key, pool); - source_url = svn_uri_join(repos_root, source_url + 1, pool); - apr_hash_set(full_path_mergeinfo, source_url, + + apr_hash_set(full_path_mergeinfo, + svn_path_url_add_component2(repos_root, key + 1, pool), APR_HASH_KEY_STRING, val); } *mergeinfo_p = full_path_mergeinfo; Modified: subversion/branches/performance/subversion/libsvn_client/patch.c URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_client/patch.c?rev=1066452&r1=1066451&r2=1066452&view=diff ============================================================================== --- subversion/branches/performance/subversion/libsvn_client/patch.c (original) +++ subversion/branches/performance/subversion/libsvn_client/patch.c Wed Feb 2 13:04:51 2011 @@ -32,6 +32,7 @@ #include "svn_client.h" #include "svn_dirent_uri.h" #include "svn_diff.h" +#include "svn_hash.h" #include "svn_io.h" #include "svn_path.h" #include "svn_pools.h" @@ -48,7 +49,7 @@ typedef struct hunk_info_t { /* The hunk. */ - const svn_diff_hunk_t *hunk; + svn_diff_hunk_t *hunk; /* The line where the hunk matched in the target file. */ svn_linenum_t matched_line; @@ -483,7 +484,7 @@ init_prop_target(prop_patch_target_t **p content_info = apr_pcalloc(result_pool, sizeof(*content_info)); - /* All other fields in are FALSE or NULL due to apr_pcalloc().*/ + /* All other fields are FALSE or NULL due to apr_pcalloc(). */ content_info->current_line = 1; content_info->eol_style = svn_subst_eol_style_none; content_info->lines = apr_array_make(result_pool, 0, @@ -834,7 +835,7 @@ seek_to_line(target_content_info_t *cont * Do temporary allocations in POOL. */ static svn_error_t * match_hunk(svn_boolean_t *matched, target_content_info_t *content_info, - const svn_diff_hunk_t *hunk, int fuzz, + svn_diff_hunk_t *hunk, int fuzz, svn_boolean_t ignore_whitespace, svn_boolean_t match_modified, apr_pool_t *pool) { @@ -861,12 +862,12 @@ match_hunk(svn_boolean_t *matched, targe trailing_context = svn_diff_hunk_get_trailing_context(hunk); if (match_modified) { - SVN_ERR(svn_diff_hunk_reset_modified_text(hunk)); + svn_diff_hunk_reset_modified_text(hunk); hunk_length = svn_diff_hunk_get_modified_length(hunk); } else { - SVN_ERR(svn_diff_hunk_reset_original_text(hunk)); + svn_diff_hunk_reset_original_text(hunk); hunk_length = svn_diff_hunk_get_original_length(hunk); } iterpool = svn_pool_create(pool); @@ -950,7 +951,7 @@ match_hunk(svn_boolean_t *matched, targe static svn_error_t * scan_for_match(svn_linenum_t *matched_line, target_content_info_t *content_info, - const svn_diff_hunk_t *hunk, svn_boolean_t match_first, + svn_diff_hunk_t *hunk, svn_boolean_t match_first, svn_linenum_t upper_line, int fuzz, svn_boolean_t ignore_whitespace, svn_boolean_t match_modified, @@ -1022,7 +1023,7 @@ scan_for_match(svn_linenum_t *matched_li static svn_error_t * match_existing_target(svn_boolean_t *match, target_content_info_t *content_info, - const svn_diff_hunk_t *hunk, + svn_diff_hunk_t *hunk, svn_stream_t *stream, apr_pool_t *scratch_pool) { @@ -1031,7 +1032,7 @@ match_existing_target(svn_boolean_t *mat svn_boolean_t eof; svn_boolean_t hunk_eof; - SVN_ERR(svn_diff_hunk_reset_modified_text(hunk)); + svn_diff_hunk_reset_modified_text(hunk); iterpool = svn_pool_create(scratch_pool); do @@ -1087,7 +1088,7 @@ match_existing_target(svn_boolean_t *mat static svn_error_t * get_hunk_info(hunk_info_t **hi, patch_target_t *target, target_content_info_t *content_info, - const svn_diff_hunk_t *hunk, int fuzz, + svn_diff_hunk_t *hunk, int fuzz, svn_boolean_t ignore_whitespace, svn_boolean_t is_prop_hunk, svn_cancel_func_t cancel_func, void *cancel_baton, @@ -1301,7 +1302,7 @@ copy_lines_to_target(target_content_info * Do temporary allocations in POOL. */ static svn_error_t * reject_hunk(patch_target_t *target, target_content_info_t *content_info, - const svn_diff_hunk_t *hunk, const char *prop_name, + svn_diff_hunk_t *hunk, const char *prop_name, apr_pool_t *pool) { const char *hunk_header; @@ -1419,7 +1420,7 @@ apply_hunk(patch_target_t *target, targe /* Write the hunk's version to the patched result. * Don't write the lines which matched with fuzz. */ lines_read = 0; - SVN_ERR(svn_diff_hunk_reset_modified_text(hi->hunk)); + svn_diff_hunk_reset_modified_text(hi->hunk); iterpool = svn_pool_create(pool); do { @@ -1701,6 +1702,9 @@ apply_one_patch(patch_target_t **patch_t svn_pool_clear(iterpool); + if (cancel_func) + SVN_ERR((cancel_func)(cancel_baton)); + hi = APR_ARRAY_IDX(target->content_info->hunks, i, hunk_info_t *); if (hi->already_applied) continue; @@ -1935,8 +1939,7 @@ create_missing_parents(patch_target_t *t svn_pool_clear(iterpool); - component = APR_ARRAY_IDX(components, i, - const char *); + component = APR_ARRAY_IDX(components, i, const char *); local_abspath = svn_dirent_join(local_abspath, component, scratch_pool); SVN_ERR(svn_wc_read_kind(&wc_kind, ctx->wc_ctx, local_abspath, TRUE, @@ -1990,8 +1993,7 @@ create_missing_parents(patch_target_t *t for (i = 0; i < present_components; i++) { const char *component; - component = APR_ARRAY_IDX(components, i, - const char *); + component = APR_ARRAY_IDX(components, i, const char *); local_abspath = svn_dirent_join(local_abspath, component, scratch_pool); } @@ -2011,10 +2013,9 @@ create_missing_parents(patch_target_t *t svn_pool_clear(iterpool); - component = APR_ARRAY_IDX(components, i, - const char *); + component = APR_ARRAY_IDX(components, i, const char *); local_abspath = svn_dirent_join(local_abspath, component, - scratch_pool); + scratch_pool); if (dry_run) { if (ctx->notify_func2) @@ -2211,6 +2212,9 @@ install_patched_prop_targets(patch_targe svn_pool_clear(iterpool); + if (ctx->cancel_func) + SVN_ERR(ctx->cancel_func(ctx->cancel_baton)); + /* For a deleted prop we only set the value to NULL. */ if (prop_target->operation == svn_diff_op_deleted) { @@ -2267,8 +2271,6 @@ install_patched_prop_targets(patch_targe { SVN_ERR(svn_io_file_create(target->local_abspath, "", scratch_pool)); - if (ctx->cancel_func) - SVN_ERR(ctx->cancel_func(ctx->cancel_baton)); SVN_ERR(svn_wc_add_from_disk(ctx->wc_ctx, target->local_abspath, /* suppress notification */ NULL, NULL, @@ -2368,14 +2370,14 @@ find_existing_children(void *baton, /* Indicate in *EMPTY whether the directory at LOCAL_ABSPATH has any * versioned or unversioned children. Consider any DELETED_TARGETS, - * as well as paths listed in DELETED_ABSPATHS_LIST (which may be NULL) - * as already deleted. Use WC_CTX as the working copy context. + * as well as paths occuring as keys of DELETED_ABSPATHS_HASH (which may + * be NULL) as already deleted. Use WC_CTX as the working copy context. * Do temporary allocations in SCRATCH_POOL. */ static svn_error_t * check_dir_empty(svn_boolean_t *empty, const char *local_abspath, svn_wc_context_t *wc_ctx, apr_array_header_t *deleted_targets, - apr_array_header_t *deleted_abspath_list, + apr_hash_t *deleted_abspath_hash, apr_pool_t *scratch_pool) { struct status_baton btn; @@ -2423,13 +2425,17 @@ check_dir_empty(svn_boolean_t *empty, co break; } } - if (! deleted && deleted_abspath_list) + if (! deleted && deleted_abspath_hash) { - for (j = 0; j < deleted_abspath_list->nelts; j++) + apr_hash_index_t *hi; + + for (hi = apr_hash_first(scratch_pool, deleted_abspath_hash); + hi; + hi = apr_hash_next(hi)) { const char *abspath; - abspath = APR_ARRAY_IDX(deleted_abspath_list, j, const char *); + abspath = svn__apr_hash_index_key(hi); if (! svn_path_compare_paths(found, abspath)) { deleted = TRUE; @@ -2447,33 +2453,6 @@ check_dir_empty(svn_boolean_t *empty, co return SVN_NO_ERROR; } -/* Push a copy of EMPTY_DIR, allocated in RESULT_POOL, onto the EMPTY_DIRS - * array if no directory matching EMPTY_DIR is already in the array. */ -static void -push_if_unique(apr_array_header_t *empty_dirs, const char *empty_dir, - apr_pool_t *result_pool) -{ - svn_boolean_t is_unique; - int i; - - is_unique = TRUE; - for (i = 0; i < empty_dirs->nelts; i++) - { - const char *empty_dir2; - - empty_dir2 = APR_ARRAY_IDX(empty_dirs, i, const char *); - if (strcmp(empty_dir, empty_dir2) == 0) - { - is_unique = FALSE; - break; - } - } - - if (is_unique) - APR_ARRAY_PUSH(empty_dirs, const char *) = apr_pstrdup(result_pool, - empty_dir); -} - /* Delete all directories from the working copy which are left empty * by deleted TARGETS. Use client context CTX. * If DRY_RUN is TRUE, do not modify the working copy. @@ -2482,11 +2461,13 @@ static svn_error_t * delete_empty_dirs(apr_array_header_t *targets_info, svn_client_ctx_t *ctx, svn_boolean_t dry_run, apr_pool_t *scratch_pool) { - apr_array_header_t *empty_dirs; + apr_hash_t *empty_dirs; + apr_hash_t *non_empty_dirs; apr_array_header_t *deleted_targets; apr_pool_t *iterpool; svn_boolean_t again; int i; + apr_hash_index_t *hi; /* Get a list of all deleted targets. */ deleted_targets = apr_array_make(scratch_pool, 0, sizeof(patch_target_t *)); @@ -2504,7 +2485,8 @@ delete_empty_dirs(apr_array_header_t *ta return SVN_NO_ERROR; /* Look for empty parent directories of deleted targets. */ - empty_dirs = apr_array_make(scratch_pool, 0, sizeof(const char *)); + empty_dirs = apr_hash_make(scratch_pool); + non_empty_dirs = apr_hash_make(scratch_pool); iterpool = svn_pool_create(scratch_pool); for (i = 0; i < targets_info->nelts; i++) { @@ -2519,17 +2501,24 @@ delete_empty_dirs(apr_array_header_t *ta target_info = APR_ARRAY_IDX(targets_info, i, patch_target_info_t *); parent = svn_dirent_dirname(target_info->local_abspath, iterpool); + + if (apr_hash_get(non_empty_dirs, parent, APR_HASH_KEY_STRING)) + continue; + else if (apr_hash_get(empty_dirs, parent, APR_HASH_KEY_STRING)) + continue; + SVN_ERR(check_dir_empty(&parent_empty, parent, ctx->wc_ctx, deleted_targets, NULL, iterpool)); if (parent_empty) - { - APR_ARRAY_PUSH(empty_dirs, const char *) = - apr_pstrdup(scratch_pool, parent); - } + apr_hash_set(empty_dirs, apr_pstrdup(scratch_pool, parent), + APR_HASH_KEY_STRING, ""); + else + apr_hash_set(non_empty_dirs, apr_pstrdup(scratch_pool, parent), + APR_HASH_KEY_STRING, ""); } /* We have nothing to do if there aren't any empty directories. */ - if (empty_dirs->nelts == 0) + if (apr_hash_count(empty_dirs) == 0) { svn_pool_destroy(iterpool); return SVN_NO_ERROR; @@ -2538,7 +2527,7 @@ delete_empty_dirs(apr_array_header_t *ta /* Determine the minimal set of empty directories we need to delete. */ do { - apr_array_header_t *empty_dirs_copy; + apr_hash_t *empty_dirs_copy; svn_pool_clear(iterpool); @@ -2548,32 +2537,43 @@ delete_empty_dirs(apr_array_header_t *ta /* Rebuild the empty dirs list, replacing empty dirs which have * an empty parent with their parent. */ again = FALSE; - empty_dirs_copy = apr_array_copy(iterpool, empty_dirs); - apr_array_clear(empty_dirs); - for (i = 0; i < empty_dirs_copy->nelts; i++) + empty_dirs_copy = apr_hash_copy(iterpool, empty_dirs); + SVN_ERR(svn_hash__clear(empty_dirs, iterpool)); + + for (hi = apr_hash_first(iterpool, empty_dirs_copy); + hi; + hi = apr_hash_next(hi)) { svn_boolean_t parent_empty; const char *empty_dir; const char *parent; - empty_dir = APR_ARRAY_IDX(empty_dirs_copy, i, const char *); + empty_dir = svn__apr_hash_index_key(hi); parent = svn_dirent_dirname(empty_dir, iterpool); + + if (apr_hash_get(empty_dirs, parent, APR_HASH_KEY_STRING)) + continue; + SVN_ERR(check_dir_empty(&parent_empty, parent, ctx->wc_ctx, deleted_targets, empty_dirs_copy, iterpool)); if (parent_empty) { again = TRUE; - push_if_unique(empty_dirs, parent, scratch_pool); + apr_hash_set(empty_dirs, apr_pstrdup(scratch_pool, parent), + APR_HASH_KEY_STRING, ""); } else - push_if_unique(empty_dirs, empty_dir, scratch_pool); + apr_hash_set(empty_dirs, apr_pstrdup(scratch_pool, empty_dir), + APR_HASH_KEY_STRING, ""); } } while (again); /* Finally, delete empty directories. */ - for (i = 0; i < empty_dirs->nelts; i++) + for (hi = apr_hash_first(scratch_pool, empty_dirs); + hi; + hi = apr_hash_next(hi)) { const char *empty_dir; @@ -2582,7 +2582,12 @@ delete_empty_dirs(apr_array_header_t *ta if (ctx->cancel_func) SVN_ERR(ctx->cancel_func(ctx->cancel_baton)); - empty_dir = APR_ARRAY_IDX(empty_dirs, i, const char *); + empty_dir = svn__apr_hash_index_key(hi); + if (! dry_run) + SVN_ERR(svn_wc_delete4(ctx->wc_ctx, empty_dir, FALSE, FALSE, + ctx->cancel_func, ctx->cancel_baton, + NULL, NULL, /* no duplicate notification */ + iterpool)); if (ctx->notify_func2) { svn_wc_notify_t *notify; @@ -2591,11 +2596,6 @@ delete_empty_dirs(apr_array_header_t *ta iterpool); (*ctx->notify_func2)(ctx->notify_baton2, notify, iterpool); } - if (! dry_run) - SVN_ERR(svn_wc_delete4(ctx->wc_ctx, empty_dir, FALSE, FALSE, - ctx->cancel_func, ctx->cancel_baton, - NULL, NULL, /* no duplicate notification */ - iterpool)); } svn_pool_destroy(iterpool); @@ -2643,13 +2643,13 @@ apply_patches(void *baton, { svn_patch_t *patch; apr_pool_t *iterpool; - apr_file_t *patch_file; + svn_patch_file_t *patch_file; apr_array_header_t *targets_info; apply_patches_baton_t *btn = baton; /* Try to open the patch file. */ - SVN_ERR(svn_io_file_open(&patch_file, btn->patch_abspath, - APR_READ | APR_BINARY, 0, scratch_pool)); + SVN_ERR(svn_diff_open_patch_file(&patch_file, btn->patch_abspath, + scratch_pool)); /* Apply patches. */ targets_info = apr_array_make(scratch_pool, 0, @@ -2707,8 +2707,6 @@ apply_patches(void *baton, } SVN_ERR(send_patch_notification(target, btn->ctx, iterpool)); } - - SVN_ERR(svn_diff_close_patch(patch, iterpool)); } } while (patch); @@ -2717,7 +2715,7 @@ apply_patches(void *baton, SVN_ERR(delete_empty_dirs(targets_info, btn->ctx, btn->dry_run, scratch_pool)); - SVN_ERR(svn_io_file_close(patch_file, iterpool)); + SVN_ERR(svn_diff_close_patch_file(patch_file, iterpool)); svn_pool_destroy(iterpool); return SVN_NO_ERROR; @@ -2738,6 +2736,7 @@ svn_client_patch(const char *patch_abspa apr_pool_t *scratch_pool) { apply_patches_baton_t baton; + svn_node_kind_t kind; if (strip_count < 0) return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL, @@ -2747,6 +2746,22 @@ svn_client_patch(const char *patch_abspa return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL, _("'%s' is not a local path"), local_abspath); + SVN_ERR(svn_io_check_path(patch_abspath, &kind, scratch_pool)); + if (kind == svn_node_none) + return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL, + _("'%s' does not exist"), patch_abspath); + if (kind != svn_node_file) + return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL, + _("'%s' is not a file"), patch_abspath); + + SVN_ERR(svn_io_check_path(local_abspath, &kind, scratch_pool)); + if (kind == svn_node_none) + return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL, + _("'%s' does not exist"), local_abspath); + if (kind != svn_node_dir) + return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL, + _("'%s' is not a directory"), local_abspath); + baton.patch_abspath = patch_abspath; baton.abs_wc_path = local_abspath; baton.dry_run = dry_run; Modified: subversion/branches/performance/subversion/libsvn_client/prop_commands.c URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_client/prop_commands.c?rev=1066452&r1=1066451&r2=1066452&view=diff ============================================================================== --- subversion/branches/performance/subversion/libsvn_client/prop_commands.c (original) +++ subversion/branches/performance/subversion/libsvn_client/prop_commands.c Wed Feb 2 13:04:51 2011 @@ -746,6 +746,9 @@ remote_propget(apr_hash_t *props, { apr_hash_t *dirents; apr_hash_t *prop_hash; + const svn_string_t *val; + const char *target_full_url = + svn_path_url_add_component2(target_prefix, target_relative, work_pool); if (kind == svn_node_dir) { @@ -761,29 +764,22 @@ remote_propget(apr_hash_t *props, } else if (kind == svn_node_none) { - return svn_error_createf - (SVN_ERR_ENTRY_NOT_FOUND, NULL, - _("'%s' does not exist in revision %ld"), - svn_uri_join(target_prefix, target_relative, work_pool), revnum); + return svn_error_createf(SVN_ERR_ENTRY_NOT_FOUND, NULL, + _("'%s' does not exist in revision %ld"), + target_full_url, revnum); } else { - return svn_error_createf - (SVN_ERR_NODE_UNKNOWN_KIND, NULL, - _("Unknown node kind for '%s'"), - svn_uri_join(target_prefix, target_relative, work_pool)); - } - - { - svn_string_t *val = apr_hash_get(prop_hash, propname, - APR_HASH_KEY_STRING); - if (val) - { - apr_hash_set(props, - svn_uri_join(target_prefix, target_relative, perm_pool), - APR_HASH_KEY_STRING, svn_string_dup(val, perm_pool)); - } - } + return svn_error_createf(SVN_ERR_NODE_UNKNOWN_KIND, NULL, + _("Unknown node kind for '%s'"), + target_full_url); + } + + if ((val = apr_hash_get(prop_hash, propname, APR_HASH_KEY_STRING))) + { + apr_hash_set(props, apr_pstrdup(perm_pool, target_full_url), + APR_HASH_KEY_STRING, svn_string_dup(val, perm_pool)); + } if (depth >= svn_depth_files && kind == svn_node_dir @@ -1071,6 +1067,8 @@ remote_proplist(const char *target_prefi apr_hash_t *dirents; apr_hash_t *prop_hash, *final_hash; apr_hash_index_t *hi; + const char *target_full_url = + svn_path_url_add_component2(target_prefix, target_relative, scratchpool); if (kind == svn_node_dir) { @@ -1086,10 +1084,9 @@ remote_proplist(const char *target_prefi } else { - return svn_error_createf - (SVN_ERR_NODE_UNKNOWN_KIND, NULL, - _("Unknown node kind for '%s'"), - svn_uri_join(target_prefix, target_relative, pool)); + return svn_error_createf(SVN_ERR_NODE_UNKNOWN_KIND, NULL, + _("Unknown node kind for '%s'"), + target_full_url); } /* Filter out non-regular properties, since the RA layer returns all @@ -1115,9 +1112,7 @@ remote_proplist(const char *target_prefi } } - call_receiver(svn_uri_join(target_prefix, target_relative, scratchpool), - final_hash, receiver, receiver_baton, - pool); + call_receiver(target_full_url, final_hash, receiver, receiver_baton, pool); if (depth > svn_depth_empty && (kind == svn_node_dir) && (apr_hash_count(dirents) > 0)) Modified: subversion/branches/performance/subversion/libsvn_client/ra.c URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_client/ra.c?rev=1066452&r1=1066451&r2=1066452&view=diff ============================================================================== --- subversion/branches/performance/subversion/libsvn_client/ra.c (original) +++ subversion/branches/performance/subversion/libsvn_client/ra.c Wed Feb 2 13:04:51 2011 @@ -759,20 +759,10 @@ svn_client__repos_locations(const char * "repository or refers to an unrelated object"), path_or_url_local_style(path, pool), end_revnum); - /* Repository paths might be absolute, but we want to treat them as - relative. - ### Aren't they always absolute? */ - if (start_path[0] == '/') - start_path = start_path + 1; - if (end_path[0] == '/') - end_path = end_path + 1; - /* Set our return variables */ - *start_url = svn_uri_join(repos_url, svn_path_uri_encode(start_path, - pool), pool); + *start_url = svn_path_url_add_component2(repos_url, start_path + 1, pool); if (end->kind != svn_opt_revision_unspecified) - *end_url = svn_uri_join(repos_url, svn_path_uri_encode(end_path, - pool), pool); + *end_url = svn_path_url_add_component2(repos_url, end_path + 1, pool); svn_pool_destroy(subpool); return SVN_NO_ERROR; Modified: subversion/branches/performance/subversion/libsvn_client/repos_diff.c URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_client/repos_diff.c?rev=1066452&r1=1066451&r2=1066452&view=diff ============================================================================== --- subversion/branches/performance/subversion/libsvn_client/repos_diff.c (original) +++ subversion/branches/performance/subversion/libsvn_client/repos_diff.c Wed Feb 2 13:04:51 2011 @@ -32,6 +32,8 @@ * each file have been created the diff callback is invoked to display * the difference between the two files. */ +#include + #include "svn_hash.h" #include "svn_wc.h" #include "svn_pools.h" @@ -66,6 +68,10 @@ struct edit_baton { /* RA_SESSION is the open session for making requests to the RA layer */ svn_ra_session_t *ra_session; + /* TRUE if RA_SESSION is open to a repository URL using the http or https + scheme. */ + svn_boolean_t is_dav_session; + /* The rev1 from the '-r Rev1:Rev2' command line option */ svn_revnum_t revision; @@ -1168,9 +1174,9 @@ change_file_prop(void *file_baton, if (b->skip) return SVN_NO_ERROR; - /* Issue #3657 'phantom svn:eol-style changes cause spurious merge text - conflicts'. When communicating with the repository via ra_serf and - ra_neon, the change_dir_prop and change_file_prop svn_delta_editor_t + /* Issue #3657 'dav update report handler in skelta mode can cause + spurious conflicts'. When communicating with the repository via ra_serf + and ra_neon, the change_dir_prop and change_file_prop svn_delta_editor_t callbacks are called (obviously) when a directory or file property has changed between the start and end of the edit. Less obvious however, is that these callbacks may be made describing *all* of the properties @@ -1178,11 +1184,24 @@ change_file_prop(void *file_baton, (Specifically ra_neon does this for diff/merge and ra_serf does it for diff/merge/update/switch). - Normally this is fairly harmless, but if it appears that the - svn:eol-style property has changed on a file, then we can get spurious - text conflicts (i.e. Issue #3657). To prevent this, we populate - FILE_BATON->PRISTINE_PROPS only with actual property changes. */ - if (value) + This means that the change_[file|dir]_prop svn_delta_editor_t callbacks + may be made where there are no property changes (i.e. a noop change of + NAME from VALUE to VALUE). Normally this is harmless, but during a + merge it can result in spurious conflicts if the WC's pristine property + NAME has a value other than VALUE. In an ideal world the mod_dav_svn + update report handler, when in 'skelta' mode and describing changes to + a path on which a property has changed, wouldn't ask the client to later + fetch all properties and figure out what has changed itself. The server + already knows which properties have changed! + + Regardless, such a change is not yet implemented, and even when it is, + the client should DTRT with regard to older servers which behave this + way. Hence this little hack: We populate FILE_BATON->PROPCHANGES only + with *actual* property changes. + + See http://subversion.tigris.org/issues/show_bug.cgi?id=3657#desc9 and + http://svn.haxx.se/dev/archive-2010-08/0351.shtml for more details. */ + if (value && b->edit_baton->is_dav_session) { const char *current_prop = svn_prop_get_value(b->pristine_props, name); if (current_prop && strcmp(current_prop, value->data) == 0) @@ -1210,6 +1229,15 @@ change_dir_prop(void *dir_baton, if (db->skip) return SVN_NO_ERROR; + /* See the comment re issue #3657 in the change_file_prop() callback. */ + if (value && db->edit_baton->is_dav_session) + { + const char *current_prop = svn_prop_get_value(db->pristine_props, + name); + if (current_prop && strcmp(current_prop, value->data) == 0) + return SVN_NO_ERROR; + } + propchange = apr_array_push(db->propchanges); propchange->name = apr_pstrdup(db->pool, name); propchange->value = value ? svn_string_dup(value, db->pool) : NULL; @@ -1309,6 +1337,10 @@ svn_client__get_diff_editor(const char * svn_delta_editor_t *tree_editor = svn_delta_default_editor(subpool); struct edit_baton *eb = apr_palloc(subpool, sizeof(*eb)); const char *target_abspath; + const char *session_url; + apr_status_t status; + apr_uri_t apr_uri; + SVN_ERR(svn_dirent_get_absolute(&target_abspath, target, pool)); eb->target = target; @@ -1317,6 +1349,23 @@ svn_client__get_diff_editor(const char * eb->diff_cmd_baton = diff_cmd_baton; eb->dry_run = dry_run; eb->ra_session = ra_session; + + SVN_ERR(svn_ra_get_session_url(ra_session, &session_url, subpool)); + status = apr_uri_parse(subpool, session_url, &apr_uri); + if (status) + { + return svn_error_createf(SVN_ERR_BAD_URL, NULL, + _("Unable to parse URL '%s'"), session_url); + } + else + { + if (svn_cstring_casecmp(apr_uri.scheme, "https") == 0 + || svn_cstring_casecmp(apr_uri.scheme, "http") == 0) + eb->is_dav_session = TRUE; + else + eb->is_dav_session = FALSE; + } + eb->revision = revision; eb->empty_file = NULL; eb->empty_hash = apr_hash_make(subpool); Modified: subversion/branches/performance/subversion/libsvn_client/status.c URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_client/status.c?rev=1066452&r1=1066451&r2=1066452&view=diff ============================================================================== --- subversion/branches/performance/subversion/libsvn_client/status.c (original) +++ subversion/branches/performance/subversion/libsvn_client/status.c Wed Feb 2 13:04:51 2011 @@ -585,6 +585,9 @@ svn_client_status_dup(const svn_client_s if (status->changelist) st->changelist = apr_pstrdup(result_pool, status->changelist); + if (status->ood_changed_author) + st->ood_changed_author = apr_pstrdup(result_pool, status->ood_changed_author); + if (status->repos_lock) st->repos_lock = svn_lock_dup(status->repos_lock, result_pool); Modified: subversion/branches/performance/subversion/libsvn_client/switch.c URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_client/switch.c?rev=1066452&r1=1066451&r2=1066452&view=diff ============================================================================== --- subversion/branches/performance/subversion/libsvn_client/switch.c (original) +++ subversion/branches/performance/subversion/libsvn_client/switch.c Wed Feb 2 13:04:51 2011 @@ -170,11 +170,9 @@ switch_internal(svn_revnum_t *result_rev /* Disallow a switch operation to change the repository root of the target. */ if (! svn_uri_is_ancestor(source_root, url)) - return svn_error_createf - (SVN_ERR_WC_INVALID_SWITCH, NULL, - _("'%s'\n" - "is not the same repository as\n" - "'%s'"), url, source_root); + return svn_error_createf(SVN_ERR_WC_INVALID_SWITCH, NULL, + _("'%s'\nis not the same repository as\n'%s'"), + url, source_root); SVN_ERR(svn_ra_reparent(ra_session, url, pool)); Modified: subversion/branches/performance/subversion/libsvn_client/update.c URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_client/update.c?rev=1066452&r1=1066451&r2=1066452&view=diff ============================================================================== --- subversion/branches/performance/subversion/libsvn_client/update.c (original) +++ subversion/branches/performance/subversion/libsvn_client/update.c Wed Feb 2 13:04:51 2011 @@ -298,7 +298,7 @@ svn_client__update_internal(svn_revnum_t { const char *anchor_abspath, *lockroot_abspath; svn_error_t *err; - svn_opt_revision_t peg_revision = *((svn_opt_revision_t *)revision); + svn_opt_revision_t peg_revision = *revision; SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath)); SVN_ERR_ASSERT(! (innerupdate && make_parents)); Modified: subversion/branches/performance/subversion/libsvn_client/util.c URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_client/util.c?rev=1066452&r1=1066451&r2=1066452&view=diff ============================================================================== --- subversion/branches/performance/subversion/libsvn_client/util.c (original) +++ subversion/branches/performance/subversion/libsvn_client/util.c Wed Feb 2 13:04:51 2011 @@ -36,6 +36,7 @@ #include "private/svn_client_private.h" #include "private/svn_wc_private.h" +#include "private/svn_fspath.h" #include "client.h" @@ -217,11 +218,10 @@ svn_client__path_relative_to_root(const "root URL '%s'"), abspath_or_url, repos_root); } - rel_url = svn_path_uri_decode(rel_url, result_pool); - *rel_path = include_leading_slash - ? apr_pstrcat(result_pool, "/", rel_url, - (char *)NULL) - : rel_url; + if (include_leading_slash) + *rel_path = svn_fspath__canonicalize(rel_url, result_pool); + else + *rel_path = apr_pstrdup(result_pool, rel_url); } return SVN_NO_ERROR; Modified: subversion/branches/performance/subversion/libsvn_delta/path_driver.c URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_delta/path_driver.c?rev=1066452&r1=1066451&r2=1066452&view=diff ============================================================================== --- subversion/branches/performance/subversion/libsvn_delta/path_driver.c (original) +++ subversion/branches/performance/subversion/libsvn_delta/path_driver.c Wed Feb 2 13:04:51 2011 @@ -31,6 +31,7 @@ #include "svn_dirent_uri.h" #include "svn_path.h" #include "svn_sorts.h" +#include "private/svn_fspath.h" /*** Helper functions. ***/