📄 prop_commands.c
字号:
/* * prop_commands.c: Implementation of propset, propget, and proplist. * * ==================================================================== * Copyright (c) 2000-2006 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. ***/#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_props.h"#include "svn_ctype.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_tis_valid_prop_name(const char *name){ const char *p = name; /* The characters we allow use identical representations in UTF8 and ASCII, so we can just test for the appropriate ASCII codes. But we can't use standard C character notation ('A', 'B', etc) because there's no guarantee that this C environment is using ASCII. */ if (!(svn_ctype_isalpha(*p) || *p == SVN_CTYPE_ASCII_COLON || *p == SVN_CTYPE_ASCII_UNDERSCORE)) return FALSE; p++; for (; *p; p++) { if (!(svn_ctype_isalnum(*p) || *p == SVN_CTYPE_ASCII_MINUS || *p == SVN_CTYPE_ASCII_DOT || *p == SVN_CTYPE_ASCII_COLON || *p == SVN_CTYPE_ASCII_UNDERSCORE)) 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_tis_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;}/* 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) { return svn_error_createf (SVN_ERR_CLIENT_PROPERTY_NAME, NULL, _("'%s' is a wcprop, thus not accessible to clients"), name); } return SVN_NO_ERROR;}/* 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. */ svn_boolean_t force; /* True iff force was passed. */};/* An entries-walk callback for svn_client_propset2. * * 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_set2(wb->propname, wb->propval, path, adm_access, wb->force, 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_propset2(const char *propname, const svn_string_t *propval, const char *target, svn_boolean_t recurse, svn_boolean_t skip_checks, svn_client_ctx_t *ctx, apr_pool_t *pool){ svn_wc_adm_access_t *adm_access; const svn_wc_entry_t *node; /* Since Subversion controls the "svn:" property namespace, we don't honor the 'skip_checks' flag here. Unusual property combinations, like svn:eol-style with a non-text svn:mime-type, are understandable, but revprops on local targets are not. */ 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); } SVN_ERR(error_if_wcprop_name(propname)); if (svn_path_is_url(target)) { /* The rationale for not supporting this is that it makes it too easy to possibly overwrite someone else's change without noticing. (See also tools/examples/svnput.c). Besides, we don't have a client context for auth or log getting in this function anyway. */ return svn_error_createf (SVN_ERR_UNSUPPORTED_FEATURE, NULL, _("Setting property on non-local target '%s' is not 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_open3(&adm_access, NULL, target, TRUE, recurse ? -1 : 0, ctx->cancel_func, ctx->cancel_baton, 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"), svn_path_local_style(target, pool)); 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; wb.force = skip_checks; SVN_ERR(svn_wc_walk_entries2(target, adm_access, &walk_callbacks, &wb, FALSE, ctx->cancel_func, ctx->cancel_baton, pool)); } else { SVN_ERR(svn_wc_prop_set2(propname, propval, target, adm_access, skip_checks, pool)); } SVN_ERR(svn_wc_adm_close(adm_access)); 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_client_ctx_t *ctx; SVN_ERR(svn_client_create_context(&ctx, pool)); return svn_client_propset2(propname, propval, target, recurse, FALSE, ctx, pool);}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){ svn_ra_session_t *ra_session; 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_client__open_ra_session_internal(&ra_session, 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_session, revision, NULL, pool)); /* The actual RA call. */ SVN_ERR(svn_ra_change_rev_prop(ra_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)); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -