~svn/ubuntu/raring/subversion/ppa

« back to all changes in this revision

Viewing changes to subversion/libsvn_ra_local/ra_plugin.c

  • Committer: Bazaar Package Importer
  • Author(s): Adam Conrad
  • Date: 2005-12-05 01:26:14 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20051205012614-qom4xfypgtsqc2xq
Tags: 1.2.3dfsg1-3ubuntu1
Merge with the final Debian release of 1.2.3dfsg1-3, bringing in
fixes to the clean target, better documentation of the libdb4.3
upgrade and build fixes to work with swig1.3_1.3.27.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * ra_plugin.c : the main RA module for local repository access
 
3
 *
 
4
 * ====================================================================
 
5
 * Copyright (c) 2000-2004 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
#include "ra_local.h"
 
20
#include "svn_ra.h"
 
21
#include "svn_fs.h"
 
22
#include "svn_delta.h"
 
23
#include "svn_repos.h"
 
24
#include "svn_pools.h"
 
25
#include "svn_time.h"
 
26
#include "svn_props.h"
 
27
#include "svn_path.h"
 
28
#include "svn_private_config.h"
 
29
#include "../libsvn_ra/ra_loader.h"
 
30
 
 
31
#define APR_WANT_STRFUNC
 
32
#include <apr_want.h>
 
33
 
 
34
#include <assert.h>
 
35
 
 
36
/*----------------------------------------------------------------*/
 
37
 
 
38
 
 
39
/* The reporter vtable needed by do_update() */
 
40
typedef struct reporter_baton_t
 
41
{
 
42
  svn_ra_local__session_baton_t *session;
 
43
  void *report_baton;
 
44
 
 
45
} reporter_baton_t;
 
46
 
 
47
 
 
48
static void *
 
49
make_reporter_baton (svn_ra_local__session_baton_t *session,
 
50
                     void *report_baton,
 
51
                     apr_pool_t *pool)
 
52
{
 
53
  reporter_baton_t *rbaton = apr_palloc (pool, sizeof (*rbaton));
 
54
  rbaton->session = session;
 
55
  rbaton->report_baton = report_baton;
 
56
  return rbaton;
 
57
}
 
58
 
 
59
 
 
60
static svn_error_t *
 
61
reporter_set_path (void *reporter_baton,
 
62
                   const char *path,
 
63
                   svn_revnum_t revision,
 
64
                   svn_boolean_t start_empty,
 
65
                   const char *lock_token,
 
66
                   apr_pool_t *pool)
 
67
{
 
68
  reporter_baton_t *rbaton = reporter_baton;
 
69
  return svn_repos_set_path2 (rbaton->report_baton, path,
 
70
                              revision, start_empty, lock_token, pool);
 
71
}
 
72
 
 
73
 
 
74
static svn_error_t *
 
75
reporter_delete_path (void *reporter_baton,
 
76
                      const char *path,
 
77
                      apr_pool_t *pool)
 
78
{
 
79
  reporter_baton_t *rbaton = reporter_baton;
 
80
  return svn_repos_delete_path (rbaton->report_baton, path, pool);
 
81
}
 
82
 
 
83
 
 
84
static svn_error_t *
 
85
reporter_link_path (void *reporter_baton,
 
86
                    const char *path,
 
87
                    const char *url,
 
88
                    svn_revnum_t revision,
 
89
                    svn_boolean_t start_empty,
 
90
                    const char *lock_token,
 
91
                    apr_pool_t *pool)
 
92
{
 
93
  reporter_baton_t *rbaton = reporter_baton;
 
94
  const char *fs_path = NULL;
 
95
  const char *repos_url_decoded;
 
96
  int repos_url_len;
 
97
 
 
98
  url = svn_path_uri_decode(url, pool);
 
99
  repos_url_decoded = svn_path_uri_decode(rbaton->session->repos_url, pool);
 
100
  repos_url_len = strlen(repos_url_decoded);
 
101
  if (strncmp(url, repos_url_decoded, repos_url_len) != 0)
 
102
    return svn_error_createf (SVN_ERR_RA_ILLEGAL_URL, NULL,
 
103
                              _("'%s'\n"
 
104
                                "is not the same repository as\n"
 
105
                                "'%s'"), url, rbaton->session->repos_url);
 
106
  fs_path = url + repos_url_len;
 
107
 
 
108
  return svn_repos_link_path2 (rbaton->report_baton, path, fs_path, revision,
 
109
                              start_empty, lock_token, pool);
 
110
}
 
111
 
 
112
 
 
113
static svn_error_t *
 
114
reporter_finish_report (void *reporter_baton,
 
115
                        apr_pool_t *pool)
 
116
{
 
117
  reporter_baton_t *rbaton = reporter_baton;
 
118
  return svn_repos_finish_report (rbaton->report_baton, pool);
 
119
}
 
120
 
 
121
 
 
122
static svn_error_t *
 
123
reporter_abort_report (void *reporter_baton,
 
124
                       apr_pool_t *pool)
 
125
{
 
126
  reporter_baton_t *rbaton = reporter_baton;
 
127
  return svn_repos_abort_report (rbaton->report_baton, pool);
 
128
}
 
129
 
 
130
 
 
131
static const svn_ra_reporter2_t ra_local_reporter = 
 
132
{
 
133
  reporter_set_path,
 
134
  reporter_delete_path,
 
135
  reporter_link_path,
 
136
  reporter_finish_report,
 
137
  reporter_abort_report
 
138
};
 
139
 
 
140
static svn_error_t *
 
141
svn_ra_local__get_file_revs (svn_ra_session_t *session,
 
142
                             const char *path,
 
143
                             svn_revnum_t start,
 
144
                             svn_revnum_t end,
 
145
                             svn_ra_file_rev_handler_t handler,
 
146
                             void *handler_baton,
 
147
                             apr_pool_t *pool)
 
148
{
 
149
  svn_ra_local__session_baton_t *sbaton = session->priv;
 
150
  const char *abs_path = sbaton->fs_path;
 
151
 
 
152
  /* Concatenate paths */
 
153
  abs_path = svn_path_join (abs_path, path, pool);
 
154
 
 
155
  return svn_repos_get_file_revs (sbaton->repos, abs_path, start, end, NULL,
 
156
                                  NULL, handler, handler_baton, pool);
 
157
}
 
158
 
 
159
/* Pool cleanup handler: Ensure that the access descriptor of the filesystem
 
160
   DATA is set to NULL. */
 
161
static apr_status_t
 
162
cleanup_access (void *data)
 
163
{
 
164
  svn_error_t *serr;
 
165
  svn_fs_t *fs = data;
 
166
 
 
167
  serr = svn_fs_set_access (fs, NULL);
 
168
 
 
169
  if (serr)
 
170
    {
 
171
      apr_status_t apr_err = serr->apr_err;
 
172
      svn_error_clear(serr);
 
173
      return apr_err;
 
174
    }
 
175
 
 
176
  return APR_SUCCESS;
 
177
}
 
178
 
 
179
static svn_error_t *
 
180
get_username (svn_ra_session_t *session,
 
181
              apr_pool_t *pool)
 
182
{
 
183
  svn_ra_local__session_baton_t *baton = session->priv;
 
184
  svn_auth_iterstate_t *iterstate;
 
185
  svn_fs_access_t *access_ctx;
 
186
 
 
187
  /* If we've already found the username don't ask for it again. */
 
188
  if (! baton->username)
 
189
    {
 
190
      /* Get a username somehow, so we have some svn:author property to
 
191
         attach to a commit. */
 
192
      if (baton->callbacks->auth_baton)
 
193
        {
 
194
          void *creds;
 
195
          svn_auth_cred_username_t *username_creds;
 
196
          SVN_ERR (svn_auth_first_credentials (&creds, &iterstate,
 
197
                                               SVN_AUTH_CRED_USERNAME,
 
198
                                               baton->uuid, /* realmstring */
 
199
                                               baton->callbacks->auth_baton,
 
200
                                               pool));
 
201
          
 
202
          /* No point in calling next_creds(), since that assumes that the
 
203
             first_creds() somehow failed to authenticate.  But there's no
 
204
             challenge going on, so we use whatever creds we get back on
 
205
             the first try. */
 
206
          username_creds = creds;
 
207
          if (username_creds && username_creds->username)
 
208
            {
 
209
              baton->username = apr_pstrdup (session->pool,
 
210
                                             username_creds->username);
 
211
              svn_error_clear (svn_auth_save_credentials (iterstate, pool));
 
212
            }
 
213
          else
 
214
            baton->username = "";
 
215
        }
 
216
      else
 
217
        baton->username = "";
 
218
    }
 
219
 
 
220
  /* If we have a real username, attach it to the filesystem so that it can
 
221
     be used to validate locks.  Even if there already is a user context
 
222
     associated, it may contain irrelevant lock tokens, so always create a new.
 
223
  */
 
224
  if (*baton->username)
 
225
    {
 
226
      SVN_ERR (svn_fs_create_access (&access_ctx, baton->username,
 
227
                                     pool));
 
228
      SVN_ERR (svn_fs_set_access (baton->fs, access_ctx));
 
229
 
 
230
      /* Make sure this context is disassociated when the pool gets
 
231
         destroyed. */
 
232
      apr_pool_cleanup_register (pool, baton->fs, cleanup_access,
 
233
                                 apr_pool_cleanup_null);
 
234
    }
 
235
 
 
236
  return SVN_NO_ERROR;
 
237
}
 
238
 
 
239
 
 
240
/*----------------------------------------------------------------*/
 
241
 
 
242
/** The RA vtable routines **/
 
243
 
 
244
#define RA_LOCAL_DESCRIPTION \
 
245
        N_("Module for accessing a repository on local disk.")
 
246
 
 
247
static const char *
 
248
svn_ra_local__get_description (void)
 
249
{
 
250
  return _(RA_LOCAL_DESCRIPTION);
 
251
}
 
252
 
 
253
static const char * const *
 
254
svn_ra_local__get_schemes (apr_pool_t *pool)
 
255
{
 
256
  static const char *schemes[] = { "file", NULL };
 
257
 
 
258
  return schemes;
 
259
}
 
260
 
 
261
static svn_error_t *
 
262
svn_ra_local__open (svn_ra_session_t *session,
 
263
                    const char *repos_URL,
 
264
                    const svn_ra_callbacks_t *callbacks,
 
265
                    void *callback_baton,
 
266
                    apr_hash_t *config,
 
267
                    apr_pool_t *pool)
 
268
{
 
269
  svn_ra_local__session_baton_t *baton;
 
270
  
 
271
  /* Allocate and stash the session_baton args we have already. */
 
272
  baton = apr_pcalloc (pool, sizeof(*baton));
 
273
  baton->repository_URL = apr_pstrdup (session->pool, repos_URL);
 
274
  baton->callbacks = callbacks;
 
275
  baton->callback_baton = callback_baton;
 
276
  
 
277
  /* Look through the URL, figure out which part points to the
 
278
     repository, and which part is the path *within* the
 
279
     repository. */
 
280
  SVN_ERR_W (svn_ra_local__split_URL (&(baton->repos),
 
281
                                      &(baton->repos_url),
 
282
                                      &(baton->fs_path),
 
283
                                      baton->repository_URL,
 
284
                                      session->pool),
 
285
             _("Unable to open an ra_local session to URL"));
 
286
 
 
287
  /* Cache the filesystem object from the repos here for
 
288
     convenience. */
 
289
  baton->fs = svn_repos_fs (baton->repos);
 
290
 
 
291
  /* Cache the repository UUID as well */
 
292
  SVN_ERR (svn_fs_get_uuid (baton->fs, &baton->uuid, session->pool));
 
293
 
 
294
  /* Be sure username is NULL so we know to look it up / ask for it */
 
295
  baton->username = NULL;
 
296
 
 
297
  session->priv = baton;
 
298
  return SVN_NO_ERROR;
 
299
}
 
300
 
 
301
 
 
302
 
 
303
static svn_error_t *
 
304
svn_ra_local__get_latest_revnum (svn_ra_session_t *session,
 
305
                                 svn_revnum_t *latest_revnum,
 
306
                                 apr_pool_t *pool)
 
307
{
 
308
  svn_ra_local__session_baton_t *baton = session->priv;
 
309
 
 
310
  SVN_ERR (svn_fs_youngest_rev (latest_revnum, baton->fs, pool));
 
311
 
 
312
  return SVN_NO_ERROR;
 
313
}
 
314
 
 
315
 
 
316
 
 
317
static svn_error_t *
 
318
svn_ra_local__get_dated_revision (svn_ra_session_t *session,
 
319
                                  svn_revnum_t *revision,
 
320
                                  apr_time_t tm,
 
321
                                  apr_pool_t *pool)
 
322
{
 
323
  svn_ra_local__session_baton_t *baton = session->priv;
 
324
 
 
325
  SVN_ERR (svn_repos_dated_revision (revision, baton->repos, tm, pool));
 
326
 
 
327
  return SVN_NO_ERROR;
 
328
}
 
329
 
 
330
 
 
331
static svn_error_t *
 
332
svn_ra_local__change_rev_prop (svn_ra_session_t *session,
 
333
                               svn_revnum_t rev,
 
334
                               const char *name,
 
335
                               const svn_string_t *value,
 
336
                               apr_pool_t *pool)
 
337
{
 
338
  svn_ra_local__session_baton_t *baton = session->priv;
 
339
 
 
340
  SVN_ERR (get_username (session, pool));
 
341
 
 
342
  SVN_ERR (svn_repos_fs_change_rev_prop2 (baton->repos, rev, baton->username,
 
343
                                          name, value, NULL, NULL, pool));
 
344
 
 
345
  return SVN_NO_ERROR;
 
346
}
 
347
 
 
348
 
 
349
static svn_error_t *
 
350
svn_ra_local__get_uuid (svn_ra_session_t *session,
 
351
                        const char **uuid,
 
352
                        apr_pool_t *pool)
 
353
{
 
354
  svn_ra_local__session_baton_t *baton = session->priv;
 
355
 
 
356
  *uuid = baton->uuid;
 
357
 
 
358
  return SVN_NO_ERROR;
 
359
}
 
360
 
 
361
static svn_error_t *
 
362
svn_ra_local__get_repos_root (svn_ra_session_t *session,
 
363
                              const char **url,
 
364
                              apr_pool_t *pool)
 
365
{
 
366
  svn_ra_local__session_baton_t *baton = session->priv;
 
367
 
 
368
  *url = baton->repos_url;
 
369
 
 
370
  return SVN_NO_ERROR;
 
371
}
 
372
 
 
373
static svn_error_t *
 
374
svn_ra_local__rev_proplist (svn_ra_session_t *session,
 
375
                            svn_revnum_t rev,
 
376
                            apr_hash_t **props,
 
377
                            apr_pool_t *pool)
 
378
{
 
379
  svn_ra_local__session_baton_t *baton = session->priv;
 
380
 
 
381
  SVN_ERR (svn_repos_fs_revision_proplist (props, baton->repos, rev,
 
382
                                           NULL, NULL, pool));
 
383
 
 
384
  return SVN_NO_ERROR;
 
385
}
 
386
 
 
387
 
 
388
static svn_error_t *
 
389
svn_ra_local__rev_prop (svn_ra_session_t *session,
 
390
                        svn_revnum_t rev,
 
391
                        const char *name,
 
392
                        svn_string_t **value,
 
393
                        apr_pool_t *pool)
 
394
{
 
395
  svn_ra_local__session_baton_t *baton = session->priv;
 
396
 
 
397
  SVN_ERR (svn_repos_fs_revision_prop (value, baton->repos, rev, name,
 
398
                                       NULL, NULL, pool));
 
399
 
 
400
  return SVN_NO_ERROR;
 
401
}
 
402
 
 
403
 
 
404
struct deltify_etc_baton
 
405
{
 
406
  svn_fs_t *fs;                    /* the fs to deltify in */
 
407
  svn_repos_t *repos;              /* repos for unlocking */
 
408
  const char *fs_path;             /* fs-path part of split session URL */
 
409
  apr_hash_t *lock_tokens;         /* tokens to unlock, if any */
 
410
  apr_pool_t *pool;                /* pool for scratch work */
 
411
  svn_commit_callback_t callback;  /* the original callback */
 
412
  void *callback_baton;            /* the original callback's baton */
 
413
};
 
414
 
 
415
/* This implements 'svn_commit_callback_t'.  Its invokes the original
 
416
   (wrapped) callback, but also does deltification on the new revision and
 
417
   possibly unlocks committed paths.
 
418
   BATON is 'struct deltify_etc_baton *'. */
 
419
static svn_error_t * 
 
420
deltify_etc (svn_revnum_t new_revision,
 
421
             const char *date,
 
422
             const char *author,
 
423
             void *baton)
 
424
{
 
425
  struct deltify_etc_baton *db = baton;
 
426
  svn_error_t *err1, *err2;
 
427
  apr_hash_index_t *hi;
 
428
  apr_pool_t *iterpool;
 
429
 
 
430
  /* Invoke the original callback first, in case someone's waiting to
 
431
     know the revision number so they can go off and annotate an
 
432
     issue or something. */
 
433
  err1 = (*db->callback) (new_revision, date, author, db->callback_baton);
 
434
 
 
435
  /* Maybe unlock the paths. */
 
436
  if (db->lock_tokens)
 
437
    {
 
438
      iterpool = svn_pool_create (db->pool);
 
439
      for (hi = apr_hash_first (db->pool, db->lock_tokens); hi;
 
440
           hi = apr_hash_next (hi))
 
441
        {
 
442
          const void *rel_path;
 
443
          void *val;
 
444
          const char *abs_path, *token;
 
445
 
 
446
          svn_pool_clear (iterpool);
 
447
          apr_hash_this (hi, &rel_path, NULL, &val);
 
448
          token = val;
 
449
          abs_path = svn_path_join (db->fs_path, rel_path, iterpool);
 
450
          /* We may get errors here if the lock was broken or stolen
 
451
             after the commit succeeded.  This is fine and should be
 
452
             ignored. */
 
453
          svn_error_clear (svn_repos_fs_unlock (db->repos, abs_path, token,
 
454
                                                FALSE, iterpool));
 
455
        }
 
456
      svn_pool_destroy (iterpool);
 
457
    }
 
458
 
 
459
  /* But, deltification shouldn't be stopped just because someone's
 
460
     random callback failed, so proceed unconditionally on to
 
461
     deltification. */
 
462
  err2 = svn_fs_deltify_revision (db->fs, new_revision, db->pool);
 
463
 
 
464
  /* It's more interesting if the original callback failed, so let
 
465
     that one dominate. */
 
466
  if (err1)
 
467
    {
 
468
      svn_error_clear (err2);
 
469
      return err1;
 
470
    }
 
471
 
 
472
  return err2;
 
473
}
 
474
 
 
475
 
 
476
static svn_error_t *
 
477
svn_ra_local__get_commit_editor (svn_ra_session_t *session,
 
478
                                 const svn_delta_editor_t **editor,
 
479
                                 void **edit_baton,
 
480
                                 const char *log_msg,
 
481
                                 svn_commit_callback_t callback,
 
482
                                 void *callback_baton,
 
483
                                 apr_hash_t *lock_tokens,
 
484
                                 svn_boolean_t keep_locks,
 
485
                                 apr_pool_t *pool)
 
486
{
 
487
  svn_ra_local__session_baton_t *sess_baton = session->priv;
 
488
  struct deltify_etc_baton *db = apr_palloc (pool, sizeof(*db));
 
489
  apr_hash_index_t *hi;
 
490
  svn_fs_access_t *fs_access;
 
491
 
 
492
  db->fs = sess_baton->fs;
 
493
  db->repos = sess_baton->repos;
 
494
  db->fs_path = sess_baton->fs_path;
 
495
  if (! keep_locks)
 
496
    db->lock_tokens = lock_tokens;
 
497
  else
 
498
    db->lock_tokens = NULL;
 
499
  db->pool = pool;
 
500
  db->callback = callback;
 
501
  db->callback_baton = callback_baton;
 
502
 
 
503
  SVN_ERR (get_username (session, pool));
 
504
 
 
505
  /* If there are lock tokens to add, do so. */
 
506
  if (lock_tokens)
 
507
    {
 
508
      SVN_ERR (svn_fs_get_access (&fs_access, sess_baton->fs));
 
509
 
 
510
      /* If there is no access context, the filesystem will scream if a
 
511
         lock is needed. */      
 
512
      if (fs_access)
 
513
        {
 
514
          for (hi = apr_hash_first (pool, lock_tokens); hi;
 
515
               hi = apr_hash_next (hi))
 
516
            {
 
517
              void *val;
 
518
              const char *token;
 
519
 
 
520
              apr_hash_this (hi, NULL, NULL, &val);
 
521
              token = val;
 
522
              SVN_ERR (svn_fs_access_add_lock_token (fs_access, token));
 
523
            }
 
524
        }
 
525
    }
 
526
              
 
527
  /* Get the repos commit-editor */     
 
528
  SVN_ERR (svn_repos_get_commit_editor2
 
529
           (editor, edit_baton, sess_baton->repos, NULL,
 
530
            svn_path_uri_decode (sess_baton->repos_url, pool),
 
531
            sess_baton->fs_path,
 
532
            sess_baton->username, log_msg,
 
533
            deltify_etc, db, pool));
 
534
 
 
535
  return SVN_NO_ERROR;
 
536
}
 
537
 
 
538
 
 
539
static svn_error_t *
 
540
make_reporter (svn_ra_session_t *session,
 
541
               const svn_ra_reporter2_t **reporter,
 
542
               void **report_baton,
 
543
               svn_revnum_t revision,
 
544
               const char *target,
 
545
               const char *other_url,
 
546
               svn_boolean_t text_deltas,
 
547
               svn_boolean_t recurse,
 
548
               svn_boolean_t ignore_ancestry,
 
549
               const svn_delta_editor_t *editor,
 
550
               void *edit_baton,
 
551
               apr_pool_t *pool)
 
552
{
 
553
  svn_ra_local__session_baton_t *sbaton = session->priv;
 
554
  void *rbaton;
 
555
  int repos_url_len;
 
556
  const char *other_fs_path = NULL;
 
557
  const char *repos_url_decoded;
 
558
 
 
559
  /* Get the HEAD revision if one is not supplied. */
 
560
  if (! SVN_IS_VALID_REVNUM(revision))
 
561
    SVN_ERR (svn_ra_local__get_latest_revnum (session, &revision, pool));
 
562
 
 
563
  /* If OTHER_URL was provided, validate it and convert it into a
 
564
     regular filesystem path. */
 
565
  if (other_url)
 
566
    {
 
567
      other_url = svn_path_uri_decode (other_url, pool);
 
568
      repos_url_decoded = svn_path_uri_decode (sbaton->repos_url, pool);
 
569
      repos_url_len = strlen(repos_url_decoded);
 
570
      
 
571
      /* Sanity check:  the other_url better be in the same repository as
 
572
         the original session url! */
 
573
      if (strncmp (other_url, repos_url_decoded, repos_url_len) != 0)
 
574
        return svn_error_createf 
 
575
          (SVN_ERR_RA_ILLEGAL_URL, NULL,
 
576
           _("'%s'\n"
 
577
             "is not the same repository as\n"
 
578
             "'%s'"), other_url, sbaton->repos_url);
 
579
 
 
580
      other_fs_path = other_url + repos_url_len;
 
581
    }
 
582
 
 
583
  /* Pass back our reporter */
 
584
  *reporter = &ra_local_reporter;
 
585
 
 
586
  SVN_ERR (get_username (session, pool));
 
587
  
 
588
  /* Build a reporter baton. */
 
589
  SVN_ERR (svn_repos_begin_report (&rbaton,
 
590
                                   revision,
 
591
                                   sbaton->username,
 
592
                                   sbaton->repos, 
 
593
                                   sbaton->fs_path,
 
594
                                   target, 
 
595
                                   other_fs_path,
 
596
                                   text_deltas,
 
597
                                   recurse,
 
598
                                   ignore_ancestry,
 
599
                                   editor, 
 
600
                                   edit_baton,
 
601
                                   NULL,
 
602
                                   NULL,
 
603
                                   pool));
 
604
  
 
605
  /* Wrap the report baton given us by the repos layer with our own
 
606
     reporter baton. */
 
607
  *report_baton = make_reporter_baton (sbaton, rbaton, pool);
 
608
 
 
609
  return SVN_NO_ERROR;
 
610
}
 
611
 
 
612
 
 
613
static svn_error_t *
 
614
svn_ra_local__do_update (svn_ra_session_t *session,
 
615
                         const svn_ra_reporter2_t **reporter,
 
616
                         void **report_baton,
 
617
                         svn_revnum_t update_revision,
 
618
                         const char *update_target,
 
619
                         svn_boolean_t recurse,
 
620
                         const svn_delta_editor_t *update_editor,
 
621
                         void *update_baton,
 
622
                         apr_pool_t *pool)
 
623
{
 
624
  return make_reporter (session,
 
625
                        reporter,
 
626
                        report_baton,
 
627
                        update_revision,
 
628
                        update_target,
 
629
                        NULL,
 
630
                        TRUE,
 
631
                        recurse,
 
632
                        FALSE,
 
633
                        update_editor,
 
634
                        update_baton,
 
635
                        pool);
 
636
}
 
637
 
 
638
 
 
639
static svn_error_t *
 
640
svn_ra_local__do_switch (svn_ra_session_t *session,
 
641
                         const svn_ra_reporter2_t **reporter,
 
642
                         void **report_baton,
 
643
                         svn_revnum_t update_revision,
 
644
                         const char *update_target,
 
645
                         svn_boolean_t recurse,
 
646
                         const char *switch_url,
 
647
                         const svn_delta_editor_t *update_editor,
 
648
                         void *update_baton,
 
649
                         apr_pool_t *pool)
 
650
{
 
651
  return make_reporter (session,
 
652
                        reporter,
 
653
                        report_baton,
 
654
                        update_revision,
 
655
                        update_target,
 
656
                        switch_url,
 
657
                        TRUE,
 
658
                        recurse,
 
659
                        TRUE,
 
660
                        update_editor,
 
661
                        update_baton,
 
662
                        pool);
 
663
}
 
664
 
 
665
 
 
666
static svn_error_t *
 
667
svn_ra_local__do_status (svn_ra_session_t *session,
 
668
                         const svn_ra_reporter2_t **reporter,
 
669
                         void **report_baton,
 
670
                         const char *status_target,
 
671
                         svn_revnum_t revision,
 
672
                         svn_boolean_t recurse,
 
673
                         const svn_delta_editor_t *status_editor,
 
674
                         void *status_baton,
 
675
                         apr_pool_t *pool)
 
676
{
 
677
  return make_reporter (session,
 
678
                        reporter,
 
679
                        report_baton,
 
680
                        revision,
 
681
                        status_target,
 
682
                        NULL,
 
683
                        FALSE,
 
684
                        recurse,
 
685
                        FALSE,
 
686
                        status_editor,
 
687
                        status_baton,
 
688
                        pool);
 
689
}
 
690
 
 
691
 
 
692
static svn_error_t *
 
693
svn_ra_local__do_diff (svn_ra_session_t *session,
 
694
                       const svn_ra_reporter2_t **reporter,
 
695
                       void **report_baton,
 
696
                       svn_revnum_t update_revision,
 
697
                       const char *update_target,
 
698
                       svn_boolean_t recurse,
 
699
                       svn_boolean_t ignore_ancestry,
 
700
                       const char *switch_url,
 
701
                       const svn_delta_editor_t *update_editor,
 
702
                       void *update_baton,
 
703
                       apr_pool_t *pool)
 
704
{
 
705
  return make_reporter (session,
 
706
                        reporter,
 
707
                        report_baton,
 
708
                        update_revision,
 
709
                        update_target,
 
710
                        switch_url,
 
711
                        TRUE,
 
712
                        recurse,
 
713
                        ignore_ancestry,
 
714
                        update_editor,
 
715
                        update_baton,
 
716
                        pool);
 
717
}
 
718
 
 
719
 
 
720
static svn_error_t *
 
721
svn_ra_local__get_log (svn_ra_session_t *session,
 
722
                       const apr_array_header_t *paths,
 
723
                       svn_revnum_t start,
 
724
                       svn_revnum_t end,
 
725
                       int limit,
 
726
                       svn_boolean_t discover_changed_paths,
 
727
                       svn_boolean_t strict_node_history,
 
728
                       svn_log_message_receiver_t receiver,
 
729
                       void *receiver_baton,
 
730
                       apr_pool_t *pool)
 
731
{
 
732
  svn_ra_local__session_baton_t *sbaton = session->priv;
 
733
  int i;
 
734
  apr_array_header_t *abs_paths =
 
735
    apr_array_make (pool, 0, sizeof (const char *));
 
736
 
 
737
  if (paths)
 
738
    {
 
739
      for (i = 0; i < paths->nelts; i++)
 
740
        {
 
741
          const char *abs_path = "";
 
742
          const char *relative_path = (((const char **)(paths)->elts)[i]);
 
743
          
 
744
          /* Append the relative paths to the base FS path to get an
 
745
             absolute repository path. */
 
746
          abs_path = svn_path_join (sbaton->fs_path, relative_path, pool);
 
747
          (*((const char **)(apr_array_push (abs_paths)))) = abs_path;
 
748
        }
 
749
    }
 
750
 
 
751
  return svn_repos_get_logs3 (sbaton->repos,
 
752
                              abs_paths,
 
753
                              start,
 
754
                              end,
 
755
                              limit,
 
756
                              discover_changed_paths,
 
757
                              strict_node_history,
 
758
                              NULL, NULL,
 
759
                              receiver,
 
760
                              receiver_baton,
 
761
                              pool);
 
762
}
 
763
 
 
764
 
 
765
static svn_error_t *
 
766
svn_ra_local__do_check_path (svn_ra_session_t *session,
 
767
                             const char *path,
 
768
                             svn_revnum_t revision,
 
769
                             svn_node_kind_t *kind,
 
770
                             apr_pool_t *pool)
 
771
{
 
772
  svn_ra_local__session_baton_t *sbaton = session->priv;
 
773
  svn_fs_root_t *root;
 
774
  const char *abs_path = sbaton->fs_path;
 
775
 
 
776
  /* ### Not sure if this counts as a workaround or not.  The
 
777
     session baton uses the empty string to mean root, and not
 
778
     sure that should change.  However, it would be better to use
 
779
     a path library function to add this separator -- hardcoding
 
780
     it is totally bogus.  See issue #559, though it may be only
 
781
     tangentially related. */
 
782
  if (abs_path[0] == '\0')
 
783
    abs_path = "/";
 
784
 
 
785
  /* If we were given a relative path to append, append it. */
 
786
  if (path)
 
787
    abs_path = svn_path_join (abs_path, path, pool);
 
788
 
 
789
  if (! SVN_IS_VALID_REVNUM (revision))
 
790
    SVN_ERR (svn_fs_youngest_rev (&revision, sbaton->fs, pool));
 
791
  SVN_ERR (svn_fs_revision_root (&root, sbaton->fs, revision, pool));
 
792
  SVN_ERR (svn_fs_check_path (kind, root, abs_path, pool));
 
793
  return SVN_NO_ERROR;
 
794
}
 
795
 
 
796
 
 
797
static svn_error_t *
 
798
svn_ra_local__stat (svn_ra_session_t *session,
 
799
                    const char *path,
 
800
                    svn_revnum_t revision,
 
801
                    svn_dirent_t **dirent,
 
802
                    apr_pool_t *pool)
 
803
{
 
804
  svn_ra_local__session_baton_t *sbaton = session->priv;
 
805
  svn_fs_root_t *root;
 
806
  const char *abs_path = sbaton->fs_path;
 
807
  
 
808
  /* ### see note above in __do_check_path() */
 
809
  if (abs_path[0] == '\0')
 
810
    abs_path = "/";
 
811
 
 
812
  if (path)
 
813
    abs_path = svn_path_join (abs_path, path, pool);
 
814
 
 
815
  if (! SVN_IS_VALID_REVNUM (revision))
 
816
    SVN_ERR (svn_fs_youngest_rev (&revision, sbaton->fs, pool));
 
817
  SVN_ERR (svn_fs_revision_root (&root, sbaton->fs, revision, pool));
 
818
 
 
819
  SVN_ERR (svn_repos_stat (dirent, root, abs_path, pool));
 
820
 
 
821
  return SVN_NO_ERROR;
 
822
}
 
823
 
 
824
 
 
825
 
 
826
 
 
827
static svn_error_t *
 
828
get_node_props (apr_hash_t **props,
 
829
                svn_ra_local__session_baton_t *sbaton,
 
830
                svn_fs_root_t *root,
 
831
                const char *path,
 
832
                apr_pool_t *pool)
 
833
{
 
834
  svn_revnum_t cmt_rev;
 
835
  const char *cmt_date, *cmt_author;
 
836
 
 
837
  /* Create a hash with props attached to the fs node. */
 
838
  SVN_ERR (svn_fs_node_proplist (props, root, path, pool));
 
839
      
 
840
  /* Now add some non-tweakable metadata to the hash as well... */
 
841
    
 
842
  /* The so-called 'entryprops' with info about CR & friends. */
 
843
  SVN_ERR (svn_repos_get_committed_info (&cmt_rev, &cmt_date,
 
844
                                         &cmt_author, root, path, pool));
 
845
 
 
846
  apr_hash_set (*props, 
 
847
                SVN_PROP_ENTRY_COMMITTED_REV, 
 
848
                APR_HASH_KEY_STRING, 
 
849
                svn_string_createf (pool, "%ld", cmt_rev));
 
850
  apr_hash_set (*props, 
 
851
                SVN_PROP_ENTRY_COMMITTED_DATE, 
 
852
                APR_HASH_KEY_STRING, 
 
853
                cmt_date ? svn_string_create (cmt_date, pool) : NULL);
 
854
  apr_hash_set (*props, 
 
855
                SVN_PROP_ENTRY_LAST_AUTHOR, 
 
856
                APR_HASH_KEY_STRING, 
 
857
                cmt_author ? svn_string_create (cmt_author, pool) : NULL);
 
858
  apr_hash_set (*props, 
 
859
                SVN_PROP_ENTRY_UUID,
 
860
                APR_HASH_KEY_STRING, 
 
861
                svn_string_create (sbaton->uuid, pool));
 
862
 
 
863
  /* We have no 'wcprops' in ra_local, but might someday. */
 
864
  
 
865
  return SVN_NO_ERROR;
 
866
}
 
867
 
 
868
 
 
869
/* Getting just one file. */
 
870
static svn_error_t *
 
871
svn_ra_local__get_file (svn_ra_session_t *session,
 
872
                        const char *path,
 
873
                        svn_revnum_t revision,
 
874
                        svn_stream_t *stream,
 
875
                        svn_revnum_t *fetched_rev,
 
876
                        apr_hash_t **props,
 
877
                        apr_pool_t *pool)
 
878
{
 
879
  svn_fs_root_t *root;
 
880
  svn_stream_t *contents;
 
881
  svn_revnum_t youngest_rev;
 
882
  svn_ra_local__session_baton_t *sbaton = session->priv;
 
883
  const char *abs_path = sbaton->fs_path;
 
884
 
 
885
  /* ### Not sure if this counts as a workaround or not.  The
 
886
     session baton uses the empty string to mean root, and not
 
887
     sure that should change.  However, it would be better to use
 
888
     a path library function to add this separator -- hardcoding
 
889
     it is totally bogus.  See issue #559, though it may be only
 
890
     tangentially related. */
 
891
  if (abs_path[0] == '\0')
 
892
    abs_path = "/";
 
893
 
 
894
  /* If we were given a relative path to append, append it. */
 
895
  if (path)
 
896
    abs_path = svn_path_join (abs_path, path, pool);
 
897
 
 
898
  /* Open the revision's root. */
 
899
  if (! SVN_IS_VALID_REVNUM (revision))
 
900
    {
 
901
      SVN_ERR (svn_fs_youngest_rev (&youngest_rev, sbaton->fs, pool));
 
902
      SVN_ERR (svn_fs_revision_root (&root, sbaton->fs, youngest_rev, pool));
 
903
      if (fetched_rev != NULL)
 
904
        *fetched_rev = youngest_rev;
 
905
    }
 
906
  else
 
907
    SVN_ERR (svn_fs_revision_root (&root, sbaton->fs, revision, pool));
 
908
 
 
909
  if (stream)
 
910
    {
 
911
      /* Get a stream representing the file's contents. */
 
912
      SVN_ERR (svn_fs_file_contents (&contents, root, abs_path, pool));
 
913
      
 
914
      /* Now push data from the fs stream back at the caller's stream.
 
915
         Note that this particular RA layer does not computing a
 
916
         checksum as we go, and confirming it against the repository's
 
917
         checksum when done.  That's because it calls
 
918
         svn_fs_file_contents() directly, which already checks the
 
919
         stored checksum, and all we're doing here is writing bytes in
 
920
         a loop.  Truly, Nothing Can Go Wrong :-).  But RA layers that
 
921
         go over a network should confirm the checksum. */
 
922
      SVN_ERR (svn_stream_copy (contents, stream, pool));
 
923
      SVN_ERR (svn_stream_close (contents));
 
924
    }
 
925
 
 
926
  /* Handle props if requested. */
 
927
  if (props)
 
928
    SVN_ERR (get_node_props (props, sbaton, root, abs_path, pool));
 
929
 
 
930
  return SVN_NO_ERROR;
 
931
}
 
932
 
 
933
 
 
934
 
 
935
/* Getting a directory's entries */
 
936
static svn_error_t *
 
937
svn_ra_local__get_dir (svn_ra_session_t *session,
 
938
                       const char *path,
 
939
                       svn_revnum_t revision,
 
940
                       apr_hash_t **dirents,
 
941
                       svn_revnum_t *fetched_rev,
 
942
                       apr_hash_t **props,
 
943
                       apr_pool_t *pool)
 
944
{
 
945
  svn_fs_root_t *root;
 
946
  svn_revnum_t youngest_rev;
 
947
  apr_hash_t *entries;
 
948
  apr_hash_index_t *hi;
 
949
  svn_ra_local__session_baton_t *sbaton = session->priv;
 
950
  const char *abs_path = sbaton->fs_path;
 
951
  apr_pool_t *subpool;
 
952
 
 
953
  /* ### Not sure if this counts as a workaround or not.  The
 
954
     session baton uses the empty string to mean root, and not
 
955
     sure that should change.  However, it would be better to use
 
956
     a path library function to add this separator -- hardcoding
 
957
     it is totally bogus.  See issue #559, though it may be only
 
958
     tangentially related. */
 
959
  if (abs_path[0] == '\0')
 
960
    abs_path = "/";
 
961
 
 
962
  /* If we were given a relative path to append, append it. */
 
963
  if (path)
 
964
    abs_path = svn_path_join (abs_path, path, pool);
 
965
 
 
966
  /* Open the revision's root. */
 
967
  if (! SVN_IS_VALID_REVNUM (revision))
 
968
    {
 
969
      SVN_ERR (svn_fs_youngest_rev (&youngest_rev, sbaton->fs, pool));
 
970
      SVN_ERR (svn_fs_revision_root (&root, sbaton->fs, youngest_rev, pool));
 
971
      if (fetched_rev != NULL)
 
972
        *fetched_rev = youngest_rev;
 
973
    }
 
974
  else
 
975
    SVN_ERR (svn_fs_revision_root (&root, sbaton->fs, revision, pool));
 
976
 
 
977
  if (dirents)
 
978
    {
 
979
      /* Get the dir's entries. */
 
980
      SVN_ERR (svn_fs_dir_entries (&entries, root, abs_path, pool));
 
981
      
 
982
      /* Loop over the fs dirents, and build a hash of general
 
983
         svn_dirent_t's. */
 
984
      *dirents = apr_hash_make (pool);
 
985
      subpool = svn_pool_create (pool);
 
986
      for (hi = apr_hash_first (pool, entries); hi; hi = apr_hash_next (hi))
 
987
        {
 
988
          const void *key;
 
989
          void *val;
 
990
          apr_hash_t *prophash;
 
991
          const char *datestring, *entryname, *fullpath;
 
992
          svn_fs_dirent_t *fs_entry;
 
993
          svn_dirent_t *entry = apr_pcalloc (pool, sizeof(*entry));
 
994
 
 
995
          svn_pool_clear (subpool);
 
996
 
 
997
          apr_hash_this (hi, &key, NULL, &val);
 
998
          entryname = (const char *) key;
 
999
          fs_entry = (svn_fs_dirent_t *) val;
 
1000
          
 
1001
          /* node kind */
 
1002
          fullpath = svn_path_join (abs_path, entryname, subpool);
 
1003
          entry->kind = fs_entry->kind;
 
1004
          
 
1005
          /* size  */
 
1006
          if (entry->kind == svn_node_dir)
 
1007
            entry->size = 0;
 
1008
          else
 
1009
            SVN_ERR (svn_fs_file_length (&(entry->size), root,
 
1010
                                         fullpath, subpool));
 
1011
          
 
1012
          /* has_props? */
 
1013
          SVN_ERR (svn_fs_node_proplist (&prophash, root, fullpath, subpool));
 
1014
          entry->has_props = (apr_hash_count (prophash)) ? TRUE : FALSE;
 
1015
          
 
1016
          /* created_rev & friends */
 
1017
          SVN_ERR (svn_repos_get_committed_info (&(entry->created_rev),
 
1018
                                                 &datestring,
 
1019
                                                 &(entry->last_author),
 
1020
                                                 root, fullpath, subpool));
 
1021
          if (datestring)
 
1022
            SVN_ERR (svn_time_from_cstring (&(entry->time), datestring, pool));
 
1023
          if (entry->last_author)
 
1024
            entry->last_author = apr_pstrdup (pool, entry->last_author);
 
1025
          
 
1026
          /* Store. */
 
1027
          apr_hash_set (*dirents, entryname, APR_HASH_KEY_STRING, entry);
 
1028
        }
 
1029
      svn_pool_destroy (subpool);
 
1030
    }
 
1031
 
 
1032
  /* Handle props if requested. */
 
1033
  if (props)
 
1034
    SVN_ERR (get_node_props (props, sbaton, root, abs_path, pool));
 
1035
 
 
1036
  return SVN_NO_ERROR;
 
1037
}
 
1038
 
 
1039
static svn_error_t *
 
1040
svn_ra_local__get_locations (svn_ra_session_t *session,
 
1041
                             apr_hash_t **locations,
 
1042
                             const char *relative_path,
 
1043
                             svn_revnum_t peg_revision,
 
1044
                             apr_array_header_t *location_revisions,
 
1045
                             apr_pool_t *pool)
 
1046
{
 
1047
  svn_ra_local__session_baton_t *sbaton = session->priv;
 
1048
  const char *abs_path;
 
1049
 
 
1050
  /* Append the relative path to the base FS path to get an
 
1051
     absolute repository path. */
 
1052
  abs_path = svn_path_join (sbaton->fs_path, relative_path, pool);
 
1053
 
 
1054
  SVN_ERR (svn_repos_trace_node_locations (sbaton->fs, locations, abs_path,
 
1055
                                           peg_revision, location_revisions,
 
1056
                                           NULL, NULL, pool));
 
1057
 
 
1058
  return SVN_NO_ERROR;
 
1059
}
 
1060
 
 
1061
 
 
1062
 
 
1063
static svn_error_t *
 
1064
svn_ra_local__lock (svn_ra_session_t *session,
 
1065
                    apr_hash_t *path_revs,
 
1066
                    const char *comment,
 
1067
                    svn_boolean_t force,
 
1068
                    svn_ra_lock_callback_t lock_func, 
 
1069
                    void *lock_baton,
 
1070
                    apr_pool_t *pool)
 
1071
{
 
1072
  svn_ra_local__session_baton_t *sess = session->priv;
 
1073
  apr_hash_index_t *hi;
 
1074
  apr_pool_t *iterpool = svn_pool_create (pool);
 
1075
 
 
1076
  /* A username is absolutely required to lock a path. */
 
1077
  SVN_ERR (get_username (session, pool));
 
1078
 
 
1079
  for (hi = apr_hash_first (pool, path_revs); hi; hi = apr_hash_next (hi))
 
1080
    {
 
1081
      svn_lock_t *lock;
 
1082
      const void *key;
 
1083
      const char *path;
 
1084
      void *val;
 
1085
      svn_revnum_t *revnum;
 
1086
      const char *abs_path;
 
1087
      svn_error_t *err, *callback_err = NULL;
 
1088
 
 
1089
      svn_pool_clear (iterpool);
 
1090
      apr_hash_this (hi, &key, NULL, &val);
 
1091
      path = key;
 
1092
      revnum = val;
 
1093
 
 
1094
      abs_path = svn_path_join (sess->fs_path, path, iterpool);
 
1095
 
 
1096
      /* This wrapper will call pre- and post-lock hooks. */
 
1097
      err = svn_repos_fs_lock (&lock, sess->repos, abs_path, NULL, comment, 0,
 
1098
                               0 /* no expiration */, *revnum, force, 
 
1099
                               iterpool);
 
1100
 
 
1101
      if (err && !SVN_ERR_IS_LOCK_ERROR (err))
 
1102
        return err;
 
1103
 
 
1104
      if (lock_func)
 
1105
        callback_err = lock_func (lock_baton, path, TRUE, err ? NULL : lock,
 
1106
                                  err, iterpool);
 
1107
 
 
1108
      svn_error_clear (err);
 
1109
 
 
1110
      if (callback_err)
 
1111
        return callback_err;
 
1112
    }
 
1113
 
 
1114
  svn_pool_destroy (iterpool);
 
1115
 
 
1116
  return SVN_NO_ERROR;
 
1117
}
 
1118
 
 
1119
 
 
1120
static svn_error_t *
 
1121
svn_ra_local__unlock (svn_ra_session_t *session,
 
1122
                      apr_hash_t *path_tokens,
 
1123
                      svn_boolean_t force,
 
1124
                      svn_ra_lock_callback_t lock_func, 
 
1125
                      void *lock_baton,
 
1126
                      apr_pool_t *pool)
 
1127
{
 
1128
  svn_ra_local__session_baton_t *sess = session->priv;
 
1129
  apr_hash_index_t *hi;
 
1130
  apr_pool_t *iterpool = svn_pool_create (pool);
 
1131
 
 
1132
  /* A username is absolutely required to unlock a path. */
 
1133
  SVN_ERR (get_username (session, pool));
 
1134
 
 
1135
  for (hi = apr_hash_first (pool, path_tokens); hi; hi = apr_hash_next (hi))
 
1136
    {
 
1137
      const void *key;
 
1138
      const char *path;
 
1139
      void *val;
 
1140
      const char *abs_path, *token;
 
1141
      svn_error_t *err, *callback_err = NULL;
 
1142
 
 
1143
      svn_pool_clear (iterpool);
 
1144
      apr_hash_this (hi, &key, NULL, &val);
 
1145
      path = key;
 
1146
      /* Since we can't store NULL values in a hash, we turn "" to
 
1147
         NULL here. */
 
1148
      if (strcmp (val, "") != 0)
 
1149
        token = val;
 
1150
      else
 
1151
        token = NULL;
 
1152
 
 
1153
      abs_path = svn_path_join (sess->fs_path, path, iterpool);
 
1154
 
 
1155
      /* This wrapper will call pre- and post-unlock hooks. */
 
1156
      err = svn_repos_fs_unlock (sess->repos, abs_path, token, force,
 
1157
                                 iterpool);
 
1158
 
 
1159
      if (err && !SVN_ERR_IS_UNLOCK_ERROR (err))
 
1160
        return err;
 
1161
 
 
1162
      if (lock_func)
 
1163
        callback_err = lock_func (lock_baton, path, FALSE, NULL, err, iterpool);
 
1164
 
 
1165
      svn_error_clear (err);
 
1166
 
 
1167
      if (callback_err)
 
1168
        return callback_err;
 
1169
    }
 
1170
 
 
1171
  svn_pool_destroy (iterpool);
 
1172
 
 
1173
  return SVN_NO_ERROR;
 
1174
}
 
1175
 
 
1176
 
 
1177
 
 
1178
static svn_error_t *
 
1179
svn_ra_local__get_lock (svn_ra_session_t *session,
 
1180
                        svn_lock_t **lock,
 
1181
                        const char *path,
 
1182
                        apr_pool_t *pool)
 
1183
{
 
1184
  svn_ra_local__session_baton_t *sess = session->priv;
 
1185
  const char *abs_path;
 
1186
 
 
1187
  /* Get the absolute path. */
 
1188
  abs_path = svn_path_join (sess->fs_path, path, pool);
 
1189
 
 
1190
  SVN_ERR (svn_fs_get_lock (lock, sess->fs, abs_path, pool));
 
1191
 
 
1192
  return SVN_NO_ERROR;
 
1193
}
 
1194
 
 
1195
 
 
1196
 
 
1197
static svn_error_t *
 
1198
svn_ra_local__get_locks (svn_ra_session_t *session,
 
1199
                         apr_hash_t **locks,
 
1200
                         const char *path,
 
1201
                         apr_pool_t *pool)
 
1202
{
 
1203
  svn_ra_local__session_baton_t *sess = session->priv;
 
1204
  const char *abs_path;
 
1205
 
 
1206
  /* Get the absolute path. */
 
1207
  abs_path = svn_path_join (sess->fs_path, path, pool);
 
1208
 
 
1209
  /* Kinda silly to call the repos wrapper, since we have no authz
 
1210
     func to give it.  But heck, why not. */
 
1211
  SVN_ERR (svn_repos_fs_get_locks (locks, sess->repos, abs_path,
 
1212
                                   NULL, NULL, pool));
 
1213
 
 
1214
  return SVN_NO_ERROR;
 
1215
}
 
1216
 
 
1217
 
 
1218
 
 
1219
 
 
1220
/*----------------------------------------------------------------*/
 
1221
 
 
1222
static const svn_version_t *
 
1223
ra_local_version (void)
 
1224
{
 
1225
  SVN_VERSION_BODY;
 
1226
}
 
1227
 
 
1228
/** The ra_vtable **/
 
1229
 
 
1230
static const svn_ra__vtable_t ra_local_vtable =
 
1231
{
 
1232
  ra_local_version,
 
1233
  svn_ra_local__get_description,
 
1234
  svn_ra_local__get_schemes,
 
1235
  svn_ra_local__open,
 
1236
  svn_ra_local__get_latest_revnum,
 
1237
  svn_ra_local__get_dated_revision,
 
1238
  svn_ra_local__change_rev_prop,
 
1239
  svn_ra_local__rev_proplist,
 
1240
  svn_ra_local__rev_prop,
 
1241
  svn_ra_local__get_commit_editor,
 
1242
  svn_ra_local__get_file,
 
1243
  svn_ra_local__get_dir,
 
1244
  svn_ra_local__do_update,
 
1245
  svn_ra_local__do_switch,
 
1246
  svn_ra_local__do_status,
 
1247
  svn_ra_local__do_diff,
 
1248
  svn_ra_local__get_log,
 
1249
  svn_ra_local__do_check_path,
 
1250
  svn_ra_local__stat,
 
1251
  svn_ra_local__get_uuid,
 
1252
  svn_ra_local__get_repos_root,
 
1253
  svn_ra_local__get_locations,
 
1254
  svn_ra_local__get_file_revs,
 
1255
  svn_ra_local__lock,
 
1256
  svn_ra_local__unlock,
 
1257
  svn_ra_local__get_lock,
 
1258
  svn_ra_local__get_locks,
 
1259
};
 
1260
 
 
1261
 
 
1262
/*----------------------------------------------------------------*/
 
1263
 
 
1264
/** The One Public Routine, called by libsvn_ra **/
 
1265
 
 
1266
svn_error_t *
 
1267
svn_ra_local__init (const svn_version_t *loader_version,
 
1268
                    const svn_ra__vtable_t **vtable,
 
1269
                    apr_pool_t *pool)
 
1270
{
 
1271
  static const svn_version_checklist_t checklist[] =
 
1272
    {
 
1273
      { "svn_subr",  svn_subr_version },
 
1274
      { "svn_delta", svn_delta_version },
 
1275
      { "svn_repos", svn_repos_version },
 
1276
      { "svn_fs",    svn_fs_version },
 
1277
      { NULL, NULL }
 
1278
    };
 
1279
 
 
1280
  
 
1281
  /* Simplified version check to make sure we can safely use the
 
1282
     VTABLE parameter. The RA loader does a more exhaustive check. */
 
1283
  if (loader_version->major != SVN_VER_MAJOR)
 
1284
    return svn_error_createf (SVN_ERR_VERSION_MISMATCH, NULL,
 
1285
                              _("Unsupported RA loader version (%d) for "
 
1286
                                "ra_local"),
 
1287
                              loader_version->major);
 
1288
 
 
1289
  SVN_ERR (svn_ver_check_list (ra_local_version(), checklist));
 
1290
 
 
1291
#ifndef SVN_LIBSVN_CLIENT_LINKS_RA_LOCAL
 
1292
  /* This assumes that POOL was the pool used to load the dso. */
 
1293
  SVN_ERR (svn_fs_initialize (pool));
 
1294
#endif
 
1295
 
 
1296
  *vtable = &ra_local_vtable;
 
1297
 
 
1298
  return SVN_NO_ERROR;
 
1299
}
 
1300
 
 
1301
/* Compatibility wrapper for the 1.1 and before API. */
 
1302
#define NAME "ra_local"
 
1303
#define DESCRIPTION RA_LOCAL_DESCRIPTION
 
1304
#define VTBL ra_local_vtable
 
1305
#define INITFUNC svn_ra_local__init
 
1306
#define COMPAT_INITFUNC svn_ra_local_init
 
1307
#include "../libsvn_ra/wrapper_template.h"