📄 prop_commands.c
字号:
/*
* prop_commands.c: Implementation of propset, propget, and proplist.
*
* ====================================================================
* Copyright (c) 2000-2004 CollabNet. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://subversion.tigris.org/license-1.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
*
* This software consists of voluntary contributions made by many
* individuals. For exact contribution history, see the revision
* history and logs, available at http://subversion.tigris.org/.
* ====================================================================
*/
/* ==================================================================== */
/*** Includes. ***/
#include <ctype.h>
#define APR_WANT_STRFUNC
#include <apr_want.h>
#include "svn_client.h"
#include "client.h"
#include "svn_path.h"
#include "svn_pools.h"
#include "svn_private_config.h"
/*** Code. ***/
/* Check whether the UTF8 NAME is a valid property name. For now, this means
* the ASCII subset of an XML "Name".
* XML "Name" is defined at http://www.w3.org/TR/REC-xml#sec-common-syn */
static svn_boolean_t
is_valid_prop_name (const char *name)
{
const char *p = name;
/* Each byte of a UTF8-encoded non-ASCII character has its high bit set and
* so will be rejected by this function. */
if (! isalpha (*p) && ! strchr ("_:", *p))
return FALSE;
p++;
for (; *p; p++)
{
if (! isalnum (*p) && ! strchr (".-_:", *p))
return FALSE;
}
return TRUE;
}
/* 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;
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;
}
/* A baton for propset_walk_cb. */
struct propset_walk_baton
{
const char *propname; /* The name of the property to set. */
const svn_string_t *propval; /* The value to set. */
svn_wc_adm_access_t *base_access; /* Access for the tree being walked. */
};
/* An entries-walk callback for svn_client_propset.
*
* For the path given by PATH and ENTRY,
* set the property named wb->PROPNAME to the value wb->PROPVAL,
* where "wb" is the WALK_BATON of type "struct propset_walk_baton *".
*/
static svn_error_t *
propset_walk_cb (const char *path,
const svn_wc_entry_t *entry,
void *walk_baton,
apr_pool_t *pool)
{
struct propset_walk_baton *wb = walk_baton;
svn_error_t *err;
svn_wc_adm_access_t *adm_access;
/* We're going to receive dirents twice; we want to ignore the
first one (where it's a child of a parent dir), and only use
the second one (where we're looking at THIS_DIR). */
if ((entry->kind == svn_node_dir)
&& (strcmp (entry->name, SVN_WC_ENTRY_THIS_DIR) != 0))
return SVN_NO_ERROR;
/* Ignore the entry if it does not exist at the time of interest. */
if (entry->schedule == svn_wc_schedule_delete)
return SVN_NO_ERROR;
SVN_ERR (svn_wc_adm_retrieve (&adm_access, wb->base_access,
(entry->kind == svn_node_dir ? path
: svn_path_dirname (path, pool)),
pool));
err = svn_wc_prop_set (wb->propname, wb->propval,
path, adm_access, pool);
if (err)
{
if (err->apr_err != SVN_ERR_ILLEGAL_TARGET)
return err;
svn_error_clear (err);
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_client_propset (const char *propname,
const svn_string_t *propval,
const char *target,
svn_boolean_t recurse,
apr_pool_t *pool)
{
svn_wc_adm_access_t *adm_access;
const svn_wc_entry_t *node;
if (is_revision_prop_name (propname))
{
return svn_error_createf (SVN_ERR_CLIENT_PROPERTY_NAME, NULL,
_("Revision property '%s' not allowed "
"in this context"), propname);
}
if (svn_path_is_url (target))
{
/* ### Note that this function will need to take an auth baton
if it's ever to support setting properties remotely. */
return svn_error_createf
(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
_("Setting property on non-local target '%s' not yet supported"),
target);
}
if (propval && ! is_valid_prop_name (propname))
return svn_error_createf (SVN_ERR_CLIENT_PROPERTY_NAME, NULL,
_("Bad property name: '%s'"), propname);
SVN_ERR (svn_wc_adm_probe_open2 (&adm_access, NULL, target, TRUE,
recurse ? -1 : 0, pool));
SVN_ERR (svn_wc_entry (&node, target, adm_access, FALSE, pool));
if (!node)
return svn_error_createf (SVN_ERR_UNVERSIONED_RESOURCE, NULL,
_("'%s' is not under version control"),
target);
if (recurse && node->kind == svn_node_dir)
{
static const svn_wc_entry_callbacks_t walk_callbacks
= { propset_walk_cb };
struct propset_walk_baton wb;
wb.base_access = adm_access;
wb.propname = propname;
wb.propval = propval;
SVN_ERR (svn_wc_walk_entries (target, adm_access,
&walk_callbacks, &wb, FALSE, pool));
}
else
{
SVN_ERR (svn_wc_prop_set (propname, propval, target, adm_access, pool));
}
SVN_ERR (svn_wc_adm_close (adm_access));
return SVN_NO_ERROR;
}
svn_error_t *
svn_client_revprop_set (const char *propname,
const svn_string_t *propval,
const char *URL,
const svn_opt_revision_t *revision,
svn_revnum_t *set_rev,
svn_boolean_t force,
svn_client_ctx_t *ctx,
apr_pool_t *pool)
{
void *ra_baton, *session;
svn_ra_plugin_t *ra_lib;
if ((strcmp (propname, SVN_PROP_REVISION_AUTHOR) == 0)
&& propval
&& strchr (propval->data, '\n') != NULL
&& (! force))
return svn_error_create (SVN_ERR_CLIENT_REVISION_AUTHOR_CONTAINS_NEWLINE,
NULL, _("Value will not be set unless forced"));
if (propval && ! is_valid_prop_name (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_ra_init_ra_libs (&ra_baton, pool));
SVN_ERR (svn_ra_get_ra_library (&ra_lib, ra_baton, URL, pool));
SVN_ERR (svn_client__open_ra_session (&session, ra_lib, URL, NULL,
NULL, NULL, FALSE, TRUE,
ctx, pool));
/* Resolve the revision into something real, and return that to the
caller as well. */
SVN_ERR (svn_client__get_revision_number
(set_rev, ra_lib, session, revision, NULL, pool));
/* The actual RA call. */
SVN_ERR (ra_lib->change_rev_prop (session, *set_rev, propname, propval,
pool));
return SVN_NO_ERROR;
}
/* Set *PROPS to the pristine (base) properties at PATH, 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 POOL.
*/
static svn_error_t *
pristine_or_working_props (apr_hash_t **props,
const char *path,
svn_wc_adm_access_t *adm_access,
svn_boolean_t pristine,
apr_pool_t *pool)
{
if (pristine)
SVN_ERR (svn_wc_get_prop_diffs (NULL, props, path, adm_access, pool));
else
SVN_ERR (svn_wc_prop_list (props, path, adm_access, pool));
return SVN_NO_ERROR;
}
/* Set *PROPVAL to the pristine (base) value of property PROPNAME at
* PATH, if PRISTINE is true, or else the working value if PRISTINE is
* false. Allocate *PROPVAL in POOL.
*/
static svn_error_t *
pristine_or_working_propval (const svn_string_t **propval,
const char *propname,
const char *path,
svn_wc_adm_access_t *adm_access,
svn_boolean_t pristine,
apr_pool_t *pool)
{
if (pristine)
{
apr_hash_t *pristine_props;
SVN_ERR (svn_wc_get_prop_diffs (NULL, &pristine_props, path, adm_access,
pool));
*propval = apr_hash_get (pristine_props, propname, APR_HASH_KEY_STRING);
}
else /* get the working revision */
{
SVN_ERR (svn_wc_prop_get (propval, propname, path, adm_access, pool));
}
return SVN_NO_ERROR;
}
/* A baton for propget_walk_cb. */
struct propget_walk_baton
{
const char *propname; /* The name of the property to get. */
svn_boolean_t pristine; /* Select base rather than working props. */
svn_wc_adm_access_t *base_access; /* Access for the tree being walked. */
apr_hash_t *props; /* Out: mapping of (path:propval). */
};
/* An entries-walk callback for svn_client_propget.
*
* For the path given by PATH and ENTRY,
* populate wb->PROPS with the values of property wb->PROPNAME,
* where "wb" is the WALK_BATON of type "struct propget_walk_baton *".
* If wb->PRISTINE is true, use the base value, else use the working value.
*
* The keys of wb->PROPS will be 'const char *' paths, rooted at the
* path svn_wc_adm_access_path(ADM_ACCESS), and the values are
* 'const svn_string_t *' property values.
*/
static svn_error_t *
propget_walk_cb (const char *path,
const svn_wc_entry_t *entry,
void *walk_baton,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -