📄 version.c
字号:
long as that pool. */
apr_pool_t *pool;
};
/* APR pool cleanup function to deltify against a just-committed
revision. DATA is a 'struct cleanup_deltify_baton *'.
If any errors occur, log them in the httpd server error log, but
return APR_SUCCESS no matter what, as this is a pool cleanup
function and deltification is not a matter of correctness
anyway. */
static apr_status_t cleanup_deltify(void *data)
{
struct cleanup_deltify_baton *cdb = data;
svn_repos_t *repos;
svn_error_t *err;
/* It's okay to allocate in the pool that's being cleaned up, and
it's also okay to register new cleanups against that pool. But
if you create subpools of it, you must make sure to destroy them
at the end of the cleanup. So we do all our work in this
subpool, then destroy it before exiting. */
apr_pool_t *subpool = svn_pool_create(cdb->pool);
err = svn_repos_open(&repos, cdb->repos_path, subpool);
if (err)
{
ap_log_perror(APLOG_MARK, APLOG_ERR, err->apr_err, cdb->pool,
"cleanup_deltify: error opening repository '%s'",
cdb->repos_path);
svn_error_clear(err);
goto cleanup;
}
err = svn_fs_deltify_revision(svn_repos_fs(repos),
cdb->revision, subpool);
if (err)
{
ap_log_perror(APLOG_MARK, APLOG_ERR, err->apr_err, cdb->pool,
"cleanup_deltify: error deltifying against revision %ld"
" in repository '%s'",
cdb->revision, cdb->repos_path);
svn_error_clear(err);
}
cleanup:
svn_pool_destroy(subpool);
return APR_SUCCESS;
}
/* Register the cleanup_deltify function on POOL, which should be the
connection pool for the request. This way the time needed for
deltification won't delay the response to the client.
REPOS is the repository in which deltify, and REVISION is the
revision against which to deltify. POOL is both the pool on which
to register the cleanup function and the pool that will be used for
temporary allocations while deltifying. */
static void register_deltification_cleanup(svn_repos_t *repos,
svn_revnum_t revision,
apr_pool_t *pool)
{
struct cleanup_deltify_baton *cdb = apr_palloc(pool, sizeof(*cdb));
cdb->repos_path = svn_repos_path(repos, pool);
cdb->revision = revision;
cdb->pool = pool;
apr_pool_cleanup_register(pool, cdb, cleanup_deltify, apr_pool_cleanup_null);
}
dav_error *dav_svn_checkin(dav_resource *resource,
int keep_checked_out,
dav_resource **version_resource)
{
svn_error_t *serr;
dav_error *err;
const char *uri;
/* ### mod_dav has a flawed architecture, in the sense that it first
tries to auto-checkin the modified resource, then attempts to
auto-checkin the parent resource (if the parent resource was
auto-checked-out). Instead, the provider should be in charge:
mod_dav should provide a *set* of resources that need
auto-checkin, and the provider can decide how to do it. (One
txn? Many txns? Etc.) */
if (resource->type != DAV_RESOURCE_TYPE_WORKING)
return dav_new_error_tag(resource->pool, HTTP_INTERNAL_SERVER_ERROR,
SVN_ERR_UNSUPPORTED_FEATURE,
"CHECKIN called on non-working resource.",
SVN_DAV_ERROR_NAMESPACE,
SVN_DAV_ERROR_TAG);
/* Try to commit the txn if it exists. */
if (resource->info->root.txn_name)
{
svn_fs_txn_t *txn;
const char *conflict_msg;
svn_revnum_t new_rev;
err = open_txn(&txn, resource->info->repos->fs,
resource->info->root.txn_name, resource->pool);
/* If we failed to open the txn, don't worry about it. It may
have already been committed when a child resource was
checked in. */
if (! err)
{
err = set_auto_log_message(resource);
if (err)
return err;
serr = svn_repos_fs_commit_txn(&conflict_msg,
resource->info->repos->repos,
&new_rev,
resource->info->root.txn,
resource->pool);
if (serr != NULL)
{
const char *msg;
svn_error_clear(svn_fs_abort_txn(resource->info->root.txn,
resource->pool));
if (serr->apr_err == SVN_ERR_FS_CONFLICT)
{
msg = apr_psprintf(resource->pool,
"A conflict occurred during the CHECKIN "
"processing. The problem occurred with "
"the \"%s\" resource.",
conflict_msg);
}
else
msg = "An error occurred while committing the transaction.";
return dav_svn_convert_err(serr, HTTP_CONFLICT, msg,
resource->pool);
}
/* Commit was successful, so schedule deltification. */
register_deltification_cleanup(resource->info->repos->repos,
new_rev,
resource->info->r->connection->pool);
/* If caller wants it, return the new VR that was created by
the checkin. */
if (version_resource)
{
uri = dav_svn_build_uri(resource->info->repos,
DAV_SVN_BUILD_URI_VERSION,
new_rev, resource->info->repos_path,
0, resource->pool);
err = dav_svn_create_version_resource(version_resource, uri,
resource->pool);
if (err)
return err;
}
}
/* whether the txn was committed, aborted, or inaccessible,
it's gone now. the resource needs to lose all knowledge
of it. */
resource->info->root.txn_name = NULL;
resource->info->root.txn = NULL;
}
/* Convert the working resource back into an regular one. */
if (! keep_checked_out)
{
resource->info->auto_checked_out = FALSE;
return dav_svn_working_to_regular_resource(resource);
}
return NULL;
}
static dav_error *dav_svn_avail_reports(const dav_resource *resource,
const dav_report_elem **reports)
{
/* ### further restrict to the public space? */
if (resource->type != DAV_RESOURCE_TYPE_REGULAR) {
*reports = NULL;
return NULL;
}
*reports = avail_reports;
return NULL;
}
static int dav_svn_report_label_header_allowed(const apr_xml_doc *doc)
{
return 0;
}
/* Respond to a S:dated-rev-report request. The request contains a
* DAV:creationdate element giving the requested date; the response
* contains a DAV:version-name element giving the most recent revision
* as of that date. */
static dav_error * dav_svn__drev_report(const dav_resource *resource,
const apr_xml_doc *doc,
ap_filter_t *output)
{
apr_xml_elem *child;
int ns;
apr_time_t tm = (apr_time_t) -1;
svn_revnum_t rev;
apr_bucket_brigade *bb;
svn_error_t *err;
apr_status_t apr_err;
dav_error *derr = NULL;
/* Find the DAV:creationdate element and get the requested time from it. */
ns = dav_svn_find_ns(doc->namespaces, "DAV:");
if (ns != -1)
{
for (child = doc->root->first_child; child != NULL; child = child->next)
{
if (child->ns != ns || strcmp(child->name, "creationdate") != 0)
continue;
/* If this fails, we'll notice below, so ignore any error for now. */
svn_error_clear
(svn_time_from_cstring(&tm, dav_xml_get_cdata(child,
resource->pool, 1),
resource->pool));
}
}
if (tm == (apr_time_t) -1)
{
return dav_new_error(resource->pool, HTTP_BAD_REQUEST, 0,
"The request does not contain a valid "
"'DAV:creationdate' element.");
}
/* Do the actual work of finding the revision by date. */
if ((err = svn_repos_dated_revision(&rev, resource->info->repos->repos, tm,
resource->pool)) != SVN_NO_ERROR)
{
svn_error_clear (err);
return dav_new_error(resource->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
"Could not access revision times.");
}
bb = apr_brigade_create(resource->pool, output->c->bucket_alloc);
apr_err = ap_fprintf(output, bb,
DAV_XML_HEADER DEBUG_CR
"<S:dated-rev-report xmlns:S=\"" SVN_XML_NAMESPACE "\" "
"xmlns:D=\"DAV:\">" DEBUG_CR
"<D:version-name>%ld</D:version-name>"
"</S:dated-rev-report>", rev);
if (apr_err)
derr = dav_svn_convert_err(svn_error_create(apr_err, 0, NULL),
HTTP_INTERNAL_SERVER_ERROR,
"Error writing REPORT response.",
resource->pool);
/* Flush the contents of the brigade (returning an error only if we
don't already have one). */
if (((apr_err = ap_fflush(output, bb))) && (! derr))
derr = dav_svn_convert_err(svn_error_create(apr_err, 0, NULL),
HTTP_INTERNAL_SERVER_ERROR,
"Error flushing brigade.",
resource->pool);
return derr;
}
static apr_status_t send_get_locations_report(ap_filter_t *output,
apr_bucket_brigade *bb,
const dav_resource *resource,
apr_hash_t *fs_locations)
{
apr_hash_index_t *hi;
apr_pool_t *pool;
apr_status_t apr_err;
pool = resource->pool;
apr_err = ap_fprintf(output, bb, DAV_XML_HEADER DEBUG_CR
"<S:get-locations-report xmlns:S=\"" SVN_XML_NAMESPACE
"\" xmlns:D=\"DAV:\">" DEBUG_CR);
if (apr_err)
return apr_err;
for (hi = apr_hash_first(pool, fs_locations); hi; hi = apr_hash_next (hi))
{
const void *key;
void *value;
const char *path_quoted;
apr_hash_this(hi, &key, NULL, &value);
path_quoted = apr_xml_quote_string(pool, value, 1);
apr_err = ap_fprintf(output, bb, "<S:location "
"rev=\"%ld\" path=\"%s\"/>" DEBUG_CR,
*(svn_revnum_t *)key, path_quoted);
if (apr_err)
return apr_err;
}
return ap_fprintf(output, bb, "</S:get-locations-report>" DEBUG_CR);
}
dav_error *dav_svn__get_locations_report(const dav_resource *resource,
const apr_xml_doc *doc,
ap_filter_t *output)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -