diff options
Diffstat (limited to 'subversion/libsvn_client/prop_commands.c')
-rw-r--r-- | subversion/libsvn_client/prop_commands.c | 1024 |
1 files changed, 692 insertions, 332 deletions
diff --git a/subversion/libsvn_client/prop_commands.c b/subversion/libsvn_client/prop_commands.c index e453830..06c4d21 100644 --- a/subversion/libsvn_client/prop_commands.c +++ b/subversion/libsvn_client/prop_commands.c @@ -38,43 +38,22 @@ #include "svn_pools.h" #include "svn_props.h" #include "svn_hash.h" +#include "svn_sorts.h" #include "svn_private_config.h" #include "private/svn_wc_private.h" +#include "private/svn_ra_private.h" #include "private/svn_client_private.h" /*** Code. ***/ -/* Check whether NAME is a revision property name. - * - * Return TRUE if it is. - * Return FALSE if it is not. - */ -static svn_boolean_t -is_revision_prop_name(const char *name) -{ - apr_size_t i; - static const char *revision_props[] = - { - SVN_PROP_REVISION_ALL_PROPS - }; - - for (i = 0; i < sizeof(revision_props) / sizeof(revision_props[0]); i++) - { - if (strcmp(name, revision_props[i]) == 0) - return TRUE; - } - return FALSE; -} - - /* Return an SVN_ERR_CLIENT_PROPERTY_NAME error if NAME is a wcprop, else return SVN_NO_ERROR. */ static svn_error_t * error_if_wcprop_name(const char *name) { - if (svn_property_kind(NULL, name) == svn_prop_wc_kind) + if (svn_property_kind2(name) == svn_prop_wc_kind) { return svn_error_createf (SVN_ERR_CLIENT_PROPERTY_NAME, NULL, @@ -109,7 +88,7 @@ get_file_for_validation(const svn_string_t **mime_type, pool)); if (mime_type) - *mime_type = apr_hash_get(props, SVN_PROP_MIME_TYPE, APR_HASH_KEY_STRING); + *mime_type = svn_hash_gets(props, SVN_PROP_MIME_TYPE); return SVN_NO_ERROR; } @@ -117,7 +96,8 @@ get_file_for_validation(const svn_string_t **mime_type, static svn_error_t * -do_url_propset(const char *propname, +do_url_propset(const char *url, + const char *propname, const svn_string_t *propval, const svn_node_kind_t kind, const svn_revnum_t base_revision_for_url, @@ -133,8 +113,10 @@ do_url_propset(const char *propname, if (kind == svn_node_file) { void *file_baton; - SVN_ERR(editor->open_file("", root_baton, base_revision_for_url, - pool, &file_baton)); + const char *uri_basename = svn_uri_basename(url, pool); + + SVN_ERR(editor->open_file(uri_basename, root_baton, + base_revision_for_url, pool, &file_baton)); SVN_ERR(editor->change_file_prop(file_baton, propname, propval, pool)); SVN_ERR(editor->close_file(file_baton, NULL, pool)); } @@ -158,7 +140,7 @@ propset_on_url(const char *propname, svn_client_ctx_t *ctx, apr_pool_t *pool) { - enum svn_prop_kind prop_kind = svn_property_kind(NULL, propname); + enum svn_prop_kind prop_kind = svn_property_kind2(propname); svn_ra_session_t *ra_session; svn_node_kind_t node_kind; const char *message; @@ -174,9 +156,8 @@ propset_on_url(const char *propname, /* Open an RA session for the URL. Note that we don't have a local directory, nor a place to put temp files. */ - SVN_ERR(svn_client__open_ra_session_internal(&ra_session, NULL, target, - NULL, NULL, FALSE, TRUE, - ctx, pool)); + SVN_ERR(svn_client_open_ra_session2(&ra_session, target, NULL, + ctx, pool, pool)); SVN_ERR(svn_ra_check_path(ra_session, "", base_revision_for_url, &node_kind, pool)); @@ -186,6 +167,18 @@ propset_on_url(const char *propname, _("Path '%s' does not exist in revision %ld"), target, base_revision_for_url); + if (node_kind == svn_node_file) + { + /* We need to reparent our session one directory up, since editor + semantics require the root is a directory. + + ### How does this interact with authz? */ + const char *parent_url; + parent_url = svn_uri_dirname(target, pool); + + SVN_ERR(svn_ra_reparent(ra_session, parent_url, pool)); + } + /* Setting an inappropriate property is not allowed (unless overridden by 'skip_checks', in some circumstances). Deleting an inappropriate property is allowed, however, since older clients @@ -227,6 +220,9 @@ propset_on_url(const char *propname, message, ctx, pool)); /* Fetch RA commit editor. */ + SVN_ERR(svn_ra__register_editor_shim_callbacks(ra_session, + svn_client__get_shim_callbacks(ctx->wc_ctx, + NULL, pool))); SVN_ERR(svn_ra_get_commit_editor3(ra_session, &editor, &edit_baton, commit_revprops, commit_callback, @@ -234,8 +230,8 @@ propset_on_url(const char *propname, NULL, TRUE, /* No lock tokens */ pool)); - err = do_url_propset(propname, propval, node_kind, base_revision_for_url, - editor, edit_baton, pool); + err = do_url_propset(target, propname, propval, node_kind, + base_revision_for_url, editor, edit_baton, pool); if (err) { @@ -248,37 +244,6 @@ propset_on_url(const char *propname, return editor->close_edit(edit_baton, pool); } -/* Baton for set_props_cb */ -struct set_props_baton -{ - svn_client_ctx_t *ctx; - const char *local_abspath; - svn_depth_t depth; - svn_node_kind_t kind; - const char *propname; - const svn_string_t *propval; - svn_boolean_t skip_checks; - const apr_array_header_t *changelist_filter; -}; - -/* Working copy lock callback for svn_client_propset4 */ -static svn_error_t * -set_props_cb(void *baton, - apr_pool_t *result_pool, - apr_pool_t *scratch_pool) -{ - struct set_props_baton *bt = baton; - - SVN_ERR(svn_wc_prop_set4(bt->ctx->wc_ctx, bt->local_abspath, bt->propname, - bt->propval, bt->depth, bt->skip_checks, - bt->changelist_filter, - bt->ctx->cancel_func, bt->ctx->cancel_baton, - bt->ctx->notify_func2, bt->ctx->notify_baton2, - scratch_pool)); - - return SVN_NO_ERROR; -} - /* Check that PROPNAME is a valid name for a versioned property. Return an * error if it is not valid, specifically if it is: * - the name of a standard Subversion rev-prop; or @@ -296,7 +261,7 @@ static svn_error_t * check_prop_name(const char *propname, const svn_string_t *propval) { - if (is_revision_prop_name(propname)) + if (svn_prop_is_known_svn_rev_prop(propname)) return svn_error_createf(SVN_ERR_CLIENT_PROPERTY_NAME, NULL, _("Revision property '%s' not allowed " "in this context"), propname); @@ -341,8 +306,6 @@ svn_client_propset_local(const char *propname, { svn_node_kind_t kind; const char *target_abspath; - svn_error_t *err; - struct set_props_baton baton; const char *target = APR_ARRAY_IDX(targets, i, const char *); svn_pool_clear(iterpool); @@ -353,11 +316,11 @@ svn_client_propset_local(const char *propname, SVN_ERR(svn_dirent_get_absolute(&target_abspath, target, iterpool)); - err = svn_wc_read_kind(&kind, ctx->wc_ctx, target_abspath, FALSE, - iterpool); + /* Call prop_set for deleted nodes to have special errors */ + SVN_ERR(svn_wc_read_kind2(&kind, ctx->wc_ctx, target_abspath, + FALSE, FALSE, iterpool)); - if ((err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND) - || (!err && (kind == svn_node_unknown || kind == svn_node_none))) + if (kind == svn_node_unknown || kind == svn_node_none) { if (ctx->notify_func2) { @@ -368,24 +331,14 @@ svn_client_propset_local(const char *propname, ctx->notify_func2(ctx->notify_baton2, notify, iterpool); } - - svn_error_clear(err); } - else - SVN_ERR(err); - - baton.ctx = ctx; - baton.local_abspath = target_abspath; - baton.depth = depth; - baton.kind = kind; - baton.propname = propname; - baton.propval = propval; - baton.skip_checks = skip_checks; - baton.changelist_filter = changelists; - - SVN_ERR(svn_wc__call_with_write_lock(set_props_cb, &baton, - ctx->wc_ctx, target_abspath, - FALSE, iterpool, iterpool)); + + SVN_WC__CALL_WITH_WRITE_LOCK( + svn_wc_prop_set4(ctx->wc_ctx, target_abspath, propname, + propval, depth, skip_checks, changelists, + ctx->cancel_func, ctx->cancel_baton, + ctx->notify_func2, ctx->notify_baton2, iterpool), + ctx->wc_ctx, target_abspath, FALSE /* lock_anchor */, iterpool); } svn_pool_destroy(iterpool); @@ -514,10 +467,9 @@ svn_client_revprop_set2(const char *propname, return svn_error_createf(SVN_ERR_CLIENT_PROPERTY_NAME, NULL, _("Bad property name: '%s'"), propname); - /* Open an RA session for the URL. Note that we don't have a local - directory, nor a place to put temp files. */ - SVN_ERR(svn_client__open_ra_session_internal(&ra_session, NULL, URL, NULL, - NULL, FALSE, TRUE, ctx, pool)); + /* Open an RA session for the URL. */ + SVN_ERR(svn_client_open_ra_session2(&ra_session, URL, NULL, + ctx, pool, pool)); /* Resolve the revision into something real, and return that to the caller as well. */ @@ -566,68 +518,30 @@ svn_client_revprop_set2(const char *propname, return SVN_NO_ERROR; } - -/* Set *PROPS to the pristine (base) properties at LOCAL_ABSPATH, if PRISTINE - * is true, or else the working value if PRISTINE is false. - * - * The keys of *PROPS will be 'const char *' property names, and the - * values 'const svn_string_t *' property values. Allocate *PROPS - * and its contents in RESULT_POOL. Use SCRATCH_POOL for temporary - * allocations. - */ -static svn_error_t * -pristine_or_working_props(apr_hash_t **props, - svn_wc_context_t *wc_ctx, - const char *local_abspath, - svn_boolean_t pristine, - apr_pool_t *result_pool, - apr_pool_t *scratch_pool) -{ - if (pristine) - { - return svn_error_trace(svn_wc_get_pristine_props(props, - wc_ctx, - local_abspath, - result_pool, - scratch_pool)); - } - - /* ### until svn_wc_prop_list2() returns a NULL value for locally-deleted - ### nodes, then let's check manually. */ - { - svn_boolean_t deleted; - - SVN_ERR(svn_wc__node_is_status_deleted(&deleted, wc_ctx, local_abspath, - scratch_pool)); - if (deleted) - { - *props = NULL; - return SVN_NO_ERROR; - } - } - - return svn_error_trace(svn_wc_prop_list2(props, wc_ctx, local_abspath, - result_pool, scratch_pool)); -} - - /* Helper for the remote case of svn_client_propget. * - * Get the value of property PROPNAME in REVNUM, using RA_LIB and - * SESSION. Store the value ('svn_string_t *') in PROPS, under the - * path key "TARGET_PREFIX/TARGET_RELATIVE" ('const char *'). + * If PROPS is not null, then get the value of property PROPNAME in REVNUM, + using RA_LIB and SESSION. Store the value ('svn_string_t *') in PROPS, + under the path key "TARGET_PREFIX/TARGET_RELATIVE" ('const char *'). + * + * If INHERITED_PROPS is not null, then set *INHERITED_PROPS to a + * depth-first ordered array of svn_prop_inherited_item_t * structures + * representing the PROPNAME properties inherited by the target. If + * INHERITABLE_PROPS in not null and no inheritable properties are found, + * then set *INHERITED_PROPS to an empty array. * * Recurse according to DEPTH, similarly to svn_client_propget3(). * * KIND is the kind of the node at "TARGET_PREFIX/TARGET_RELATIVE". * Yes, caller passes this; it makes the recursion more efficient :-). * - * Allocate the keys and values in PERM_POOL, but do all temporary - * work in WORK_POOL. The two pools can be the same; recursive - * calls may use a different WORK_POOL, however. + * Allocate PROPS and *INHERITED_PROPS in RESULT_POOL, but do all temporary + * work in SCRATCH_POOL. The two pools can be the same; recursive + * calls may use a different SCRATCH_POOL, however. */ static svn_error_t * remote_propget(apr_hash_t *props, + apr_array_header_t **inherited_props, const char *propname, const char *target_prefix, const char *target_relative, @@ -635,26 +549,27 @@ remote_propget(apr_hash_t *props, svn_revnum_t revnum, svn_ra_session_t *ra_session, svn_depth_t depth, - apr_pool_t *perm_pool, - apr_pool_t *work_pool) + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) { apr_hash_t *dirents; - apr_hash_t *prop_hash; + apr_hash_t *prop_hash = NULL; const svn_string_t *val; const char *target_full_url = - svn_path_url_add_component2(target_prefix, target_relative, work_pool); + svn_path_url_add_component2(target_prefix, target_relative, + scratch_pool); if (kind == svn_node_dir) { SVN_ERR(svn_ra_get_dir2(ra_session, (depth >= svn_depth_files ? &dirents : NULL), NULL, &prop_hash, target_relative, revnum, - SVN_DIRENT_KIND, work_pool)); + SVN_DIRENT_KIND, scratch_pool)); } else if (kind == svn_node_file) { SVN_ERR(svn_ra_get_file(ra_session, target_relative, revnum, - NULL, NULL, &prop_hash, work_pool)); + NULL, NULL, &prop_hash, scratch_pool)); } else if (kind == svn_node_none) { @@ -669,10 +584,59 @@ remote_propget(apr_hash_t *props, target_full_url); } - if ((val = apr_hash_get(prop_hash, propname, APR_HASH_KEY_STRING))) + if (inherited_props) + { + const char *repos_root_url; + + /* We will filter out all but PROPNAME later, making a final copy + in RESULT_POOL, so pass SCRATCH_POOL for all pools. */ + SVN_ERR(svn_ra_get_inherited_props(ra_session, inherited_props, + target_relative, revnum, + scratch_pool, scratch_pool)); + SVN_ERR(svn_ra_get_repos_root2(ra_session, &repos_root_url, + scratch_pool)); + SVN_ERR(svn_client__iprop_relpaths_to_urls(*inherited_props, + repos_root_url, + scratch_pool, + scratch_pool)); + } + + /* Make a copy of any inherited PROPNAME properties in RESULT_POOL. */ + if (inherited_props) + { + int i; + apr_array_header_t *final_iprops = + apr_array_make(result_pool, 1, sizeof(svn_prop_inherited_item_t *)); + + for (i = 0; i < (*inherited_props)->nelts; i++) + { + svn_prop_inherited_item_t *iprop = + APR_ARRAY_IDX((*inherited_props), i, svn_prop_inherited_item_t *); + svn_string_t *iprop_val = svn_hash_gets(iprop->prop_hash, propname); + + if (iprop_val) + { + svn_prop_inherited_item_t *new_iprop = + apr_palloc(result_pool, sizeof(*new_iprop)); + new_iprop->path_or_url = + apr_pstrdup(result_pool, iprop->path_or_url); + new_iprop->prop_hash = apr_hash_make(result_pool); + svn_hash_sets(new_iprop->prop_hash, + apr_pstrdup(result_pool, propname), + svn_string_dup(iprop_val, result_pool)); + APR_ARRAY_PUSH(final_iprops, svn_prop_inherited_item_t *) = + new_iprop; + } + } + *inherited_props = final_iprops; + } + + if (prop_hash + && (val = svn_hash_gets(prop_hash, propname))) { - apr_hash_set(props, apr_pstrdup(perm_pool, target_full_url), - APR_HASH_KEY_STRING, svn_string_dup(val, perm_pool)); + svn_hash_sets(props, + apr_pstrdup(result_pool, target_full_url), + svn_string_dup(val, result_pool)); } if (depth >= svn_depth_files @@ -680,9 +644,9 @@ remote_propget(apr_hash_t *props, && apr_hash_count(dirents) > 0) { apr_hash_index_t *hi; - apr_pool_t *iterpool = svn_pool_create(work_pool); + apr_pool_t *iterpool = svn_pool_create(scratch_pool); - for (hi = apr_hash_first(work_pool, dirents); + for (hi = apr_hash_first(scratch_pool, dirents); hi; hi = apr_hash_next(hi)) { @@ -702,7 +666,7 @@ remote_propget(apr_hash_t *props, new_target_relative = svn_relpath_join(target_relative, this_name, iterpool); - SVN_ERR(remote_propget(props, + SVN_ERR(remote_propget(props, NULL, propname, target_prefix, new_target_relative, @@ -710,7 +674,7 @@ remote_propget(apr_hash_t *props, revnum, ra_session, depth_below_here, - perm_pool, iterpool)); + result_pool, iterpool)); } svn_pool_destroy(iterpool); @@ -739,9 +703,8 @@ recursive_propget_receiver(void *baton, if (apr_hash_count(props)) { apr_hash_index_t *hi = apr_hash_first(scratch_pool, props); - apr_hash_set(b->props, apr_pstrdup(b->pool, local_abspath), - APR_HASH_KEY_STRING, - svn_string_dup(svn__apr_hash_index_val(hi), b->pool)); + svn_hash_sets(b->props, apr_pstrdup(b->pool, local_abspath), + svn_string_dup(svn__apr_hash_index_val(hi), b->pool)); } return SVN_NO_ERROR; @@ -762,7 +725,7 @@ recursive_propget_receiver(void *baton, Treat DEPTH as in svn_client_propget3(). */ static svn_error_t * -get_prop_from_wc(apr_hash_t *props, +get_prop_from_wc(apr_hash_t **props, const char *propname, const char *target_abspath, svn_boolean_t pristine, @@ -783,12 +746,24 @@ get_prop_from_wc(apr_hash_t *props, if (depth == svn_depth_unknown) depth = svn_depth_infinity; - rb.props = props; + if (!pristine && depth == svn_depth_infinity + && (!changelists || changelists->nelts == 0)) + { + /* Handle this common svn:mergeinfo case more efficient than the target + list handling in the recursive retrieval. */ + SVN_ERR(svn_wc__prop_retrieve_recursive( + props, ctx->wc_ctx, target_abspath, propname, + result_pool, scratch_pool)); + return SVN_NO_ERROR; + } + + *props = apr_hash_make(result_pool); + rb.props = *props; rb.pool = result_pool; rb.wc_ctx = ctx->wc_ctx; SVN_ERR(svn_wc__prop_list_recursive(ctx->wc_ctx, target_abspath, - propname, depth, FALSE, pristine, + propname, depth, pristine, changelists, recursive_propget_receiver, &rb, ctx->cancel_func, ctx->cancel_baton, @@ -799,7 +774,8 @@ get_prop_from_wc(apr_hash_t *props, /* Note: this implementation is very similar to svn_client_proplist. */ svn_error_t * -svn_client_propget4(apr_hash_t **props, +svn_client_propget5(apr_hash_t **props, + apr_array_header_t **inherited_props, const char *propname, const char *target, const svn_opt_revision_t *peg_revision, @@ -812,6 +788,8 @@ svn_client_propget4(apr_hash_t **props, apr_pool_t *scratch_pool) { svn_revnum_t revnum; + svn_boolean_t local_explicit_props; + svn_boolean_t local_iprops; SVN_ERR(error_if_wcprop_name(propname)); if (!svn_path_is_url(target)) @@ -821,11 +799,19 @@ svn_client_propget4(apr_hash_t **props, target); revision = svn_cl__rev_default_to_peg(revision, peg_revision); - *props = apr_hash_make(result_pool); + local_explicit_props = + (! svn_path_is_url(target) + && SVN_CLIENT__REVKIND_IS_LOCAL_TO_WC(peg_revision->kind) + && SVN_CLIENT__REVKIND_IS_LOCAL_TO_WC(revision->kind)); + + local_iprops = + (local_explicit_props + && (peg_revision->kind == svn_opt_revision_working + || peg_revision->kind == svn_opt_revision_unspecified ) + && (revision->kind == svn_opt_revision_working + || revision->kind == svn_opt_revision_unspecified )); - if (! svn_path_is_url(target) - && SVN_CLIENT__REVKIND_IS_LOCAL_TO_WC(peg_revision->kind) - && SVN_CLIENT__REVKIND_IS_LOCAL_TO_WC(revision->kind)) + if (local_explicit_props) { svn_node_kind_t kind; svn_boolean_t pristine; @@ -835,8 +821,9 @@ svn_client_propget4(apr_hash_t **props, pristine = (revision->kind == svn_opt_revision_committed || revision->kind == svn_opt_revision_base); - SVN_ERR(svn_wc_read_kind(&kind, ctx->wc_ctx, target, FALSE, - scratch_pool)); + SVN_ERR(svn_wc_read_kind2(&kind, ctx->wc_ctx, target, + pristine, FALSE, + scratch_pool)); if (kind == svn_node_unknown || kind == svn_node_none) { @@ -859,28 +846,137 @@ svn_client_propget4(apr_hash_t **props, else if (err) return svn_error_trace(err); - SVN_ERR(get_prop_from_wc(*props, propname, target, + if (inherited_props && local_iprops) + { + const char *repos_root_url; + + SVN_ERR(svn_wc__get_iprops(inherited_props, ctx->wc_ctx, + target, propname, + result_pool, scratch_pool)); + SVN_ERR(svn_client_get_repos_root(&repos_root_url, NULL, + target, ctx, scratch_pool, + scratch_pool)); + SVN_ERR(svn_client__iprop_relpaths_to_urls(*inherited_props, + repos_root_url, + result_pool, + scratch_pool)); + } + + SVN_ERR(get_prop_from_wc(props, propname, target, pristine, kind, - depth, changelists, ctx, scratch_pool, - result_pool)); + depth, changelists, ctx, result_pool, + scratch_pool)); } - else + + if ((inherited_props && !local_iprops) + || !local_explicit_props) { - const char *url; svn_ra_session_t *ra_session; svn_node_kind_t kind; + svn_opt_revision_t new_operative_rev; + svn_opt_revision_t new_peg_rev; + + /* Peg or operative revisions may be WC specific for + TARGET's explicit props, but still require us to + contact the repository for the inherited properties. */ + if (SVN_CLIENT__REVKIND_NEEDS_WC(peg_revision->kind) + || SVN_CLIENT__REVKIND_NEEDS_WC(revision->kind)) + { + svn_revnum_t origin_rev; + const char *repos_relpath; + const char *repos_root_url; + const char *repos_uuid; + const char *local_abspath; + const char *copy_root_abspath; + svn_boolean_t is_copy; + + /* Avoid assertion on the next line when somebody accidentally asks for + a working copy revision on a URL */ + if (svn_path_is_url(target)) + return svn_error_create(SVN_ERR_CLIENT_VERSIONED_PATH_REQUIRED, + NULL, NULL); + + SVN_ERR_ASSERT(svn_dirent_is_absolute(target)); + local_abspath = target; + + if (SVN_CLIENT__REVKIND_NEEDS_WC(peg_revision->kind)) + { + SVN_ERR(svn_wc__node_get_origin(&is_copy, + &origin_rev, + &repos_relpath, + &repos_root_url, + &repos_uuid, + ©_root_abspath, + ctx->wc_ctx, + local_abspath, + FALSE, /* scan_deleted */ + result_pool, + scratch_pool)); + if (repos_relpath) + { + target = svn_path_url_add_component2(repos_root_url, + repos_relpath, + scratch_pool); + if (SVN_CLIENT__REVKIND_NEEDS_WC(peg_revision->kind)) + { + svn_revnum_t resolved_peg_rev; + + SVN_ERR(svn_client__get_revision_number( + &resolved_peg_rev, NULL, ctx->wc_ctx, + local_abspath, NULL, peg_revision, scratch_pool)); + new_peg_rev.kind = svn_opt_revision_number; + new_peg_rev.value.number = resolved_peg_rev; + peg_revision = &new_peg_rev; + } + + if (SVN_CLIENT__REVKIND_NEEDS_WC(revision->kind)) + { + svn_revnum_t resolved_operative_rev; + + SVN_ERR(svn_client__get_revision_number( + &resolved_operative_rev, NULL, ctx->wc_ctx, + local_abspath, NULL, revision, scratch_pool)); + new_operative_rev.kind = svn_opt_revision_number; + new_operative_rev.value.number = resolved_operative_rev; + revision = &new_operative_rev; + } + } + else + { + /* TARGET doesn't exist in the repository, so there are + obviously not inherited props to be found there. */ + local_iprops = TRUE; + *inherited_props = apr_array_make( + result_pool, 0, sizeof(svn_prop_inherited_item_t *)); + } + } + } - /* Get an RA plugin for this filesystem object. */ - SVN_ERR(svn_client__ra_session_from_path(&ra_session, &revnum, - &url, target, NULL, - peg_revision, - revision, ctx, scratch_pool)); - - SVN_ERR(svn_ra_check_path(ra_session, "", revnum, &kind, scratch_pool)); - - SVN_ERR(remote_propget(*props, propname, url, "", - kind, revnum, ra_session, - depth, result_pool, scratch_pool)); + /* Do we still have anything to ask the repository about? */ + if (!local_explicit_props || !local_iprops) + { + svn_client__pathrev_t *loc; + + /* Get an RA plugin for this filesystem object. */ + SVN_ERR(svn_client__ra_session_from_path2(&ra_session, &loc, + target, NULL, + peg_revision, + revision, ctx, + scratch_pool)); + + SVN_ERR(svn_ra_check_path(ra_session, "", loc->rev, &kind, + scratch_pool)); + + if (!local_explicit_props) + *props = apr_hash_make(result_pool); + + SVN_ERR(remote_propget(!local_explicit_props ? *props : NULL, + !local_iprops ? inherited_props : NULL, + propname, loc->url, "", + kind, loc->rev, ra_session, + depth, result_pool, scratch_pool)); + revnum = loc->rev; + } } if (actual_revnum) @@ -898,35 +994,46 @@ svn_client_revprop_get(const char *propname, apr_pool_t *pool) { svn_ra_session_t *ra_session; + apr_pool_t *subpool = svn_pool_create(pool); + svn_error_t *err; /* Open an RA session for the URL. Note that we don't have a local directory, nor a place to put temp files. */ - SVN_ERR(svn_client__open_ra_session_internal(&ra_session, NULL, URL, NULL, - NULL, FALSE, TRUE, ctx, pool)); + SVN_ERR(svn_client_open_ra_session2(&ra_session, URL, NULL, + ctx, subpool, subpool)); /* Resolve the revision into something real, and return that to the caller as well. */ SVN_ERR(svn_client__get_revision_number(set_rev, NULL, ctx->wc_ctx, NULL, - ra_session, revision, pool)); + ra_session, revision, subpool)); /* The actual RA call. */ - return svn_ra_rev_prop(ra_session, *set_rev, propname, propval, pool); + err = svn_ra_rev_prop(ra_session, *set_rev, propname, propval, pool); + + /* Close RA session */ + svn_pool_destroy(subpool); + return svn_error_trace(err); } -/* Call RECEIVER for the given PATH and PROP_HASH. +/* Call RECEIVER for the given PATH and its PROP_HASH and/or + * INHERITED_PROPERTIES. * - * If PROP_HASH is null or has zero count, do nothing. + * If PROP_HASH is null or has zero count or INHERITED_PROPERTIES is null, + * then do nothing. */ static svn_error_t* call_receiver(const char *path, apr_hash_t *prop_hash, - svn_proplist_receiver_t receiver, + apr_array_header_t *inherited_properties, + svn_proplist_receiver2_t receiver, void *receiver_baton, - apr_pool_t *pool) + apr_pool_t *scratch_pool) { - if (prop_hash && apr_hash_count(prop_hash)) - SVN_ERR(receiver(receiver_baton, path, prop_hash, pool)); + if ((prop_hash && apr_hash_count(prop_hash)) + || inherited_properties) + SVN_ERR(receiver(receiver_baton, path, prop_hash, inherited_properties, + scratch_pool)); return SVN_NO_ERROR; } @@ -934,20 +1041,23 @@ call_receiver(const char *path, /* Helper for the remote case of svn_client_proplist. * - * Push a new 'svn_client_proplist_item_t *' item onto PROPLIST, - * containing the properties for "TARGET_PREFIX/TARGET_RELATIVE" in - * REVNUM, obtained using RA_LIB and SESSION. The item->node_name - * will be "TARGET_PREFIX/TARGET_RELATIVE", and the value will be a - * hash mapping 'const char *' property names onto 'svn_string_t *' - * property values. + * If GET_EXPLICIT_PROPS is true, then call RECEIVER for paths at or under + * "TARGET_PREFIX/TARGET_RELATIVE@REVNUM" (obtained using RA_SESSION) which + * have regular properties. If GET_TARGET_INHERITED_PROPS is true, then send + * the target's inherited properties to the callback. + * + * The 'path' and keys for 'prop_hash' and 'inherited_prop' arguments to + * RECEIVER are all URLs. * - * Allocate the new item and its contents in POOL. - * Do all looping, recursion, and temporary work in SCRATCHPOOL. + * RESULT_POOL is used to allocated the 'path', 'prop_hash', and + * 'inherited_prop' arguments to RECEIVER. SCRATCH_POOL is used for all + * other (temporary) allocations. * * KIND is the kind of the node at "TARGET_PREFIX/TARGET_RELATIVE". * * If the target is a directory, only fetch properties for the files - * and directories at depth DEPTH. + * and directories at depth DEPTH. DEPTH has not effect on inherited + * properties. */ static svn_error_t * remote_proplist(const char *target_prefix, @@ -955,29 +1065,36 @@ remote_proplist(const char *target_prefix, svn_node_kind_t kind, svn_revnum_t revnum, svn_ra_session_t *ra_session, + svn_boolean_t get_explicit_props, + svn_boolean_t get_target_inherited_props, svn_depth_t depth, - svn_proplist_receiver_t receiver, + svn_proplist_receiver2_t receiver, void *receiver_baton, - apr_pool_t *pool, - apr_pool_t *scratchpool) + svn_cancel_func_t cancel_func, + void *cancel_baton, + apr_pool_t *scratch_pool) { apr_hash_t *dirents; - apr_hash_t *prop_hash, *final_hash; + apr_hash_t *prop_hash = NULL; apr_hash_index_t *hi; const char *target_full_url = - svn_path_url_add_component2(target_prefix, target_relative, scratchpool); + svn_path_url_add_component2(target_prefix, target_relative, scratch_pool); + apr_array_header_t *inherited_props; + /* Note that we pass only the SCRATCH_POOL to svn_ra_get[dir*|file*] because + we'll be filtering out non-regular properties from PROP_HASH before we + return. */ if (kind == svn_node_dir) { SVN_ERR(svn_ra_get_dir2(ra_session, (depth > svn_depth_empty) ? &dirents : NULL, NULL, &prop_hash, target_relative, revnum, - SVN_DIRENT_KIND, scratchpool)); + SVN_DIRENT_KIND, scratch_pool)); } else if (kind == svn_node_file) { SVN_ERR(svn_ra_get_file(ra_session, target_relative, revnum, - NULL, NULL, &prop_hash, scratchpool)); + NULL, NULL, &prop_hash, scratch_pool)); } else { @@ -986,38 +1103,60 @@ remote_proplist(const char *target_prefix, target_full_url); } - /* Filter out non-regular properties, since the RA layer returns all - kinds. Copy regular properties keys/vals from the prop_hash - allocated in SCRATCHPOOL to the "final" hash allocated in POOL. */ - final_hash = apr_hash_make(pool); - for (hi = apr_hash_first(scratchpool, prop_hash); - hi; - hi = apr_hash_next(hi)) + if (get_target_inherited_props) { - const char *name = svn__apr_hash_index_key(hi); - apr_ssize_t klen = svn__apr_hash_index_klen(hi); - svn_string_t *value = svn__apr_hash_index_val(hi); - svn_prop_kind_t prop_kind; - - prop_kind = svn_property_kind(NULL, name); + const char *repos_root_url; + + SVN_ERR(svn_ra_get_inherited_props(ra_session, &inherited_props, + target_relative, revnum, + scratch_pool, scratch_pool)); + SVN_ERR(svn_ra_get_repos_root2(ra_session, &repos_root_url, + scratch_pool)); + SVN_ERR(svn_client__iprop_relpaths_to_urls(inherited_props, + repos_root_url, + scratch_pool, + scratch_pool)); + } + else + { + inherited_props = NULL; + } - if (prop_kind == svn_prop_regular_kind) + if (!get_explicit_props) + prop_hash = NULL; + else + { + /* Filter out non-regular properties, since the RA layer returns all + kinds. Copy regular properties keys/vals from the prop_hash + allocated in SCRATCH_POOL to the "final" hash allocated in + RESULT_POOL. */ + for (hi = apr_hash_first(scratch_pool, prop_hash); + hi; + hi = apr_hash_next(hi)) { - name = apr_pstrdup(pool, name); - value = svn_string_dup(value, pool); - apr_hash_set(final_hash, name, klen, value); + const char *name = svn__apr_hash_index_key(hi); + apr_ssize_t klen = svn__apr_hash_index_klen(hi); + svn_prop_kind_t prop_kind; + + prop_kind = svn_property_kind2(name); + + if (prop_kind != svn_prop_regular_kind) + { + apr_hash_set(prop_hash, name, klen, NULL); + } } } - SVN_ERR(call_receiver(target_full_url, final_hash, receiver, receiver_baton, - pool)); + SVN_ERR(call_receiver(target_full_url, prop_hash, inherited_props, + receiver, receiver_baton, scratch_pool)); if (depth > svn_depth_empty + && get_explicit_props && (kind == svn_node_dir) && (apr_hash_count(dirents) > 0)) { - apr_pool_t *subpool = svn_pool_create(scratchpool); + apr_pool_t *iterpool = svn_pool_create(scratch_pool); - for (hi = apr_hash_first(scratchpool, dirents); + for (hi = apr_hash_first(scratch_pool, dirents); hi; hi = apr_hash_next(hi)) { @@ -1025,10 +1164,13 @@ remote_proplist(const char *target_prefix, svn_dirent_t *this_ent = svn__apr_hash_index_val(hi); const char *new_target_relative; - svn_pool_clear(subpool); + if (cancel_func) + SVN_ERR(cancel_func(cancel_baton)); + + svn_pool_clear(iterpool); new_target_relative = svn_relpath_join(target_relative, - this_name, subpool); + this_name, iterpool); if (this_ent->kind == svn_node_file || depth > svn_depth_files) @@ -1043,15 +1185,16 @@ remote_proplist(const char *target_prefix, this_ent->kind, revnum, ra_session, + TRUE /* get_explicit_props */, + FALSE /* get_target_inherited_props */, depth_below_here, - receiver, - receiver_baton, - pool, - subpool)); + receiver, receiver_baton, + cancel_func, cancel_baton, + iterpool)); } } - svn_pool_destroy(subpool); + svn_pool_destroy(iterpool); } return SVN_NO_ERROR; @@ -1062,8 +1205,9 @@ remote_proplist(const char *target_prefix, struct recursive_proplist_receiver_baton { svn_wc_context_t *wc_ctx; /* Working copy context. */ - svn_proplist_receiver_t wrapped_receiver; /* Proplist receiver to call. */ + svn_proplist_receiver2_t wrapped_receiver; /* Proplist receiver to call. */ void *wrapped_receiver_baton; /* Baton for the proplist receiver. */ + apr_array_header_t *iprops; /* Anchor, anchor_abspath pair for converting to relative paths */ const char *anchor; @@ -1079,6 +1223,27 @@ recursive_proplist_receiver(void *baton, { struct recursive_proplist_receiver_baton *b = baton; const char *path; + apr_array_header_t *iprops = NULL; + + if (b->iprops + && ! strcmp(local_abspath, b->anchor_abspath)) + { + /* Report iprops with the properties for the anchor */ + iprops = b->iprops; + b->iprops = NULL; + } + else if (b->iprops) + { + /* No report for the root? + Report iprops anyway */ + + SVN_ERR(b->wrapped_receiver(b->wrapped_receiver_baton, + b->anchor ? b->anchor : b->anchor_abspath, + NULL /* prop_hash */, + b->iprops, + scratch_pool)); + b->iprops = NULL; + } /* Attempt to convert absolute paths to relative paths for * presentation purposes, if needed. */ @@ -1093,117 +1258,309 @@ recursive_proplist_receiver(void *baton, path = local_abspath; return svn_error_trace(b->wrapped_receiver(b->wrapped_receiver_baton, - path, props, scratch_pool)); + path, props, iprops, + scratch_pool)); } -svn_error_t * -svn_client_proplist3(const char *path_or_url, - const svn_opt_revision_t *peg_revision, - const svn_opt_revision_t *revision, - svn_depth_t depth, - const apr_array_header_t *changelists, - svn_proplist_receiver_t receiver, - void *receiver_baton, - svn_client_ctx_t *ctx, - apr_pool_t *pool) -{ - const char *url; - - peg_revision = svn_cl__rev_default_to_head_or_working(peg_revision, - path_or_url); - revision = svn_cl__rev_default_to_peg(revision, peg_revision); +/* Helper for svn_client_proplist4 when retrieving properties and/or + inherited properties from the repository. Except as noted below, + all arguments are as per svn_client_proplist4. - if (depth == svn_depth_unknown) - depth = svn_depth_empty; - - if (! svn_path_is_url(path_or_url) - && SVN_CLIENT__REVKIND_IS_LOCAL_TO_WC(peg_revision->kind) - && SVN_CLIENT__REVKIND_IS_LOCAL_TO_WC(revision->kind)) + GET_EXPLICIT_PROPS controls if explicit props are retrieved. */ +static svn_error_t * +get_remote_props(const char *path_or_url, + const svn_opt_revision_t *peg_revision, + const svn_opt_revision_t *revision, + svn_depth_t depth, + svn_boolean_t get_explicit_props, + svn_boolean_t get_target_inherited_props, + svn_proplist_receiver2_t receiver, + void *receiver_baton, + svn_client_ctx_t *ctx, + apr_pool_t *scratch_pool) +{ + svn_ra_session_t *ra_session; + svn_node_kind_t kind; + svn_opt_revision_t new_operative_rev; + svn_opt_revision_t new_peg_rev; + svn_client__pathrev_t *loc; + + /* Peg or operative revisions may be WC specific for + PATH_OR_URL's explicit props, but still require us to + contact the repository for the inherited properties. */ + if (SVN_CLIENT__REVKIND_NEEDS_WC(peg_revision->kind) + || SVN_CLIENT__REVKIND_NEEDS_WC(revision->kind)) { - svn_boolean_t pristine; - svn_node_kind_t kind; - apr_hash_t *changelist_hash = NULL; + svn_revnum_t origin_rev; + const char *repos_relpath; + const char *repos_root_url; + const char *repos_uuid; const char *local_abspath; + const char *copy_root_abspath; + svn_boolean_t is_copy; - SVN_ERR(svn_dirent_get_absolute(&local_abspath, path_or_url, pool)); - - pristine = ((revision->kind == svn_opt_revision_committed) - || (revision->kind == svn_opt_revision_base)); - - SVN_ERR(svn_wc_read_kind(&kind, ctx->wc_ctx, local_abspath, FALSE, - pool)); - - if (kind == svn_node_unknown || kind == svn_node_none) - { - /* svn uses SVN_ERR_UNVERSIONED_RESOURCE as warning only - for this function. */ - return svn_error_createf(SVN_ERR_UNVERSIONED_RESOURCE, NULL, - _("'%s' is not under version control"), - svn_dirent_local_style(local_abspath, - pool)); - } + /* Avoid assertion on the next line when somebody accidentally asks for + a working copy revision on a URL */ + if (svn_path_is_url(path_or_url)) + return svn_error_create(SVN_ERR_CLIENT_VERSIONED_PATH_REQUIRED, + NULL, NULL); - if (changelists && changelists->nelts) - SVN_ERR(svn_hash_from_cstring_keys(&changelist_hash, - changelists, pool)); + SVN_ERR(svn_dirent_get_absolute(&local_abspath, path_or_url, + scratch_pool)); - /* Fetch, recursively or not. */ - if (kind == svn_node_dir) + if (SVN_CLIENT__REVKIND_NEEDS_WC(peg_revision->kind)) { - struct recursive_proplist_receiver_baton rb; - - rb.wc_ctx = ctx->wc_ctx; - rb.wrapped_receiver = receiver; - rb.wrapped_receiver_baton = receiver_baton; - - if (strcmp(path_or_url, local_abspath) != 0) + SVN_ERR(svn_wc__node_get_origin(&is_copy, + &origin_rev, + &repos_relpath, + &repos_root_url, + &repos_uuid, + ©_root_abspath, + ctx->wc_ctx, + local_abspath, + FALSE, /* scan_deleted */ + scratch_pool, + scratch_pool)); + if (repos_relpath) { - rb.anchor = path_or_url; - rb.anchor_abspath = local_abspath; + path_or_url = + svn_path_url_add_component2(repos_root_url, + repos_relpath, + scratch_pool); + if (SVN_CLIENT__REVKIND_NEEDS_WC(peg_revision->kind)) + { + svn_revnum_t resolved_peg_rev; + + SVN_ERR(svn_client__get_revision_number(&resolved_peg_rev, + NULL, ctx->wc_ctx, + local_abspath, NULL, + peg_revision, + scratch_pool)); + new_peg_rev.kind = svn_opt_revision_number; + new_peg_rev.value.number = resolved_peg_rev; + peg_revision = &new_peg_rev; + } + + if (SVN_CLIENT__REVKIND_NEEDS_WC(revision->kind)) + { + svn_revnum_t resolved_operative_rev; + + SVN_ERR(svn_client__get_revision_number( + &resolved_operative_rev, + NULL, ctx->wc_ctx, + local_abspath, NULL, + revision, + scratch_pool)); + new_operative_rev.kind = svn_opt_revision_number; + new_operative_rev.value.number = resolved_operative_rev; + revision = &new_operative_rev; + } } else { - rb.anchor = NULL; - rb.anchor_abspath = NULL; + /* PATH_OR_URL doesn't exist in the repository, so there are + obviously not inherited props to be found there. If we + aren't looking for explicit props then we're done. */ + if (!get_explicit_props) + return SVN_NO_ERROR; } + } + } + + /* Get an RA session for this URL. */ + SVN_ERR(svn_client__ra_session_from_path2(&ra_session, &loc, + path_or_url, NULL, + peg_revision, + revision, ctx, + scratch_pool)); + + SVN_ERR(svn_ra_check_path(ra_session, "", loc->rev, &kind, + scratch_pool)); + + SVN_ERR(remote_proplist(loc->url, "", kind, loc->rev, ra_session, + get_explicit_props, + get_target_inherited_props, + depth, receiver, receiver_baton, + ctx->cancel_func, ctx->cancel_baton, + scratch_pool)); + return SVN_NO_ERROR; +} - SVN_ERR(svn_wc__prop_list_recursive(ctx->wc_ctx, local_abspath, NULL, - depth, - FALSE, pristine, changelists, - recursive_proplist_receiver, &rb, - ctx->cancel_func, - ctx->cancel_baton, pool)); +/* Helper for svn_client_proplist4 when retrieving properties and + possibly inherited properties from the WC. All arguments are as + per svn_client_proplist4. */ +static svn_error_t * +get_local_props(const char *path_or_url, + const svn_opt_revision_t *revision, + svn_depth_t depth, + const apr_array_header_t *changelists, + svn_boolean_t get_target_inherited_props, + svn_proplist_receiver2_t receiver, + void *receiver_baton, + svn_client_ctx_t *ctx, + apr_pool_t *scratch_pool) +{ + svn_boolean_t pristine; + svn_node_kind_t kind; + apr_hash_t *changelist_hash = NULL; + const char *local_abspath; + apr_array_header_t *iprops = NULL; + + SVN_ERR(svn_dirent_get_absolute(&local_abspath, path_or_url, + scratch_pool)); + + pristine = ((revision->kind == svn_opt_revision_committed) + || (revision->kind == svn_opt_revision_base)); + + SVN_ERR(svn_wc_read_kind2(&kind, ctx->wc_ctx, local_abspath, + pristine, FALSE, scratch_pool)); + + if (kind == svn_node_unknown || kind == svn_node_none) + { + /* svn uses SVN_ERR_UNVERSIONED_RESOURCE as warning only + for this function. */ + return svn_error_createf(SVN_ERR_UNVERSIONED_RESOURCE, NULL, + _("'%s' is not under version control"), + svn_dirent_local_style(local_abspath, + scratch_pool)); + } + + if (get_target_inherited_props) + { + const char *repos_root_url; + + SVN_ERR(svn_wc__get_iprops(&iprops, ctx->wc_ctx, local_abspath, + NULL, scratch_pool, scratch_pool)); + SVN_ERR(svn_client_get_repos_root(&repos_root_url, NULL, local_abspath, + ctx, scratch_pool, scratch_pool)); + SVN_ERR(svn_client__iprop_relpaths_to_urls(iprops, repos_root_url, + scratch_pool, + scratch_pool)); + } + + if (changelists && changelists->nelts) + SVN_ERR(svn_hash_from_cstring_keys(&changelist_hash, + changelists, scratch_pool)); + + /* Fetch, recursively or not. */ + if (kind == svn_node_dir) + { + struct recursive_proplist_receiver_baton rb; + + rb.wc_ctx = ctx->wc_ctx; + rb.wrapped_receiver = receiver; + rb.wrapped_receiver_baton = receiver_baton; + rb.iprops = iprops; + rb.anchor_abspath = local_abspath; + + if (strcmp(path_or_url, local_abspath) != 0) + { + rb.anchor = path_or_url; } - else if (svn_wc__changelist_match(ctx->wc_ctx, local_abspath, - changelist_hash, pool)) + else { - apr_hash_t *hash; + rb.anchor = NULL; + } - SVN_ERR(pristine_or_working_props(&hash, ctx->wc_ctx, local_abspath, - pristine, pool, pool)); - SVN_ERR(call_receiver(path_or_url, hash, - receiver, receiver_baton, pool)); + SVN_ERR(svn_wc__prop_list_recursive(ctx->wc_ctx, local_abspath, NULL, + depth, pristine, changelists, + recursive_proplist_receiver, &rb, + ctx->cancel_func, ctx->cancel_baton, + scratch_pool)); + if (rb.iprops) + { + /* We didn't report for the root. Report iprops anyway */ + SVN_ERR(call_receiver(path_or_url, NULL /* props */, rb.iprops, + receiver, receiver_baton, scratch_pool)); } } - else /* remote target */ + else if (svn_wc__changelist_match(ctx->wc_ctx, local_abspath, + changelist_hash, scratch_pool)) { - svn_ra_session_t *ra_session; - svn_node_kind_t kind; - apr_pool_t *subpool = svn_pool_create(pool); - svn_revnum_t revnum; + apr_hash_t *props; + + if (pristine) + SVN_ERR(svn_wc_get_pristine_props(&props, + ctx->wc_ctx, local_abspath, + scratch_pool, scratch_pool)); + else + { + svn_error_t *err; + + err = svn_wc_prop_list2(&props, ctx->wc_ctx, local_abspath, + scratch_pool, scratch_pool); + + + if (err) + { + if (err->apr_err != SVN_ERR_WC_PATH_UNEXPECTED_STATUS) + return svn_error_trace(err); + /* As svn_wc_prop_list2() doesn't return NULL for locally-deleted + let's do that here. */ + svn_error_clear(err); + props = apr_hash_make(scratch_pool); + } + } + + SVN_ERR(call_receiver(path_or_url, props, iprops, + receiver, receiver_baton, scratch_pool)); - /* Get an RA session for this URL. */ - SVN_ERR(svn_client__ra_session_from_path(&ra_session, &revnum, - &url, path_or_url, NULL, - peg_revision, - revision, ctx, pool)); + } + return SVN_NO_ERROR; +} - SVN_ERR(svn_ra_check_path(ra_session, "", revnum, &kind, pool)); +svn_error_t * +svn_client_proplist4(const char *path_or_url, + const svn_opt_revision_t *peg_revision, + const svn_opt_revision_t *revision, + svn_depth_t depth, + const apr_array_header_t *changelists, + svn_boolean_t get_target_inherited_props, + svn_proplist_receiver2_t receiver, + void *receiver_baton, + svn_client_ctx_t *ctx, + apr_pool_t *scratch_pool) +{ + svn_boolean_t local_explicit_props; + svn_boolean_t local_iprops; - SVN_ERR(remote_proplist(url, "", kind, revnum, ra_session, depth, - receiver, receiver_baton, pool, subpool)); - svn_pool_destroy(subpool); + peg_revision = svn_cl__rev_default_to_head_or_working(peg_revision, + path_or_url); + revision = svn_cl__rev_default_to_peg(revision, peg_revision); + + if (depth == svn_depth_unknown) + depth = svn_depth_empty; + + /* Are explicit props available locally? */ + local_explicit_props = + (! svn_path_is_url(path_or_url) + && SVN_CLIENT__REVKIND_IS_LOCAL_TO_WC(peg_revision->kind) + && SVN_CLIENT__REVKIND_IS_LOCAL_TO_WC(revision->kind)); + + /* If we want iprops are they available locally? */ + local_iprops = + (get_target_inherited_props /* We want iprops */ + && local_explicit_props /* No local explicit props means no local iprops. */ + && (peg_revision->kind == svn_opt_revision_working + || peg_revision->kind == svn_opt_revision_unspecified ) + && (revision->kind == svn_opt_revision_working + || revision->kind == svn_opt_revision_unspecified )); + + if ((get_target_inherited_props && !local_iprops) + || !local_explicit_props) + { + SVN_ERR(get_remote_props(path_or_url, peg_revision, revision, depth, + !local_explicit_props, + (get_target_inherited_props && !local_iprops), + receiver, receiver_baton, ctx, scratch_pool)); + } + + if (local_explicit_props) + { + SVN_ERR(get_local_props(path_or_url, revision, depth, changelists, + local_iprops, receiver, receiver_baton, ctx, + scratch_pool)); } return SVN_NO_ERROR; @@ -1219,20 +1576,23 @@ svn_client_revprop_list(apr_hash_t **props, { svn_ra_session_t *ra_session; apr_hash_t *proplist; + apr_pool_t *subpool = svn_pool_create(pool); + svn_error_t *err; /* Open an RA session for the URL. Note that we don't have a local directory, nor a place to put temp files. */ - SVN_ERR(svn_client__open_ra_session_internal(&ra_session, NULL, URL, NULL, - NULL, FALSE, TRUE, ctx, pool)); + SVN_ERR(svn_client_open_ra_session2(&ra_session, URL, NULL, + ctx, subpool, subpool)); /* Resolve the revision into something real, and return that to the caller as well. */ SVN_ERR(svn_client__get_revision_number(set_rev, NULL, ctx->wc_ctx, NULL, - ra_session, revision, pool)); + ra_session, revision, subpool)); /* The actual RA call. */ - SVN_ERR(svn_ra_rev_proplist(ra_session, *set_rev, &proplist, pool)); + err = svn_ra_rev_proplist(ra_session, *set_rev, &proplist, pool); *props = proplist; - return SVN_NO_ERROR; + svn_pool_destroy(subpool); /* Close RA session */ + return svn_error_trace(err); } |