Alien-SVN
view release on metacpan or search on metacpan
src/subversion/subversion/libsvn_wc/props.c view on Meta::CPAN
return SVN_NO_ERROR;
}
/* Validate that a file has a 'non-binary' MIME type and contains
* self-consistent line endings. If not, then return an error.
*
* Call GETTER (which must not be NULL) with GETTER_BATON to get the
* file's MIME type and/or content. If the MIME type is non-null and
* is categorized as 'binary' then return an error and do not request
* the file content.
*
* Use PATH (a local path or a URL) only for error messages.
*/
static svn_error_t *
validate_eol_prop_against_file(const char *path,
svn_wc_canonicalize_svn_prop_get_file_t getter,
void *getter_baton,
apr_pool_t *pool)
{
svn_stream_t *translating_stream;
svn_error_t *err;
const svn_string_t *mime_type;
const char *path_display
= svn_path_is_url(path) ? path : svn_dirent_local_style(path, pool);
/* First just ask the "getter" for the MIME type. */
SVN_ERR(getter(&mime_type, NULL, getter_baton, pool));
/* See if this file has been determined to be binary. */
if (mime_type && svn_mime_type_is_binary(mime_type->data))
return svn_error_createf
(SVN_ERR_ILLEGAL_TARGET, NULL,
_("Can't set '%s': "
"file '%s' has binary mime type property"),
SVN_PROP_EOL_STYLE, path_display);
/* Now ask the getter for the contents of the file; this will do a
newline translation. All we really care about here is whether or
not the function fails on inconsistent line endings. The
function is "translating" to an empty stream. This is
sneeeeeeeeeeeaky. */
translating_stream = svn_subst_stream_translated(svn_stream_empty(pool),
"", FALSE, NULL, FALSE,
pool);
err = getter(NULL, translating_stream, getter_baton, pool);
err = svn_error_compose_create(err, svn_stream_close(translating_stream));
if (err && err->apr_err == SVN_ERR_IO_INCONSISTENT_EOL)
return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, err,
_("File '%s' has inconsistent newlines"),
path_display);
return svn_error_trace(err);
}
static svn_error_t *
do_propset(svn_wc__db_t *db,
const char *local_abspath,
svn_node_kind_t kind,
const char *name,
const svn_string_t *value,
svn_boolean_t skip_checks,
svn_wc_notify_func2_t notify_func,
void *notify_baton,
apr_pool_t *scratch_pool)
{
apr_hash_t *prophash;
svn_wc_notify_action_t notify_action;
svn_skel_t *work_item = NULL;
svn_boolean_t clear_recorded_info = FALSE;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR_W(svn_wc__db_read_props(&prophash, db, local_abspath,
scratch_pool, scratch_pool),
_("Failed to load current properties"));
/* 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
allowed (and other clients possibly still allow) setting it in
the first place. */
if (value && svn_prop_is_svn_prop(name))
{
const svn_string_t *new_value;
struct getter_baton gb;
gb.mime_type = svn_hash_gets(prophash, SVN_PROP_MIME_TYPE);
gb.local_abspath = local_abspath;
SVN_ERR(svn_wc_canonicalize_svn_prop(&new_value, name, value,
local_abspath, kind,
skip_checks,
get_file_for_validation, &gb,
scratch_pool));
value = new_value;
}
if (kind == svn_node_file
&& (strcmp(name, SVN_PROP_EXECUTABLE) == 0
|| strcmp(name, SVN_PROP_NEEDS_LOCK) == 0))
{
SVN_ERR(svn_wc__wq_build_sync_file_flags(&work_item, db, local_abspath,
scratch_pool, scratch_pool));
}
/* If we're changing this file's list of expanded keywords, then
* we'll need to invalidate its text timestamp, since keyword
* expansion affects the comparison of working file to text base.
*
* Here we retrieve the old list of expanded keywords; after the
* property is set, we'll grab the new list and see if it differs
* from the old one.
*/
if (kind == svn_node_file && strcmp(name, SVN_PROP_KEYWORDS) == 0)
{
svn_string_t *old_value = svn_hash_gets(prophash, SVN_PROP_KEYWORDS);
src/subversion/subversion/libsvn_wc/props.c view on Meta::CPAN
}
else if (kind == svn_node_file && strcmp(name, SVN_PROP_EOL_STYLE) == 0)
{
svn_string_t *old_value = svn_hash_gets(prophash, SVN_PROP_EOL_STYLE);
if (((value == NULL) != (old_value == NULL))
|| (value && ! svn_string_compare(value, old_value)))
{
clear_recorded_info = TRUE;
}
}
/* Find out what type of property change we are doing: add, modify, or
delete. */
if (svn_hash_gets(prophash, name) == NULL)
{
if (value == NULL)
/* Deleting a non-existent property. */
notify_action = svn_wc_notify_property_deleted_nonexistent;
else
/* Adding a property. */
notify_action = svn_wc_notify_property_added;
}
else
{
if (value == NULL)
/* Deleting the property. */
notify_action = svn_wc_notify_property_deleted;
else
/* Modifying property. */
notify_action = svn_wc_notify_property_modified;
}
/* Now we have all the properties in our hash. Simply merge the new
property into it. */
svn_hash_sets(prophash, name, value);
/* Drop it right into the db.. */
SVN_ERR(svn_wc__db_op_set_props(db, local_abspath, prophash,
clear_recorded_info, NULL, work_item,
scratch_pool));
/* Run our workqueue item for sync'ing flags with props. */
if (work_item)
SVN_ERR(svn_wc__wq_run(db, local_abspath, NULL, NULL, scratch_pool));
if (notify_func)
{
svn_wc_notify_t *notify = svn_wc_create_notify(local_abspath,
notify_action,
scratch_pool);
notify->prop_name = name;
notify->kind = kind;
(*notify_func)(notify_baton, notify, scratch_pool);
}
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__db_t *db; /* Database for the tree being walked. */
svn_boolean_t force; /* True iff force was passed. */
svn_wc_notify_func2_t notify_func;
void *notify_baton;
};
/* An node-walk callback for svn_wc_prop_set4().
*
* For LOCAL_ABSPATH, 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 *local_abspath,
svn_node_kind_t kind,
void *walk_baton,
apr_pool_t *scratch_pool)
{
struct propset_walk_baton *wb = walk_baton;
svn_error_t *err;
err = do_propset(wb->db, local_abspath, kind, wb->propname, wb->propval,
wb->force, wb->notify_func, wb->notify_baton, scratch_pool);
if (err && (err->apr_err == SVN_ERR_ILLEGAL_TARGET
|| err->apr_err == SVN_ERR_WC_PATH_UNEXPECTED_STATUS))
{
svn_error_clear(err);
err = SVN_NO_ERROR;
}
return svn_error_trace(err);
}
svn_error_t *
svn_wc_prop_set4(svn_wc_context_t *wc_ctx,
const char *local_abspath,
const char *name,
const svn_string_t *value,
svn_depth_t depth,
svn_boolean_t skip_checks,
const apr_array_header_t *changelist_filter,
svn_cancel_func_t cancel_func,
void *cancel_baton,
svn_wc_notify_func2_t notify_func,
void *notify_baton,
apr_pool_t *scratch_pool)
{
enum svn_prop_kind prop_kind = svn_property_kind2(name);
svn_wc__db_status_t status;
svn_node_kind_t kind;
svn_wc__db_t *db = wc_ctx->db;
/* we don't do entry properties here */
if (prop_kind == svn_prop_entry_kind)
return svn_error_createf(SVN_ERR_BAD_PROP_KIND, NULL,
_("Property '%s' is an entry property"), name);
/* Check to see if we're setting the dav cache. */
if (prop_kind == svn_prop_wc_kind)
{
SVN_ERR_ASSERT(depth == svn_depth_empty);
return svn_error_trace(wcprop_set(wc_ctx->db, local_abspath,
name, value, scratch_pool));
}
SVN_ERR(svn_wc__db_read_info(&status, &kind, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL,
wc_ctx->db, local_abspath,
scratch_pool, scratch_pool));
if (status != svn_wc__db_status_normal
&& status != svn_wc__db_status_added
&& status != svn_wc__db_status_incomplete)
{
return svn_error_createf(SVN_ERR_WC_INVALID_SCHEDULE, NULL,
_("Can't set properties on '%s':"
" invalid status for updating properties."),
svn_dirent_local_style(local_abspath,
scratch_pool));
}
/* We have to do this little DIR_ABSPATH dance for backwards compat.
But from 1.7 onwards, all locks are of infinite depth, and from 1.6
backward we never call this API with depth > empty, so we only need
to do the write check once per call, here (and not for every node in
the node walker).
### Note that we could check for a write lock on local_abspath first
### if we would want to. And then justy check for kind if that fails.
### ... but we need kind for the "svn:" property checks anyway */
{
const char *dir_abspath;
if (kind == svn_node_dir)
dir_abspath = local_abspath;
else
dir_abspath = svn_dirent_dirname(local_abspath, scratch_pool);
/* Verify that we're holding this directory's write lock. */
SVN_ERR(svn_wc__write_check(db, dir_abspath, scratch_pool));
}
if (depth == svn_depth_empty || kind != svn_node_dir)
{
apr_hash_t *changelist_hash = NULL;
if (changelist_filter && changelist_filter->nelts)
SVN_ERR(svn_hash_from_cstring_keys(&changelist_hash, changelist_filter,
scratch_pool));
if (!svn_wc__internal_changelist_match(wc_ctx->db, local_abspath,
changelist_hash, scratch_pool))
return SVN_NO_ERROR;
SVN_ERR(do_propset(wc_ctx->db, local_abspath,
kind == svn_node_dir
? svn_node_dir
: svn_node_file,
name, value, skip_checks,
notify_func, notify_baton, scratch_pool));
}
else
{
struct propset_walk_baton wb;
wb.propname = name;
wb.propval = value;
wb.db = wc_ctx->db;
wb.force = skip_checks;
wb.notify_func = notify_func;
wb.notify_baton = notify_baton;
SVN_ERR(svn_wc__internal_walk_children(wc_ctx->db, local_abspath,
FALSE, changelist_filter,
propset_walk_cb, &wb,
depth,
cancel_func, cancel_baton,
scratch_pool));
}
return SVN_NO_ERROR;
}
/* Check that NAME names a regular prop. Return an error if it names an
* entry prop or a WC prop. */
static svn_error_t *
ensure_prop_is_regular_kind(const char *name)
{
enum svn_prop_kind prop_kind = svn_property_kind2(name);
/* we don't do entry properties here */
if (prop_kind == svn_prop_entry_kind)
return svn_error_createf(SVN_ERR_BAD_PROP_KIND, NULL,
_("Property '%s' is an entry property"), name);
/* Check to see if we're setting the dav cache. */
if (prop_kind == svn_prop_wc_kind)
return svn_error_createf(SVN_ERR_BAD_PROP_KIND, NULL,
_("Property '%s' is a WC property, not "
"a regular property"), name);
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__canonicalize_props(apr_hash_t **prepared_props,
const char *local_abspath,
svn_node_kind_t node_kind,
const apr_hash_t *props,
svn_boolean_t skip_some_checks,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
const svn_string_t *mime_type;
struct getter_baton gb;
apr_hash_index_t *hi;
/* While we allocate new parts of *PREPARED_PROPS in RESULT_POOL, we
don't promise to deep-copy the unchanged keys and values. */
*prepared_props = apr_hash_make(result_pool);
/* Before we can canonicalize svn:eol-style we need to know svn:mime-type,
* so process that first. */
mime_type = svn_hash_gets((apr_hash_t *)props, SVN_PROP_MIME_TYPE);
if (mime_type)
{
SVN_ERR(svn_wc_canonicalize_svn_prop(
&mime_type, SVN_PROP_MIME_TYPE, mime_type,
local_abspath, node_kind, skip_some_checks,
NULL, NULL, scratch_pool));
svn_hash_sets(*prepared_props, SVN_PROP_MIME_TYPE, mime_type);
}
/* Set up the context for canonicalizing the other properties. */
gb.mime_type = mime_type;
( run in 1.124 second using v1.01-cache-2.11-cpan-71847e10f99 )