diff options
Diffstat (limited to 'subversion/mod_dav_svn/version.c')
-rw-r--r-- | subversion/mod_dav_svn/version.c | 260 |
1 files changed, 115 insertions, 145 deletions
diff --git a/subversion/mod_dav_svn/version.c b/subversion/mod_dav_svn/version.c index 98208a9..638cae9 100644 --- a/subversion/mod_dav_svn/version.c +++ b/subversion/mod_dav_svn/version.c @@ -178,26 +178,33 @@ get_option(const dav_resource *resource, request_rec *r = resource->info->r; const char *repos_root_uri = dav_svn__build_uri(resource->info->repos, DAV_SVN__BUILD_URI_PUBLIC, - SVN_IGNORED_REVNUM, "", 0, resource->pool); + SVN_IGNORED_REVNUM, "", FALSE /* add_href */, + resource->pool); /* ### DAV:version-history-collection-set */ - if (elem->ns == APR_XML_NS_DAV_ID) + if (elem->ns != APR_XML_NS_DAV_ID + || strcmp(elem->name, "activity-collection-set") != 0) { - if (strcmp(elem->name, "activity-collection-set") == 0) - { - apr_text_append(resource->pool, option, - "<D:activity-collection-set>"); - apr_text_append(resource->pool, option, - dav_svn__build_uri(resource->info->repos, - DAV_SVN__BUILD_URI_ACT_COLLECTION, - SVN_INVALID_REVNUM, NULL, - 1 /* add_href */, - resource->pool)); - apr_text_append(resource->pool, option, - "</D:activity-collection-set>"); - } + /* We don't know about other options (yet). + + If we ever add multiple option request keys we should + just write the requested option value and make sure + we set the headers *once*. */ + return NULL; } + apr_text_append(resource->pool, option, + "<D:activity-collection-set>"); + + apr_text_append(resource->pool, option, + dav_svn__build_uri(resource->info->repos, + DAV_SVN__BUILD_URI_ACT_COLLECTION, + SVN_INVALID_REVNUM, NULL, + TRUE /* add_href */, + resource->pool)); + apr_text_append(resource->pool, option, + "</D:activity-collection-set>"); + /* If we're allowed (by configuration) to do so, advertise support for ephemeral transaction properties. */ if (dav_svn__check_ephemeral_txnprops_support(r)) @@ -297,25 +304,25 @@ get_option(const dav_resource *resource, apr_table_set(r->headers_out, SVN_DAV_ROOT_URI_HEADER, repos_root_uri); apr_table_set(r->headers_out, SVN_DAV_ME_RESOURCE_HEADER, apr_pstrcat(resource->pool, repos_root_uri, "/", - dav_svn__get_me_resource_uri(r), (char *)NULL)); + dav_svn__get_me_resource_uri(r), SVN_VA_NULL)); apr_table_set(r->headers_out, SVN_DAV_REV_ROOT_STUB_HEADER, apr_pstrcat(resource->pool, repos_root_uri, "/", - dav_svn__get_rev_root_stub(r), (char *)NULL)); + dav_svn__get_rev_root_stub(r), SVN_VA_NULL)); apr_table_set(r->headers_out, SVN_DAV_REV_STUB_HEADER, apr_pstrcat(resource->pool, repos_root_uri, "/", - dav_svn__get_rev_stub(r), (char *)NULL)); + dav_svn__get_rev_stub(r), SVN_VA_NULL)); apr_table_set(r->headers_out, SVN_DAV_TXN_ROOT_STUB_HEADER, apr_pstrcat(resource->pool, repos_root_uri, "/", - dav_svn__get_txn_root_stub(r), (char *)NULL)); + dav_svn__get_txn_root_stub(r), SVN_VA_NULL)); apr_table_set(r->headers_out, SVN_DAV_TXN_STUB_HEADER, apr_pstrcat(resource->pool, repos_root_uri, "/", - dav_svn__get_txn_stub(r), (char *)NULL)); + dav_svn__get_txn_stub(r), SVN_VA_NULL)); apr_table_set(r->headers_out, SVN_DAV_VTXN_ROOT_STUB_HEADER, apr_pstrcat(resource->pool, repos_root_uri, "/", - dav_svn__get_vtxn_root_stub(r), (char *)NULL)); + dav_svn__get_vtxn_root_stub(r), SVN_VA_NULL)); apr_table_set(r->headers_out, SVN_DAV_VTXN_STUB_HEADER, apr_pstrcat(resource->pool, repos_root_uri, "/", - dav_svn__get_vtxn_stub(r), (char *)NULL)); + dav_svn__get_vtxn_stub(r), SVN_VA_NULL)); apr_table_set(r->headers_out, SVN_DAV_ALLOW_BULK_UPDATES, bulk_upd_conf == CONF_BULKUPD_ON ? "On" : bulk_upd_conf == CONF_BULKUPD_OFF ? "Off" : "Prefer"); @@ -395,11 +402,9 @@ vsn_control(dav_resource *resource, const char *target) /* Only allow a NULL target, which means an create an 'empty' VCR. */ if (target != NULL) - return dav_svn__new_error_tag(resource->pool, HTTP_NOT_IMPLEMENTED, + return dav_svn__new_error_svn(resource->pool, HTTP_NOT_IMPLEMENTED, SVN_ERR_UNSUPPORTED_FEATURE, - "vsn_control called with non-null target.", - SVN_DAV_ERROR_NAMESPACE, - SVN_DAV_ERROR_TAG); + "vsn_control called with non-null target"); /* This is kind of silly. The docstring for this callback says it's supposed to "put a resource under version control". But in @@ -445,20 +450,16 @@ dav_svn__checkout(dav_resource *resource, return NULL; if (resource->type != DAV_RESOURCE_TYPE_REGULAR) - return dav_svn__new_error_tag(resource->pool, HTTP_METHOD_NOT_ALLOWED, + return dav_svn__new_error_svn(resource->pool, HTTP_METHOD_NOT_ALLOWED, SVN_ERR_UNSUPPORTED_FEATURE, "auto-checkout attempted on non-regular " - "version-controlled resource.", - SVN_DAV_ERROR_NAMESPACE, - SVN_DAV_ERROR_TAG); + "version-controlled resource"); if (resource->baselined) - return dav_svn__new_error_tag(resource->pool, HTTP_METHOD_NOT_ALLOWED, + return dav_svn__new_error_svn(resource->pool, HTTP_METHOD_NOT_ALLOWED, SVN_ERR_UNSUPPORTED_FEATURE, "auto-checkout attempted on baseline " - "collection, which is not supported.", - SVN_DAV_ERROR_NAMESPACE, - SVN_DAV_ERROR_TAG); + "collection, which is not supported"); /* See if the shared activity already exists. */ apr_err = apr_pool_userdata_get(&data, @@ -540,51 +541,41 @@ dav_svn__checkout(dav_resource *resource, if (resource->type != DAV_RESOURCE_TYPE_VERSION) { - return dav_svn__new_error_tag(resource->pool, HTTP_METHOD_NOT_ALLOWED, + return dav_svn__new_error_svn(resource->pool, HTTP_METHOD_NOT_ALLOWED, SVN_ERR_UNSUPPORTED_FEATURE, "CHECKOUT can only be performed on a " - "version resource [at this time].", - SVN_DAV_ERROR_NAMESPACE, - SVN_DAV_ERROR_TAG); + "version resource"); } if (create_activity) { - return dav_svn__new_error_tag(resource->pool, HTTP_NOT_IMPLEMENTED, + return dav_svn__new_error_svn(resource->pool, HTTP_NOT_IMPLEMENTED, SVN_ERR_UNSUPPORTED_FEATURE, "CHECKOUT cannot create an activity at " - "this time. Use MKACTIVITY first.", - SVN_DAV_ERROR_NAMESPACE, - SVN_DAV_ERROR_TAG); + "this time. Use MKACTIVITY first"); } if (is_unreserved) { - return dav_svn__new_error_tag(resource->pool, HTTP_NOT_IMPLEMENTED, + return dav_svn__new_error_svn(resource->pool, HTTP_NOT_IMPLEMENTED, SVN_ERR_UNSUPPORTED_FEATURE, "Unreserved checkouts are not yet " "available. A version history may not be " "checked out more than once, into a " - "specific activity.", - SVN_DAV_ERROR_NAMESPACE, - SVN_DAV_ERROR_TAG); + "specific activity"); } if (activities == NULL) { - return dav_svn__new_error_tag(resource->pool, HTTP_CONFLICT, + return dav_svn__new_error_svn(resource->pool, HTTP_CONFLICT, SVN_ERR_INCOMPLETE_DATA, "An activity must be provided for " - "checkout.", - SVN_DAV_ERROR_NAMESPACE, - SVN_DAV_ERROR_TAG); + "checkout"); } /* assert: nelts > 0. the below check effectively means > 1. */ if (activities->nelts != 1) { - return dav_svn__new_error_tag(resource->pool, HTTP_CONFLICT, + return dav_svn__new_error_svn(resource->pool, HTTP_CONFLICT, SVN_ERR_INCORRECT_PARAMS, "Only one activity may be specified within " - "the CHECKOUT.", - SVN_DAV_ERROR_NAMESPACE, - SVN_DAV_ERROR_TAG); + "the CHECKOUT"); } serr = dav_svn__simple_parse_uri(&parse, resource, @@ -600,21 +591,17 @@ dav_svn__checkout(dav_resource *resource, } if (parse.activity_id == NULL) { - return dav_svn__new_error_tag(resource->pool, HTTP_CONFLICT, + return dav_svn__new_error_svn(resource->pool, HTTP_CONFLICT, SVN_ERR_INCORRECT_PARAMS, - "The provided href is not an activity URI.", - SVN_DAV_ERROR_NAMESPACE, - SVN_DAV_ERROR_TAG); + "The provided href is not an activity URI"); } if ((txn_name = dav_svn__get_txn(resource->info->repos, parse.activity_id)) == NULL) { - return dav_svn__new_error_tag(resource->pool, HTTP_CONFLICT, + return dav_svn__new_error_svn(resource->pool, HTTP_CONFLICT, SVN_ERR_APMOD_ACTIVITY_NOT_FOUND, - "The specified activity does not exist.", - SVN_DAV_ERROR_NAMESPACE, - SVN_DAV_ERROR_TAG); + "The specified activity does not exist"); } /* verify the specified version resource is the "latest", thus allowing @@ -642,13 +629,11 @@ dav_svn__checkout(dav_resource *resource, if (resource->info->root.rev != youngest) { - return dav_svn__new_error_tag(resource->pool, HTTP_CONFLICT, + return dav_svn__new_error_svn(resource->pool, HTTP_CONFLICT, SVN_ERR_APMOD_BAD_BASELINE, "The specified baseline is not the " "latest baseline, so it may not be " - "checked out.", - SVN_DAV_ERROR_NAMESPACE, - SVN_DAV_ERROR_TAG); + "checked out"); } /* ### hmm. what if the transaction root's revision is different @@ -742,11 +727,9 @@ dav_svn__checkout(dav_resource *resource, { /* The item being modified is older than the one in the transaction. The client is out of date. */ - return dav_svn__new_error_tag + return dav_svn__new_error_svn (resource->pool, HTTP_CONFLICT, SVN_ERR_FS_CONFLICT, - "resource out of date; try updating", - SVN_DAV_ERROR_NAMESPACE, - SVN_DAV_ERROR_TAG); + "resource out of date; try updating"); } else if (resource->info->root.rev > txn_created_rev) { @@ -754,42 +737,25 @@ dav_svn__checkout(dav_resource *resource, revision than the one in the transaction. We'll check to see if they are still the same node, and if not, return an error. */ - const svn_fs_id_t *url_noderev_id, *txn_noderev_id; - - if ((serr = svn_fs_node_id(&txn_noderev_id, txn_root, - resource->info->repos_path, - resource->pool))) + svn_fs_node_relation_t node_relation; + if ((serr = svn_fs_node_relation(&node_relation, txn_root, + resource->info->repos_path, + resource->info->root.root, + resource->info->repos_path, + resource->pool))) { - err = dav_svn__new_error_tag + err = dav_svn__new_error_svn (resource->pool, HTTP_CONFLICT, serr->apr_err, "Unable to fetch the node revision id of the version " - "resource within the transaction.", - SVN_DAV_ERROR_NAMESPACE, - SVN_DAV_ERROR_TAG); + "resource within the revision"); svn_error_clear(serr); return err; } - if ((serr = svn_fs_node_id(&url_noderev_id, - resource->info->root.root, - resource->info->repos_path, - resource->pool))) + if (node_relation != svn_fs_node_unchanged) { - err = dav_svn__new_error_tag - (resource->pool, HTTP_CONFLICT, serr->apr_err, - "Unable to fetch the node revision id of the version " - "resource within the revision.", - SVN_DAV_ERROR_NAMESPACE, - SVN_DAV_ERROR_TAG); - svn_error_clear(serr); - return err; - } - if (svn_fs_compare_ids(url_noderev_id, txn_noderev_id) != 0) - { - return dav_svn__new_error_tag + return dav_svn__new_error_svn (resource->pool, HTTP_CONFLICT, SVN_ERR_FS_CONFLICT, - "version resource newer than txn (restart the commit)", - SVN_DAV_ERROR_NAMESPACE, - SVN_DAV_ERROR_TAG); + "version resource newer than txn (restart the commit)"); } } } @@ -806,11 +772,9 @@ static dav_error * uncheckout(dav_resource *resource) { if (resource->type != DAV_RESOURCE_TYPE_WORKING) - return dav_svn__new_error_tag(resource->pool, HTTP_INTERNAL_SERVER_ERROR, + return dav_svn__new_error_svn(resource->pool, HTTP_INTERNAL_SERVER_ERROR, SVN_ERR_UNSUPPORTED_FEATURE, - "UNCHECKOUT called on non-working resource.", - SVN_DAV_ERROR_NAMESPACE, - SVN_DAV_ERROR_TAG); + "UNCHECKOUT called on non-working resource"); /* Try to abort the txn if it exists; but don't try too hard. :-) */ if (resource->info->root.txn) @@ -877,7 +841,7 @@ cleanup_deltify(void *data) subpool, then destroy it before exiting. */ apr_pool_t *subpool = svn_pool_create(cdb->pool); - err = svn_repos_open2(&repos, cdb->repos_path, NULL, subpool); + err = svn_repos_open3(&repos, cdb->repos_path, NULL, subpool, subpool); if (err) { ap_log_perror(APLOG_MARK, APLOG_ERR, err->apr_err, cdb->pool, @@ -949,11 +913,9 @@ dav_svn__checkin(dav_resource *resource, txn? Many txns? Etc.) */ if (resource->type != DAV_RESOURCE_TYPE_WORKING) - return dav_svn__new_error_tag(resource->pool, HTTP_INTERNAL_SERVER_ERROR, + return dav_svn__new_error_svn(resource->pool, HTTP_INTERNAL_SERVER_ERROR, SVN_ERR_UNSUPPORTED_FEATURE, - "CHECKIN called on non-working resource.", - SVN_DAV_ERROR_NAMESPACE, - SVN_DAV_ERROR_TAG); + "CHECKIN called on non-working resource"); /* If the global autoversioning activity still exists, that means nobody's committed it yet. */ @@ -1010,7 +972,7 @@ dav_svn__checkin(dav_resource *resource, { const char *post_commit_err = svn_repos__post_commit_error_str (serr, resource->pool); - ap_log_perror(APLOG_MARK, APLOG_ERR, serr->apr_err, + ap_log_perror(APLOG_MARK, APLOG_ERR, APR_EGENERAL, resource->pool, "commit of r%ld succeeded, but an error occurred " "after the commit: '%s'", @@ -1079,7 +1041,7 @@ dav_svn__checkin(dav_resource *resource, uri = dav_svn__build_uri(resource->info->repos, DAV_SVN__BUILD_URI_VERSION, new_rev, resource->info->repos_path, - 0, resource->pool); + FALSE /* add_href */, resource->pool); err = dav_svn__create_version_resource(version_resource, uri, resource->pool); @@ -1130,12 +1092,16 @@ static dav_error * deliver_report(request_rec *r, const dav_resource *resource, const apr_xml_doc *doc, - ap_filter_t *output) + ap_filter_t *unused) { int ns = dav_svn__find_ns(doc->namespaces, SVN_XML_NAMESPACE); if (doc->root->ns == ns) { + dav_svn__output *output; + + output = dav_svn__output_create(resource->info->r, resource->pool); + /* ### note that these report names should have symbols... */ if (strcmp(doc->root->name, "update-report") == 0) @@ -1188,11 +1154,9 @@ deliver_report(request_rec *r, } /* ### what is a good error for an unknown report? */ - return dav_svn__new_error_tag(resource->pool, HTTP_NOT_IMPLEMENTED, + return dav_svn__new_error_svn(resource->pool, HTTP_NOT_IMPLEMENTED, SVN_ERR_UNSUPPORTED_FEATURE, - "The requested report is unknown.", - SVN_DAV_ERROR_NAMESPACE, - SVN_DAV_ERROR_TAG); + "The requested report is unknown"); } @@ -1219,13 +1183,11 @@ make_activity(dav_resource *resource) /* sanity check: make sure the resource is a valid activity, in case an older mod_dav doesn't do the check for us. */ if (! can_be_activity(resource)) - return dav_svn__new_error_tag(resource->pool, HTTP_FORBIDDEN, + return dav_svn__new_error_svn(resource->pool, HTTP_FORBIDDEN, SVN_ERR_APMOD_MALFORMED_URI, "Activities cannot be created at that " "location; query the " - "DAV:activity-collection-set property.", - SVN_DAV_ERROR_NAMESPACE, - SVN_DAV_ERROR_TAG); + "DAV:activity-collection-set property"); err = dav_svn__create_txn(resource->info->repos, &txn_name, NULL, resource->pool); @@ -1396,6 +1358,23 @@ dav_svn__push_locks(dav_resource *resource, return NULL; } +/* Implements svn_fs_lock_callback_t. */ +static svn_error_t * +unlock_many_cb(void *lock_baton, + const char *path, + const svn_lock_t *lock, + svn_error_t *fs_err, + apr_pool_t *pool) +{ + request_rec *r = lock_baton; + + if (fs_err) + ap_log_rerror(APLOG_MARK, APLOG_ERR, fs_err->apr_err, r, + "%s", fs_err->message); + + return SVN_NO_ERROR; +} + /* Helper for merge(). Free every lock in LOCKS. The locks live in REPOS. Log any errors for REQUEST. Use POOL for temporary @@ -1406,28 +1385,16 @@ release_locks(apr_hash_t *locks, request_rec *r, apr_pool_t *pool) { - apr_hash_index_t *hi; - const void *key; - void *val; apr_pool_t *subpool = svn_pool_create(pool); svn_error_t *err; - for (hi = apr_hash_first(pool, locks); hi; hi = apr_hash_next(hi)) - { - svn_pool_clear(subpool); - apr_hash_this(hi, &key, NULL, &val); - - /* The lock may be stolen or broken sometime between - svn_fs_commit_txn() and this post-commit cleanup. So ignore - any errors from this command; just free as many locks as we can. */ - err = svn_repos_fs_unlock(repos, key, val, FALSE, subpool); + err = svn_repos_fs_unlock_many(repos, locks, FALSE, unlock_many_cb, r, + subpool, subpool); - if (err) /* If we got an error, just log it and move along. */ - ap_log_rerror(APLOG_MARK, APLOG_ERR, err->apr_err, r, - "%s", err->message); - - svn_error_clear(err); - } + if (err) /* If we got an error, just log it and move along. */ + ap_log_rerror(APLOG_MARK, APLOG_ERR, err->apr_err, r, + "%s", err->message); + svn_error_clear(err); svn_pool_destroy(subpool); @@ -1441,7 +1408,7 @@ merge(dav_resource *target, int no_auto_merge, int no_checkout, apr_xml_elem *prop_elem, - ap_filter_t *output) + ap_filter_t *unused) { apr_pool_t *pool; dav_error *err; @@ -1452,6 +1419,7 @@ merge(dav_resource *target, svn_revnum_t new_rev; apr_hash_t *locks; svn_boolean_t disable_merge_response = FALSE; + dav_svn__output *output; /* We'll use the target's pool for our operation. We happen to know that it matches the request pool, which (should) have the proper lifetime. */ @@ -1464,22 +1432,18 @@ merge(dav_resource *target, || (source->type == DAV_RESOURCE_TYPE_PRIVATE && source->info->restype == DAV_SVN_RESTYPE_TXN_COLLECTION))) { - return dav_svn__new_error_tag(pool, HTTP_METHOD_NOT_ALLOWED, + return dav_svn__new_error_svn(pool, HTTP_METHOD_NOT_ALLOWED, SVN_ERR_INCORRECT_PARAMS, "MERGE can only be performed using an " "activity or transaction resource as the " - "source.", - SVN_DAV_ERROR_NAMESPACE, - SVN_DAV_ERROR_TAG); + "source"); } if (! source->exists) { - return dav_svn__new_error_tag(pool, HTTP_METHOD_NOT_ALLOWED, + return dav_svn__new_error_svn(pool, HTTP_METHOD_NOT_ALLOWED, SVN_ERR_INCORRECT_PARAMS, "MERGE activity or transaction resource " - "does not exist.", - SVN_DAV_ERROR_NAMESPACE, - SVN_DAV_ERROR_TAG); + "does not exist"); } /* Before attempting the final commit, we need to push any incoming @@ -1528,6 +1492,11 @@ merge(dav_resource *target, ### client some other way than hijacking the post-commit ### error message.*/ post_commit_err = svn_repos__post_commit_error_str(serr, pool); + ap_log_perror(APLOG_MARK, APLOG_ERR, APR_EGENERAL, pool, + "commit of r%ld succeeded, but an error occurred " + "after the commit: '%s'", + new_rev, + post_commit_err); svn_error_clear(serr); serr = SVN_NO_ERROR; } @@ -1620,6 +1589,7 @@ merge(dav_resource *target, } /* process the response for the new revision. */ + output = dav_svn__output_create(target->info->r, pool); return dav_svn__merge_response(output, source->info->repos, new_rev, post_commit_err, prop_elem, disable_merge_response, pool); |