📄 liveprops.c
字号:
/* * liveprops.c: mod_dav_svn live property provider functions for Subversion * * ==================================================================== * Copyright (c) 2000-2004 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 <util_xml.h>#include <apr_tables.h>#include <apr_md5.h>#include <mod_dav.h>#include "dav_svn.h"#include "svn_pools.h"#include "svn_time.h"#include "svn_dav.h"#include "svn_md5.h"#include "svn_props.h"/*** The namespace URIs that we use. This list and the enumeration must** stay in sync.*/static const char * const dav_svn_namespace_uris[] ={ "DAV:", SVN_DAV_PROP_NS_DAV, NULL /* sentinel */};enum { DAV_SVN_NAMESPACE_URI_DAV, /* the DAV: namespace URI */ DAV_SVN_NAMESPACE_URI /* the dav<->ra_dav namespace URI */};#define SVN_RO_DAV_PROP(name) \ { DAV_SVN_NAMESPACE_URI_DAV, #name, DAV_PROPID_##name, 0 }#define SVN_RW_DAV_PROP(name) \ { DAV_SVN_NAMESPACE_URI_DAV, #name, DAV_PROPID_##name, 1 }#define SVN_RO_DAV_PROP2(sym,name) \ { DAV_SVN_NAMESPACE_URI_DAV, #name, DAV_PROPID_##sym, 0 }#define SVN_RW_DAV_PROP2(sym,name) \ { DAV_SVN_NAMESPACE_URI_DAV, #name, DAV_PROPID_##sym, 1 }#define SVN_RO_SVN_PROP(sym,name) \ { DAV_SVN_NAMESPACE_URI, #name, SVN_PROPID_##sym, 0 }#define SVN_RW_SVN_PROP(sym,name) \ { DAV_SVN_NAMESPACE_URI, #name, SVN_PROPID_##sym, 1 }enum { SVN_PROPID_baseline_relative_path = 1, SVN_PROPID_md5_checksum, SVN_PROPID_repository_uuid, SVN_PROPID_deadprop_count};static const dav_liveprop_spec dav_svn_props[] ={ /* ### don't worry about these for a bit */#if 0 /* WebDAV properties */ SVN_RO_DAV_PROP(getcontentlanguage), /* ### make this r/w? */#endif SVN_RO_DAV_PROP(getcontentlength), SVN_RO_DAV_PROP(getcontenttype), /* ### make this r/w? */ SVN_RO_DAV_PROP(getetag), SVN_RO_DAV_PROP(creationdate), SVN_RO_DAV_PROP(getlastmodified), /* DeltaV properties */ SVN_RO_DAV_PROP2(baseline_collection, baseline-collection), SVN_RO_DAV_PROP2(checked_in, checked-in), SVN_RO_DAV_PROP2(version_controlled_configuration, version-controlled-configuration), SVN_RO_DAV_PROP2(version_name, version-name), SVN_RO_DAV_PROP2(creator_displayname, creator-displayname), SVN_RO_DAV_PROP2(auto_version, auto-version), /* SVN properties */ SVN_RO_SVN_PROP(baseline_relative_path, baseline-relative-path), SVN_RO_SVN_PROP(md5_checksum, md5-checksum), SVN_RO_SVN_PROP(repository_uuid, repository-uuid), SVN_RO_SVN_PROP(deadprop_count, deadprop-count), { 0 } /* sentinel */};static const dav_liveprop_group dav_svn_liveprop_group ={ dav_svn_props, dav_svn_namespace_uris, &dav_svn_hooks_liveprop};/* Set *PROPVAL to the value for the revision property PROPNAME on COMMITTED_REV, in the repository identified by RESOURCE, if RESOURCE's path is readable. If it is not readable, set *PROPVAL to NULL and return SVN_NO_ERROR. Use POOL for temporary allocations and the allocation of *PROPVAL. Note that this function does not check the readability of the revision property, but the readability of a path. The true readability of a revision property is determined by investigating the readability of all changed paths in the revision. For certain revision properties (e.g. svn:author and svn:date) to be readable, it is enough if at least one changed path is readable. When we already have a changed path, we can skip the check for the other changed paths in the revision and save a lot of work. This means that we will make a mistake when our path is unreadable and another changed path is readable, but we will at least only hide too much and not leak any protected properties. WARNING: This method of only checking the readability of a path is only valid to get revision properties for which it is enough if at least one changed path is readable. Using this function to get revision properties for which all changed paths must be readable might leak protected information because we will only test the readability of a single changed path.*/static svn_error_t *dav_svn_get_path_revprop(svn_string_t **propval, const dav_resource *resource, svn_revnum_t committed_rev, const char *propname, apr_pool_t *pool){ dav_svn_authz_read_baton arb; svn_boolean_t allowed; svn_fs_root_t *root; *propval = NULL; arb.r = resource->info->r; arb.repos = resource->info->repos; SVN_ERR(svn_fs_revision_root(&root, resource->info->repos->fs, committed_rev, pool)); SVN_ERR(dav_svn_authz_read(&allowed, root, resource->info->repos_path, &arb, pool)); if (! allowed) return SVN_NO_ERROR; /* Get the property of the created revision. The authz is already performed, so we don't need to do it here too. */ return svn_repos_fs_revision_prop(propval, resource->info->repos->repos, committed_rev, propname, NULL, NULL, pool);}static dav_prop_insert dav_svn_insert_prop(const dav_resource *resource, int propid, dav_prop_insert what, apr_text_header *phdr){ const char *value = NULL; const char *s; apr_pool_t *response_pool = resource->pool; apr_pool_t *p = resource->info->pool; const dav_liveprop_spec *info; int global_ns; svn_error_t *serr; /* ** Almost none of the SVN provider properties are defined if the ** resource does not exist. We do need to return the one VCC ** property and baseline-relative-path on lock-null resources, ** however, so that svn clients can run 'svn unlock' and 'svn info' ** on these things. ** ** Even though we state that the SVN properties are not defined, the ** client cannot store dead values -- we deny that thru the is_writable ** hook function. */ if ((! resource->exists) && (propid != DAV_PROPID_version_controlled_configuration) && (propid != SVN_PROPID_baseline_relative_path)) return DAV_PROP_INSERT_NOTSUPP; /* ### we may want to respond to DAV_PROPID_resourcetype for PRIVATE ### resources. need to think on "proper" interaction with mod_dav */ switch (propid) { case DAV_PROPID_getlastmodified: case DAV_PROPID_creationdate: { /* In subversion terms, the date attached to a file's CR is the true "last modified" time. However, we're defining creationdate in the same way. IMO, the "creationdate" is really the date attached to the revision in which the item *first* came into existence; this would found by tracing back through the log of the file -- probably via svn_fs_revisions_changed. gstein, is it a bad thing that we're currently using 'creationdate' to mean the same thing as 'last modified date'? */ const char *datestring; apr_time_t timeval; enum dav_svn_time_format format; /* ### for now, our global VCC has no such property. */ if (resource->type == DAV_RESOURCE_TYPE_PRIVATE && resource->info->restype == DAV_SVN_RESTYPE_VCC) { return DAV_PROP_INSERT_NOTSUPP; } if (propid == DAV_PROPID_creationdate) { /* Return an ISO8601 date; this is what the svn client expects, and rfc2518 demands it. */ format = dav_svn_time_format_iso8601; } else /* propid == DAV_PROPID_getlastmodified */ { format = dav_svn_time_format_rfc1123; } if (0 != dav_svn_get_last_modified_time(&datestring, &timeval, resource, format, p)) { return DAV_PROP_INSERT_NOTDEF; } value = apr_xml_quote_string(p, datestring, 1); break; } case DAV_PROPID_creator_displayname: { svn_revnum_t committed_rev = SVN_INVALID_REVNUM; svn_string_t *last_author = NULL; /* ### for now, our global VCC has no such property. */ if (resource->type == DAV_RESOURCE_TYPE_PRIVATE && resource->info->restype == DAV_SVN_RESTYPE_VCC) { return DAV_PROP_INSERT_NOTSUPP; } if (resource->baselined && resource->type == DAV_RESOURCE_TYPE_VERSION) { /* A baseline URI. */ committed_rev = resource->info->root.rev; } else if (resource->type == DAV_RESOURCE_TYPE_REGULAR || resource->type == DAV_RESOURCE_TYPE_WORKING || resource->type == DAV_RESOURCE_TYPE_VERSION) { /* Get the CR field out of the node's skel. Notice that the root object might be an ID root -or- a revision root. */ serr = svn_fs_node_created_rev(&committed_rev, resource->info->root.root, resource->info->repos_path, p); if (serr != NULL) { /* ### what to do? */ svn_error_clear(serr); value = "###error###"; break; } } else { return DAV_PROP_INSERT_NOTSUPP; } serr = dav_svn_get_path_revprop(&last_author, resource, committed_rev, SVN_PROP_REVISION_AUTHOR, p); if (serr) { /* ### what to do? */ svn_error_clear(serr); value = "###error###"; break; } if (last_author == NULL) return DAV_PROP_INSERT_NOTDEF; value = apr_xml_quote_string(p, last_author->data, 1); break; } case DAV_PROPID_getcontentlanguage: /* ### need something here */ return DAV_PROP_INSERT_NOTSUPP; break; case DAV_PROPID_getcontentlength: { svn_filesize_t len = 0; /* our property, but not defined on collection resources */ if (resource->collection || resource->baselined) return DAV_PROP_INSERT_NOTSUPP; serr = svn_fs_file_length(&len, resource->info->root.root, resource->info->repos_path, p); if (serr != NULL) { svn_error_clear(serr); value = "0"; /* ### what to do? */ break; } value = apr_psprintf(p, "%" SVN_FILESIZE_T_FMT, len); break; } case DAV_PROPID_getcontenttype: { /* The subversion client assumes that any file without an svn:mime-type property is of type text/plain. So it seems safe (and consistent) to assume the same on the server. */ svn_string_t *pval; const char *mime_type = NULL; if (resource->baselined && resource->type == DAV_RESOURCE_TYPE_VERSION) return DAV_PROP_INSERT_NOTSUPP; if (resource->type == DAV_RESOURCE_TYPE_PRIVATE && resource->info->restype == DAV_SVN_RESTYPE_VCC) { return DAV_PROP_INSERT_NOTSUPP; } if (resource->collection) /* defaults for directories */ { if (resource->info->repos->xslt_uri) mime_type = "text/xml"; else mime_type = "text/html; charset=UTF-8"; } else { if ((serr = svn_fs_node_prop(&pval, resource->info->root.root, resource->info->repos_path, SVN_PROP_MIME_TYPE, p))) { svn_error_clear(serr); pval = NULL; } if (pval) mime_type = pval->data; else if ((! resource->info->repos->is_svn_client) && resource->info->r->content_type) mime_type = resource->info->r->content_type; else mime_type = "text/plain"; /* default for file */ if ((serr = svn_mime_type_validate(mime_type, p))) { /* Probably serr->apr == SVN_ERR_BAD_MIME_TYPE, but there's no point even checking. No matter what the error is, we can't claim to have a mime type for this resource. */ svn_error_clear(serr); return DAV_PROP_INSERT_NOTDEF; } } value = mime_type; break; } case DAV_PROPID_getetag: if (resource->type == DAV_RESOURCE_TYPE_PRIVATE && resource->info->restype == DAV_SVN_RESTYPE_VCC) { return DAV_PROP_INSERT_NOTSUPP; } value = dav_svn_getetag(resource, p); break; case DAV_PROPID_auto_version: /* we only support one autoversioning behavior, and thus only return this one static value; someday when we support locking, there are other possible values/behaviors for this. */ if (resource->info->repos->autoversioning) value = "DAV:checkout-checkin"; else return DAV_PROP_INSERT_NOTDEF; break; case DAV_PROPID_baseline_collection: /* only defined for Baselines */ /* ### whoops. also defined for a VCC. deal with it later. */ if (resource->type != DAV_RESOURCE_TYPE_VERSION || !resource->baselined) return DAV_PROP_INSERT_NOTSUPP; value = dav_svn_build_uri(resource->info->repos, DAV_SVN_BUILD_URI_BC, resource->info->root.rev, NULL, 1 /* add_href */, p); break; case DAV_PROPID_checked_in:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -