svn_error_t * svn_client_revprop_set2(const char *propname, const svn_string_t *propval, const svn_string_t *original_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; svn_boolean_t be_atomic; 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, _("Author name should not contain a newline;" " value will not be set unless forced")); if (propval && ! svn_prop_name_is_valid(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, NULL, URL, 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, NULL, ctx->wc_ctx, NULL, ra_session, revision, pool)); SVN_ERR(svn_ra_has_capability(ra_session, &be_atomic, SVN_RA_CAPABILITY_ATOMIC_REVPROPS, pool)); if (be_atomic) { /* Convert ORIGINAL_PROPVAL to an OLD_VALUE_P. */ const svn_string_t *const *old_value_p; const svn_string_t *unset = NULL; if (original_propval == NULL) old_value_p = NULL; else if (original_propval->data == NULL) old_value_p = &unset; else old_value_p = &original_propval; /* The actual RA call. */ SVN_ERR(svn_ra_change_rev_prop2(ra_session, *set_rev, propname, old_value_p, propval, pool)); } else { /* The actual RA call. */ SVN_ERR(check_and_set_revprop(set_rev, ra_session, propname, original_propval, propval, pool)); } if (ctx->notify_func2) { svn_wc_notify_t *notify = svn_wc_create_notify_url(URL, propval == NULL ? svn_wc_notify_revprop_deleted : svn_wc_notify_revprop_set, pool); notify->prop_name = propname; notify->revision = *set_rev; (*ctx->notify_func2)(ctx->notify_baton2, notify, pool); } return SVN_NO_ERROR; }
static svn_error_t * file_rev_handler(void *baton, const char *path, svn_revnum_t revnum, apr_hash_t *rev_props, svn_boolean_t merged_revision, svn_txdelta_window_handler_t *content_delta_handler, void **content_delta_baton, apr_array_header_t *prop_diffs, apr_pool_t *pool) { struct file_rev_baton *frb = baton; svn_stream_t *last_stream; svn_stream_t *cur_stream; struct delta_baton *delta_baton; apr_pool_t *filepool; /* Clear the current pool. */ svn_pool_clear(frb->currpool); /* If this file has a non-textual mime-type, bail out. */ if (! frb->ignore_mime_type) SVN_ERR(check_mimetype(prop_diffs, frb->target, frb->currpool)); if (frb->ctx->notify_func2) { svn_wc_notify_t *notify = svn_wc_create_notify_url( svn_path_url_add_component2(frb->repos_root_url, path+1, pool), svn_wc_notify_blame_revision, pool); notify->path = path; notify->kind = svn_node_none; notify->content_state = notify->prop_state = svn_wc_notify_state_inapplicable; notify->lock_state = svn_wc_notify_lock_state_inapplicable; notify->revision = revnum; notify->rev_props = rev_props; frb->ctx->notify_func2(frb->ctx->notify_baton2, notify, pool); } if (frb->ctx->cancel_func) SVN_ERR(frb->ctx->cancel_func(frb->ctx->cancel_baton)); /* If there were no content changes, we couldn't care less about this revision now. Note that we checked the mime type above, so things work if the user just changes the mime type in a commit. Also note that we don't switch the pools in this case. This is important, since the tempfile will be removed by the pool and we need the tempfile from the last revision with content changes. */ if (!content_delta_handler) return SVN_NO_ERROR; frb->merged_revision = merged_revision; /* Create delta baton. */ delta_baton = apr_palloc(frb->currpool, sizeof(*delta_baton)); /* Prepare the text delta window handler. */ if (frb->last_filename) SVN_ERR(svn_stream_open_readonly(&delta_baton->source_stream, frb->last_filename, frb->currpool, pool)); else /* Means empty stream below. */ delta_baton->source_stream = NULL; last_stream = svn_stream_disown(delta_baton->source_stream, pool); if (frb->include_merged_revisions && !frb->merged_revision) filepool = frb->filepool; else filepool = frb->currpool; SVN_ERR(svn_stream_open_unique(&cur_stream, &delta_baton->filename, NULL, svn_io_file_del_on_pool_cleanup, filepool, filepool)); /* Get window handler for applying delta. */ svn_txdelta_apply(last_stream, cur_stream, NULL, NULL, frb->currpool, &delta_baton->wrapped_handler, &delta_baton->wrapped_baton); /* Wrap the window handler with our own. */ delta_baton->file_rev_baton = frb; *content_delta_handler = window_handler; *content_delta_baton = delta_baton; /* Create the rev structure. */ frb->rev = apr_pcalloc(frb->mainpool, sizeof(struct rev)); if (revnum < frb->start_rev) { /* We shouldn't get more than one revision before the starting revision (unless of including merged revisions). */ SVN_ERR_ASSERT((frb->last_filename == NULL) || frb->include_merged_revisions); /* The file existed before start_rev; generate no blame info for lines from this revision (or before). */ frb->rev->revision = SVN_INVALID_REVNUM; } else { SVN_ERR_ASSERT(revnum <= frb->end_rev); /* Set values from revision props. */ frb->rev->revision = revnum; frb->rev->rev_props = svn_prop_hash_dup(rev_props, frb->mainpool); } if (frb->include_merged_revisions) frb->rev->path = apr_pstrdup(frb->mainpool, path); return SVN_NO_ERROR; }