📄 version.c
字号:
/* * version.c: mod_dav_svn versioning provider functions for Subversion * * ==================================================================== * Copyright (c) 2000-2006 CollabNet. All rights reserved. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at http://subversion.tigris.org/license-1.html. * If newer versions of this license are posted there, you may use a * newer version instead, at your option. * * This software consists of voluntary contributions made by many * individuals. For exact contribution history, see the revision * history and logs, available at http://subversion.tigris.org/. * ==================================================================== */#include <httpd.h>#include <http_log.h>#include <mod_dav.h>#include <apr_tables.h>#include <apr_uuid.h>#include "svn_fs.h"#include "svn_xml.h"#include "svn_repos.h"#include "svn_dav.h"#include "svn_time.h"#include "svn_pools.h"#include "svn_props.h"#include "svn_dav.h"#include "svn_base64.h"#include "dav_svn.h"/* ### should move these report names to a public header to share with ### the client (and third parties). */static const dav_report_elem avail_reports[] = { { SVN_XML_NAMESPACE, "update-report" }, { SVN_XML_NAMESPACE, "log-report" }, { SVN_XML_NAMESPACE, "dated-rev-report" }, { SVN_XML_NAMESPACE, "get-locations" }, { SVN_XML_NAMESPACE, "file-revs-report" }, { SVN_XML_NAMESPACE, "get-locks-report" }, { SVN_XML_NAMESPACE, "replay-report" }, { NULL },};/* declare these static functions early, so we can use them anywhere. */static dav_error *dav_svn_make_activity(dav_resource *resource);svn_error_t *dav_svn_attach_auto_revprops(svn_fs_txn_t *txn, const char *fs_path, apr_pool_t *pool){ const char *logmsg; svn_string_t *logval; svn_error_t *serr; logmsg = apr_psprintf(pool, "Autoversioning commit: a non-deltaV client made " "a change to\n%s", fs_path); logval = svn_string_create(logmsg, pool); if ((serr = svn_repos_fs_change_txn_prop(txn, SVN_PROP_REVISION_LOG, logval, pool))) return serr; /* Notate that this revision was created by autoversioning. (Tools like post-commit email scripts might not care to send an email for every autoversioning change.) */ if ((serr = svn_repos_fs_change_txn_prop(txn, SVN_PROP_REVISION_AUTOVERSIONED, svn_string_create("*", pool), pool))) return serr; return SVN_NO_ERROR;}/* Helper: attach an auto-generated svn:log property to a txn within an auto-checked-out working resource. */static dav_error *set_auto_revprops(dav_resource *resource){ svn_error_t *serr; if (! (resource->type == DAV_RESOURCE_TYPE_WORKING && resource->info->auto_checked_out)) return dav_new_error(resource->pool, HTTP_INTERNAL_SERVER_ERROR, 0, "Set_auto_revprops called on invalid resource."); if ((serr = dav_svn_attach_auto_revprops(resource->info->root.txn, resource->info->repos_path, resource->pool))) return dav_svn_convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "Error setting a revision property " " on auto-checked-out resource's txn. ", resource->pool); return NULL;}static dav_error *open_txn(svn_fs_txn_t **ptxn, svn_fs_t *fs, const char *txn_name, apr_pool_t *pool){ svn_error_t *serr; serr = svn_fs_open_txn(ptxn, fs, txn_name, pool); if (serr != NULL) { if (serr->apr_err == SVN_ERR_FS_NO_SUCH_TRANSACTION) { /* ### correct HTTP error? */ return dav_svn_convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "The transaction specified by the " "activity does not exist", pool); } /* ### correct HTTP error? */ return dav_svn_convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "There was a problem opening the " "transaction specified by this " "activity.", pool); } return NULL;}static void dav_svn_get_vsn_options(apr_pool_t *p, apr_text_header *phdr){ /* Note: we append pieces with care for Web Folders's 63-char limit on the DAV: header */ apr_text_append(p, phdr, "version-control,checkout,working-resource"); apr_text_append(p, phdr, "merge,baseline,activity,version-controlled-collection"); /* ### fork-control? */}static dav_error *dav_svn_get_option(const dav_resource *resource, const apr_xml_elem *elem, apr_text_header *option){ /* ### DAV:version-history-collection-set */ if (elem->ns == APR_XML_NS_DAV_ID) { 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>"); } } return NULL;}static int dav_svn_versionable(const dav_resource *resource){ return 0;}static dav_auto_version dav_svn_auto_versionable(const dav_resource *resource){ /* The svn client attempts to proppatch a baseline when changing unversioned revision props. Thus we allow baselines to be "auto-checked-out" by mod_dav. See issue #916. */ if (resource->type == DAV_RESOURCE_TYPE_VERSION && resource->baselined) return DAV_AUTO_VERSION_ALWAYS; /* No other autoversioning is allowed unless the SVNAutoversioning directive is used. */ if (resource->info->repos->autoversioning) { /* This allows a straight-out PUT on a public file or collection VCR. mod_dav's auto-versioning subsystem will check to see if it's possible to auto-checkout a regular resource. */ if (resource->type == DAV_RESOURCE_TYPE_REGULAR) return DAV_AUTO_VERSION_ALWAYS; /* mod_dav's auto-versioning subsystem will also check to see if it's possible to auto-checkin a working resource that was auto-checked-out. We *only* allow auto-versioning on a working resource if it was auto-checked-out. */ if (resource->type == DAV_RESOURCE_TYPE_WORKING && resource->info->auto_checked_out) return DAV_AUTO_VERSION_ALWAYS; } /* Default: whatever it is, assume it's not auto-versionable */ return DAV_AUTO_VERSION_NEVER;}static dav_error *dav_svn_vsn_control(dav_resource *resource, const char *target){ /* All mod_dav_svn resources are versioned objects; so it doesn't make sense to call vsn_control on a resource that exists . */ if (resource->exists) return dav_new_error(resource->pool, HTTP_BAD_REQUEST, 0, "vsn_control called on already-versioned resource."); /* 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, SVN_ERR_UNSUPPORTED_FEATURE, "vsn_control called with non-null target.", SVN_DAV_ERROR_NAMESPACE, SVN_DAV_ERROR_TAG); /* This is kind of silly. The docstring for this callback says it's supposed to "put a resource under version control". But in Subversion, all REGULAR resources (bc's or public URIs) are already under version control. So we don't need to do a thing to the resource, just return. */ return NULL;}dav_error *dav_svn_checkout(dav_resource *resource, int auto_checkout, int is_unreserved, int is_fork_ok, int create_activity, apr_array_header_t *activities, dav_resource **working_resource){ const char *txn_name; svn_error_t *serr; apr_status_t apr_err; dav_error *derr; dav_svn_uri_info parse; /* Auto-Versioning Stuff */ if (auto_checkout) { dav_resource *res; /* ignored */ const char *uuid_buf; void *data; const char *shared_activity, *shared_txn_name = NULL; /* Baselines can be auto-checked-out -- grudgingly -- so we can allow clients to proppatch unversioned rev props. See issue #916. */ if ((resource->type == DAV_RESOURCE_TYPE_VERSION) && resource->baselined) /* ### We're violating deltaV big time here, by allowing a dav_auto_checkout() on something that mod_dav assumes is a VCR, not a VR. Anyway, mod_dav thinks we're checking out the resource 'in place', so that no working resource is returned. (It passes NULL as **working_resource.) */ return NULL; if (resource->type != DAV_RESOURCE_TYPE_REGULAR) return dav_svn__new_error_tag(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); if (resource->baselined) return dav_svn__new_error_tag(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); /* See if the shared activity already exists. */ apr_err = apr_pool_userdata_get(&data, DAV_SVN_AUTOVERSIONING_ACTIVITY, resource->info->r->pool); if (apr_err) return dav_svn_convert_err(svn_error_create(apr_err, 0, NULL), HTTP_INTERNAL_SERVER_ERROR, "Error fetching pool userdata.", resource->pool); shared_activity = data; if (! shared_activity) { /* Build a shared activity for all auto-checked-out resources. */ uuid_buf = svn_uuid_generate(resource->info->r->pool); shared_activity = apr_pstrdup(resource->info->r->pool, uuid_buf); derr = dav_svn_create_activity(resource->info->repos, &shared_txn_name, resource->info->r->pool); if (derr) return derr; derr = dav_svn_store_activity(resource->info->repos, shared_activity, shared_txn_name); if (derr) return derr; /* Save the shared activity in r->pool for others to use. */ apr_err = apr_pool_userdata_set(shared_activity, DAV_SVN_AUTOVERSIONING_ACTIVITY, NULL, resource->info->r->pool); if (apr_err) return dav_svn_convert_err(svn_error_create(apr_err, 0, NULL), HTTP_INTERNAL_SERVER_ERROR, "Error setting pool userdata.", resource->pool); } if (! shared_txn_name) { shared_txn_name = dav_svn_get_txn(resource->info->repos, shared_activity); if (! shared_txn_name) return dav_new_error(resource->pool, HTTP_INTERNAL_SERVER_ERROR, 0, "Cannot look up a txn_name by activity"); } /* Tweak the VCR in-place, making it into a WR. (Ignore the NULL return value.) */ res = dav_svn_create_working_resource(resource, shared_activity, shared_txn_name,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -