diff options
Diffstat (limited to 'subversion/mod_dav_svn/lock.c')
-rw-r--r-- | subversion/mod_dav_svn/lock.c | 96 |
1 files changed, 86 insertions, 10 deletions
diff --git a/subversion/mod_dav_svn/lock.c b/subversion/mod_dav_svn/lock.c index 68d6de5..06c038a 100644 --- a/subversion/mod_dav_svn/lock.c +++ b/subversion/mod_dav_svn/lock.c @@ -92,7 +92,7 @@ svn_lock_to_dav_lock(dav_lock **dlock, "<D:owner xmlns:D=\"DAV:\">", apr_xml_quote_string(pool, slock->comment, 1), - "</D:owner>", (char *)NULL); + "</D:owner>", SVN_VA_NULL); } else { @@ -134,7 +134,7 @@ unescape_xml(const char **output, apr_xml_doc *xml_doc; apr_status_t apr_err; const char *xml_input = apr_pstrcat - (pool, "<?xml version=\"1.0\" encoding=\"utf-8\"?>", input, (char *)NULL); + (pool, "<?xml version=\"1.0\" encoding=\"utf-8\"?>", input, SVN_VA_NULL); apr_err = apr_xml_parser_feed(xml_parser, xml_input, strlen(xml_input)); if (!apr_err) @@ -274,8 +274,13 @@ parse_locktoken(apr_pool_t *pool, static const char * format_locktoken(apr_pool_t *p, const dav_locktoken *locktoken) { - /* libsvn_fs already produces a valid locktoken URI. */ - return apr_pstrdup(p, locktoken->uuid_str); + svn_stringbuf_t *formatted + = svn_stringbuf_create_ensure(strlen(locktoken->uuid_str), p); + + /* libsvn_fs produces a locktoken URI that will be valid XML when + escaped. */ + svn_xml_escape_cdata_cstring(&formatted, locktoken->uuid_str, p); + return formatted->data; } @@ -782,7 +787,31 @@ append_locks(dav_lockdb *lockdb, DAV_ERR_LOCK_SAVE_LOCK, "Anonymous lock creation is not allowed."); } - else if (serr && (serr->apr_err == SVN_ERR_REPOS_HOOK_FAILURE || + else if (serr && serr->apr_err == SVN_ERR_REPOS_POST_LOCK_HOOK_FAILED) + { + /* The lock was created in the repository, so we should report the node + as locked to the client */ + + /* First log the hook failure, for diagnostics. This clears serr */ + dav_svn__log_err(info->r, + dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, + "Post lock hook failure.", + resource->pool), + APLOG_WARNING); + + /* How can we report the error to the client? + + We can't return an error code, as that would make it impossible + to return the lock details? + + Add yet another custom header? + Just an header doesn't handle a full error chain... + + ### Current behavior: we don't report an error. + */ + + } + else if (serr && (svn_error_find_cause(serr, SVN_ERR_REPOS_HOOK_FAILURE) || serr->apr_err == SVN_ERR_FS_NO_SUCH_LOCK || serr->apr_err == SVN_ERR_FS_LOCK_EXPIRED || SVN_ERR_IS_LOCK_ERROR(serr))) @@ -838,14 +867,14 @@ remove_lock(dav_lockdb *lockdb, /* Sanity check: if the resource has no associated path in the fs, then there's nothing to do. */ if (! resource->info->repos_path) - return 0; + return NULL; /* Another easy out: if an svn client sent a 'keep_locks' header (typically in a DELETE request, as part of 'svn commit --no-unlock'), then ignore dav_method_delete()'s attempt to unconditionally remove the lock. */ if (info->keep_locks) - return 0; + return NULL; /* If the resource's fs path is unreadable, we don't allow a lock to be removed from it. */ @@ -892,6 +921,22 @@ remove_lock(dav_lockdb *lockdb, DAV_ERR_LOCK_SAVE_LOCK, "Anonymous lock removal is not allowed."); } + else if (serr && serr->apr_err == SVN_ERR_REPOS_POST_UNLOCK_HOOK_FAILED + && !resource->info->repos->is_svn_client) + { + /* Generic DAV clients don't understand the specific error code we + would produce here as being just a warning, so lets produce a + success result. We removed the lock anyway. */ + + /* First log the hook failure, for diagnostics. This clears serr */ + dav_svn__log_err(info->r, + dav_svn__convert_err(serr, + HTTP_INTERNAL_SERVER_ERROR, + "Post unlock hook failure.", + resource->pool), + APLOG_WARNING); + + } else if (serr) return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "Failed to remove a lock.", @@ -905,10 +950,41 @@ remove_lock(dav_lockdb *lockdb, resource->info->r->pool)); } - return 0; + return NULL; +} + +static dav_error * +remove_lock_svn_output(dav_lockdb *lockdb, + const dav_resource *resource, + const dav_locktoken *locktoken) +{ + dav_error *derr = remove_lock(lockdb, resource, locktoken); + int status; + + if (!derr + || !resource->info->repos + || !resource->info->repos->is_svn_client + || (strcmp(lockdb->info->r->method, "UNLOCK") != 0)) + return derr; + + /* Ok, we have a nice error chain but mod_dav doesn't offer us a way to + present it to the client as it will only use the status code for + generating a standard error... + + Luckily the unlock processing for the "UNLOCK" method is very simple: + call this function and return the result. + + That allows us to just force a response and tell httpd that we are done */ + status = dav_svn__error_response_tag(lockdb->info->r, derr); + + /* status = DONE */ + + /* And push an error that will make mod_dav just report that it is done */ + return dav_push_error(resource->pool, status, derr->error_id, NULL, derr); } + /* ** Refresh all locks, found on the specified resource, which has a ** locktoken in the provided list. @@ -980,7 +1056,7 @@ refresh_locks(dav_lockdb *lockdb, DAV_ERR_LOCK_SAVE_LOCK, "Anonymous lock refreshing is not allowed."); } - else if (serr && (serr->apr_err == SVN_ERR_REPOS_HOOK_FAILURE || + else if (serr && (svn_error_find_cause(serr, SVN_ERR_REPOS_HOOK_FAILURE) || serr->apr_err == SVN_ERR_FS_NO_SUCH_LOCK || serr->apr_err == SVN_ERR_FS_LOCK_EXPIRED || SVN_ERR_IS_LOCK_ERROR(serr))) @@ -1014,7 +1090,7 @@ const dav_hooks_locks dav_svn__hooks_locks = { find_lock, has_locks, append_locks, - remove_lock, + remove_lock_svn_output, refresh_locks, NULL, NULL /* hook structure context */ |