Reorganize the output to "svnserve --help".
[svn.git] / subversion / mod_dav_svn / liveprops.c
blob05bc7df9b2e74df61a4f6877254360f487996fb9
1 /*
2 * liveprops.c: mod_dav_svn live property provider functions for Subversion
4 * ====================================================================
5 * Copyright (c) 2000-2007 CollabNet. All rights reserved.
7 * This software is licensed as described in the file COPYING, which
8 * you should have received as part of this distribution. The terms
9 * are also available at http://subversion.tigris.org/license-1.html.
10 * If newer versions of this license are posted there, you may use a
11 * newer version instead, at your option.
13 * This software consists of voluntary contributions made by many
14 * individuals. For exact contribution history, see the revision
15 * history and logs, available at http://subversion.tigris.org/.
16 * ====================================================================
19 #include <apr_tables.h>
20 #include <apr_md5.h>
22 #include <httpd.h>
23 #include <http_core.h>
24 #include <util_xml.h>
25 #include <mod_dav.h>
27 #include "svn_pools.h"
28 #include "svn_time.h"
29 #include "svn_dav.h"
30 #include "svn_md5.h"
31 #include "svn_props.h"
33 #include "private/svn_dav_protocol.h"
35 #include "dav_svn.h"
39 ** The namespace URIs that we use. This list and the enumeration must
40 ** stay in sync.
42 static const char * const namespace_uris[] =
44 "DAV:",
45 SVN_DAV_PROP_NS_DAV,
47 NULL /* sentinel */
49 enum {
50 NAMESPACE_URI_DAV, /* the DAV: namespace URI */
51 NAMESPACE_URI /* the dav<->ra_dav namespace URI */
54 #define SVN_RO_DAV_PROP(name) \
55 { NAMESPACE_URI_DAV, #name, DAV_PROPID_##name, 0 }
56 #define SVN_RW_DAV_PROP(name) \
57 { NAMESPACE_URI_DAV, #name, DAV_PROPID_##name, 1 }
58 #define SVN_RO_DAV_PROP2(sym,name) \
59 { NAMESPACE_URI_DAV, #name, DAV_PROPID_##sym, 0 }
60 #define SVN_RW_DAV_PROP2(sym,name) \
61 { NAMESPACE_URI_DAV, #name, DAV_PROPID_##sym, 1 }
63 #define SVN_RO_SVN_PROP(sym,name) \
64 { NAMESPACE_URI, #name, SVN_PROPID_##sym, 0 }
65 #define SVN_RW_SVN_PROP(sym,name) \
66 { NAMESPACE_URI, #name, SVN_PROPID_##sym, 1 }
69 enum {
70 SVN_PROPID_baseline_relative_path = 1,
71 SVN_PROPID_md5_checksum,
72 SVN_PROPID_repository_uuid,
73 SVN_PROPID_deadprop_count
77 static const dav_liveprop_spec props[] =
79 /* ### don't worry about these for a bit */
80 #if 0
81 /* WebDAV properties */
82 SVN_RO_DAV_PROP(getcontentlanguage), /* ### make this r/w? */
83 #endif
84 SVN_RO_DAV_PROP(getcontentlength),
85 SVN_RO_DAV_PROP(getcontenttype), /* ### make this r/w? */
86 SVN_RO_DAV_PROP(getetag),
87 SVN_RO_DAV_PROP(creationdate),
88 SVN_RO_DAV_PROP(getlastmodified),
90 /* DeltaV properties */
91 SVN_RO_DAV_PROP2(baseline_collection, baseline-collection),
92 SVN_RO_DAV_PROP2(checked_in, checked-in),
93 SVN_RO_DAV_PROP2(version_controlled_configuration,
94 version-controlled-configuration),
95 SVN_RO_DAV_PROP2(version_name, version-name),
96 SVN_RO_DAV_PROP2(creator_displayname, creator-displayname),
97 SVN_RO_DAV_PROP2(auto_version, auto-version),
99 /* SVN properties */
100 SVN_RO_SVN_PROP(baseline_relative_path, baseline-relative-path),
101 SVN_RO_SVN_PROP(md5_checksum, md5-checksum),
102 SVN_RO_SVN_PROP(repository_uuid, repository-uuid),
103 SVN_RO_SVN_PROP(deadprop_count, deadprop-count),
105 { 0 } /* sentinel */
109 /* Set *PROPVAL to the value for the revision property PROPNAME on
110 COMMITTED_REV, in the repository identified by RESOURCE, if
111 RESOURCE's path is readable. If it is not readable, set *PROPVAL
112 to NULL and return SVN_NO_ERROR. Use POOL for temporary
113 allocations and the allocation of *PROPVAL.
115 Note that this function does not check the readability of the
116 revision property, but the readability of a path. The true
117 readability of a revision property is determined by investigating
118 the readability of all changed paths in the revision. For certain
119 revision properties (e.g. svn:author and svn:date) to be readable,
120 it is enough if at least one changed path is readable. When we
121 already have a changed path, we can skip the check for the other
122 changed paths in the revision and save a lot of work. This means
123 that we will make a mistake when our path is unreadable and another
124 changed path is readable, but we will at least only hide too much
125 and not leak any protected properties.
127 WARNING: This method of only checking the readability of a path is
128 only valid to get revision properties for which it is enough if at
129 least one changed path is readable. Using this function to get
130 revision properties for which all changed paths must be readable
131 might leak protected information because we will only test the
132 readability of a single changed path.
134 static svn_error_t *
135 get_path_revprop(svn_string_t **propval,
136 const dav_resource *resource,
137 svn_revnum_t committed_rev,
138 const char *propname,
139 apr_pool_t *pool)
141 *propval = NULL;
143 if (! dav_svn__allow_read(resource, committed_rev, pool))
144 return SVN_NO_ERROR;
146 /* Get the property of the created revision. The authz is already
147 performed, so we don't need to do it here too. */
148 return svn_repos_fs_revision_prop(propval,
149 resource->info->repos->repos,
150 committed_rev,
151 propname,
152 NULL, NULL, pool);
156 enum time_format {
157 time_format_iso8601,
158 time_format_rfc1123
162 /* Given a mod_dav_svn @a resource, set @a *timeval and @a *datestring
163 to the last-modified-time of the resource. The datestring will be
164 formatted according to @a format. Use @a pool for both
165 scratchwork, and to allocate @a *datestring.
167 If @a timeval or @a datestring is NULL, don't touch it.
169 Return zero on success, non-zero if an error occurs. */
170 static int
171 get_last_modified_time(const char **datestring,
172 apr_time_t *timeval,
173 const dav_resource *resource,
174 enum time_format format,
175 apr_pool_t *pool)
177 svn_revnum_t committed_rev = SVN_INVALID_REVNUM;
178 svn_string_t *committed_date = NULL;
179 svn_error_t *serr;
180 apr_time_t timeval_tmp;
182 if ((datestring == NULL) && (timeval == NULL))
183 return 0;
185 if (resource->baselined && resource->type == DAV_RESOURCE_TYPE_VERSION)
187 /* A baseline URI. */
188 committed_rev = resource->info->root.rev;
190 else if (resource->type == DAV_RESOURCE_TYPE_REGULAR
191 || resource->type == DAV_RESOURCE_TYPE_WORKING
192 || resource->type == DAV_RESOURCE_TYPE_VERSION)
194 serr = svn_fs_node_created_rev(&committed_rev,
195 resource->info->root.root,
196 resource->info->repos_path, pool);
197 if (serr != NULL)
199 svn_error_clear(serr);
200 return 1;
203 else
205 /* unsupported resource kind -- has no mod-time */
206 return 1;
209 serr = get_path_revprop(&committed_date,
210 resource,
211 committed_rev,
212 SVN_PROP_REVISION_DATE,
213 pool);
214 if (serr)
216 svn_error_clear(serr);
217 return 1;
220 if (committed_date == NULL)
221 return 1;
223 /* return the ISO8601 date as an apr_time_t */
224 serr = svn_time_from_cstring(&timeval_tmp, committed_date->data, pool);
225 if (serr != NULL)
227 svn_error_clear(serr);
228 return 1;
231 if (timeval)
232 memcpy(timeval, &timeval_tmp, sizeof(*timeval));
234 if (! datestring)
235 return 0;
237 if (format == time_format_iso8601)
239 *datestring = committed_date->data;
241 else if (format == time_format_rfc1123)
243 apr_time_exp_t tms;
244 apr_status_t status;
246 /* convert the apr_time_t into an apr_time_exp_t */
247 status = apr_time_exp_gmt(&tms, timeval_tmp);
248 if (status != APR_SUCCESS)
249 return 1;
251 /* stolen from dav/fs/repos.c :-) */
252 *datestring = apr_psprintf(pool, "%s, %.2d %s %d %.2d:%.2d:%.2d GMT",
253 apr_day_snames[tms.tm_wday],
254 tms.tm_mday, apr_month_snames[tms.tm_mon],
255 tms.tm_year + 1900,
256 tms.tm_hour, tms.tm_min, tms.tm_sec);
258 else /* unknown time format */
260 return 1;
263 return 0;
266 static dav_prop_insert
267 insert_prop(const dav_resource *resource,
268 int propid,
269 dav_prop_insert what,
270 apr_text_header *phdr)
272 const char *value = NULL;
273 const char *s;
274 apr_pool_t *response_pool = resource->pool;
275 apr_pool_t *p = resource->info->pool;
276 const dav_liveprop_spec *info;
277 int global_ns;
278 svn_error_t *serr;
281 ** Almost none of the SVN provider properties are defined if the
282 ** resource does not exist. We do need to return the one VCC
283 ** property and baseline-relative-path on lock-null resources,
284 ** however, so that svn clients can run 'svn unlock' and 'svn info'
285 ** on these things.
287 ** Even though we state that the SVN properties are not defined, the
288 ** client cannot store dead values -- we deny that thru the is_writable
289 ** hook function.
291 if ((! resource->exists)
292 && (propid != DAV_PROPID_version_controlled_configuration)
293 && (propid != SVN_PROPID_baseline_relative_path))
294 return DAV_PROP_INSERT_NOTSUPP;
296 /* ### we may want to respond to DAV_PROPID_resourcetype for PRIVATE
297 ### resources. need to think on "proper" interaction with mod_dav */
299 switch (propid)
301 case DAV_PROPID_getlastmodified:
302 case DAV_PROPID_creationdate:
304 /* In subversion terms, the date attached to a file's CR is
305 the true "last modified" time. However, we're defining
306 creationdate in the same way. IMO, the "creationdate" is
307 really the date attached to the revision in which the item
308 *first* came into existence; this would found by tracing
309 back through the log of the file -- probably via
310 svn_fs_revisions_changed. gstein, is it a bad thing that
311 we're currently using 'creationdate' to mean the same thing
312 as 'last modified date'? */
313 const char *datestring;
314 apr_time_t timeval;
315 enum time_format format;
317 /* ### for now, our global VCC has no such property. */
318 if (resource->type == DAV_RESOURCE_TYPE_PRIVATE
319 && resource->info->restype == DAV_SVN_RESTYPE_VCC)
321 return DAV_PROP_INSERT_NOTSUPP;
324 if (propid == DAV_PROPID_creationdate)
326 /* Return an ISO8601 date; this is what the svn client
327 expects, and rfc2518 demands it. */
328 format = time_format_iso8601;
330 else /* propid == DAV_PROPID_getlastmodified */
332 format = time_format_rfc1123;
335 if (0 != get_last_modified_time(&datestring, &timeval,
336 resource, format, p))
338 return DAV_PROP_INSERT_NOTDEF;
341 value = apr_xml_quote_string(p, datestring, 1);
342 break;
345 case DAV_PROPID_creator_displayname:
347 svn_revnum_t committed_rev = SVN_INVALID_REVNUM;
348 svn_string_t *last_author = NULL;
350 /* ### for now, our global VCC has no such property. */
351 if (resource->type == DAV_RESOURCE_TYPE_PRIVATE
352 && resource->info->restype == DAV_SVN_RESTYPE_VCC)
354 return DAV_PROP_INSERT_NOTSUPP;
357 if (resource->baselined && resource->type == DAV_RESOURCE_TYPE_VERSION)
359 /* A baseline URI. */
360 committed_rev = resource->info->root.rev;
362 else if (resource->type == DAV_RESOURCE_TYPE_REGULAR
363 || resource->type == DAV_RESOURCE_TYPE_WORKING
364 || resource->type == DAV_RESOURCE_TYPE_VERSION)
366 /* Get the CR field out of the node's skel. Notice that the
367 root object might be an ID root -or- a revision root. */
368 serr = svn_fs_node_created_rev(&committed_rev,
369 resource->info->root.root,
370 resource->info->repos_path, p);
371 if (serr != NULL)
373 /* ### what to do? */
374 svn_error_clear(serr);
375 value = "###error###";
376 break;
379 else
381 return DAV_PROP_INSERT_NOTSUPP;
384 serr = get_path_revprop(&last_author,
385 resource,
386 committed_rev,
387 SVN_PROP_REVISION_AUTHOR,
389 if (serr)
391 /* ### what to do? */
392 svn_error_clear(serr);
393 value = "###error###";
394 break;
397 if (last_author == NULL)
398 return DAV_PROP_INSERT_NOTDEF;
400 value = apr_xml_quote_string(p, last_author->data, 1);
401 break;
404 case DAV_PROPID_getcontentlanguage:
405 /* ### need something here */
406 return DAV_PROP_INSERT_NOTSUPP;
407 break;
409 case DAV_PROPID_getcontentlength:
411 svn_filesize_t len = 0;
413 /* our property, but not defined on collection resources */
414 if (resource->collection || resource->baselined)
415 return DAV_PROP_INSERT_NOTSUPP;
417 serr = svn_fs_file_length(&len, resource->info->root.root,
418 resource->info->repos_path, p);
419 if (serr != NULL)
421 svn_error_clear(serr);
422 value = "0"; /* ### what to do? */
423 break;
426 value = apr_psprintf(p, "%" SVN_FILESIZE_T_FMT, len);
427 break;
430 case DAV_PROPID_getcontenttype:
432 /* The subversion client assumes that any file without an
433 svn:mime-type property is of type text/plain. So it seems
434 safe (and consistent) to assume the same on the server. */
435 svn_string_t *pval;
436 const char *mime_type = NULL;
438 if (resource->baselined && resource->type == DAV_RESOURCE_TYPE_VERSION)
439 return DAV_PROP_INSERT_NOTSUPP;
441 if (resource->type == DAV_RESOURCE_TYPE_PRIVATE
442 && resource->info->restype == DAV_SVN_RESTYPE_VCC)
444 return DAV_PROP_INSERT_NOTSUPP;
447 if (resource->collection) /* defaults for directories */
449 if (resource->info->repos->xslt_uri)
450 mime_type = "text/xml";
451 else
452 mime_type = "text/html; charset=UTF-8";
454 else
456 if ((serr = svn_fs_node_prop(&pval, resource->info->root.root,
457 resource->info->repos_path,
458 SVN_PROP_MIME_TYPE, p)))
460 svn_error_clear(serr);
461 pval = NULL;
464 if (pval)
465 mime_type = pval->data;
466 else if ((! resource->info->repos->is_svn_client)
467 && resource->info->r->content_type)
468 mime_type = resource->info->r->content_type;
469 else
470 mime_type = ap_default_type(resource->info->r);
472 if ((serr = svn_mime_type_validate(mime_type, p)))
474 /* Probably serr->apr == SVN_ERR_BAD_MIME_TYPE, but
475 there's no point even checking. No matter what the
476 error is, we can't claim to have a mime type for
477 this resource. */
478 svn_error_clear(serr);
479 return DAV_PROP_INSERT_NOTDEF;
483 value = mime_type;
484 break;
487 case DAV_PROPID_getetag:
488 if (resource->type == DAV_RESOURCE_TYPE_PRIVATE
489 && resource->info->restype == DAV_SVN_RESTYPE_VCC)
491 return DAV_PROP_INSERT_NOTSUPP;
494 value = dav_svn__getetag(resource, p);
495 break;
497 case DAV_PROPID_auto_version:
498 /* we only support one autoversioning behavior, and thus only
499 return this one static value; someday when we support
500 locking, there are other possible values/behaviors for this. */
501 if (resource->info->repos->autoversioning)
502 value = "DAV:checkout-checkin";
503 else
504 return DAV_PROP_INSERT_NOTDEF;
505 break;
507 case DAV_PROPID_baseline_collection:
508 /* only defined for Baselines */
509 /* ### whoops. also defined for a VCC. deal with it later. */
510 if (resource->type != DAV_RESOURCE_TYPE_VERSION || !resource->baselined)
511 return DAV_PROP_INSERT_NOTSUPP;
512 value = dav_svn__build_uri(resource->info->repos, DAV_SVN__BUILD_URI_BC,
513 resource->info->root.rev, NULL,
514 1 /* add_href */, p);
515 break;
517 case DAV_PROPID_checked_in:
518 /* only defined for VCRs (in the public space and in a BC space) */
519 /* ### note that a VCC (a special VCR) is defined as _PRIVATE for now */
520 if (resource->type == DAV_RESOURCE_TYPE_PRIVATE
521 && resource->info->restype == DAV_SVN_RESTYPE_VCC)
523 svn_revnum_t revnum;
525 serr = svn_fs_youngest_rev(&revnum, resource->info->repos->fs, p);
526 if (serr != NULL)
528 /* ### what to do? */
529 svn_error_clear(serr);
530 value = "###error###";
531 break;
533 s = dav_svn__build_uri(resource->info->repos,
534 DAV_SVN__BUILD_URI_BASELINE,
535 revnum, NULL, 0 /* add_href */, p);
536 value = apr_psprintf(p, "<D:href>%s</D:href>",
537 apr_xml_quote_string(p, s, 1));
539 else if (resource->type != DAV_RESOURCE_TYPE_REGULAR)
541 /* not defined for this resource type */
542 return DAV_PROP_INSERT_NOTSUPP;
544 else
546 svn_revnum_t rev_to_use =
547 dav_svn__get_safe_cr(resource->info->root.root,
548 resource->info->repos_path, p);
550 s = dav_svn__build_uri(resource->info->repos,
551 DAV_SVN__BUILD_URI_VERSION,
552 rev_to_use, resource->info->repos_path,
553 0 /* add_href */, p);
554 value = apr_psprintf(p, "<D:href>%s</D:href>",
555 apr_xml_quote_string(p, s, 1));
557 break;
559 case DAV_PROPID_version_controlled_configuration:
560 /* only defined for VCRs */
561 /* ### VCRs within the BC should not have this property! */
562 /* ### note that a VCC (a special VCR) is defined as _PRIVATE for now */
563 if (resource->type != DAV_RESOURCE_TYPE_REGULAR)
564 return DAV_PROP_INSERT_NOTSUPP;
565 value = dav_svn__build_uri(resource->info->repos, DAV_SVN__BUILD_URI_VCC,
566 SVN_IGNORED_REVNUM, NULL,
567 1 /* add_href */, p);
568 break;
570 case DAV_PROPID_version_name:
571 /* only defined for Version Resources and Baselines */
572 /* ### whoops. also defined for VCRs. deal with it later. */
573 if ((resource->type != DAV_RESOURCE_TYPE_VERSION)
574 && (! resource->versioned))
575 return DAV_PROP_INSERT_NOTSUPP;
577 if (resource->type == DAV_RESOURCE_TYPE_PRIVATE
578 && resource->info->restype == DAV_SVN_RESTYPE_VCC)
580 return DAV_PROP_INSERT_NOTSUPP;
583 if (resource->baselined)
585 /* just the revision number for baselines */
586 value = apr_psprintf(p, "%ld",
587 resource->info->root.rev);
589 else
591 svn_revnum_t committed_rev = SVN_INVALID_REVNUM;
593 /* Get the CR field out of the node's skel. Notice that the
594 root object might be an ID root -or- a revision root. */
595 serr = svn_fs_node_created_rev(&committed_rev,
596 resource->info->root.root,
597 resource->info->repos_path, p);
598 if (serr != NULL)
600 /* ### what to do? */
601 svn_error_clear(serr);
602 value = "###error###";
603 break;
606 /* Convert the revision into a quoted string */
607 s = apr_psprintf(p, "%ld", committed_rev);
608 value = apr_xml_quote_string(p, s, 1);
610 break;
612 case SVN_PROPID_baseline_relative_path:
613 /* only defined for VCRs */
614 /* ### VCRs within the BC should not have this property! */
615 /* ### note that a VCC (a special VCR) is defined as _PRIVATE for now */
616 if (resource->type != DAV_RESOURCE_TYPE_REGULAR)
617 return DAV_PROP_INSERT_NOTSUPP;
619 /* drop the leading slash, so it is relative */
620 s = resource->info->repos_path + 1;
621 value = apr_xml_quote_string(p, s, 1);
622 break;
624 case SVN_PROPID_md5_checksum:
625 if ((! resource->collection)
626 && (! resource->baselined)
627 && (resource->type == DAV_RESOURCE_TYPE_REGULAR
628 || resource->type == DAV_RESOURCE_TYPE_WORKING
629 || resource->type == DAV_RESOURCE_TYPE_VERSION))
631 unsigned char digest[APR_MD5_DIGESTSIZE];
633 serr = svn_fs_file_md5_checksum(digest,
634 resource->info->root.root,
635 resource->info->repos_path, p);
636 if (serr != NULL)
638 /* ### what to do? */
639 svn_error_clear(serr);
640 value = "###error###";
641 break;
644 value = svn_md5_digest_to_cstring(digest, p);
646 if (! value)
647 return DAV_PROP_INSERT_NOTSUPP;
649 else
650 return DAV_PROP_INSERT_NOTSUPP;
652 break;
654 case SVN_PROPID_repository_uuid:
655 serr = svn_fs_get_uuid(resource->info->repos->fs, &value, p);
656 if (serr != NULL)
658 /* ### what to do? */
659 svn_error_clear(serr);
660 value = "###error###";
661 break;
663 break;
665 case SVN_PROPID_deadprop_count:
667 unsigned int propcount;
668 apr_hash_t *proplist;
670 if (resource->type != DAV_RESOURCE_TYPE_REGULAR)
671 return DAV_PROP_INSERT_NOTSUPP;
673 serr = svn_fs_node_proplist(&proplist,
674 resource->info->root.root,
675 resource->info->repos_path, p);
676 if (serr != NULL)
678 /* ### what to do? */
679 svn_error_clear(serr);
680 value = "###error###";
681 break;
684 propcount = apr_hash_count(proplist);
685 value = apr_psprintf(p, "%u", propcount);
686 break;
689 default:
690 /* ### what the heck was this property? */
691 return DAV_PROP_INSERT_NOTDEF;
694 /* assert: value != NULL */
696 /* get the information and global NS index for the property */
697 global_ns = dav_get_liveprop_info(propid, &dav_svn__liveprop_group, &info);
699 /* assert: info != NULL && info->name != NULL */
701 if (what == DAV_PROP_INSERT_NAME
702 || (what == DAV_PROP_INSERT_VALUE && *value == '\0')) {
703 s = apr_psprintf(response_pool, "<lp%d:%s/>" DEBUG_CR, global_ns,
704 info->name);
706 else if (what == DAV_PROP_INSERT_VALUE) {
707 s = apr_psprintf(response_pool, "<lp%d:%s>%s</lp%d:%s>" DEBUG_CR,
708 global_ns, info->name, value, global_ns, info->name);
710 else {
711 /* assert: what == DAV_PROP_INSERT_SUPPORTED */
712 s = apr_psprintf(response_pool,
713 "<D:supported-live-property D:name=\"%s\" "
714 "D:namespace=\"%s\"/>" DEBUG_CR,
715 info->name, namespace_uris[info->ns]);
717 apr_text_append(response_pool, phdr, s);
719 /* we inserted whatever was asked for */
720 return what;
724 static int
725 is_writable(const dav_resource *resource, int propid)
727 const dav_liveprop_spec *info;
729 (void) dav_get_liveprop_info(propid, &dav_svn__liveprop_group, &info);
730 return info->is_writable;
734 static dav_error *
735 patch_validate(const dav_resource *resource,
736 const apr_xml_elem *elem,
737 int operation,
738 void **context,
739 int *defer_to_dead)
741 /* NOTE: this function will not be called unless/until we have
742 modifiable (writable) live properties. */
743 return NULL;
747 static dav_error *
748 patch_exec(const dav_resource *resource,
749 const apr_xml_elem *elem,
750 int operation,
751 void *context,
752 dav_liveprop_rollback **rollback_ctx)
754 /* NOTE: this function will not be called unless/until we have
755 modifiable (writable) live properties. */
756 return NULL;
760 static void
761 patch_commit(const dav_resource *resource,
762 int operation,
763 void *context,
764 dav_liveprop_rollback *rollback_ctx)
766 /* NOTE: this function will not be called unless/until we have
767 modifiable (writable) live properties. */
770 static dav_error *
771 patch_rollback(const dav_resource *resource,
772 int operation,
773 void *context,
774 dav_liveprop_rollback *rollback_ctx)
776 /* NOTE: this function will not be called unless/until we have
777 modifiable (writable) live properties. */
778 return NULL;
782 static const dav_hooks_liveprop hooks_liveprop = {
783 insert_prop,
784 is_writable,
785 namespace_uris,
786 patch_validate,
787 patch_exec,
788 patch_commit,
789 patch_rollback,
793 const dav_liveprop_group dav_svn__liveprop_group =
795 props,
796 namespace_uris,
797 &hooks_liveprop
801 void
802 dav_svn__gather_propsets(apr_array_header_t *uris)
804 /* ### what should we use for a URL to describe the available prop set? */
805 /* ### for now... nothing. we will *only* have DAV properties */
806 #if 0
807 *(const char **)apr_array_push(uris) =
808 "<http://subversion.tigris.org/dav/propset/svn/1>";
809 #endif
814 dav_svn__find_liveprop(const dav_resource *resource,
815 const char *ns_uri,
816 const char *name,
817 const dav_hooks_liveprop **hooks)
819 /* don't try to find any liveprops if this isn't "our" resource */
820 if (resource->hooks != &dav_svn__hooks_repository)
821 return 0;
823 return dav_do_find_liveprop(ns_uri, name, &dav_svn__liveprop_group, hooks);
827 void
828 dav_svn__insert_all_liveprops(request_rec *r,
829 const dav_resource *resource,
830 dav_prop_insert what,
831 apr_text_header *phdr)
833 const dav_liveprop_spec *spec;
834 apr_pool_t *pool;
835 apr_pool_t *subpool;
837 /* don't insert any liveprops if this isn't "our" resource */
838 if (resource->hooks != &dav_svn__hooks_repository)
839 return;
841 if (!resource->exists)
843 /* a lock-null resource */
845 ** ### technically, we should insert empty properties. dunno offhand
846 ** ### what part of the spec said this, but it was essentially thus:
847 ** ### "the properties should be defined, but may have no value".
849 return;
852 pool = resource->info->pool;
853 subpool = svn_pool_create(pool);
854 resource->info->pool = subpool;
856 for (spec = props; spec->name != NULL; ++spec)
858 svn_pool_clear(subpool);
859 (void) insert_prop(resource, spec->propid, what, phdr);
862 resource->info->pool = pool;
863 svn_pool_destroy(subpool);
865 /* ### we know the others aren't defined as liveprops */