svn_error_t * svn_repos__validate_prop(const char *name, const svn_string_t *value, apr_pool_t *pool) { svn_prop_kind_t kind = svn_property_kind2(name); /* Allow deleting any property, even a property we don't allow to set. */ if (value == NULL) return SVN_NO_ERROR; /* Disallow setting non-regular properties. */ if (kind != svn_prop_regular_kind) return svn_error_createf (SVN_ERR_REPOS_BAD_ARGS, NULL, _("Storage of non-regular property '%s' is disallowed through the " "repository interface, and could indicate a bug in your client"), name); /* Validate "svn:" properties. */ if (svn_prop_is_svn_prop(name) && value != NULL) { /* Validate that translated props (e.g., svn:log) are UTF-8 with * LF line endings. */ if (svn_prop_needs_translation(name)) { if (!svn_utf__is_valid(value->data, value->len)) { return svn_error_createf (SVN_ERR_BAD_PROPERTY_VALUE, NULL, _("Cannot accept '%s' property because it is not encoded in " "UTF-8"), name); } /* Disallow inconsistent line ending style, by simply looking for * carriage return characters ('\r'). */ if (strchr(value->data, '\r') != NULL) { return svn_error_createf (SVN_ERR_BAD_PROPERTY_VALUE, NULL, _("Cannot accept non-LF line endings in '%s' property"), name); } } /* "svn:date" should be a valid date. */ if (strcmp(name, SVN_PROP_REVISION_DATE) == 0) { apr_time_t temp; svn_error_t *err; err = svn_time_from_cstring(&temp, value->data, pool); if (err) return svn_error_create(SVN_ERR_BAD_PROPERTY_VALUE, err, NULL); } } return SVN_NO_ERROR; }
svn_boolean_t svn_prop_needs_translation(const char *propname) { /* ### Someday, we may want to be picky and choosy about which properties require UTF8 and EOL conversion. For now, all "svn:" props need it. */ return svn_prop_is_svn_prop(propname); }
svn_boolean_t svn_prop_has_svn_prop(const apr_hash_t *props, apr_pool_t *pool) { apr_hash_index_t *hi; const void *prop_name; if (! props) return FALSE; for (hi = apr_hash_first(pool, (apr_hash_t *)props); hi; hi = apr_hash_next(hi)) { apr_hash_this(hi, &prop_name, NULL, NULL); if (svn_prop_is_svn_prop((const char *) prop_name)) return TRUE; } return FALSE; }
static svn_error_t * propset_on_url(const char *propname, const svn_string_t *propval, const char *target, svn_boolean_t skip_checks, svn_revnum_t base_revision_for_url, const apr_hash_t *revprop_table, svn_commit_callback2_t commit_callback, void *commit_baton, svn_client_ctx_t *ctx, apr_pool_t *pool) { enum svn_prop_kind prop_kind = svn_property_kind(NULL, propname); svn_ra_session_t *ra_session; svn_node_kind_t node_kind; const char *message; const svn_delta_editor_t *editor; void *edit_baton; apr_hash_t *commit_revprops; svn_error_t *err; if (prop_kind != svn_prop_regular_kind) return svn_error_createf (SVN_ERR_BAD_PROP_KIND, NULL, _("Property '%s' is not a regular property"), 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_ra_check_path(ra_session, "", base_revision_for_url, &node_kind, pool)); if (node_kind == svn_node_none) return svn_error_createf (SVN_ERR_FS_NOT_FOUND, NULL, _("Path '%s' does not exist in revision %ld"), target, base_revision_for_url); /* 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 (propval && svn_prop_is_svn_prop(propname)) { const svn_string_t *new_value; struct getter_baton gb; gb.ra_session = ra_session; gb.base_revision_for_url = base_revision_for_url; SVN_ERR(svn_wc_canonicalize_svn_prop(&new_value, propname, propval, target, node_kind, skip_checks, get_file_for_validation, &gb, pool)); propval = new_value; } /* Create a new commit item and add it to the array. */ if (SVN_CLIENT__HAS_LOG_MSG_FUNC(ctx)) { svn_client_commit_item3_t *item; const char *tmp_file; apr_array_header_t *commit_items = apr_array_make(pool, 1, sizeof(item)); item = svn_client_commit_item3_create(pool); item->url = target; item->state_flags = SVN_CLIENT_COMMIT_ITEM_PROP_MODS; APR_ARRAY_PUSH(commit_items, svn_client_commit_item3_t *) = item; SVN_ERR(svn_client__get_log_msg(&message, &tmp_file, commit_items, ctx, pool)); if (! message) return SVN_NO_ERROR; } else message = ""; SVN_ERR(svn_client__ensure_revprop_table(&commit_revprops, revprop_table, message, ctx, pool)); /* Fetch RA commit editor. */ SVN_ERR(svn_ra_get_commit_editor3(ra_session, &editor, &edit_baton, commit_revprops, commit_callback, commit_baton, NULL, TRUE, /* No lock tokens */ pool)); err = do_url_propset(propname, propval, node_kind, base_revision_for_url, editor, edit_baton, pool); if (err) { /* At least try to abort the edit (and fs txn) before throwing err. */ svn_error_clear(editor->abort_edit(edit_baton, pool)); return svn_error_trace(err); } /* Close the edit. */ return editor->close_edit(edit_baton, pool); }