~svn/ubuntu/oneiric/subversion/ppa

« back to all changes in this revision

Viewing changes to subversion/libsvn_ra_serf/serf.c

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2006-12-13 17:57:16 UTC
  • mfrom: (1.1.6 upstream) (0.1.3 etch)
  • Revision ID: james.westby@ubuntu.com-20061213175716-2ysv6z4w5dpa2r2f
Tags: 1.4.2dfsg1-2ubuntu1
* Merge with Debian unstable; remaining changes:
  - Create pot file on build.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * serf.c :  entry point for ra_serf
 
3
 *
 
4
 * ====================================================================
 
5
 * Copyright (c) 2006 CollabNet.  All rights reserved.
 
6
 *
 
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.
 
12
 *
 
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
 * ====================================================================
 
17
 */
 
18
 
 
19
 
 
20
 
 
21
#define APR_WANT_STRFUNC
 
22
#include <apr_want.h>
 
23
 
 
24
#include <apr_uri.h>
 
25
 
 
26
#include <expat.h>
 
27
 
 
28
#include <serf.h>
 
29
 
 
30
#include "svn_pools.h"
 
31
#include "svn_ra.h"
 
32
#include "svn_dav.h"
 
33
#include "svn_xml.h"
 
34
#include "../libsvn_ra/ra_loader.h"
 
35
#include "svn_config.h"
 
36
#include "svn_delta.h"
 
37
#include "svn_version.h"
 
38
#include "svn_path.h"
 
39
#include "svn_time.h"
 
40
#include "svn_private_config.h"
 
41
 
 
42
#include "ra_serf.h"
 
43
 
 
44
 
 
45
static const svn_version_t *
 
46
ra_serf_version(void)
 
47
{
 
48
  SVN_VERSION_BODY;
 
49
}
 
50
 
 
51
#define RA_SERF_DESCRIPTION \
 
52
    N_("Access repository via WebDAV protocol through serf.")
 
53
 
 
54
static const char *
 
55
ra_serf_get_description(void)
 
56
{
 
57
  return _(RA_SERF_DESCRIPTION);
 
58
}
 
59
 
 
60
static const char * const *
 
61
ra_serf_get_schemes(apr_pool_t *pool)
 
62
{
 
63
  static const char *serf_ssl[] = { "http", "https", NULL };
 
64
#if 0
 
65
  /* ### Temporary: to shut up a warning. */
 
66
  static const char *serf_no_ssl[] = { "http", NULL };
 
67
#endif
 
68
 
 
69
  /* TODO: Runtime detection. */
 
70
  return serf_ssl;
 
71
}
 
72
 
 
73
static svn_error_t *
 
74
load_config(svn_ra_serf__session_t *session,
 
75
            apr_hash_t *config_hash,
 
76
            apr_pool_t *pool)
 
77
{
 
78
  svn_config_t *config;
 
79
  const char *server_group;
 
80
 
 
81
  config = apr_hash_get(config_hash, SVN_CONFIG_CATEGORY_SERVERS,
 
82
                        APR_HASH_KEY_STRING);
 
83
 
 
84
  SVN_ERR(svn_config_get_bool(config, &session->using_compression,
 
85
                              SVN_CONFIG_SECTION_GLOBAL,
 
86
                              SVN_CONFIG_OPTION_HTTP_COMPRESSION, TRUE));
 
87
 
 
88
  server_group = svn_config_find_group(config,
 
89
                                       session->repos_url.hostname,
 
90
                                       SVN_CONFIG_SECTION_GROUPS, pool);
 
91
 
 
92
  if (server_group)
 
93
    {
 
94
      SVN_ERR(svn_config_get_bool(config, &session->using_compression,
 
95
                                  server_group,
 
96
                                  SVN_CONFIG_OPTION_HTTP_COMPRESSION,
 
97
                                  session->using_compression));
 
98
    }
 
99
 
 
100
  return SVN_NO_ERROR;
 
101
}
 
102
 
 
103
static svn_error_t *
 
104
svn_ra_serf__open(svn_ra_session_t *session,
 
105
                  const char *repos_URL,
 
106
                  const svn_ra_callbacks2_t *callbacks,
 
107
                  void *callback_baton,
 
108
                  apr_hash_t *config,
 
109
                  apr_pool_t *pool)
 
110
{
 
111
  apr_status_t status;
 
112
  svn_ra_serf__session_t *serf_sess;
 
113
  apr_uri_t url;
 
114
 
 
115
  serf_sess = apr_pcalloc(pool, sizeof(*serf_sess));
 
116
  apr_pool_create(&serf_sess->pool, pool);
 
117
  serf_sess->bkt_alloc = serf_bucket_allocator_create(serf_sess->pool, NULL,
 
118
                                                      NULL);
 
119
  serf_sess->cached_props = apr_hash_make(pool);
 
120
  serf_sess->wc_callbacks = callbacks;
 
121
  serf_sess->wc_callback_baton = callback_baton;
 
122
 
 
123
  /* todo: reuse serf context across sessions */
 
124
  serf_sess->context = serf_context_create(pool);
 
125
 
 
126
  apr_uri_parse(serf_sess->pool, repos_URL, &url);
 
127
  serf_sess->repos_url = url;
 
128
  serf_sess->repos_url_str = apr_pstrdup(serf_sess->pool, repos_URL);
 
129
 
 
130
  if (!url.port)
 
131
    {
 
132
      url.port = apr_uri_port_of_scheme(url.scheme);
 
133
    }
 
134
  serf_sess->using_ssl = (strcasecmp(url.scheme, "https") == 0);
 
135
 
 
136
  SVN_ERR(load_config(serf_sess, config, pool));
 
137
 
 
138
  /* register cleanups */
 
139
  apr_pool_cleanup_register(serf_sess->pool, serf_sess,
 
140
                            svn_ra_serf__cleanup_serf_session,
 
141
                            apr_pool_cleanup_null);
 
142
 
 
143
  serf_sess->conns = apr_palloc(pool, sizeof(*serf_sess->conns) * 4);
 
144
 
 
145
  serf_sess->conns[0] = apr_pcalloc(pool, sizeof(*serf_sess->conns[0]));
 
146
  serf_sess->conns[0]->bkt_alloc =
 
147
          serf_bucket_allocator_create(serf_sess->pool, NULL, NULL);
 
148
 
 
149
  /* fetch the DNS record for this host */
 
150
  status = apr_sockaddr_info_get(&serf_sess->conns[0]->address, url.hostname,
 
151
                                 APR_UNSPEC, url.port, 0, pool);
 
152
  if (status)
 
153
    {
 
154
      return svn_error_createf(status, NULL,
 
155
                               _("Could not lookup hostname: %s://%s"),
 
156
                               url.scheme, url.hostname);
 
157
    }
 
158
 
 
159
  serf_sess->conns[0]->using_ssl = serf_sess->using_ssl;
 
160
  serf_sess->conns[0]->using_compression = serf_sess->using_compression;
 
161
  serf_sess->conns[0]->hostinfo = url.hostinfo;
 
162
 
 
163
  /* go ahead and tell serf about the connection. */
 
164
  serf_sess->conns[0]->conn =
 
165
      serf_connection_create(serf_sess->context, serf_sess->conns[0]->address,
 
166
                             svn_ra_serf__conn_setup, serf_sess->conns[0],
 
167
                             svn_ra_serf__conn_closed, serf_sess->conns[0],
 
168
                             serf_sess->pool);
 
169
 
 
170
  serf_sess->num_conns = 1;
 
171
 
 
172
  session->priv = serf_sess;
 
173
 
 
174
  return SVN_NO_ERROR;
 
175
}
 
176
 
 
177
static svn_error_t *
 
178
svn_ra_serf__reparent(svn_ra_session_t *ra_session,
 
179
                      const char *url,
 
180
                      apr_pool_t *pool)
 
181
{
 
182
  svn_ra_serf__session_t *session = ra_session->priv;
 
183
  apr_uri_t new_url;
 
184
 
 
185
  /* If it's the URL we already have, wave our hands and do nothing. */
 
186
  if (strcmp(session->repos_url_str, url) == 0)
 
187
    {
 
188
      return SVN_NO_ERROR;
 
189
    }
 
190
 
 
191
  /* Do we need to check that it's the same host and port? */
 
192
  apr_uri_parse(session->pool, url, &new_url);
 
193
 
 
194
  session->repos_url.path = new_url.path;
 
195
  session->repos_url_str = apr_pstrdup(pool, url);
 
196
 
 
197
  return SVN_NO_ERROR;
 
198
}
 
199
 
 
200
static svn_error_t *
 
201
svn_ra_serf__get_latest_revnum(svn_ra_session_t *ra_session,
 
202
                               svn_revnum_t *latest_revnum,
 
203
                               apr_pool_t *pool)
 
204
{
 
205
  apr_hash_t *props;
 
206
  svn_ra_serf__session_t *session = ra_session->priv;
 
207
  const char *vcc_url, *baseline_url, *version_name;
 
208
 
 
209
  props = apr_hash_make(pool);
 
210
 
 
211
  SVN_ERR(svn_ra_serf__discover_root(&vcc_url, NULL,
 
212
                                     session, session->conns[0],
 
213
                                     session->repos_url.path, pool));
 
214
 
 
215
  if (!vcc_url)
 
216
    {
 
217
      abort();
 
218
    }
 
219
 
 
220
  /* Using the version-controlled-configuration, fetch the checked-in prop. */
 
221
  SVN_ERR(svn_ra_serf__retrieve_props(props, session, session->conns[0],
 
222
                                      vcc_url, SVN_INVALID_REVNUM, "0",
 
223
                                      checked_in_props, pool));
 
224
 
 
225
  baseline_url = svn_ra_serf__get_prop(props, vcc_url,
 
226
                                       "DAV:", "checked-in");
 
227
 
 
228
  if (!baseline_url)
 
229
    {
 
230
      abort();
 
231
    }
 
232
 
 
233
  /* Using the checked-in property, fetch:
 
234
   *    baseline-connection *and* version-name
 
235
   */
 
236
  SVN_ERR(svn_ra_serf__retrieve_props(props, session, session->conns[0],
 
237
                                      baseline_url, SVN_INVALID_REVNUM,
 
238
                                      "0", baseline_props, pool));
 
239
 
 
240
  version_name = svn_ra_serf__get_prop(props, baseline_url,
 
241
                                       "DAV:", "version-name");
 
242
 
 
243
  if (!version_name)
 
244
    {
 
245
      abort();
 
246
    }
 
247
 
 
248
  *latest_revnum = SVN_STR_TO_REV(version_name);
 
249
 
 
250
  return SVN_NO_ERROR;
 
251
}
 
252
 
 
253
static svn_error_t *
 
254
svn_ra_serf__get_dated_revision(svn_ra_session_t *session,
 
255
                                svn_revnum_t *revision,
 
256
                                apr_time_t tm,
 
257
                                apr_pool_t *pool)
 
258
{
 
259
  abort();
 
260
}
 
261
 
 
262
static svn_error_t *
 
263
svn_ra_serf__rev_proplist(svn_ra_session_t *ra_session,
 
264
                          svn_revnum_t rev,
 
265
                          apr_hash_t **ret_props,
 
266
                          apr_pool_t *pool)
 
267
{
 
268
  svn_ra_serf__session_t *session = ra_session->priv;
 
269
  apr_hash_t *props;
 
270
  const char *vcc_url;
 
271
 
 
272
  props = apr_hash_make(pool);
 
273
  *ret_props = apr_hash_make(pool);
 
274
 
 
275
  SVN_ERR(svn_ra_serf__discover_root(&vcc_url, NULL,
 
276
                                     session, session->conns[0],
 
277
                                     session->repos_url.path, pool));
 
278
 
 
279
  SVN_ERR(svn_ra_serf__retrieve_props(props, session, session->conns[0],
 
280
                                      vcc_url, rev, "0", all_props, pool));
 
281
 
 
282
  svn_ra_serf__walk_all_props(props, vcc_url, rev, svn_ra_serf__set_bare_props,
 
283
                              *ret_props, pool);
 
284
 
 
285
  return SVN_NO_ERROR;
 
286
}
 
287
 
 
288
static svn_error_t *
 
289
svn_ra_serf__rev_prop(svn_ra_session_t *session,
 
290
                      svn_revnum_t rev,
 
291
                      const char *name,
 
292
                      svn_string_t **value,
 
293
                      apr_pool_t *pool)
 
294
{
 
295
  apr_hash_t *props;
 
296
 
 
297
  SVN_ERR(svn_ra_serf__rev_proplist(session, rev, &props, pool));
 
298
 
 
299
  *value = apr_hash_get(props, name, APR_HASH_KEY_STRING);
 
300
 
 
301
  return SVN_NO_ERROR;
 
302
}
 
303
 
 
304
static svn_error_t *
 
305
fetch_path_props(svn_ra_serf__propfind_context_t **ret_prop_ctx,
 
306
                 apr_hash_t **ret_props,
 
307
                 const char **ret_path,
 
308
                 svn_revnum_t *ret_revision,
 
309
                 svn_ra_serf__session_t *session,
 
310
                 const char *rel_path,
 
311
                 svn_revnum_t revision,
 
312
                 const svn_ra_serf__dav_props_t *desired_props,
 
313
                 apr_pool_t *pool)
 
314
{
 
315
  svn_ra_serf__propfind_context_t *prop_ctx;
 
316
  apr_hash_t *props;
 
317
  const char *path;
 
318
 
 
319
  path = session->repos_url.path;
 
320
 
 
321
  /* If we have a relative path, append it. */
 
322
  if (rel_path)
 
323
    {
 
324
      path = svn_path_url_add_component(path, rel_path, pool);
 
325
    }
 
326
 
 
327
  props = apr_hash_make(pool);
 
328
 
 
329
  prop_ctx = NULL;
 
330
 
 
331
  /* If we were given a specific revision, we have to fetch the VCC and
 
332
   * do a PROPFIND off of that.
 
333
   */
 
334
  if (!SVN_IS_VALID_REVNUM(revision))
 
335
    {
 
336
      svn_ra_serf__deliver_props(&prop_ctx, props, session, session->conns[0],
 
337
                                 path, revision, "0", desired_props, TRUE,
 
338
                                 NULL, session->pool);
 
339
    }
 
340
  else
 
341
    {
 
342
      const char *vcc_url, *relative_url, *basecoll_url;
 
343
 
 
344
      SVN_ERR(svn_ra_serf__discover_root(&vcc_url, &relative_url,
 
345
                                         session, session->conns[0],
 
346
                                         path, pool));
 
347
      
 
348
      SVN_ERR(svn_ra_serf__retrieve_props(props, session, session->conns[0],
 
349
                                          vcc_url, revision,
 
350
                                          "0", baseline_props, pool));
 
351
      
 
352
      basecoll_url = svn_ra_serf__get_ver_prop(props, vcc_url, revision,
 
353
                                               "DAV:", "baseline-collection");
 
354
      
 
355
      if (!basecoll_url)
 
356
        {
 
357
          abort();
 
358
        }
 
359
    
 
360
      /* We will try again with our new path; however, we're now 
 
361
       * technically an unversioned resource because we are accessing
 
362
       * the revision's baseline-collection.
 
363
       */  
 
364
      prop_ctx = NULL;
 
365
      path = svn_path_url_add_component(basecoll_url, relative_url, pool);
 
366
      revision = SVN_INVALID_REVNUM;
 
367
      svn_ra_serf__deliver_props(&prop_ctx, props, session, session->conns[0],
 
368
                                 path, revision, "0",
 
369
                                 desired_props, TRUE,
 
370
                                 NULL, session->pool);
 
371
    }
 
372
 
 
373
  SVN_ERR(svn_ra_serf__wait_for_props(prop_ctx, session, pool));
 
374
 
 
375
  *ret_path = path;
 
376
  *ret_prop_ctx = prop_ctx;
 
377
  *ret_props = props;
 
378
  *ret_revision = revision;
 
379
 
 
380
  return SVN_NO_ERROR;
 
381
}
 
382
 
 
383
static svn_error_t *
 
384
svn_ra_serf__check_path(svn_ra_session_t *ra_session,
 
385
                        const char *rel_path,
 
386
                        svn_revnum_t revision,
 
387
                        svn_node_kind_t *kind,
 
388
                        apr_pool_t *pool)
 
389
{
 
390
  svn_ra_serf__session_t *session = ra_session->priv;
 
391
  apr_hash_t *props;
 
392
  svn_ra_serf__propfind_context_t *prop_ctx;
 
393
  const char *path, *res_type;
 
394
  svn_revnum_t fetched_rev;
 
395
 
 
396
  SVN_ERR(fetch_path_props(&prop_ctx, &props, &path, &fetched_rev,
 
397
                           session, rel_path,
 
398
                           revision, check_path_props, pool));
 
399
 
 
400
  if (svn_ra_serf__propfind_status_code(prop_ctx) == 404)
 
401
    {
 
402
      *kind = svn_node_none;
 
403
    }
 
404
  else
 
405
    {
 
406
      res_type = svn_ra_serf__get_ver_prop(props, path, fetched_rev,
 
407
                                           "DAV:", "resourcetype");
 
408
      if (!res_type)
 
409
        {
 
410
          /* How did this happen? */
 
411
          abort();
 
412
        }
 
413
      else if (strcmp(res_type, "collection") == 0)
 
414
        {
 
415
          *kind = svn_node_dir;
 
416
        }
 
417
      else
 
418
        {
 
419
          *kind = svn_node_file;
 
420
        }
 
421
    }
 
422
 
 
423
  return SVN_NO_ERROR;
 
424
}
 
425
 
 
426
static svn_error_t *
 
427
dirent_walker(void *baton,
 
428
              const char *ns, apr_ssize_t ns_len,
 
429
              const char *name, apr_ssize_t name_len,
 
430
              const svn_string_t *val,
 
431
              apr_pool_t *pool)
 
432
{
 
433
  svn_dirent_t *entry = baton;
 
434
 
 
435
  if (strcmp(ns, SVN_DAV_PROP_NS_CUSTOM) == 0)
 
436
    {
 
437
      entry->has_props = TRUE;
 
438
    }
 
439
  else if (strcmp(ns, SVN_DAV_PROP_NS_SVN) == 0)
 
440
    {
 
441
      entry->has_props = TRUE;
 
442
    }
 
443
  else if (strcmp(ns, "DAV:") == 0)
 
444
    {
 
445
      if (strcmp(name, "version-name") == 0)
 
446
        {
 
447
          entry->created_rev = SVN_STR_TO_REV(val->data);
 
448
        }
 
449
      else if (strcmp(name, "creator-displayname") == 0)
 
450
        {
 
451
          entry->last_author = val->data;
 
452
        }
 
453
      else if (strcmp(name, "creationdate") == 0)
 
454
        {
 
455
          SVN_ERR(svn_time_from_cstring(&entry->time, val->data, pool));
 
456
        }
 
457
      else if (strcmp(name, "getcontentlength") == 0)
 
458
        {
 
459
          entry->size = apr_atoi64(val->data);
 
460
        }
 
461
      else if (strcmp(name, "resourcetype") == 0)
 
462
        {
 
463
          if (strcmp(val->data, "collection") == 0)
 
464
            {
 
465
              entry->kind = svn_node_dir;
 
466
            }
 
467
          else
 
468
            {
 
469
              entry->kind = svn_node_file;
 
470
            }
 
471
        }
 
472
    }
 
473
 
 
474
  return SVN_NO_ERROR;
 
475
}
 
476
 
 
477
struct path_dirent_visitor_t {
 
478
  apr_hash_t *full_paths;
 
479
  apr_hash_t *base_paths;
 
480
  const char *orig_path;
 
481
};
 
482
 
 
483
static svn_error_t *
 
484
path_dirent_walker(void *baton,
 
485
                   const char *path, apr_ssize_t path_len,
 
486
                   const char *ns, apr_ssize_t ns_len,
 
487
                   const char *name, apr_ssize_t name_len,
 
488
                   const svn_string_t *val,
 
489
                   apr_pool_t *pool)
 
490
{
 
491
  struct path_dirent_visitor_t *dirents = baton;
 
492
  svn_dirent_t *entry;
 
493
 
 
494
  /* Skip our original path. */
 
495
  if (strcmp(path, dirents->orig_path) == 0)
 
496
    {
 
497
      return SVN_NO_ERROR;
 
498
    }
 
499
 
 
500
  entry = apr_hash_get(dirents->full_paths, path, path_len);
 
501
 
 
502
  if (!entry)
 
503
    {
 
504
      const char *base_name;
 
505
 
 
506
      entry = apr_pcalloc(pool, sizeof(*entry));
 
507
 
 
508
      apr_hash_set(dirents->full_paths, path, path_len, entry);
 
509
 
 
510
      base_name = svn_path_uri_decode(svn_path_basename(path, pool), pool);
 
511
 
 
512
      apr_hash_set(dirents->base_paths, base_name, APR_HASH_KEY_STRING, entry);
 
513
    }
 
514
 
 
515
  return dirent_walker(entry, ns, ns_len, name, name_len, val, pool);
 
516
}
 
517
 
 
518
static svn_error_t *
 
519
svn_ra_serf__stat(svn_ra_session_t *ra_session,
 
520
                  const char *rel_path,
 
521
                  svn_revnum_t revision,
 
522
                  svn_dirent_t **dirent,
 
523
                  apr_pool_t *pool)
 
524
{
 
525
  svn_ra_serf__session_t *session = ra_session->priv;
 
526
  apr_hash_t *props;
 
527
  svn_ra_serf__propfind_context_t *prop_ctx;
 
528
  const char *path;
 
529
  svn_revnum_t fetched_rev;
 
530
  svn_dirent_t *entry;
 
531
 
 
532
  SVN_ERR(fetch_path_props(&prop_ctx, &props, &path, &fetched_rev,
 
533
                           session, rel_path, revision, all_props, pool));
 
534
 
 
535
  entry = apr_pcalloc(pool, sizeof(*entry));
 
536
 
 
537
  svn_ra_serf__walk_all_props(props, path, fetched_rev, dirent_walker, entry,
 
538
                              pool);
 
539
 
 
540
  *dirent = entry;
 
541
 
 
542
  return SVN_NO_ERROR;
 
543
}
 
544
 
 
545
static svn_error_t *
 
546
svn_ra_serf__get_dir(svn_ra_session_t *ra_session,
 
547
                     apr_hash_t **dirents,
 
548
                     svn_revnum_t *fetched_rev,
 
549
                     apr_hash_t **ret_props,
 
550
                     const char *rel_path,
 
551
                     svn_revnum_t revision,
 
552
                     apr_uint32_t dirent_fields,
 
553
                     apr_pool_t *pool)
 
554
{
 
555
  svn_ra_serf__session_t *session = ra_session->priv;
 
556
  apr_hash_t *props;
 
557
  const char *path;
 
558
 
 
559
  path = session->repos_url.path;
 
560
 
 
561
  /* If we have a relative path, append it. */
 
562
  if (rel_path)
 
563
    {
 
564
      path = svn_path_url_add_component(path, rel_path, pool);
 
565
    }
 
566
 
 
567
  props = apr_hash_make(pool);
 
568
 
 
569
  if (SVN_IS_VALID_REVNUM(revision) || fetched_rev)
 
570
    {
 
571
      const char *vcc_url, *relative_url, *basecoll_url;
 
572
 
 
573
      SVN_ERR(svn_ra_serf__discover_root(&vcc_url, &relative_url,
 
574
                                         session, session->conns[0],
 
575
                                         path, pool));
 
576
 
 
577
      SVN_ERR(svn_ra_serf__retrieve_props(props, session, session->conns[0],
 
578
                                          vcc_url, revision,
 
579
                                          "0", baseline_props, pool));
 
580
      
 
581
      basecoll_url = svn_ra_serf__get_ver_prop(props, vcc_url, revision,
 
582
                                               "DAV:", "baseline-collection");
 
583
      
 
584
      if (!basecoll_url)
 
585
        {
 
586
          abort();
 
587
        }
 
588
 
 
589
      if (fetched_rev)
 
590
       {
 
591
         *fetched_rev = revision;
 
592
       }
 
593
 
 
594
      path = svn_path_url_add_component(basecoll_url, relative_url, pool);
 
595
      revision = SVN_INVALID_REVNUM;
 
596
    }
 
597
 
 
598
  /* If we're asked for children, fetch them now. */
 
599
  if (dirents)
 
600
    {
 
601
      svn_ra_serf__propfind_context_t *prop_ctx;
 
602
      struct path_dirent_visitor_t dirent_walk;
 
603
 
 
604
      prop_ctx = NULL;
 
605
      svn_ra_serf__deliver_props(&prop_ctx, props, session, session->conns[0],
 
606
                                 path, revision, "1", all_props, TRUE,
 
607
                                 NULL, session->pool);
 
608
      
 
609
      SVN_ERR(svn_ra_serf__wait_for_props(prop_ctx, session, pool));
 
610
 
 
611
      /* We're going to create two hashes to help the walker along.
 
612
       * We're going to return the 2nd one back to the caller as it
 
613
       * will have the basenames it expects.
 
614
       */
 
615
      dirent_walk.full_paths = apr_hash_make(pool);
 
616
      dirent_walk.base_paths = apr_hash_make(pool);
 
617
      dirent_walk.orig_path = svn_path_canonicalize(path, pool);
 
618
 
 
619
      svn_ra_serf__walk_all_paths(props, revision, path_dirent_walker,
 
620
                                  &dirent_walk, pool);
 
621
 
 
622
      *dirents = dirent_walk.base_paths;
 
623
    }
 
624
 
 
625
  /* If we're asked for the directory properties, fetch them too. */
 
626
  if (ret_props)
 
627
    {
 
628
      props = apr_hash_make(pool);
 
629
      *ret_props = apr_hash_make(pool);
 
630
 
 
631
      SVN_ERR(svn_ra_serf__retrieve_props(props, session, session->conns[0],
 
632
                                          path, revision, "0", all_props,
 
633
                                          pool));
 
634
      svn_ra_serf__walk_all_props(props, path, revision,
 
635
                                  svn_ra_serf__set_flat_props,
 
636
                                  *ret_props, pool);
 
637
    }
 
638
 
 
639
  return SVN_NO_ERROR;
 
640
}
 
641
 
 
642
static svn_error_t *
 
643
svn_ra_serf__get_repos_root(svn_ra_session_t *ra_session,
 
644
                            const char **url,
 
645
                            apr_pool_t *pool)
 
646
{
 
647
  svn_ra_serf__session_t *session = ra_session->priv;
 
648
 
 
649
  if (!session->repos_root_str)
 
650
    {
 
651
      const char *vcc_url;
 
652
 
 
653
      SVN_ERR(svn_ra_serf__discover_root(&vcc_url, NULL,
 
654
                                         session, session->conns[0],
 
655
                                         session->repos_url.path, pool));
 
656
    }
 
657
 
 
658
  *url = session->repos_root_str;
 
659
  return SVN_NO_ERROR;
 
660
}
 
661
 
 
662
static svn_error_t *
 
663
svn_ra_serf__get_uuid(svn_ra_session_t *ra_session,
 
664
                      const char **uuid,
 
665
                      apr_pool_t *pool)
 
666
{
 
667
  svn_ra_serf__session_t *session = ra_session->priv;
 
668
  apr_hash_t *props;
 
669
  const char *root_url;
 
670
 
 
671
  props = apr_hash_make(pool);
 
672
 
 
673
  svn_ra_serf__get_repos_root(ra_session, &root_url, pool);
 
674
 
 
675
  SVN_ERR(svn_ra_serf__retrieve_props(props, session, session->conns[0],
 
676
                                      root_url, SVN_INVALID_REVNUM, "0",
 
677
                                      uuid_props, pool));
 
678
  *uuid = svn_ra_serf__get_prop(props, root_url,
 
679
                                SVN_DAV_PROP_NS_DAV, "repository-uuid");
 
680
 
 
681
  if (!*uuid)
 
682
    {
 
683
      abort();
 
684
    }
 
685
 
 
686
  return SVN_NO_ERROR;
 
687
}
 
688
 
 
689
static const svn_ra__vtable_t serf_vtable = {
 
690
  ra_serf_version,
 
691
  ra_serf_get_description,
 
692
  ra_serf_get_schemes,
 
693
  svn_ra_serf__open,
 
694
  svn_ra_serf__reparent,
 
695
  svn_ra_serf__get_latest_revnum,
 
696
  svn_ra_serf__get_dated_revision,
 
697
  svn_ra_serf__change_rev_prop,
 
698
  svn_ra_serf__rev_proplist,
 
699
  svn_ra_serf__rev_prop,
 
700
  svn_ra_serf__get_commit_editor,
 
701
  svn_ra_serf__get_file,
 
702
  svn_ra_serf__get_dir,
 
703
  svn_ra_serf__do_update,
 
704
  svn_ra_serf__do_switch,
 
705
  svn_ra_serf__do_status,
 
706
  svn_ra_serf__do_diff,
 
707
  svn_ra_serf__get_log,
 
708
  svn_ra_serf__check_path,
 
709
  svn_ra_serf__stat,
 
710
  svn_ra_serf__get_uuid,
 
711
  svn_ra_serf__get_repos_root,
 
712
  svn_ra_serf__get_locations,
 
713
  svn_ra_serf__get_file_revs,
 
714
  svn_ra_serf__lock,
 
715
  svn_ra_serf__unlock,
 
716
  svn_ra_serf__get_lock,
 
717
  svn_ra_serf__get_locks,
 
718
  svn_ra_serf__replay,
 
719
};
 
720
 
 
721
svn_error_t *
 
722
svn_ra_serf__init(const svn_version_t *loader_version,
 
723
                  const svn_ra__vtable_t **vtable,
 
724
                  apr_pool_t *pool)
 
725
{
 
726
  static const svn_version_checklist_t checklist[] =
 
727
    {
 
728
      { "svn_subr",  svn_subr_version },
 
729
      { "svn_delta", svn_delta_version },
 
730
      { NULL, NULL }
 
731
    };
 
732
 
 
733
  SVN_ERR(svn_ver_check_list(ra_serf_version(), checklist));
 
734
 
 
735
  /* Simplified version check to make sure we can safely use the
 
736
     VTABLE parameter. The RA loader does a more exhaustive check. */
 
737
  if (loader_version->major != SVN_VER_MAJOR)
 
738
    {
 
739
      return svn_error_createf
 
740
        (SVN_ERR_VERSION_MISMATCH, NULL,
 
741
         _("Unsupported RA loader version (%d) for ra_serf"),
 
742
         loader_version->major);
 
743
    }
 
744
 
 
745
  *vtable = &serf_vtable;
 
746
 
 
747
  return SVN_NO_ERROR;
 
748
}
 
749
 
 
750
/* Compatibility wrapper for pre-1.2 subversions.  Needed? */
 
751
#define NAME "ra_serf"
 
752
#define DESCRIPTION RA_SERF_DESCRIPTION
 
753
#define VTBL serf_vtable
 
754
#define INITFUNC svn_ra_serf__init
 
755
#define COMPAT_INITFUNC svn_ra_serf_init
 
756
#include "../libsvn_ra/wrapper_template.h"