In the command-line client, forbid
[svn.git] / subversion / libsvn_ra_serf / property.c
blob1340f5cb88e6d0f04ad77c50144932c385a1c092
1 /*
2 * property.c : property routines for ra_serf
4 * ====================================================================
5 * Copyright (c) 2006-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 * ====================================================================
21 #include <serf.h>
23 #include "svn_path.h"
24 #include "svn_base64.h"
25 #include "svn_xml.h"
27 #include "private/svn_dav_protocol.h"
28 #include "svn_private_config.h"
30 #include "ra_serf.h"
33 /* Our current parsing state we're in for the PROPFIND response. */
34 typedef enum {
35 NONE = 0,
36 RESPONSE,
37 PROP,
38 PROPVAL,
39 } prop_state_e;
41 typedef struct {
42 apr_pool_t *pool;
44 /* Current ns, attribute name, and value of the property we're parsing */
45 const char *ns;
47 const char *name;
49 const char *val;
50 apr_size_t val_len;
52 const char *encoding;
54 } prop_info_t;
57 * This structure represents a pending PROPFIND response.
59 struct svn_ra_serf__propfind_context_t {
60 /* pool to issue allocations from */
61 apr_pool_t *pool;
63 svn_ra_serf__handler_t *handler;
65 /* associated serf session */
66 svn_ra_serf__session_t *sess;
67 svn_ra_serf__connection_t *conn;
69 /* the requested path */
70 const char *path;
72 /* the requested version (number and string form) */
73 svn_revnum_t rev;
74 const char *label;
76 /* the request depth */
77 const char *depth;
79 /* the list of requested properties */
80 const svn_ra_serf__dav_props_t *find_props;
82 /* should we cache the values of this propfind in our session? */
83 svn_boolean_t cache_props;
85 /* hash table that will be updated with the properties
87 * This can be shared between multiple svn_ra_serf__propfind_context_t
88 * structures
90 apr_hash_t *ret_props;
92 /* If we're dealing with a Depth: 1 response,
93 * we may be dealing with multiple paths.
95 const char *current_path;
97 /* Returned status code. */
98 int status_code;
100 /* Are we done issuing the PROPFIND? */
101 svn_boolean_t done;
103 /* Context from XML stream */
104 svn_ra_serf__xml_parser_t *parser_ctx;
106 /* If not-NULL, add us to this list when we're done. */
107 svn_ra_serf__list_t **done_list;
109 svn_ra_serf__list_t done_item;
112 const svn_string_t *
113 svn_ra_serf__get_ver_prop_string(apr_hash_t *props,
114 const char *path,
115 svn_revnum_t rev,
116 const char *ns,
117 const char *name)
119 apr_hash_t *ver_props, *path_props, *ns_props;
120 void *val = NULL;
122 ver_props = apr_hash_get(props, &rev, sizeof(rev));
123 if (ver_props)
125 path_props = apr_hash_get(ver_props, path, APR_HASH_KEY_STRING);
127 if (path_props)
129 ns_props = apr_hash_get(path_props, ns, APR_HASH_KEY_STRING);
130 if (ns_props)
132 val = apr_hash_get(ns_props, name, APR_HASH_KEY_STRING);
137 return val;
140 const char *
141 svn_ra_serf__get_ver_prop(apr_hash_t *props,
142 const char *path,
143 svn_revnum_t rev,
144 const char *ns,
145 const char *name)
147 const svn_string_t *val;
149 val = svn_ra_serf__get_ver_prop_string(props, path, rev, ns, name);
151 if (val)
153 return val->data;
156 return NULL;
159 const char *
160 svn_ra_serf__get_prop(apr_hash_t *props,
161 const char *path,
162 const char *ns,
163 const char *name)
165 return svn_ra_serf__get_ver_prop(props, path, SVN_INVALID_REVNUM, ns, name);
168 void
169 svn_ra_serf__set_ver_prop(apr_hash_t *props,
170 const char *path, svn_revnum_t rev,
171 const char *ns, const char *name,
172 const svn_string_t *val, apr_pool_t *pool)
174 apr_hash_t *ver_props, *path_props, *ns_props;
176 ver_props = apr_hash_get(props, &rev, sizeof(rev));
177 if (!ver_props)
179 ver_props = apr_hash_make(pool);
180 apr_hash_set(props, apr_pmemdup(pool, &rev, sizeof(rev)), sizeof(rev),
181 ver_props);
184 path_props = apr_hash_get(ver_props, path, APR_HASH_KEY_STRING);
186 if (!path_props)
188 path_props = apr_hash_make(pool);
189 path = apr_pstrdup(pool, path);
190 apr_hash_set(ver_props, path, APR_HASH_KEY_STRING, path_props);
192 /* todo: we know that we'll fail the next check, but fall through
193 * for now for simplicity's sake.
197 ns_props = apr_hash_get(path_props, ns, APR_HASH_KEY_STRING);
198 if (!ns_props)
200 ns_props = apr_hash_make(pool);
201 ns = apr_pstrdup(pool, ns);
202 apr_hash_set(path_props, ns, APR_HASH_KEY_STRING, ns_props);
205 apr_hash_set(ns_props, name, APR_HASH_KEY_STRING, val);
208 void
209 svn_ra_serf__set_prop(apr_hash_t *props,
210 const char *path,
211 const char *ns, const char *name,
212 const svn_string_t *val, apr_pool_t *pool)
214 svn_ra_serf__set_ver_prop(props, path, SVN_INVALID_REVNUM, ns, name,
215 val, pool);
218 static prop_info_t *
219 push_state(svn_ra_serf__xml_parser_t *parser,
220 svn_ra_serf__propfind_context_t *propfind,
221 prop_state_e state)
223 svn_ra_serf__xml_push_state(parser, state);
225 if (state == PROPVAL)
227 prop_info_t *info;
229 info = apr_pcalloc(parser->state->pool, sizeof(*info));
230 info->pool = parser->state->pool;
232 parser->state->private = info;
235 return parser->state->private;
239 * Expat callback invoked on a start element tag for a PROPFIND response.
241 static svn_error_t *
242 start_propfind(svn_ra_serf__xml_parser_t *parser,
243 void *userData,
244 svn_ra_serf__dav_props_t name,
245 const char **attrs)
247 svn_ra_serf__propfind_context_t *ctx = userData;
248 prop_state_e state;
249 prop_info_t *info;
251 state = parser->state->current_state;
253 if (state == NONE && strcmp(name.name, "response") == 0)
255 svn_ra_serf__xml_push_state(parser, RESPONSE);
257 else if (state == RESPONSE && strcmp(name.name, "href") == 0)
259 info = push_state(parser, ctx, PROPVAL);
260 info->ns = name.namespace;
261 info->name = apr_pstrdup(info->pool, name.name);
263 else if (state == RESPONSE && strcmp(name.name, "prop") == 0)
265 push_state(parser, ctx, PROP);
267 else if (state == PROP)
269 info = push_state(parser, ctx, PROPVAL);
270 info->ns = name.namespace;
271 info->name = apr_pstrdup(info->pool, name.name);
272 info->encoding = apr_pstrdup(info->pool,
273 svn_xml_get_attr_value("V:encoding", attrs));
276 return SVN_NO_ERROR;
280 * Expat callback invoked on an end element tag for a PROPFIND response.
282 static svn_error_t *
283 end_propfind(svn_ra_serf__xml_parser_t *parser,
284 void *userData,
285 svn_ra_serf__dav_props_t name)
287 svn_ra_serf__propfind_context_t *ctx = userData;
288 prop_state_e state;
289 prop_info_t *info;
291 state = parser->state->current_state;
292 info = parser->state->private;
294 if (state == RESPONSE && strcmp(name.name, "response") == 0)
296 svn_ra_serf__xml_pop_state(parser);
298 else if (state == PROP && strcmp(name.name, "prop") == 0)
300 svn_ra_serf__xml_pop_state(parser);
302 else if (state == PROPVAL)
304 const char *ns, *pname, *val;
305 svn_string_t *val_str;
307 /* if we didn't see a CDATA element, we may want the tag name
308 * as long as it isn't equivalent to the property name.
310 if (!info->val)
312 if (strcmp(info->name, name.name) != 0)
314 info->val = name.name;
315 info->val_len = strlen(info->val);
317 else
319 info->val = "";
320 info->val_len = 0;
324 if (parser->state->prev->current_state == RESPONSE &&
325 strcmp(name.name, "href") == 0)
327 if (strcmp(ctx->depth, "1") == 0)
329 ctx->current_path = svn_path_canonicalize(info->val, ctx->pool);
331 else
333 ctx->current_path = ctx->path;
336 else if (info->encoding)
338 if (strcmp(info->encoding, "base64") == 0)
340 svn_string_t encoded;
341 const svn_string_t *decoded;
343 encoded.data = info->val;
344 encoded.len = info->val_len;
346 decoded = svn_base64_decode_string(&encoded, parser->state->pool);
347 info->val = decoded->data;
348 info->val_len = decoded->len;
350 else
352 return svn_error_createf(SVN_ERR_RA_DAV_MALFORMED_DATA,
353 NULL,
354 _("Got unrecognized encoding '%s'"),
355 info->encoding);
359 ns = apr_pstrdup(ctx->pool, info->ns);
360 pname = apr_pstrdup(ctx->pool, info->name);
361 val = apr_pmemdup(ctx->pool, info->val, info->val_len);
362 val_str = svn_string_ncreate(val, info->val_len, ctx->pool);
364 /* set the return props and update our cache too. */
365 svn_ra_serf__set_ver_prop(ctx->ret_props,
366 ctx->current_path, ctx->rev,
367 ns, pname, val_str,
368 ctx->pool);
369 if (ctx->cache_props)
371 ns = apr_pstrdup(ctx->sess->pool, info->ns);
372 pname = apr_pstrdup(ctx->sess->pool, info->name);
373 val = apr_pmemdup(ctx->sess->pool, info->val, info->val_len);
374 val_str = svn_string_ncreate(val, info->val_len, ctx->sess->pool);
376 svn_ra_serf__set_ver_prop(ctx->sess->cached_props,
377 ctx->current_path, ctx->rev,
378 ns, pname, val_str,
379 ctx->sess->pool);
382 svn_ra_serf__xml_pop_state(parser);
385 return SVN_NO_ERROR;
389 * Expat callback invoked on CDATA elements in a PROPFIND response.
391 * This callback can be called multiple times.
393 static svn_error_t *
394 cdata_propfind(svn_ra_serf__xml_parser_t *parser,
395 void *userData,
396 const char *data,
397 apr_size_t len)
399 svn_ra_serf__propfind_context_t *ctx = userData;
400 prop_state_e state;
401 prop_info_t *info;
403 UNUSED_CTX(ctx);
405 state = parser->state->current_state;
406 info = parser->state->private;
408 if (state == PROPVAL)
410 svn_ra_serf__expand_string(&info->val, &info->val_len, data, len,
411 info->pool);
414 return SVN_NO_ERROR;
417 static apr_status_t
418 setup_propfind(serf_request_t *request,
419 void *setup_baton,
420 serf_bucket_t **req_bkt,
421 serf_response_acceptor_t *acceptor,
422 void **acceptor_baton,
423 serf_response_handler_t *handler,
424 void **handler_baton,
425 apr_pool_t *pool)
427 svn_ra_serf__propfind_context_t *ctx = setup_baton;
428 svn_ra_serf__xml_parser_t *parser_ctx = ctx->parser_ctx;
430 *req_bkt =
431 svn_ra_serf__bucket_propfind_create(ctx->conn, ctx->path, ctx->label,
432 ctx->depth, ctx->find_props,
433 serf_request_get_alloc(request));
435 if (ctx->conn->using_ssl)
437 *req_bkt =
438 serf_bucket_ssl_encrypt_create(*req_bkt, ctx->conn->ssl_context,
439 serf_request_get_alloc(request));
441 if (!ctx->conn->ssl_context)
443 ctx->conn->ssl_context =
444 serf_bucket_ssl_encrypt_context_get(*req_bkt);
448 parser_ctx->pool = pool;
449 parser_ctx->user_data = ctx;
450 parser_ctx->start = start_propfind;
451 parser_ctx->end = end_propfind;
452 parser_ctx->cdata = cdata_propfind;
453 parser_ctx->status_code = &ctx->status_code;
454 parser_ctx->done = &ctx->done;
455 parser_ctx->done_list = ctx->done_list;
456 parser_ctx->done_item = &ctx->done_item;
458 *handler = svn_ra_serf__handle_xml_parser;
459 *handler_baton = parser_ctx;
461 return APR_SUCCESS;
464 static svn_boolean_t
465 check_cache(apr_hash_t *ret_props,
466 svn_ra_serf__session_t *sess,
467 const char *path,
468 svn_revnum_t rev,
469 const svn_ra_serf__dav_props_t *find_props,
470 apr_pool_t *pool)
472 svn_boolean_t cache_hit = TRUE;
473 const svn_ra_serf__dav_props_t *prop;
475 /* check to see if we have any of this information cached */
476 prop = find_props;
477 while (prop && prop->namespace)
479 const svn_string_t *val;
481 val = svn_ra_serf__get_ver_prop_string(sess->cached_props, path, rev,
482 prop->namespace, prop->name);
483 if (val)
485 svn_ra_serf__set_ver_prop(ret_props, path, rev,
486 prop->namespace, prop->name, val, pool);
488 else
490 cache_hit = FALSE;
492 prop++;
495 return cache_hit;
499 * This function will deliver a PROP_CTX PROPFIND request in the SESS
500 * serf context for the properties listed in LOOKUP_PROPS at URL for
501 * DEPTH ("0","1","infinity").
503 * This function will not block waiting for the response. If the
504 * request can be satisfied from a local cache, set PROP_CTX to NULL
505 * as a signal to callers of that fact. Otherwise, callers are
506 * expected to call svn_ra_serf__wait_for_props().
508 svn_error_t *
509 svn_ra_serf__deliver_props(svn_ra_serf__propfind_context_t **prop_ctx,
510 apr_hash_t *ret_props,
511 svn_ra_serf__session_t *sess,
512 svn_ra_serf__connection_t *conn,
513 const char *path,
514 svn_revnum_t rev,
515 const char *depth,
516 const svn_ra_serf__dav_props_t *find_props,
517 svn_boolean_t cache_props,
518 svn_ra_serf__list_t **done_list,
519 apr_pool_t *pool)
521 svn_ra_serf__propfind_context_t *new_prop_ctx;
523 if (!*prop_ctx)
525 svn_ra_serf__handler_t *handler;
527 if (cache_props == TRUE)
529 svn_boolean_t cache_satisfy;
531 cache_satisfy = check_cache(ret_props, sess, path, rev, find_props,
532 pool);
534 if (cache_satisfy)
536 *prop_ctx = NULL;
537 return SVN_NO_ERROR;
541 new_prop_ctx = apr_pcalloc(pool, sizeof(*new_prop_ctx));
543 new_prop_ctx->pool = apr_hash_pool_get(ret_props);
544 new_prop_ctx->path = path;
545 new_prop_ctx->cache_props = cache_props;
546 new_prop_ctx->find_props = find_props;
547 new_prop_ctx->ret_props = ret_props;
548 new_prop_ctx->depth = depth;
549 new_prop_ctx->done = FALSE;
550 new_prop_ctx->sess = sess;
551 new_prop_ctx->conn = conn;
552 new_prop_ctx->rev = rev;
553 new_prop_ctx->done_list = done_list;
555 if (SVN_IS_VALID_REVNUM(rev))
557 new_prop_ctx->label = apr_ltoa(pool, rev);
559 else
561 new_prop_ctx->label = NULL;
564 handler = apr_pcalloc(pool, sizeof(*handler));
566 handler->method = "PROPFIND";
567 handler->delegate = setup_propfind;
568 handler->delegate_baton = new_prop_ctx;
569 handler->session = new_prop_ctx->sess;
570 handler->conn = new_prop_ctx->conn;
572 new_prop_ctx->handler = handler;
574 new_prop_ctx->parser_ctx = apr_pcalloc(pool,
575 sizeof(*new_prop_ctx->parser_ctx));
577 *prop_ctx = new_prop_ctx;
580 /* create request */
581 svn_ra_serf__request_create((*prop_ctx)->handler);
583 return SVN_NO_ERROR;
586 svn_boolean_t
587 svn_ra_serf__propfind_is_done(svn_ra_serf__propfind_context_t *ctx)
589 return ctx->done;
593 svn_ra_serf__propfind_status_code(svn_ra_serf__propfind_context_t *ctx)
595 return ctx->status_code;
599 * This helper function will block until the PROP_CTX indicates that is done
600 * or another error is returned.
602 svn_error_t *
603 svn_ra_serf__wait_for_props(svn_ra_serf__propfind_context_t *prop_ctx,
604 svn_ra_serf__session_t *sess,
605 apr_pool_t *pool)
607 svn_error_t *err;
609 err = svn_ra_serf__context_run_wait(&prop_ctx->done, sess, pool);
610 if (prop_ctx->parser_ctx->error)
612 svn_error_clear(err);
613 SVN_ERR(prop_ctx->parser_ctx->error);
615 return err;
619 * This is a blocking version of deliver_props.
621 svn_error_t *
622 svn_ra_serf__retrieve_props(apr_hash_t *prop_vals,
623 svn_ra_serf__session_t *sess,
624 svn_ra_serf__connection_t *conn,
625 const char *url,
626 svn_revnum_t rev,
627 const char *depth,
628 const svn_ra_serf__dav_props_t *props,
629 apr_pool_t *pool)
631 svn_ra_serf__propfind_context_t *prop_ctx = NULL;
633 SVN_ERR(svn_ra_serf__deliver_props(&prop_ctx, prop_vals, sess, conn, url,
634 rev, depth, props, TRUE, NULL, pool));
635 if (prop_ctx)
637 SVN_ERR(svn_ra_serf__wait_for_props(prop_ctx, sess, pool));
640 return SVN_NO_ERROR;
643 svn_error_t *
644 svn_ra_serf__search_for_base_props(apr_hash_t *props,
645 const char **remaining_path,
646 const char **missing_path,
647 svn_ra_serf__session_t *session,
648 svn_ra_serf__connection_t *conn,
649 const char *url,
650 apr_pool_t *pool)
652 const char *path = url, *present_path = "";
653 const char *vcc_url;
657 SVN_ERR(svn_ra_serf__retrieve_props(props, session, conn,
658 path, SVN_INVALID_REVNUM,
659 "0", base_props, pool));
660 vcc_url =
661 svn_ra_serf__get_ver_prop(props, path,
662 SVN_INVALID_REVNUM,
663 "DAV:",
664 "version-controlled-configuration");
665 if (vcc_url)
666 break;
668 /* This happens when the file is missing in HEAD. */
670 /* Okay, strip off. */
671 present_path = svn_path_join(svn_path_basename(path, pool),
672 present_path, pool);
673 path = svn_path_dirname(path, pool);
675 while (!svn_path_is_empty(path));
677 /* Error out if entire URL was bogus (not a single part of it exists
678 in the repository!) */
679 if (svn_path_is_empty(path))
680 return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL,
681 _("No part of path '%s' was found in "
682 "repository HEAD"), url);
684 *missing_path = present_path;
685 *remaining_path = path;
687 return SVN_NO_ERROR;
690 void
691 svn_ra_serf__walk_all_props(apr_hash_t *props,
692 const char *name,
693 svn_revnum_t rev,
694 svn_ra_serf__walker_visitor_t walker,
695 void *baton,
696 apr_pool_t *pool)
698 apr_hash_index_t *ns_hi;
699 apr_hash_t *ver_props, *path_props;
701 ver_props = apr_hash_get(props, &rev, sizeof(rev));
703 if (!ver_props)
705 return;
708 path_props = apr_hash_get(ver_props, name, strlen(name));
710 if (!path_props)
712 return;
715 for (ns_hi = apr_hash_first(pool, path_props); ns_hi;
716 ns_hi = apr_hash_next(ns_hi))
718 void *ns_val;
719 const void *ns_name;
720 apr_ssize_t ns_len;
721 apr_hash_index_t *name_hi;
722 apr_hash_this(ns_hi, &ns_name, &ns_len, &ns_val);
723 for (name_hi = apr_hash_first(pool, ns_val); name_hi;
724 name_hi = apr_hash_next(name_hi))
726 void *prop_val;
727 const void *prop_name;
728 apr_ssize_t prop_len;
730 apr_hash_this(name_hi, &prop_name, &prop_len, &prop_val);
731 /* use a subpool? */
732 walker(baton, ns_name, ns_len, prop_name, prop_len, prop_val, pool);
737 void
738 svn_ra_serf__walk_all_paths(apr_hash_t *props,
739 svn_revnum_t rev,
740 svn_ra_serf__path_rev_walker_t walker,
741 void *baton,
742 apr_pool_t *pool)
744 apr_hash_index_t *path_hi;
745 apr_hash_t *ver_props;
747 ver_props = apr_hash_get(props, &rev, sizeof(rev));
749 if (!ver_props)
751 return;
754 for (path_hi = apr_hash_first(pool, ver_props); path_hi;
755 path_hi = apr_hash_next(path_hi))
757 void *path_props;
758 const void *path_name;
759 apr_ssize_t path_len;
760 apr_hash_index_t *ns_hi;
762 apr_hash_this(path_hi, &path_name, &path_len, &path_props);
763 for (ns_hi = apr_hash_first(pool, path_props); ns_hi;
764 ns_hi = apr_hash_next(ns_hi))
766 void *ns_val;
767 const void *ns_name;
768 apr_ssize_t ns_len;
769 apr_hash_index_t *name_hi;
770 apr_hash_this(ns_hi, &ns_name, &ns_len, &ns_val);
771 for (name_hi = apr_hash_first(pool, ns_val); name_hi;
772 name_hi = apr_hash_next(name_hi))
774 void *prop_val;
775 const void *prop_name;
776 apr_ssize_t prop_len;
778 apr_hash_this(name_hi, &prop_name, &prop_len, &prop_val);
779 /* use a subpool? */
780 walker(baton, path_name, path_len, ns_name, ns_len,
781 prop_name, prop_len, prop_val, pool);
787 static svn_error_t *
788 set_bare_props(svn_ra_serf__prop_set_t setprop, void *baton,
789 const char *ns, apr_ssize_t ns_len,
790 const char *name, apr_ssize_t name_len,
791 const svn_string_t *val,
792 apr_pool_t *pool)
794 const char *prop_name;
796 if (strcmp(ns, SVN_DAV_PROP_NS_CUSTOM) == 0)
797 prop_name = name;
798 else if (strcmp(ns, SVN_DAV_PROP_NS_SVN) == 0)
799 prop_name = apr_pstrcat(pool, SVN_PROP_PREFIX, name, NULL);
800 else if (strcmp(ns, SVN_PROP_PREFIX) == 0)
801 prop_name = apr_pstrcat(pool, SVN_PROP_PREFIX, name, NULL);
802 else if (strcmp(ns, "") == 0)
803 prop_name = name;
804 else
806 /* do nothing for now? */
807 return SVN_NO_ERROR;
810 return setprop(baton, prop_name, val, pool);
813 svn_error_t *
814 svn_ra_serf__set_baton_props(svn_ra_serf__prop_set_t setprop, void *baton,
815 const char *ns, apr_ssize_t ns_len,
816 const char *name, apr_ssize_t name_len,
817 const svn_string_t *val,
818 apr_pool_t *pool)
820 const char *prop_name;
822 if (strcmp(ns, SVN_DAV_PROP_NS_CUSTOM) == 0)
823 prop_name = name;
824 else if (strcmp(ns, SVN_DAV_PROP_NS_SVN) == 0)
825 prop_name = apr_pstrcat(pool, SVN_PROP_PREFIX, name, NULL);
826 else if (strcmp(ns, SVN_PROP_PREFIX) == 0)
827 prop_name = apr_pstrcat(pool, SVN_PROP_PREFIX, name, NULL);
828 else if (strcmp(ns, "") == 0)
829 prop_name = name;
830 else if (strcmp(name, SVN_DAV__VERSION_NAME) == 0)
831 prop_name = SVN_PROP_ENTRY_COMMITTED_REV;
832 else if (strcmp(name, SVN_DAV__CREATIONDATE) == 0)
833 prop_name = SVN_PROP_ENTRY_COMMITTED_DATE;
834 else if (strcmp(name, "creator-displayname") == 0)
835 prop_name = SVN_PROP_ENTRY_LAST_AUTHOR;
836 else if (strcmp(name, "repository-uuid") == 0)
837 prop_name = SVN_PROP_ENTRY_UUID;
838 else if (strcmp(name, "lock-token") == 0)
839 prop_name = SVN_PROP_ENTRY_LOCK_TOKEN;
840 else if (strcmp(name, "checked-in") == 0)
841 prop_name = SVN_RA_SERF__WC_CHECKED_IN_URL;
842 else
844 /* do nothing for now? */
845 return SVN_NO_ERROR;
848 return setprop(baton, prop_name, val, pool);
851 static svn_error_t *
852 set_hash_props(void *baton,
853 const char *name,
854 const svn_string_t *value,
855 apr_pool_t *pool)
857 apr_hash_t *props = baton;
859 apr_hash_set(props, name, APR_HASH_KEY_STRING, value);
861 return SVN_NO_ERROR;
864 svn_error_t *
865 svn_ra_serf__set_flat_props(void *baton,
866 const char *ns, apr_ssize_t ns_len,
867 const char *name, apr_ssize_t name_len,
868 const svn_string_t *val,
869 apr_pool_t *pool)
871 return svn_ra_serf__set_baton_props(set_hash_props, baton,
872 ns, ns_len, name, name_len, val, pool);
875 svn_error_t *
876 svn_ra_serf__set_bare_props(void *baton,
877 const char *ns, apr_ssize_t ns_len,
878 const char *name, apr_ssize_t name_len,
879 const svn_string_t *val,
880 apr_pool_t *pool)
882 return set_bare_props(set_hash_props, baton,
883 ns, ns_len, name, name_len, val, pool);
887 svn_error_t *
888 svn_ra_serf__get_baseline_info(const char **bc_url,
889 const char **bc_relative,
890 svn_ra_serf__session_t *session,
891 const char *url,
892 svn_revnum_t revision,
893 apr_pool_t *pool)
895 const char *vcc_url, *relative_url, *basecoll_url, *baseline_url;
896 apr_hash_t *props = apr_hash_make(pool);
898 /* No URL? No sweat. We'll use the session URL. */
899 if (! url)
900 url = session->repos_url.path;
902 SVN_ERR(svn_ra_serf__discover_root(&vcc_url, &relative_url,
903 session, session->conns[0], url, pool));
905 if (revision != SVN_INVALID_REVNUM)
907 SVN_ERR(svn_ra_serf__retrieve_props(props, session, session->conns[0],
908 vcc_url, revision, "0",
909 baseline_props, pool));
910 basecoll_url = svn_ra_serf__get_ver_prop(props, vcc_url, revision,
911 "DAV:", "baseline-collection");
913 else
915 SVN_ERR(svn_ra_serf__retrieve_props(props, session, session->conns[0],
916 vcc_url, revision, "0",
917 checked_in_props, pool));
918 baseline_url = svn_ra_serf__get_ver_prop(props, vcc_url, revision,
919 "DAV:", "checked-in");
920 if (!baseline_url)
922 return svn_error_create(SVN_ERR_RA_DAV_OPTIONS_REQ_FAILED, NULL,
923 _("The OPTIONS response did not include the "
924 "requested checked-in value"));
927 SVN_ERR(svn_ra_serf__retrieve_props(props, session, session->conns[0],
928 baseline_url, revision, "0",
929 baseline_props, pool));
930 basecoll_url = svn_ra_serf__get_ver_prop(props, baseline_url, revision,
931 "DAV:", "baseline-collection");
934 if (!basecoll_url)
936 return svn_error_create(SVN_ERR_RA_DAV_OPTIONS_REQ_FAILED, NULL,
937 _("The OPTIONS response did not include the "
938 "requested baseline-collection value"));
940 *bc_url = basecoll_url;
941 *bc_relative = relative_url;
942 return SVN_NO_ERROR;