Upstream-Status: Backport Index: subversion/mod_dav_svn/dav_svn.h =================================================================== --- a/subversion/mod_dav_svn/dav_svn.h (revision 1461956) +++ b/subversion/mod_dav_svn/dav_svn.h (working copy) @@ -254,6 +254,9 @@ struct dav_resource_private { interface (ie: /path/to/item?p=PEGREV]? */ svn_boolean_t pegged; + /* Cache any revprop change error */ + svn_error_t *revprop_error; + /* Pool to allocate temporary data from */ apr_pool_t *pool; }; Index: subversion/mod_dav_svn/deadprops.c =================================================================== --- a/subversion/mod_dav_svn/deadprops.c (revision 1461956) +++ b/subversion/mod_dav_svn/deadprops.c (working copy) @@ -49,8 +49,7 @@ struct dav_db { struct dav_deadprop_rollback { - dav_prop_name name; - svn_string_t value; + int dummy; }; @@ -134,6 +133,7 @@ save_value(dav_db *db, const dav_prop_name *name, { const char *propname; svn_error_t *serr; + apr_pool_t *subpool; /* get the repos-local name */ get_repos_propname(db, name, &propname); @@ -151,10 +151,14 @@ save_value(dav_db *db, const dav_prop_name *name, } /* Working Baseline or Working (Version) Resource */ + + /* A subpool to cope with mod_dav making multiple calls, e.g. during + PROPPATCH with multiple values. */ + subpool = svn_pool_create(db->resource->pool); if (db->resource->baselined) if (db->resource->working) serr = svn_repos_fs_change_txn_prop(db->resource->info->root.txn, - propname, value, db->resource->pool); + propname, value, subpool); else { /* ### VIOLATING deltaV: you can't proppatch a baseline, it's @@ -168,19 +172,29 @@ save_value(dav_db *db, const dav_prop_name *name, propname, value, TRUE, TRUE, db->authz_read_func, db->authz_read_baton, - db->resource->pool); + subpool); + /* mod_dav doesn't handle the returned error very well, it + generates its own generic error that will be returned to + the client. Cache the detailed error here so that it can + be returned a second time when the rollback mechanism + triggers. */ + if (serr) + db->resource->info->revprop_error = svn_error_dup(serr); + /* Tell the logging subsystem about the revprop change. */ dav_svn__operational_log(db->resource->info, svn_log__change_rev_prop( db->resource->info->root.rev, propname, - db->resource->pool)); + subpool)); } else serr = svn_repos_fs_change_node_prop(db->resource->info->root.root, get_repos_path(db->resource->info), - propname, value, db->resource->pool); + propname, value, subpool); + svn_pool_destroy(subpool); + if (serr != NULL) return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, NULL, @@ -395,6 +409,7 @@ db_remove(dav_db *db, const dav_prop_name *name) { svn_error_t *serr; const char *propname; + apr_pool_t *subpool; /* get the repos-local name */ get_repos_propname(db, name, &propname); @@ -403,6 +418,10 @@ db_remove(dav_db *db, const dav_prop_name *name) if (propname == NULL) return NULL; + /* A subpool to cope with mod_dav making multiple calls, e.g. during + PROPPATCH with multiple values. */ + subpool = svn_pool_create(db->resource->pool); + /* Working Baseline or Working (Version) Resource */ if (db->resource->baselined) if (db->resource->working) @@ -419,11 +438,12 @@ db_remove(dav_db *db, const dav_prop_name *name) propname, NULL, TRUE, TRUE, db->authz_read_func, db->authz_read_baton, - db->resource->pool); + subpool); else serr = svn_repos_fs_change_node_prop(db->resource->info->root.root, get_repos_path(db->resource->info), - propname, NULL, db->resource->pool); + propname, NULL, subpool); + svn_pool_destroy(subpool); if (serr != NULL) return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "could not remove a property", @@ -598,19 +618,14 @@ db_get_rollback(dav_db *db, const dav_prop_name *name, dav_deadprop_rollback **prollback) { - dav_error *err; - dav_deadprop_rollback *ddp; - svn_string_t *propval; + /* This gets called by mod_dav in preparation for a revprop change. + mod_dav_svn doesn't need to make any changes during rollback, but + we want the rollback mechanism to trigger. Making changes in + response to post-revprop-change hook errors would be positively + wrong. */ - if ((err = get_value(db, name, &propval)) != NULL) - return err; + *prollback = apr_palloc(db->p, sizeof(dav_deadprop_rollback)); - ddp = apr_palloc(db->p, sizeof(*ddp)); - ddp->name = *name; - ddp->value.data = propval ? propval->data : NULL; - ddp->value.len = propval ? propval->len : 0; - - *prollback = ddp; return NULL; } @@ -618,12 +633,20 @@ db_get_rollback(dav_db *db, static dav_error * db_apply_rollback(dav_db *db, dav_deadprop_rollback *rollback) { - if (rollback->value.data == NULL) - { - return db_remove(db, &rollback->name); - } + dav_error *derr; - return save_value(db, &rollback->name, &rollback->value); + if (! db->resource->info->revprop_error) + return NULL; + + /* Returning the original revprop change error here will cause this + detailed error to get returned to the client in preference to the + more generic error created by mod_dav. */ + derr = dav_svn__convert_err(db->resource->info->revprop_error, + HTTP_INTERNAL_SERVER_ERROR, NULL, + db->resource->pool); + db->resource->info->revprop_error = NULL; + + return derr; }