static svn_error_t * file_change_prop(void *file_baton, const char *name, const svn_string_t *value, apr_pool_t *scratch_pool) { struct file_baton_t *fb = file_baton; svn_prop_kind_t prop_kind; prop_kind = svn_property_kind2(name); if (prop_kind != svn_prop_regular_kind || ! strcmp(name, SVN_PROP_MERGEINFO)) { /* We can't handle DAV, ENTRY and merge specific props here */ return SVN_NO_ERROR; } /* We store all properties in the hash for immediate addition with the svn_wc_add_from_disk3() call */ if (! fb->properties) fb->properties = apr_hash_make(fb->pool); if (value != NULL) svn_hash_sets(fb->properties, apr_pstrdup(fb->pool, name), svn_string_dup(value, fb->pool)); return SVN_NO_ERROR; }
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; }
static svn_error_t * change_file_prop(void *file_baton, const char *name, const svn_string_t *value, apr_pool_t *pool) { node_baton_t *fb = file_baton; edit_baton_t *eb = fb->edit_baton; /* only regular properties can pass over libsvn_ra */ if (svn_property_kind2(name) != svn_prop_regular_kind) return SVN_NO_ERROR; /* Maybe drop svn:mergeinfo. */ if (eb->strip_mergeinfo && (strcmp(name, SVN_PROP_MERGEINFO) == 0)) { eb->mergeinfo_stripped = TRUE; return SVN_NO_ERROR; } /* Maybe drop (errantly set, as this is a file) svnmerge.py properties. */ if (eb->migrate_svnmerge && (strcmp(name, "svnmerge-integrated") == 0)) { eb->svnmerge_migrated = TRUE; return SVN_NO_ERROR; } /* Remember if we see any svnmerge-blocked properties. (They really shouldn't be here, as this is a file, but whatever...) */ if (eb->migrate_svnmerge && (strcmp(name, "svnmerge-blocked") == 0)) { eb->svnmerge_blocked = TRUE; } /* Normalize svn:* properties as necessary. */ if (svn_prop_needs_translation(name)) { svn_boolean_t was_normalized; svn_boolean_t mergeinfo_tweaked = FALSE; /* Normalize encoding to UTF-8, and EOL style to LF. */ SVN_ERR(normalize_string(&value, &was_normalized, eb->source_prop_encoding, pool, pool)); /* Correct malformed mergeinfo. */ if (value && strcmp(name, SVN_PROP_MERGEINFO) == 0) { SVN_ERR(remove_r0_mergeinfo(&value, &mergeinfo_tweaked, pool, pool)); if (mergeinfo_tweaked) eb->mergeinfo_tweaked = TRUE; } if (was_normalized) (*(eb->normalized_node_props_counter))++; } return eb->wrapped_editor->change_file_prop(fb->wrapped_node_baton, name, value, pool); }
svn_error_t * svn_categorize_props(const apr_array_header_t *proplist, apr_array_header_t **entry_props, apr_array_header_t **wc_props, apr_array_header_t **regular_props, apr_pool_t *pool) { int i; if (entry_props) *entry_props = apr_array_make(pool, 1, sizeof(svn_prop_t)); if (wc_props) *wc_props = apr_array_make(pool, 1, sizeof(svn_prop_t)); if (regular_props) *regular_props = apr_array_make(pool, 1, sizeof(svn_prop_t)); for (i = 0; i < proplist->nelts; i++) { svn_prop_t *prop, *newprop; enum svn_prop_kind kind; prop = &APR_ARRAY_IDX(proplist, i, svn_prop_t); kind = svn_property_kind2(prop->name); newprop = NULL; if (kind == svn_prop_regular_kind) { if (regular_props) newprop = apr_array_push(*regular_props); } else if (kind == svn_prop_wc_kind) { if (wc_props) newprop = apr_array_push(*wc_props); } else if (kind == svn_prop_entry_kind) { if (entry_props) newprop = apr_array_push(*entry_props); } else /* Technically this can't happen, but might as well have the code ready in case that ever changes. */ return svn_error_createf(SVN_ERR_BAD_PROP_KIND, NULL, "Bad property kind for property '%s'", prop->name); if (newprop) { newprop->name = prop->name; newprop->value = prop->value; } } return SVN_NO_ERROR; }
/* Removes all non regular properties from PROPS */ void svn_ra_serf__keep_only_regular_props(apr_hash_t *props, apr_pool_t *scratch_pool) { apr_hash_index_t *hi; for (hi = apr_hash_first(scratch_pool, props); hi; hi = apr_hash_next(hi)) { const char *propname = apr_hash_this_key(hi); if (svn_property_kind2(propname) != svn_prop_regular_kind) svn_hash_sets(props, propname, NULL); } }
/* NOTE: this function is deprecated, but we cannot move it to deprecated.c because we need the SIZEOF_*_PREFIX constant symbols defined above. */ svn_prop_kind_t svn_property_kind(int *prefix_len, const char *prop_name) { svn_prop_kind_t kind = svn_property_kind2(prop_name); if (prefix_len) { if (kind == svn_prop_wc_kind) *prefix_len = SIZEOF_WC_PREFIX; else if (kind == svn_prop_entry_kind) *prefix_len = SIZEOF_ENTRY_PREFIX; else *prefix_len = 0; } return kind; }
static svn_error_t * dir_change_prop(void *dir_baton, const char *name, const svn_string_t *value, apr_pool_t *scratch_pool) { struct dir_baton_t *db = dir_baton; struct edit_baton_t *eb = db->eb; svn_prop_kind_t prop_kind; prop_kind = svn_property_kind2(name); if (prop_kind != svn_prop_regular_kind || ! strcmp(name, SVN_PROP_MERGEINFO)) { /* We can't handle DAV, ENTRY and merge specific props here */ return SVN_NO_ERROR; } if (! db->created) { /* We can still store them in the hash for immediate addition with the svn_wc_add_from_disk3() call */ if (! db->properties) db->properties = apr_hash_make(db->pool); if (value != NULL) svn_hash_sets(db->properties, apr_pstrdup(db->pool, name), svn_string_dup(value, db->pool)); } else { /* We have already notified for this directory, so don't do that again */ SVN_ERR(svn_wc_prop_set4(eb->wc_ctx, db->local_abspath, name, value, svn_depth_empty, FALSE, NULL, NULL, NULL, /* Cancellation */ NULL, NULL, /* Notification */ scratch_pool)); } return SVN_NO_ERROR; }
/* Are there any changes to relevant (normal) props in PROPS? */ static svn_boolean_t props_changed_hash(apr_hash_t *props, apr_pool_t *scratch_pool) { apr_hash_index_t *hi; if (!props) return FALSE; for (hi = apr_hash_first(scratch_pool, props); hi; hi = apr_hash_next(hi)) { const char *name = apr_hash_this_key(hi); if (svn_property_kind2(name) == svn_prop_regular_kind) { return TRUE; } } return FALSE; }
static svn_error_t * file_change_prop(void *file_baton, const char *name, const svn_string_t *value, apr_pool_t *scratch_pool) { struct file_baton_t *fb = file_baton; struct edit_baton_t *eb = fb->eb; svn_prop_kind_t prop_kind; prop_kind = svn_property_kind2(name); if (prop_kind != svn_prop_regular_kind || (eb->ignore_mergeinfo_changes && ! strcmp(name, SVN_PROP_MERGEINFO))) { /* We can't handle DAV, ENTRY and merge specific props here */ return SVN_NO_ERROR; } if (! fb->created) { /* Store properties to be added later in svn_wc_add_from_disk3() */ if (! fb->properties) fb->properties = apr_hash_make(fb->pool); if (value != NULL) svn_hash_sets(fb->properties, apr_pstrdup(fb->pool, name), svn_string_dup(value, fb->pool)); } else { SVN_ERR(svn_wc_prop_set4(eb->wc_ctx, fb->local_abspath, name, value, svn_depth_empty, FALSE, NULL, NULL, NULL, /* Cancellation */ NULL, NULL, /* Notification */ scratch_pool)); } return SVN_NO_ERROR; }
static svn_error_t * change_dir_prop(void *dir_baton, const char *name, const svn_string_t *value, apr_pool_t *pool) { node_baton_t *db = dir_baton; edit_baton_t *eb = db->edit_baton; /* Only regular properties can pass over libsvn_ra */ if (svn_property_kind2(name) != svn_prop_regular_kind) return SVN_NO_ERROR; /* Maybe drop svn:mergeinfo. */ if (eb->strip_mergeinfo && (strcmp(name, SVN_PROP_MERGEINFO) == 0)) { eb->mergeinfo_stripped = TRUE; return SVN_NO_ERROR; } /* Maybe convert svnmerge-integrated data into svn:mergeinfo. (We ignore svnmerge-blocked for now.) */ /* ### FIXME: Consult the mirror repository's HEAD prop values and ### merge svn:mergeinfo, svnmerge-integrated, and svnmerge-blocked. */ if (eb->migrate_svnmerge && (strcmp(name, "svnmerge-integrated") == 0)) { if (value) { /* svnmerge-integrated differs from svn:mergeinfo in a pair of ways. First, it can use tabs, newlines, or spaces to delimit source information. Secondly, the source paths are relative URLs, whereas svn:mergeinfo uses relative paths (not URI-encoded). */ svn_error_t *err; svn_stringbuf_t *mergeinfo_buf = svn_stringbuf_create_empty(pool); svn_mergeinfo_t mergeinfo; int i; apr_array_header_t *sources = svn_cstring_split(value->data, " \t\n", TRUE, pool); svn_string_t *new_value; for (i = 0; i < sources->nelts; i++) { const char *rel_path; apr_array_header_t *path_revs = svn_cstring_split(APR_ARRAY_IDX(sources, i, const char *), ":", TRUE, pool); /* ### TODO: Warn? */ if (path_revs->nelts != 2) continue; /* Append this source's mergeinfo data. */ rel_path = APR_ARRAY_IDX(path_revs, 0, const char *); rel_path = svn_path_uri_decode(rel_path, pool); svn_stringbuf_appendcstr(mergeinfo_buf, rel_path); svn_stringbuf_appendcstr(mergeinfo_buf, ":"); svn_stringbuf_appendcstr(mergeinfo_buf, APR_ARRAY_IDX(path_revs, 1, const char *)); svn_stringbuf_appendcstr(mergeinfo_buf, "\n"); } /* Try to parse the mergeinfo string we've created, just to check for bogosity. If all goes well, we'll unparse it again and use that as our property value. */ err = svn_mergeinfo_parse(&mergeinfo, mergeinfo_buf->data, pool); if (err) { svn_error_clear(err); return SVN_NO_ERROR; } SVN_ERR(svn_mergeinfo_to_string(&new_value, mergeinfo, pool)); value = new_value; } name = SVN_PROP_MERGEINFO; eb->svnmerge_migrated = TRUE; } /* Remember if we see any svnmerge-blocked properties. */ if (eb->migrate_svnmerge && (strcmp(name, "svnmerge-blocked") == 0)) { eb->svnmerge_blocked = TRUE; } /* Normalize svn:* properties as necessary. */ if (svn_prop_needs_translation(name)) { svn_boolean_t was_normalized; svn_boolean_t mergeinfo_tweaked = FALSE; /* Normalize encoding to UTF-8, and EOL style to LF. */ SVN_ERR(normalize_string(&value, &was_normalized, eb->source_prop_encoding, pool, pool)); /* Maybe adjust svn:mergeinfo. */ if (value && strcmp(name, SVN_PROP_MERGEINFO) == 0) { SVN_ERR(remove_r0_mergeinfo(&value, &mergeinfo_tweaked, pool, pool)); if (mergeinfo_tweaked) eb->mergeinfo_tweaked = TRUE; } if (was_normalized) (*(eb->normalized_node_props_counter))++; } return eb->wrapped_editor->change_dir_prop(db->wrapped_node_baton, name, value, pool); }
svn_error_t * svn_client__copy_foreign(const char *url, const char *dst_abspath, svn_opt_revision_t *peg_revision, svn_opt_revision_t *revision, svn_depth_t depth, svn_boolean_t make_parents, svn_boolean_t already_locked, svn_client_ctx_t *ctx, apr_pool_t *scratch_pool) { svn_ra_session_t *ra_session; svn_client__pathrev_t *loc; svn_node_kind_t kind; svn_node_kind_t wc_kind; const char *dir_abspath; SVN_ERR_ASSERT(svn_path_is_url(url)); SVN_ERR_ASSERT(svn_dirent_is_absolute(dst_abspath)); /* Do we need to validate/update revisions? */ SVN_ERR(svn_client__ra_session_from_path2(&ra_session, &loc, url, NULL, peg_revision, revision, ctx, scratch_pool)); SVN_ERR(svn_ra_check_path(ra_session, "", loc->rev, &kind, scratch_pool)); if (kind != svn_node_file && kind != svn_node_dir) return svn_error_createf( SVN_ERR_ILLEGAL_TARGET, NULL, _("'%s' is not a valid location inside a repository"), url); SVN_ERR(svn_wc_read_kind2(&wc_kind, ctx->wc_ctx, dst_abspath, FALSE, TRUE, scratch_pool)); if (wc_kind != svn_node_none) { return svn_error_createf( SVN_ERR_ENTRY_EXISTS, NULL, _("'%s' is already under version control"), svn_dirent_local_style(dst_abspath, scratch_pool)); } dir_abspath = svn_dirent_dirname(dst_abspath, scratch_pool); SVN_ERR(svn_wc_read_kind2(&wc_kind, ctx->wc_ctx, dir_abspath, FALSE, FALSE, scratch_pool)); if (wc_kind == svn_node_none) { if (make_parents) SVN_ERR(svn_client__make_local_parents(dir_abspath, make_parents, ctx, scratch_pool)); SVN_ERR(svn_wc_read_kind2(&wc_kind, ctx->wc_ctx, dir_abspath, FALSE, FALSE, scratch_pool)); } if (wc_kind != svn_node_dir) return svn_error_createf( SVN_ERR_ENTRY_NOT_FOUND, NULL, _("Can't add '%s', because no parent directory is found"), svn_dirent_local_style(dst_abspath, scratch_pool)); if (kind == svn_node_file) { svn_stream_t *target; apr_hash_t *props; apr_hash_index_t *hi; SVN_ERR(svn_stream_open_writable(&target, dst_abspath, scratch_pool, scratch_pool)); SVN_ERR(svn_ra_get_file(ra_session, "", loc->rev, target, NULL, &props, scratch_pool)); if (props != NULL) for (hi = apr_hash_first(scratch_pool, props); hi; hi = apr_hash_next(hi)) { const char *name = apr_hash_this_key(hi); if (svn_property_kind2(name) != svn_prop_regular_kind || ! strcmp(name, SVN_PROP_MERGEINFO)) { /* We can't handle DAV, ENTRY and merge specific props here */ svn_hash_sets(props, name, NULL); } } if (!already_locked) SVN_WC__CALL_WITH_WRITE_LOCK( svn_wc_add_from_disk3(ctx->wc_ctx, dst_abspath, props, TRUE /* skip checks */, ctx->notify_func2, ctx->notify_baton2, scratch_pool), ctx->wc_ctx, dir_abspath, FALSE, scratch_pool); else SVN_ERR(svn_wc_add_from_disk3(ctx->wc_ctx, dst_abspath, props, TRUE /* skip checks */, ctx->notify_func2, ctx->notify_baton2, scratch_pool)); } else { if (!already_locked) SVN_WC__CALL_WITH_WRITE_LOCK( copy_foreign_dir(ra_session, loc, ctx->wc_ctx, dst_abspath, depth, ctx->notify_func2, ctx->notify_baton2, ctx->cancel_func, ctx->cancel_baton, scratch_pool), ctx->wc_ctx, dir_abspath, FALSE, scratch_pool); else SVN_ERR(copy_foreign_dir(ra_session, loc, ctx->wc_ctx, dst_abspath, depth, ctx->notify_func2, ctx->notify_baton2, ctx->cancel_func, ctx->cancel_baton, scratch_pool)); } return SVN_NO_ERROR; }
svn_error_t * svn_ra__get_inherited_props_walk(svn_ra_session_t *session, const char *path, svn_revnum_t revision, apr_array_header_t **inherited_props, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { const char *repos_root_url; const char *session_url; const char *parent_url; apr_pool_t *iterpool = svn_pool_create(scratch_pool); *inherited_props = apr_array_make(result_pool, 1, sizeof(svn_prop_inherited_item_t *)); /* Walk to the root of the repository getting inherited props for PATH. */ SVN_ERR(svn_ra_get_repos_root2(session, &repos_root_url, scratch_pool)); SVN_ERR(svn_ra_get_session_url(session, &session_url, scratch_pool)); parent_url = session_url; while (strcmp(repos_root_url, parent_url)) { apr_hash_index_t *hi; apr_hash_t *parent_props; apr_hash_t *final_hash = apr_hash_make(result_pool); svn_error_t *err; svn_pool_clear(iterpool); parent_url = svn_uri_dirname(parent_url, scratch_pool); SVN_ERR(svn_ra_reparent(session, parent_url, iterpool)); err = session->vtable->get_dir(session, NULL, NULL, &parent_props, "", revision, SVN_DIRENT_ALL, iterpool); /* If the user doesn't have read access to a parent path then skip, but allow them to inherit from further up. */ if (err) { if ((err->apr_err == SVN_ERR_RA_NOT_AUTHORIZED) || (err->apr_err == SVN_ERR_RA_DAV_FORBIDDEN)) { svn_error_clear(err); continue; } else { return svn_error_trace(err); } } for (hi = apr_hash_first(scratch_pool, parent_props); hi; hi = apr_hash_next(hi)) { const char *name = apr_hash_this_key(hi); apr_ssize_t klen = apr_hash_this_key_len(hi); svn_string_t *value = apr_hash_this_val(hi); if (svn_property_kind2(name) == svn_prop_regular_kind) { name = apr_pstrdup(result_pool, name); value = svn_string_dup(value, result_pool); apr_hash_set(final_hash, name, klen, value); } } if (apr_hash_count(final_hash)) { svn_prop_inherited_item_t *new_iprop = apr_palloc(result_pool, sizeof(*new_iprop)); new_iprop->path_or_url = svn_uri_skip_ancestor(repos_root_url, parent_url, result_pool); new_iprop->prop_hash = final_hash; svn_sort__array_insert(*inherited_props, &new_iprop, 0); } } /* Reparent session back to original URL. */ SVN_ERR(svn_ra_reparent(session, session_url, scratch_pool)); svn_pool_destroy(iterpool); return SVN_NO_ERROR; }