📄 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"
/*
** 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
};
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),
{ 0 } /* sentinel */
};
static const dav_liveprop_group dav_svn_liveprop_group =
{
dav_svn_props,
dav_svn_namespace_uris,
&dav_svn_hooks_liveprop
};
/* Return the revision property PROPNAME's value in PROPVAL for
RESOURCE in the revision COMMITTED_REV after verifying that the
path is readable. If the property if inaccessible, SVN_NO_ERROR is
returned and *PROPVAL is NULL.
This function must only be used to retrieve properties for which it
is sufficient to have read access to a single changed path in the
revision to have access to the revprop, e.g.
SVN_PROP_REVISION_AUTHOR or SVN_PROP_REVISION_DATE.
The reason for this is that we only check readability of the
current path (which is one of the revisions' changed paths per
definition). If the current path is readable, the revprop is also
readable. While it's possible that the property is readable even
though the current path is not readable (because another path in
the same revision is readable), it's a silly situation worth
ignoring to gain the extra performance. */
static svn_error_t *svn_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;
/*
** None of SVN provider properties are defined if the resource does not
** exist. Just bail for this case.
**
** 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)
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 = svn_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;
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;
}
serr = svn_fs_node_prop (&pval, resource->info->root.root,
resource->info->repos_path,
SVN_PROP_MIME_TYPE, p);
if ((serr != NULL) || (pval == NULL))
{
svn_error_clear(serr);
if (resource->collection) /* defaults for directories */
{
if (resource->info->repos->xslt_uri)
value = "text/xml";
else
value = "text/html";
}
else
{
value = "text/plain"; /* default for file */
}
}
else
{
serr = svn_mime_type_validate (pval->data, p);
if (serr)
{
/* 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;
}
else
value = pval->data;
}
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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -