#include <apr_pools.h>
#include <apr_network_io.h>
#include "svn_types.h"
#include "svn_pools.h"
#include "svn_error.h"
#include "svn_error_codes.h"
#include "svn_dirent_uri.h"
#include "svn_path.h"
#include "svn_ra.h"
#include "svn_private_config.h"
#include "private/svn_ra_private.h"
svn_error_t *
svn_ra__assert_mergeinfo_capable_server(svn_ra_session_t *ra_session,
const char *path_or_url,
apr_pool_t *pool)
{
svn_boolean_t mergeinfo_capable;
SVN_ERR(svn_ra_has_capability(ra_session, &mergeinfo_capable,
SVN_RA_CAPABILITY_MERGEINFO, pool));
if (! mergeinfo_capable)
{
if (path_or_url == NULL)
{
svn_error_t *err = svn_ra_get_session_url(ra_session, &path_or_url,
pool);
if (err)
{
svn_error_clear(err);
path_or_url = "<repository>";
}
}
return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
_("Retrieval of mergeinfo unsupported by '%s'"),
svn_path_is_url(path_or_url)
? path_or_url
: svn_dirent_local_style(path_or_url, pool));
}
return SVN_NO_ERROR;
}
static svn_boolean_t is_atomicity_error(svn_error_t *err)
{
return svn_error_find_cause(err, SVN_ERR_FS_PROP_BASEVALUE_MISMATCH) != NULL;
}
svn_error_t *
svn_ra__release_operational_lock(svn_ra_session_t *session,
const char *lock_revprop_name,
const svn_string_t *mylocktoken,
apr_pool_t *scratch_pool)
{
svn_string_t *reposlocktoken;
svn_boolean_t be_atomic;
SVN_ERR(svn_ra_has_capability(session, &be_atomic,
SVN_RA_CAPABILITY_ATOMIC_REVPROPS,
scratch_pool));
SVN_ERR(svn_ra_rev_prop(session, 0, lock_revprop_name,
&reposlocktoken, scratch_pool));
if (reposlocktoken && svn_string_compare(reposlocktoken, mylocktoken))
{
svn_error_t *err;
err = svn_ra_change_rev_prop2(session, 0, lock_revprop_name,
be_atomic ? &mylocktoken : NULL, NULL,
scratch_pool);
if (is_atomicity_error(err))
{
return svn_error_createf(err->apr_err, err,
_("Lock was stolen by '%s'; unable to "
"remove it"), reposlocktoken->data);
}
else
SVN_ERR(err);
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_ra__get_operational_lock(const svn_string_t **lock_string_p,
const svn_string_t **stolen_lock_p,
svn_ra_session_t *session,
const char *lock_revprop_name,
svn_boolean_t steal_lock,
int num_retries,
svn_ra__lock_retry_func_t retry_func,
void *retry_baton,
svn_cancel_func_t cancel_func,
void *cancel_baton,
apr_pool_t *pool)
{
char hostname_str[APRMAXHOSTLEN + 1] = { 0 };
svn_string_t *mylocktoken, *reposlocktoken;
apr_status_t apr_err;
svn_boolean_t be_atomic;
apr_pool_t *subpool;
int i;
*lock_string_p = NULL;
if (stolen_lock_p)
*stolen_lock_p = NULL;
SVN_ERR(svn_ra_has_capability(session, &be_atomic,
SVN_RA_CAPABILITY_ATOMIC_REVPROPS, pool));
apr_err = apr_gethostname(hostname_str, sizeof(hostname_str), pool);
if (apr_err)
return svn_error_wrap_apr(apr_err,
_("Unable to determine local hostname"));
mylocktoken = svn_string_createf(pool, "%s:%s", hostname_str,
svn_uuid_generate(pool));
subpool = svn_pool_create(pool);
for (i = 0; i < num_retries; ++i)
{
svn_error_t *err;
const svn_string_t *unset = NULL;
svn_pool_clear(subpool);
if (cancel_func)
{
err = cancel_func(cancel_baton);
if (err && err->apr_err == SVN_ERR_CANCELLED)
return svn_error_compose_create(
svn_ra__release_operational_lock(session,
lock_revprop_name,
mylocktoken,
subpool),
err);
SVN_ERR(err);
}
SVN_ERR(svn_ra_rev_prop(session, 0, lock_revprop_name,
&reposlocktoken, subpool));
if (reposlocktoken)
{
if (svn_string_compare(reposlocktoken, mylocktoken))
{
*lock_string_p = mylocktoken;
return SVN_NO_ERROR;
}
else if (! steal_lock)
{
if (retry_func)
SVN_ERR(retry_func(retry_baton, reposlocktoken, subpool));
apr_sleep(apr_time_from_sec(1));
continue;
}
else
{
if (stolen_lock_p)
*stolen_lock_p = svn_string_dup(reposlocktoken, pool);
unset = reposlocktoken;
}
}
if (i < num_retries - 1)
{
err = svn_ra_change_rev_prop2(session, 0, lock_revprop_name,
be_atomic ? &unset : NULL,
mylocktoken, subpool);
if (be_atomic && err && is_atomicity_error(err))
{
svn_error_clear(err);
}
else if (be_atomic && err == SVN_NO_ERROR)
{
continue;
}
else
{
SVN_ERR(err);
}
}
}
return svn_error_createf(APR_EINVAL, NULL,
_("Couldn't get lock on destination repos "
"after %d attempts"), i);
}