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

« back to all changes in this revision

Viewing changes to subversion/libsvn_fs_x/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:
 
1
/* fs.c --- creating, opening and closing filesystems
 
2
 *
 
3
 * ====================================================================
 
4
 *    Licensed to the Apache Software Foundation (ASF) under one
 
5
 *    or more contributor license agreements.  See the NOTICE file
 
6
 *    distributed with this work for additional information
 
7
 *    regarding copyright ownership.  The ASF licenses this file
 
8
 *    to you under the Apache License, Version 2.0 (the
 
9
 *    "License"); you may not use this file except in compliance
 
10
 *    with the License.  You may obtain a copy of the License at
 
11
 *
 
12
 *      http://www.apache.org/licenses/LICENSE-2.0
 
13
 *
 
14
 *    Unless required by applicable law or agreed to in writing,
 
15
 *    software distributed under the License is distributed on an
 
16
 *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 
17
 *    KIND, either express or implied.  See the License for the
 
18
 *    specific language governing permissions and limitations
 
19
 *    under the License.
 
20
 * ====================================================================
 
21
 */
 
22
 
 
23
#include <stdlib.h>
 
24
#include <stdio.h>
 
25
#include <string.h>
 
26
 
 
27
#include <apr_general.h>
 
28
#include <apr_pools.h>
 
29
#include <apr_file_io.h>
 
30
#include <apr_thread_mutex.h>
 
31
 
 
32
#include "svn_fs.h"
 
33
#include "svn_delta.h"
 
34
#include "svn_version.h"
 
35
#include "svn_pools.h"
 
36
#include "fs.h"
 
37
#include "fs_x.h"
 
38
#include "pack.h"
 
39
#include "recovery.h"
 
40
#include "hotcopy.h"
 
41
#include "verify.h"
 
42
#include "tree.h"
 
43
#include "lock.h"
 
44
#include "id.h"
 
45
#include "revprops.h"
 
46
#include "rep-cache.h"
 
47
#include "transaction.h"
 
48
#include "util.h"
 
49
#include "svn_private_config.h"
 
50
#include "private/svn_fs_util.h"
 
51
 
 
52
#include "../libsvn_fs/fs-loader.h"
 
53
 
 
54
/* A prefix for the pool userdata variables used to hold
 
55
   per-filesystem shared data.  See fs_serialized_init. */
 
56
#define SVN_FSX_SHARED_USERDATA_PREFIX "svn-fsx-shared-"
 
57
 
 
58
 
 
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 SCRATCH_POOL for temporary
 
63
   allocations. */
 
64
static svn_error_t *
 
65
x_serialized_init(svn_fs_t *fs,
 
66
                  apr_pool_t *common_pool,
 
67
                  apr_pool_t *scratch_pool)
 
68
{
 
69
  svn_fs_x__data_t *ffd = fs->fsap_data;
 
70
  const char *key;
 
71
  void *val;
 
72
  svn_fs_x__shared_data_t *ffsd;
 
73
  apr_status_t status;
 
74
 
 
75
  /* Note that we are allocating a small amount of long-lived data for
 
76
     each separate repository opened during the lifetime of the
 
77
     svn_fs_initialize pool.  It's unlikely that anyone will notice
 
78
     the modest expenditure; the alternative is to allocate each structure
 
79
     in a subpool, add a reference-count, and add a serialized destructor
 
80
     to the FS vtable.  That's more machinery than it's worth.
 
81
 
 
82
     Picking an appropriate key for the shared data is tricky, because,
 
83
     unfortunately, a filesystem UUID is not really unique.  It is implicitly
 
84
     shared between hotcopied (1), dump / loaded (2) or naively copied (3)
 
85
     filesystems.  We tackle this problem by using a combination of the UUID
 
86
     and an instance ID as the key.  This allows us to avoid key clashing
 
87
     in (1) and (2).
 
88
 
 
89
     Speaking of (3), there is not so much we can do about it, except maybe
 
90
     provide a convenient way of fixing things.  Naively copied filesystems
 
91
     have identical filesystem UUIDs *and* instance IDs.  With the key being
 
92
     a combination of these two, clashes can be fixed by changing either of
 
93
     them (or both), e.g. with svn_fs_set_uuid(). */
 
94
 
 
95
 
 
96
  SVN_ERR_ASSERT(fs->uuid);
 
97
  SVN_ERR_ASSERT(ffd->instance_id);
 
98
 
 
99
  key = apr_pstrcat(scratch_pool, SVN_FSX_SHARED_USERDATA_PREFIX,
 
100
                    fs->uuid, ":", ffd->instance_id, SVN_VA_NULL);
 
101
  status = apr_pool_userdata_get(&val, key, common_pool);
 
102
  if (status)
 
103
    return svn_error_wrap_apr(status, _("Can't fetch FSX shared data"));
 
104
  ffsd = val;
 
105
 
 
106
  if (!ffsd)
 
107
    {
 
108
      ffsd = apr_pcalloc(common_pool, sizeof(*ffsd));
 
109
      ffsd->common_pool = common_pool;
 
110
 
 
111
      /* POSIX fcntl locks are per-process, so we need a mutex for
 
112
         intra-process synchronization when grabbing the repository write
 
113
         lock. */
 
114
      SVN_ERR(svn_mutex__init(&ffsd->fs_write_lock,
 
115
                              SVN_FS_X__USE_LOCK_MUTEX, common_pool));
 
116
 
 
117
      /* ... the pack lock ... */
 
118
      SVN_ERR(svn_mutex__init(&ffsd->fs_pack_lock,
 
119
                              SVN_FS_X__USE_LOCK_MUTEX, common_pool));
 
120
 
 
121
      /* ... not to mention locking the txn-current file. */
 
122
      SVN_ERR(svn_mutex__init(&ffsd->txn_current_lock,
 
123
                              SVN_FS_X__USE_LOCK_MUTEX, common_pool));
 
124
 
 
125
      /* We also need a mutex for synchronizing access to the active
 
126
         transaction list and free transaction pointer. */
 
127
      SVN_ERR(svn_mutex__init(&ffsd->txn_list_lock, TRUE, common_pool));
 
128
 
 
129
      key = apr_pstrdup(common_pool, key);
 
130
      status = apr_pool_userdata_set(ffsd, key, NULL, common_pool);
 
131
      if (status)
 
132
        return svn_error_wrap_apr(status, _("Can't store FSX shared data"));
 
133
    }
 
134
 
 
135
  ffd->shared = ffsd;
 
136
 
 
137
  return SVN_NO_ERROR;
 
138
}
 
139
 
 
140
 
 
141
 
 
142
/* This function is provided for Subversion 1.0.x compatibility.  It
 
143
   has no effect for fsx backed Subversion filesystems.  It conforms
 
144
   to the fs_library_vtable_t.bdb_set_errcall() API. */
 
145
static svn_error_t *
 
146
x_set_errcall(svn_fs_t *fs,
 
147
              void (*db_errcall_fcn)(const char *errpfx, char *msg))
 
148
{
 
149
 
 
150
  return SVN_NO_ERROR;
 
151
}
 
152
 
 
153
typedef struct x_freeze_baton_t {
 
154
  svn_fs_t *fs;
 
155
  svn_fs_freeze_func_t freeze_func;
 
156
  void *freeze_baton;
 
157
} x_freeze_baton_t;
 
158
 
 
159
static svn_error_t *
 
160
x_freeze_body(void *baton,
 
161
              apr_pool_t *scratch_pool)
 
162
{
 
163
  x_freeze_baton_t *b = baton;
 
164
  svn_boolean_t exists;
 
165
 
 
166
  SVN_ERR(svn_fs_x__exists_rep_cache(&exists, b->fs, scratch_pool));
 
167
  if (exists)
 
168
    SVN_ERR(svn_fs_x__with_rep_cache_lock(b->fs,
 
169
                                          b->freeze_func, b->freeze_baton,
 
170
                                          scratch_pool));
 
171
  else
 
172
    SVN_ERR(b->freeze_func(b->freeze_baton, scratch_pool));
 
173
 
 
174
  return SVN_NO_ERROR;
 
175
}
 
176
 
 
177
static svn_error_t *
 
178
x_freeze_body2(void *baton,
 
179
               apr_pool_t *scratch_pool)
 
180
{
 
181
  x_freeze_baton_t *b = baton;
 
182
  SVN_ERR(svn_fs_x__with_write_lock(b->fs, x_freeze_body, baton,
 
183
                                    scratch_pool));
 
184
 
 
185
  return SVN_NO_ERROR;
 
186
}
 
187
 
 
188
static svn_error_t *
 
189
x_freeze(svn_fs_t *fs,
 
190
         svn_fs_freeze_func_t freeze_func,
 
191
         void *freeze_baton,
 
192
         apr_pool_t *scratch_pool)
 
193
{
 
194
  x_freeze_baton_t b;
 
195
 
 
196
  b.fs = fs;
 
197
  b.freeze_func = freeze_func;
 
198
  b.freeze_baton = freeze_baton;
 
199
 
 
200
  SVN_ERR(svn_fs__check_fs(fs, TRUE));
 
201
  SVN_ERR(svn_fs_x__with_pack_lock(fs, x_freeze_body2, &b, scratch_pool));
 
202
 
 
203
  return SVN_NO_ERROR;
 
204
}
 
205
 
 
206
static svn_error_t *
 
207
x_info(const void **fsx_info,
 
208
       svn_fs_t *fs,
 
209
       apr_pool_t *result_pool,
 
210
       apr_pool_t *scratch_pool)
 
211
{
 
212
  svn_fs_x__data_t *ffd = fs->fsap_data;
 
213
  svn_fs_fsx_info_t *info = apr_palloc(result_pool, sizeof(*info));
 
214
  info->fs_type = SVN_FS_TYPE_FSX;
 
215
  info->shard_size = ffd->max_files_per_dir;
 
216
  info->min_unpacked_rev = ffd->min_unpacked_rev;
 
217
  *fsx_info = info;
 
218
  return SVN_NO_ERROR;
 
219
}
 
220
 
 
221
/* Wrapper around svn_fs_x__revision_prop() adapting between function
 
222
   signatures. */
 
223
static svn_error_t *
 
224
x_revision_prop(svn_string_t **value_p,
 
225
                svn_fs_t *fs,
 
226
                svn_revnum_t rev,
 
227
                const char *propname,
 
228
                apr_pool_t *pool)
 
229
{
 
230
  apr_pool_t *scratch_pool = svn_pool_create(pool);
 
231
  SVN_ERR(svn_fs_x__revision_prop(value_p, fs, rev, propname, pool,
 
232
                                  scratch_pool));
 
233
  svn_pool_destroy(scratch_pool);
 
234
 
 
235
  return SVN_NO_ERROR;
 
236
}
 
237
 
 
238
/* Wrapper around svn_fs_x__get_revision_proplist() adapting between function
 
239
   signatures. */
 
240
static svn_error_t *
 
241
x_revision_proplist(apr_hash_t **proplist_p,
 
242
                    svn_fs_t *fs,
 
243
                    svn_revnum_t rev,
 
244
                    apr_pool_t *pool)
 
245
{
 
246
  apr_pool_t *scratch_pool = svn_pool_create(pool);
 
247
 
 
248
  /* No need to bypass the caches for r/o access to revprops. */
 
249
  SVN_ERR(svn_fs_x__get_revision_proplist(proplist_p, fs, rev, FALSE,
 
250
                                          pool, scratch_pool));
 
251
  svn_pool_destroy(scratch_pool);
 
252
 
 
253
  return SVN_NO_ERROR;
 
254
}
 
255
 
 
256
/* Wrapper around svn_fs_x__set_uuid() adapting between function
 
257
   signatures. */
 
258
static svn_error_t *
 
259
x_set_uuid(svn_fs_t *fs,
 
260
           const char *uuid,
 
261
           apr_pool_t *scratch_pool)
 
262
{
 
263
  /* Whenever we set a new UUID, imply that FS will also be a different
 
264
   * instance (on formats that support this). */
 
265
  return svn_error_trace(svn_fs_x__set_uuid(fs, uuid, NULL, scratch_pool));
 
266
}
 
267
 
 
268
/* Wrapper around svn_fs_x__begin_txn() providing the scratch pool. */
 
269
static svn_error_t *
 
270
x_begin_txn(svn_fs_txn_t **txn_p,
 
271
            svn_fs_t *fs,
 
272
            svn_revnum_t rev,
 
273
            apr_uint32_t flags,
 
274
            apr_pool_t *pool)
 
275
{
 
276
  apr_pool_t *scratch_pool = svn_pool_create(pool);
 
277
  SVN_ERR(svn_fs_x__begin_txn(txn_p, fs, rev, flags, pool, scratch_pool));
 
278
  svn_pool_destroy(scratch_pool);
 
279
 
 
280
  return SVN_NO_ERROR;
 
281
}
 
282
 
 
283
 
 
284
 
 
285
/* The vtable associated with a specific open filesystem. */
 
286
static fs_vtable_t fs_vtable = {
 
287
  svn_fs_x__youngest_rev,
 
288
  x_revision_prop,
 
289
  x_revision_proplist,
 
290
  svn_fs_x__change_rev_prop,
 
291
  x_set_uuid,
 
292
  svn_fs_x__revision_root,
 
293
  x_begin_txn,
 
294
  svn_fs_x__open_txn,
 
295
  svn_fs_x__purge_txn,
 
296
  svn_fs_x__list_transactions,
 
297
  svn_fs_x__deltify,
 
298
  svn_fs_x__lock,
 
299
  svn_fs_x__generate_lock_token,
 
300
  svn_fs_x__unlock,
 
301
  svn_fs_x__get_lock,
 
302
  svn_fs_x__get_locks,
 
303
  svn_fs_x__info_format,
 
304
  svn_fs_x__info_config_files,
 
305
  x_info,
 
306
  svn_fs_x__verify_root,
 
307
  x_freeze,
 
308
  x_set_errcall
 
309
};
 
310
 
 
311
 
 
312
/* Creating a new filesystem. */
 
313
 
 
314
/* Set up vtable and fsap_data fields in FS. */
 
315
static svn_error_t *
 
316
initialize_fs_struct(svn_fs_t *fs)
 
317
{
 
318
  svn_fs_x__data_t *ffd = apr_pcalloc(fs->pool, sizeof(*ffd));
 
319
  fs->vtable = &fs_vtable;
 
320
  fs->fsap_data = ffd;
 
321
  return SVN_NO_ERROR;
 
322
}
 
323
 
 
324
/* Reset vtable and fsap_data fields in FS such that the FS is basically
 
325
 * closed now.  Note that FS must not hold locks when you call this. */
 
326
static void
 
327
uninitialize_fs_struct(svn_fs_t *fs)
 
328
{
 
329
  fs->vtable = NULL;
 
330
  fs->fsap_data = NULL;
 
331
}
 
332
 
 
333
/* This implements the fs_library_vtable_t.create() API.  Create a new
 
334
   fsx-backed Subversion filesystem at path PATH and link it into
 
335
   *FS.
 
336
 
 
337
   Perform temporary allocations in SCRATCH_POOL, and fs-global allocations
 
338
   in COMMON_POOL.  The latter must be serialized using COMMON_POOL_LOCK. */
 
339
static svn_error_t *
 
340
x_create(svn_fs_t *fs,
 
341
         const char *path,
 
342
         svn_mutex__t *common_pool_lock,
 
343
         apr_pool_t *scratch_pool,
 
344
         apr_pool_t *common_pool)
 
345
{
 
346
  SVN_ERR(svn_fs__check_fs(fs, FALSE));
 
347
 
 
348
  SVN_ERR(initialize_fs_struct(fs));
 
349
 
 
350
  SVN_ERR(svn_fs_x__create(fs, path, scratch_pool));
 
351
 
 
352
  SVN_ERR(svn_fs_x__initialize_caches(fs, scratch_pool));
 
353
  SVN_MUTEX__WITH_LOCK(common_pool_lock,
 
354
                       x_serialized_init(fs, common_pool, scratch_pool));
 
355
 
 
356
  return SVN_NO_ERROR;
 
357
}
 
358
 
 
359
 
 
360
 
 
361
/* Gaining access to an existing filesystem.  */
 
362
 
 
363
/* This implements the fs_library_vtable_t.open() API.  Open an FSX
 
364
   Subversion filesystem located at PATH, set *FS to point to the
 
365
   correct vtable for the filesystem.  Use SCRATCH_POOL for any temporary
 
366
   allocations, and COMMON_POOL for fs-global allocations.
 
367
   The latter must be serialized using COMMON_POOL_LOCK.  */
 
368
static svn_error_t *
 
369
x_open(svn_fs_t *fs,
 
370
       const char *path,
 
371
       svn_mutex__t *common_pool_lock,
 
372
       apr_pool_t *scratch_pool,
 
373
       apr_pool_t *common_pool)
 
374
{
 
375
  apr_pool_t *subpool = svn_pool_create(scratch_pool);
 
376
 
 
377
  SVN_ERR(svn_fs__check_fs(fs, FALSE));
 
378
 
 
379
  SVN_ERR(initialize_fs_struct(fs));
 
380
 
 
381
  SVN_ERR(svn_fs_x__open(fs, path, subpool));
 
382
 
 
383
  SVN_ERR(svn_fs_x__initialize_caches(fs, subpool));
 
384
  SVN_MUTEX__WITH_LOCK(common_pool_lock,
 
385
                       x_serialized_init(fs, common_pool, subpool));
 
386
 
 
387
  svn_pool_destroy(subpool);
 
388
 
 
389
  return SVN_NO_ERROR;
 
390
}
 
391
 
 
392
 
 
393
 
 
394
/* This implements the fs_library_vtable_t.open_for_recovery() API. */
 
395
static svn_error_t *
 
396
x_open_for_recovery(svn_fs_t *fs,
 
397
                    const char *path,
 
398
                    svn_mutex__t *common_pool_lock,
 
399
                    apr_pool_t *scratch_pool,
 
400
                    apr_pool_t *common_pool)
 
401
{
 
402
  svn_error_t * err;
 
403
  svn_revnum_t youngest_rev;
 
404
  apr_pool_t * subpool = svn_pool_create(scratch_pool);
 
405
 
 
406
  /* Recovery for FSFS is currently limited to recreating the 'current'
 
407
     file from the latest revision. */
 
408
 
 
409
  /* The only thing we have to watch out for is that the 'current' file
 
410
     might not exist or contain garbage.  So we'll try to read it here
 
411
     and provide or replace the existing file if we couldn't read it.
 
412
     (We'll also need it to exist later anyway as a source for the new
 
413
     file's permissions). */
 
414
 
 
415
  /* Use a partly-filled fs pointer first to create 'current'. */
 
416
  fs->path = apr_pstrdup(fs->pool, path);
 
417
 
 
418
  SVN_ERR(initialize_fs_struct(fs));
 
419
 
 
420
  /* Figure out the repo format and check that we can even handle it. */
 
421
  SVN_ERR(svn_fs_x__read_format_file(fs, subpool));
 
422
 
 
423
  /* Now, read 'current' and try to patch it if necessary. */
 
424
  err = svn_fs_x__youngest_rev(&youngest_rev, fs, subpool);
 
425
  if (err)
 
426
    {
 
427
      const char *file_path;
 
428
 
 
429
      /* 'current' file is missing or contains garbage.  Since we are trying
 
430
       * to recover from whatever problem there is, being picky about the
 
431
       * error code here won't do us much good.  If there is a persistent
 
432
       * problem that we can't fix, it will show up when we try rewrite the
 
433
       * file a few lines further below and we will report the failure back
 
434
       * to the caller.
 
435
       *
 
436
       * Start recovery with HEAD = 0. */
 
437
      svn_error_clear(err);
 
438
      file_path = svn_fs_x__path_current(fs, subpool);
 
439
 
 
440
      /* Best effort to ensure the file exists and is valid.
 
441
       * This may fail for r/o filesystems etc. */
 
442
      SVN_ERR(svn_io_remove_file2(file_path, TRUE, subpool));
 
443
      SVN_ERR(svn_io_file_create_empty(file_path, subpool));
 
444
      SVN_ERR(svn_fs_x__write_current(fs, 0, subpool));
 
445
    }
 
446
 
 
447
  uninitialize_fs_struct(fs);
 
448
  svn_pool_destroy(subpool);
 
449
 
 
450
  /* Now open the filesystem properly by calling the vtable method directly. */
 
451
  return x_open(fs, path, common_pool_lock, scratch_pool, common_pool);
 
452
}
 
453
 
 
454
 
 
455
 
 
456
/* This implements the fs_library_vtable_t.upgrade_fs() API. */
 
457
static svn_error_t *
 
458
x_upgrade(svn_fs_t *fs,
 
459
          const char *path,
 
460
          svn_fs_upgrade_notify_t notify_func,
 
461
          void *notify_baton,
 
462
          svn_cancel_func_t cancel_func,
 
463
          void *cancel_baton,
 
464
          svn_mutex__t *common_pool_lock,
 
465
          apr_pool_t *scratch_pool,
 
466
          apr_pool_t *common_pool)
 
467
{
 
468
  SVN_ERR(x_open(fs, path, common_pool_lock, scratch_pool, common_pool));
 
469
  return svn_fs_x__upgrade(fs, notify_func, notify_baton,
 
470
                           cancel_func, cancel_baton, scratch_pool);
 
471
}
 
472
 
 
473
static svn_error_t *
 
474
x_verify(svn_fs_t *fs,
 
475
         const char *path,
 
476
         svn_revnum_t start,
 
477
         svn_revnum_t end,
 
478
         svn_fs_progress_notify_func_t notify_func,
 
479
         void *notify_baton,
 
480
         svn_cancel_func_t cancel_func,
 
481
         void *cancel_baton,
 
482
         svn_mutex__t *common_pool_lock,
 
483
         apr_pool_t *scratch_pool,
 
484
         apr_pool_t *common_pool)
 
485
{
 
486
  SVN_ERR(x_open(fs, path, common_pool_lock, scratch_pool, common_pool));
 
487
  return svn_fs_x__verify(fs, start, end, notify_func, notify_baton,
 
488
                          cancel_func, cancel_baton, scratch_pool);
 
489
}
 
490
 
 
491
static svn_error_t *
 
492
x_pack(svn_fs_t *fs,
 
493
       const char *path,
 
494
       svn_fs_pack_notify_t notify_func,
 
495
       void *notify_baton,
 
496
       svn_cancel_func_t cancel_func,
 
497
       void *cancel_baton,
 
498
       svn_mutex__t *common_pool_lock,
 
499
       apr_pool_t *scratch_pool,
 
500
       apr_pool_t *common_pool)
 
501
{
 
502
  SVN_ERR(x_open(fs, path, common_pool_lock, scratch_pool, common_pool));
 
503
  return svn_fs_x__pack(fs, notify_func, notify_baton,
 
504
                        cancel_func, cancel_baton, scratch_pool);
 
505
}
 
506
 
 
507
 
 
508
 
 
509
 
 
510
/* This implements the fs_library_vtable_t.hotcopy() API.  Copy a
 
511
   possibly live Subversion filesystem SRC_FS from SRC_PATH to a
 
512
   DST_FS at DEST_PATH. If INCREMENTAL is TRUE, make an effort not to
 
513
   re-copy data which already exists in DST_FS.
 
514
   The CLEAN_LOGS argument is ignored and included for Subversion
 
515
   1.0.x compatibility.  The NOTIFY_FUNC and NOTIFY_BATON arguments
 
516
   are also currently ignored.
 
517
   Perform all temporary allocations in SCRATCH_POOL. */
 
518
static svn_error_t *
 
519
x_hotcopy(svn_fs_t *src_fs,
 
520
          svn_fs_t *dst_fs,
 
521
          const char *src_path,
 
522
          const char *dst_path,
 
523
          svn_boolean_t clean_logs,
 
524
          svn_boolean_t incremental,
 
525
          svn_fs_hotcopy_notify_t notify_func,
 
526
          void *notify_baton,
 
527
          svn_cancel_func_t cancel_func,
 
528
          void *cancel_baton,
 
529
          svn_mutex__t *common_pool_lock,
 
530
          apr_pool_t *scratch_pool,
 
531
          apr_pool_t *common_pool)
 
532
{
 
533
  /* Open the source repo as usual. */
 
534
  SVN_ERR(x_open(src_fs, src_path, common_pool_lock, scratch_pool,
 
535
                 common_pool));
 
536
  if (cancel_func)
 
537
    SVN_ERR(cancel_func(cancel_baton));
 
538
 
 
539
  /* Test target repo when in INCREMENTAL mode, initialize it when not.
 
540
   * For this, we need our FS internal data structures to be temporarily
 
541
   * available. */
 
542
  SVN_ERR(initialize_fs_struct(dst_fs));
 
543
  SVN_ERR(svn_fs_x__hotcopy_prepare_target(src_fs, dst_fs, dst_path,
 
544
                                           incremental, scratch_pool));
 
545
  uninitialize_fs_struct(dst_fs);
 
546
 
 
547
  /* Now, the destination repo should open just fine. */
 
548
  SVN_ERR(x_open(dst_fs, dst_path, common_pool_lock, scratch_pool,
 
549
                 common_pool));
 
550
  if (cancel_func)
 
551
    SVN_ERR(cancel_func(cancel_baton));
 
552
 
 
553
  /* Now, we may copy data as needed ... */
 
554
  return svn_fs_x__hotcopy(src_fs, dst_fs, incremental,
 
555
                           notify_func, notify_baton,
 
556
                           cancel_func, cancel_baton, scratch_pool);
 
557
}
 
558
 
 
559
 
 
560
 
 
561
/* This function is included for Subversion 1.0.x compatibility.  It
 
562
   has no effect for fsx backed Subversion filesystems.  It conforms
 
563
   to the fs_library_vtable_t.bdb_logfiles() API. */
 
564
static svn_error_t *
 
565
x_logfiles(apr_array_header_t **logfiles,
 
566
           const char *path,
 
567
           svn_boolean_t only_unused,
 
568
           apr_pool_t *pool)
 
569
{
 
570
  /* A no-op for FSX. */
 
571
  *logfiles = apr_array_make(pool, 0, sizeof(const char *));
 
572
 
 
573
  return SVN_NO_ERROR;
 
574
}
 
575
 
 
576
 
 
577
 
 
578
 
 
579
 
 
580
/* Delete the filesystem located at path PATH.  Perform any temporary
 
581
   allocations in SCRATCH_POOL. */
 
582
static svn_error_t *
 
583
x_delete_fs(const char *path,
 
584
            apr_pool_t *scratch_pool)
 
585
{
 
586
  /* Remove everything. */
 
587
  return svn_error_trace(svn_io_remove_dir2(path, FALSE, NULL, NULL,
 
588
                                            scratch_pool));
 
589
}
 
590
 
 
591
static const svn_version_t *
 
592
x_version(void)
 
593
{
 
594
  SVN_VERSION_BODY;
 
595
}
 
596
 
 
597
static const char *
 
598
x_get_description(void)
 
599
{
 
600
  return _("Module for working with an experimental (FSX) repository.");
 
601
}
 
602
 
 
603
static svn_error_t *
 
604
x_set_svn_fs_open(svn_fs_t *fs,
 
605
                  svn_error_t *(*svn_fs_open_)(svn_fs_t **,
 
606
                                               const char *,
 
607
                                               apr_hash_t *,
 
608
                                               apr_pool_t *,
 
609
                                               apr_pool_t *))
 
610
{
 
611
  svn_fs_x__data_t *ffd = fs->fsap_data;
 
612
  ffd->svn_fs_open_ = svn_fs_open_;
 
613
  return SVN_NO_ERROR;
 
614
}
 
615
 
 
616
static void *
 
617
x_info_dup(const void *fsx_info_void,
 
618
           apr_pool_t *result_pool)
 
619
{
 
620
  /* All fields are either ints or static strings. */
 
621
  const svn_fs_fsx_info_t *fsx_info = fsx_info_void;
 
622
  return apr_pmemdup(result_pool, fsx_info, sizeof(*fsx_info));
 
623
}
 
624
 
 
625
 
 
626
/* Base FS library vtable, used by the FS loader library. */
 
627
 
 
628
static fs_library_vtable_t library_vtable = {
 
629
  x_version,
 
630
  x_create,
 
631
  x_open,
 
632
  x_open_for_recovery,
 
633
  x_upgrade,
 
634
  x_verify,
 
635
  x_delete_fs,
 
636
  x_hotcopy,
 
637
  x_get_description,
 
638
  svn_fs_x__recover,
 
639
  x_pack,
 
640
  x_logfiles,
 
641
  NULL /* parse_id */,
 
642
  x_set_svn_fs_open,
 
643
  x_info_dup
 
644
};
 
645
 
 
646
svn_error_t *
 
647
svn_fs_x__init(const svn_version_t *loader_version,
 
648
               fs_library_vtable_t **vtable,
 
649
               apr_pool_t* common_pool)
 
650
{
 
651
  static const svn_version_checklist_t checklist[] =
 
652
    {
 
653
      { "svn_subr",  svn_subr_version },
 
654
      { "svn_delta", svn_delta_version },
 
655
      { "svn_fs_util", svn_fs_util__version },
 
656
      { NULL, NULL }
 
657
    };
 
658
 
 
659
  /* Simplified version check to make sure we can safely use the
 
660
     VTABLE parameter. The FS loader does a more exhaustive check. */
 
661
  if (loader_version->major != SVN_VER_MAJOR)
 
662
    return svn_error_createf(SVN_ERR_VERSION_MISMATCH, NULL,
 
663
                             _("Unsupported FS loader version (%d) for fsx"),
 
664
                             loader_version->major);
 
665
  SVN_ERR(svn_ver_check_list2(x_version(), checklist, svn_ver_equal));
 
666
 
 
667
  *vtable = &library_vtable;
 
668
  return SVN_NO_ERROR;
 
669
}