~ubuntu-branches/debian/sid/subversion/sid

« back to all changes in this revision

Viewing changes to subversion/libsvn_fs_fs/fs.c

  • Committer: Package Import Robot
  • Author(s): James McCoy
  • Date: 2015-08-07 21:32:47 UTC
  • mfrom: (0.2.15) (4.1.7 experimental)
  • Revision ID: package-import@ubuntu.com-20150807213247-ozyewtmgsr6tkewl
Tags: 1.9.0-1
* Upload to unstable
* New upstream release.
  + Security fixes
    - CVE-2015-3184: Mixed anonymous/authenticated path-based authz with
      httpd 2.4
    - CVE-2015-3187: svn_repos_trace_node_locations() reveals paths hidden
      by authz
* Add >= 2.7 requirement for python-all-dev Build-Depends, needed to run
  tests.
* Remove Build-Conflicts against ruby-test-unit.  (Closes: #791844)
* Remove patches/apache_module_dependency in favor of expressing the
  dependencies in authz_svn.load/dav_svn.load.
* Build-Depend on apache2-dev (>= 2.4.16) to ensure ap_some_authn_required()
  is available when building mod_authz_svn and Depend on apache2-bin (>=
  2.4.16) for runtime support.

Show diffs side-by-side

added added

removed removed

Lines of Context:
37
37
#include "fs_fs.h"
38
38
#include "tree.h"
39
39
#include "lock.h"
 
40
#include "hotcopy.h"
40
41
#include "id.h"
 
42
#include "pack.h"
 
43
#include "recovery.h"
41
44
#include "rep-cache.h"
 
45
#include "revprops.h"
 
46
#include "transaction.h"
 
47
#include "util.h"
 
48
#include "verify.h"
42
49
#include "svn_private_config.h"
43
50
#include "private/svn_fs_util.h"
44
 
#include "private/svn_subr_private.h"
45
51
 
46
52
#include "../libsvn_fs/fs-loader.h"
47
53
 
51
57
 
52
58
 
53
59
 
 
60
/* Initialize the part of FS that requires global serialization across all
 
61
   instances.  The caller is responsible of ensuring that serialization.
 
62
   Use COMMON_POOL for process-wide and POOL for temporary allocations. */
54
63
static svn_error_t *
55
64
fs_serialized_init(svn_fs_t *fs, apr_pool_t *common_pool, apr_pool_t *pool)
56
65
{
64
73
     each separate repository opened during the lifetime of the
65
74
     svn_fs_initialize pool.  It's unlikely that anyone will notice
66
75
     the modest expenditure; the alternative is to allocate each structure
67
 
     in a subpool, add a reference-count, and add a serialized deconstructor
 
76
     in a subpool, add a reference-count, and add a serialized destructor
68
77
     to the FS vtable.  That's more machinery than it's worth.
69
78
 
70
 
     Using the uuid to obtain the lock creates a corner case if a
71
 
     caller uses svn_fs_set_uuid on the repository in a process where
72
 
     other threads might be using the same repository through another
73
 
     FS object.  The only real-world consumer of svn_fs_set_uuid is
74
 
     "svnadmin load", so this is a low-priority problem, and we don't
75
 
     know of a better way of associating such data with the
76
 
     repository. */
 
79
     Picking an appropriate key for the shared data is tricky, because,
 
80
     unfortunately, a filesystem UUID is not really unique.  It is implicitly
 
81
     shared between hotcopied (1), dump / loaded (2) or naively copied (3)
 
82
     filesystems.  We tackle this problem by using a combination of the UUID
 
83
     and an instance ID as the key.  This allows us to avoid key clashing
 
84
     in (1) and (2) for formats >= SVN_FS_FS__MIN_INSTANCE_ID_FORMAT, which
 
85
     do support instance IDs.  For old formats the shared data (locks, shared
 
86
     transaction data, ...) will still clash.
 
87
 
 
88
     Speaking of (3), there is not so much we can do about it, except maybe
 
89
     provide a convenient way of fixing things.  Naively copied filesystems
 
90
     have identical filesystem UUIDs *and* instance IDs.  With the key being
 
91
     a combination of these two, clashes can be fixed by changing either of
 
92
     them (or both), e.g. with svn_fs_set_uuid(). */
77
93
 
78
94
  SVN_ERR_ASSERT(fs->uuid);
79
 
  key = apr_pstrcat(pool, SVN_FSFS_SHARED_USERDATA_PREFIX, fs->uuid,
80
 
                    (char *) NULL);
 
95
  SVN_ERR_ASSERT(ffd->instance_id);
 
96
 
 
97
  key = apr_pstrcat(pool, SVN_FSFS_SHARED_USERDATA_PREFIX,
 
98
                    fs->uuid, ":", ffd->instance_id, SVN_VA_NULL);
81
99
  status = apr_pool_userdata_get(&val, key, common_pool);
82
100
  if (status)
83
101
    return svn_error_wrap_apr(status, _("Can't fetch FSFS shared data"));
94
112
      SVN_ERR(svn_mutex__init(&ffsd->fs_write_lock,
95
113
                              SVN_FS_FS__USE_LOCK_MUTEX, common_pool));
96
114
 
 
115
      /* ... the pack lock ... */
 
116
      SVN_ERR(svn_mutex__init(&ffsd->fs_pack_lock,
 
117
                              SVN_FS_FS__USE_LOCK_MUTEX, common_pool));
 
118
 
97
119
      /* ... not to mention locking the txn-current file. */
98
120
      SVN_ERR(svn_mutex__init(&ffsd->txn_current_lock,
99
121
                              SVN_FS_FS__USE_LOCK_MUTEX, common_pool));
100
122
 
101
123
      /* We also need a mutex for synchronizing access to the active
102
 
         transaction list and free transaction pointer.  This one is
103
 
         enabled unconditionally. */
104
 
      SVN_ERR(svn_mutex__init(&ffsd->txn_list_lock,
105
 
                              TRUE, common_pool));
 
124
         transaction list and free transaction pointer. */
 
125
      SVN_ERR(svn_mutex__init(&ffsd->txn_list_lock, TRUE, common_pool));
106
126
 
107
127
      key = apr_pstrdup(common_pool, key);
108
128
      status = apr_pool_userdata_set(ffsd, key, NULL, common_pool);
143
163
 
144
164
  SVN_ERR(svn_fs_fs__exists_rep_cache(&exists, b->fs, pool));
145
165
  if (exists)
146
 
    SVN_ERR(svn_fs_fs__lock_rep_cache(b->fs, pool));
147
 
 
148
 
  SVN_ERR(b->freeze_func(b->freeze_baton, pool));
 
166
    SVN_ERR(svn_fs_fs__with_rep_cache_lock(b->fs,
 
167
                                           b->freeze_func, b->freeze_baton,
 
168
                                           pool));
 
169
  else
 
170
    SVN_ERR(b->freeze_func(b->freeze_baton, pool));
 
171
 
 
172
  return SVN_NO_ERROR;
 
173
}
 
174
 
 
175
static svn_error_t *
 
176
fs_freeze_body2(void *baton,
 
177
                apr_pool_t *pool)
 
178
{
 
179
  struct fs_freeze_baton_t *b = baton;
 
180
  SVN_ERR(svn_fs_fs__with_write_lock(b->fs, fs_freeze_body, baton, pool));
149
181
 
150
182
  return SVN_NO_ERROR;
151
183
}
156
188
          void *freeze_baton,
157
189
          apr_pool_t *pool)
158
190
{
 
191
  fs_fs_data_t *ffd = fs->fsap_data;
159
192
  struct fs_freeze_baton_t b;
160
193
 
161
194
  b.fs = fs;
163
196
  b.freeze_baton = freeze_baton;
164
197
 
165
198
  SVN_ERR(svn_fs__check_fs(fs, TRUE));
166
 
  SVN_ERR(svn_fs_fs__with_write_lock(fs, fs_freeze_body, &b, pool));
167
 
 
168
 
  return SVN_NO_ERROR;
 
199
 
 
200
  if (ffd->format >= SVN_FS_FS__MIN_PACK_LOCK_FORMAT)
 
201
    SVN_ERR(svn_fs_fs__with_pack_lock(fs, fs_freeze_body2, &b, pool));
 
202
  else
 
203
    SVN_ERR(fs_freeze_body2(&b, pool));
 
204
 
 
205
  return SVN_NO_ERROR;
 
206
}
 
207
 
 
208
static svn_error_t *
 
209
fs_info(const void **fsfs_info,
 
210
        svn_fs_t *fs,
 
211
        apr_pool_t *result_pool,
 
212
        apr_pool_t *scratch_pool)
 
213
{
 
214
  fs_fs_data_t *ffd = fs->fsap_data;
 
215
  svn_fs_fsfs_info_t *info = apr_palloc(result_pool, sizeof(*info));
 
216
  info->fs_type = SVN_FS_TYPE_FSFS;
 
217
  info->shard_size = ffd->max_files_per_dir;
 
218
  info->min_unpacked_rev = ffd->min_unpacked_rev;
 
219
  info->log_addressing = ffd->use_log_addressing;
 
220
  *fsfs_info = info;
 
221
  return SVN_NO_ERROR;
 
222
}
 
223
 
 
224
/* Wrapper around svn_fs_fs__set_uuid() adapting between function
 
225
   signatures. */
 
226
static svn_error_t *
 
227
fs_set_uuid(svn_fs_t *fs,
 
228
            const char *uuid,
 
229
            apr_pool_t *pool)
 
230
{
 
231
  /* Whenever we set a new UUID, imply that FS will also be a different
 
232
   * instance (on formats that support this). */
 
233
  return svn_error_trace(svn_fs_fs__set_uuid(fs, uuid, NULL, pool));
169
234
}
170
235
 
171
236
 
174
239
static fs_vtable_t fs_vtable = {
175
240
  svn_fs_fs__youngest_rev,
176
241
  svn_fs_fs__revision_prop,
177
 
  svn_fs_fs__revision_proplist,
 
242
  svn_fs_fs__get_revision_proplist,
178
243
  svn_fs_fs__change_rev_prop,
179
 
  svn_fs_fs__set_uuid,
 
244
  fs_set_uuid,
180
245
  svn_fs_fs__revision_root,
181
246
  svn_fs_fs__begin_txn,
182
247
  svn_fs_fs__open_txn,
188
253
  svn_fs_fs__unlock,
189
254
  svn_fs_fs__get_lock,
190
255
  svn_fs_fs__get_locks,
 
256
  svn_fs_fs__info_format,
 
257
  svn_fs_fs__info_config_files,
 
258
  fs_info,
191
259
  svn_fs_fs__verify_root,
192
260
  fs_freeze,
193
261
  fs_set_errcall
201
269
initialize_fs_struct(svn_fs_t *fs)
202
270
{
203
271
  fs_fs_data_t *ffd = apr_pcalloc(fs->pool, sizeof(*ffd));
 
272
  ffd->use_log_addressing = FALSE;
 
273
 
204
274
  fs->vtable = &fs_vtable;
205
275
  fs->fsap_data = ffd;
206
276
  return SVN_NO_ERROR;
207
277
}
208
278
 
 
279
/* Reset vtable and fsap_data fields in FS such that the FS is basically
 
280
 * closed now.  Note that FS must not hold locks when you call this. */
 
281
static void
 
282
uninitialize_fs_struct(svn_fs_t *fs)
 
283
{
 
284
  fs->vtable = NULL;
 
285
  fs->fsap_data = NULL;
 
286
}
 
287
 
209
288
/* This implements the fs_library_vtable_t.create() API.  Create a new
210
289
   fsfs-backed Subversion filesystem at path PATH and link it into
211
290
   *FS.  Perform temporary allocations in POOL, and fs-global allocations
212
 
   in COMMON_POOL. */
 
291
   in COMMON_POOL.  The latter must be serialized using COMMON_POOL_LOCK. */
213
292
static svn_error_t *
214
 
fs_create(svn_fs_t *fs, const char *path, apr_pool_t *pool,
 
293
fs_create(svn_fs_t *fs,
 
294
          const char *path,
 
295
          svn_mutex__t *common_pool_lock,
 
296
          apr_pool_t *pool,
215
297
          apr_pool_t *common_pool)
216
298
{
217
299
  SVN_ERR(svn_fs__check_fs(fs, FALSE));
221
303
  SVN_ERR(svn_fs_fs__create(fs, path, pool));
222
304
 
223
305
  SVN_ERR(svn_fs_fs__initialize_caches(fs, pool));
224
 
  return fs_serialized_init(fs, common_pool, pool);
 
306
  SVN_MUTEX__WITH_LOCK(common_pool_lock,
 
307
                       fs_serialized_init(fs, common_pool, pool));
 
308
 
 
309
  return SVN_NO_ERROR;
225
310
}
226
311
 
227
312
 
231
316
/* This implements the fs_library_vtable_t.open() API.  Open an FSFS
232
317
   Subversion filesystem located at PATH, set *FS to point to the
233
318
   correct vtable for the filesystem.  Use POOL for any temporary
234
 
   allocations, and COMMON_POOL for fs-global allocations. */
 
319
   allocations, and COMMON_POOL for fs-global allocations.
 
320
   The latter must be serialized using COMMON_POOL_LOCK. */
235
321
static svn_error_t *
236
 
fs_open(svn_fs_t *fs, const char *path, apr_pool_t *pool,
 
322
fs_open(svn_fs_t *fs,
 
323
        const char *path,
 
324
        svn_mutex__t *common_pool_lock,
 
325
        apr_pool_t *pool,
237
326
        apr_pool_t *common_pool)
238
327
{
 
328
  apr_pool_t *subpool = svn_pool_create(pool);
 
329
 
 
330
  SVN_ERR(svn_fs__check_fs(fs, FALSE));
 
331
 
239
332
  SVN_ERR(initialize_fs_struct(fs));
240
333
 
241
 
  SVN_ERR(svn_fs_fs__open(fs, path, pool));
242
 
 
243
 
  SVN_ERR(svn_fs_fs__initialize_caches(fs, pool));
244
 
  return fs_serialized_init(fs, common_pool, pool);
 
334
  SVN_ERR(svn_fs_fs__open(fs, path, subpool));
 
335
 
 
336
  SVN_ERR(svn_fs_fs__initialize_caches(fs, subpool));
 
337
  SVN_MUTEX__WITH_LOCK(common_pool_lock,
 
338
                       fs_serialized_init(fs, common_pool, subpool));
 
339
 
 
340
  svn_pool_destroy(subpool);
 
341
 
 
342
  return SVN_NO_ERROR;
245
343
}
246
344
 
247
345
 
250
348
static svn_error_t *
251
349
fs_open_for_recovery(svn_fs_t *fs,
252
350
                     const char *path,
253
 
                     apr_pool_t *pool, apr_pool_t *common_pool)
 
351
                     svn_mutex__t *common_pool_lock,
 
352
                     apr_pool_t *pool,
 
353
                     apr_pool_t *common_pool)
254
354
{
 
355
  svn_error_t * err;
 
356
  svn_revnum_t youngest_rev;
 
357
  apr_pool_t * subpool = svn_pool_create(pool);
 
358
 
255
359
  /* Recovery for FSFS is currently limited to recreating the 'current'
256
360
     file from the latest revision. */
257
361
 
258
362
  /* The only thing we have to watch out for is that the 'current' file
259
 
     might not exist.  So we'll try to create it here unconditionally,
260
 
     and just ignore any errors that might indicate that it's already
261
 
     present. (We'll need it to exist later anyway as a source for the
262
 
     new file's permissions). */
 
363
     might not exist or contain garbage.  So we'll try to read it here
 
364
     and provide or replace the existing file if we couldn't read it.
 
365
     (We'll also need it to exist later anyway as a source for the new
 
366
     file's permissions). */
263
367
 
264
 
  /* Use a partly-filled fs pointer first to create 'current'.  This will fail
265
 
     if 'current' already exists, but we don't care about that. */
 
368
  /* Use a partly-filled fs pointer first to create 'current'. */
266
369
  fs->path = apr_pstrdup(fs->pool, path);
267
 
  svn_error_clear(svn_io_file_create(svn_fs_fs__path_current(fs, pool),
268
 
                                     "0 1 1\n", pool));
 
370
 
 
371
  SVN_ERR(initialize_fs_struct(fs));
 
372
 
 
373
  /* Figure out the repo format and check that we can even handle it. */
 
374
  SVN_ERR(svn_fs_fs__read_format_file(fs, subpool));
 
375
 
 
376
  /* Now, read 'current' and try to patch it if necessary. */
 
377
  err = svn_fs_fs__youngest_rev(&youngest_rev, fs, subpool);
 
378
  if (err)
 
379
    {
 
380
      const char *file_path;
 
381
 
 
382
      /* 'current' file is missing or contains garbage.  Since we are trying
 
383
       * to recover from whatever problem there is, being picky about the
 
384
       * error code here won't do us much good.  If there is a persistent
 
385
       * problem that we can't fix, it will show up when we try rewrite the
 
386
       * file a few lines further below and we will report the failure back
 
387
       * to the caller.
 
388
       *
 
389
       * Start recovery with HEAD = 0. */
 
390
      svn_error_clear(err);
 
391
      file_path = svn_fs_fs__path_current(fs, subpool);
 
392
 
 
393
      /* Best effort to ensure the file exists and is valid.
 
394
       * This may fail for r/o filesystems etc. */
 
395
      SVN_ERR(svn_io_remove_file2(file_path, TRUE, subpool));
 
396
      SVN_ERR(svn_io_file_create_empty(file_path, subpool));
 
397
      SVN_ERR(svn_fs_fs__write_current(fs, 0, 1, 1, subpool));
 
398
    }
 
399
 
 
400
  uninitialize_fs_struct(fs);
 
401
  svn_pool_destroy(subpool);
269
402
 
270
403
  /* Now open the filesystem properly by calling the vtable method directly. */
271
 
  return fs_open(fs, path, pool, common_pool);
 
404
  return fs_open(fs, path, common_pool_lock, pool, common_pool);
272
405
}
273
406
 
274
407
 
275
408
 
276
409
/* This implements the fs_library_vtable_t.upgrade_fs() API. */
277
410
static svn_error_t *
278
 
fs_upgrade(svn_fs_t *fs, const char *path, apr_pool_t *pool,
 
411
fs_upgrade(svn_fs_t *fs,
 
412
           const char *path,
 
413
           svn_fs_upgrade_notify_t notify_func,
 
414
           void *notify_baton,
 
415
           svn_cancel_func_t cancel_func,
 
416
           void *cancel_baton,
 
417
           svn_mutex__t *common_pool_lock,
 
418
           apr_pool_t *pool,
279
419
           apr_pool_t *common_pool)
280
420
{
281
 
  SVN_ERR(svn_fs__check_fs(fs, FALSE));
282
 
  SVN_ERR(initialize_fs_struct(fs));
283
 
  SVN_ERR(svn_fs_fs__open(fs, path, pool));
284
 
  SVN_ERR(svn_fs_fs__initialize_caches(fs, pool));
285
 
  SVN_ERR(fs_serialized_init(fs, common_pool, pool));
286
 
  return svn_fs_fs__upgrade(fs, pool);
 
421
  SVN_ERR(fs_open(fs, path, common_pool_lock, pool, common_pool));
 
422
  return svn_fs_fs__upgrade(fs, notify_func, notify_baton,
 
423
                            cancel_func, cancel_baton, pool);
287
424
}
288
425
 
289
426
static svn_error_t *
294
431
          void *notify_baton,
295
432
          svn_cancel_func_t cancel_func,
296
433
          void *cancel_baton,
 
434
          svn_mutex__t *common_pool_lock,
297
435
          apr_pool_t *pool,
298
436
          apr_pool_t *common_pool)
299
437
{
300
 
  SVN_ERR(svn_fs__check_fs(fs, FALSE));
301
 
  SVN_ERR(initialize_fs_struct(fs));
302
 
  SVN_ERR(svn_fs_fs__open(fs, path, pool));
303
 
  SVN_ERR(svn_fs_fs__initialize_caches(fs, pool));
304
 
  SVN_ERR(fs_serialized_init(fs, common_pool, pool));
 
438
  SVN_ERR(fs_open(fs, path, common_pool_lock, pool, common_pool));
305
439
  return svn_fs_fs__verify(fs, start, end, notify_func, notify_baton,
306
440
                           cancel_func, cancel_baton, pool);
307
441
}
313
447
        void *notify_baton,
314
448
        svn_cancel_func_t cancel_func,
315
449
        void *cancel_baton,
 
450
        svn_mutex__t *common_pool_lock,
316
451
        apr_pool_t *pool,
317
452
        apr_pool_t *common_pool)
318
453
{
319
 
  SVN_ERR(svn_fs__check_fs(fs, FALSE));
320
 
  SVN_ERR(initialize_fs_struct(fs));
321
 
  SVN_ERR(svn_fs_fs__open(fs, path, pool));
322
 
  SVN_ERR(svn_fs_fs__initialize_caches(fs, pool));
323
 
  SVN_ERR(fs_serialized_init(fs, common_pool, pool));
 
454
  SVN_ERR(fs_open(fs, path, common_pool_lock, pool, common_pool));
324
455
  return svn_fs_fs__pack(fs, notify_func, notify_baton,
325
456
                         cancel_func, cancel_baton, pool);
326
457
}
333
464
   DST_FS at DEST_PATH. If INCREMENTAL is TRUE, make an effort not to
334
465
   re-copy data which already exists in DST_FS.
335
466
   The CLEAN_LOGS argument is ignored and included for Subversion
336
 
   1.0.x compatibility.  Perform all temporary allocations in POOL. */
 
467
   1.0.x compatibility.  Indicate progress via the optional NOTIFY_FUNC
 
468
   callback using NOTIFY_BATON.  Perform all temporary allocations in POOL. */
337
469
static svn_error_t *
338
470
fs_hotcopy(svn_fs_t *src_fs,
339
471
           svn_fs_t *dst_fs,
341
473
           const char *dst_path,
342
474
           svn_boolean_t clean_logs,
343
475
           svn_boolean_t incremental,
 
476
           svn_fs_hotcopy_notify_t notify_func,
 
477
           void *notify_baton,
344
478
           svn_cancel_func_t cancel_func,
345
479
           void *cancel_baton,
346
 
           apr_pool_t *pool)
 
480
           svn_mutex__t *common_pool_lock,
 
481
           apr_pool_t *pool,
 
482
           apr_pool_t *common_pool)
347
483
{
348
 
  SVN_ERR(svn_fs__check_fs(src_fs, FALSE));
349
 
  SVN_ERR(initialize_fs_struct(src_fs));
350
 
  SVN_ERR(svn_fs_fs__open(src_fs, src_path, pool));
351
 
  SVN_ERR(svn_fs_fs__initialize_caches(src_fs, pool));
352
 
  SVN_ERR(fs_serialized_init(src_fs, pool, pool));
 
484
  /* Open the source repo as usual. */
 
485
  SVN_ERR(fs_open(src_fs, src_path, common_pool_lock, pool, common_pool));
 
486
  if (cancel_func)
 
487
    SVN_ERR(cancel_func(cancel_baton));
353
488
 
354
 
  SVN_ERR(svn_fs__check_fs(dst_fs, FALSE));
 
489
  /* Test target repo when in INCREMENTAL mode, initialize it when not.
 
490
   * For this, we need our FS internal data structures to be temporarily
 
491
   * available. */
355
492
  SVN_ERR(initialize_fs_struct(dst_fs));
356
 
  /* In INCREMENTAL mode, svn_fs_fs__hotcopy() will open DST_FS.
357
 
     Otherwise, it's not an FS yet --- possibly just an empty dir --- so
358
 
     can't be opened.
359
 
   */
360
 
  return svn_fs_fs__hotcopy(src_fs, dst_fs, src_path, dst_path,
361
 
                            incremental, cancel_func, cancel_baton, pool);
 
493
  SVN_ERR(svn_fs_fs__hotcopy_prepare_target(src_fs, dst_fs, dst_path,
 
494
                                            incremental, pool));
 
495
  uninitialize_fs_struct(dst_fs);
 
496
 
 
497
  /* Now, the destination repo should open just fine. */
 
498
  SVN_ERR(fs_open(dst_fs, dst_path, common_pool_lock, pool, common_pool));
 
499
  if (cancel_func)
 
500
    SVN_ERR(cancel_func(cancel_baton));
 
501
 
 
502
  /* Now, we may copy data as needed ... */
 
503
  return svn_fs_fs__hotcopy(src_fs, dst_fs, incremental,
 
504
                            notify_func, notify_baton,
 
505
                            cancel_func, cancel_baton, pool);
362
506
}
363
507
 
364
508
 
389
533
             apr_pool_t *pool)
390
534
{
391
535
  /* Remove everything. */
392
 
  return svn_io_remove_dir2(path, FALSE, NULL, NULL, pool);
 
536
  return svn_error_trace(svn_io_remove_dir2(path, FALSE, NULL, NULL, pool));
393
537
}
394
538
 
395
539
static const svn_version_t *
409
553
                   svn_error_t *(*svn_fs_open_)(svn_fs_t **,
410
554
                                                const char *,
411
555
                                                apr_hash_t *,
 
556
                                                apr_pool_t *,
412
557
                                                apr_pool_t *))
413
558
{
414
559
  fs_fs_data_t *ffd = fs->fsap_data;
416
561
  return SVN_NO_ERROR;
417
562
}
418
563
 
 
564
static void *
 
565
fs_info_dup(const void *fsfs_info_void,
 
566
            apr_pool_t *result_pool)
 
567
{
 
568
  /* All fields are either ints or static strings. */
 
569
  const svn_fs_fsfs_info_t *fsfs_info = fsfs_info_void;
 
570
  return apr_pmemdup(result_pool, fsfs_info, sizeof(*fsfs_info));
 
571
}
 
572
 
419
573
 
420
574
/* Base FS library vtable, used by the FS loader library. */
421
575
 
433
587
  fs_pack,
434
588
  fs_logfiles,
435
589
  NULL /* parse_id */,
436
 
  fs_set_svn_fs_open
 
590
  fs_set_svn_fs_open,
 
591
  fs_info_dup
437
592
};
438
593
 
439
594
svn_error_t *
444
599
    {
445
600
      { "svn_subr",  svn_subr_version },
446
601
      { "svn_delta", svn_delta_version },
 
602
      { "svn_fs_util", svn_fs_util__version },
447
603
      { NULL, NULL }
448
604
    };
449
605