summaryrefslogtreecommitdiff
path: root/subversion/libsvn_client/prop_commands.c
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/libsvn_client/prop_commands.c')
-rw-r--r--subversion/libsvn_client/prop_commands.c1024
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,
+ &copy_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,
+ &copy_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);
}