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
31 #include "svn_fs.h"
32 #include "svn_delta.h"
33 #include "svn_version.h"
34 #include "svn_pools.h"
35 #include "batch_fsync.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 *
x_serialized_init(svn_fs_t * fs,apr_pool_t * common_pool,apr_pool_t * scratch_pool)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 svn_error_t *
svn_fs_x__initialize_shared_data(svn_fs_t * fs,svn_mutex__t * common_pool_lock,apr_pool_t * scratch_pool,apr_pool_t * common_pool)141 svn_fs_x__initialize_shared_data(svn_fs_t *fs,
142 svn_mutex__t *common_pool_lock,
143 apr_pool_t *scratch_pool,
144 apr_pool_t *common_pool)
145 {
146 SVN_MUTEX__WITH_LOCK(common_pool_lock,
147 x_serialized_init(fs, common_pool, scratch_pool));
148
149 return SVN_NO_ERROR;
150 }
151
152
153
154 /* This function is provided for Subversion 1.0.x compatibility. It
155 has no effect for fsx backed Subversion filesystems. It conforms
156 to the fs_library_vtable_t.bdb_set_errcall() API. */
157 static svn_error_t *
x_set_errcall(svn_fs_t * fs,void (* db_errcall_fcn)(const char * errpfx,char * msg))158 x_set_errcall(svn_fs_t *fs,
159 void (*db_errcall_fcn)(const char *errpfx, char *msg))
160 {
161
162 return SVN_NO_ERROR;
163 }
164
165 typedef struct x_freeze_baton_t {
166 svn_fs_t *fs;
167 svn_fs_freeze_func_t freeze_func;
168 void *freeze_baton;
169 } x_freeze_baton_t;
170
171 static svn_error_t *
x_freeze_body(void * baton,apr_pool_t * scratch_pool)172 x_freeze_body(void *baton,
173 apr_pool_t *scratch_pool)
174 {
175 x_freeze_baton_t *b = baton;
176 svn_boolean_t exists;
177
178 SVN_ERR(svn_fs_x__exists_rep_cache(&exists, b->fs, scratch_pool));
179 if (exists)
180 SVN_ERR(svn_fs_x__with_rep_cache_lock(b->fs,
181 b->freeze_func, b->freeze_baton,
182 scratch_pool));
183 else
184 SVN_ERR(b->freeze_func(b->freeze_baton, scratch_pool));
185
186 return SVN_NO_ERROR;
187 }
188
189 static svn_error_t *
x_freeze_body2(void * baton,apr_pool_t * scratch_pool)190 x_freeze_body2(void *baton,
191 apr_pool_t *scratch_pool)
192 {
193 x_freeze_baton_t *b = baton;
194 SVN_ERR(svn_fs_x__with_write_lock(b->fs, x_freeze_body, baton,
195 scratch_pool));
196
197 return SVN_NO_ERROR;
198 }
199
200 static svn_error_t *
x_freeze(svn_fs_t * fs,svn_fs_freeze_func_t freeze_func,void * freeze_baton,apr_pool_t * scratch_pool)201 x_freeze(svn_fs_t *fs,
202 svn_fs_freeze_func_t freeze_func,
203 void *freeze_baton,
204 apr_pool_t *scratch_pool)
205 {
206 x_freeze_baton_t b;
207
208 b.fs = fs;
209 b.freeze_func = freeze_func;
210 b.freeze_baton = freeze_baton;
211
212 SVN_ERR(svn_fs__check_fs(fs, TRUE));
213 SVN_ERR(svn_fs_x__with_pack_lock(fs, x_freeze_body2, &b, scratch_pool));
214
215 return SVN_NO_ERROR;
216 }
217
218 static svn_error_t *
x_info(const void ** fsx_info,svn_fs_t * fs,apr_pool_t * result_pool,apr_pool_t * scratch_pool)219 x_info(const void **fsx_info,
220 svn_fs_t *fs,
221 apr_pool_t *result_pool,
222 apr_pool_t *scratch_pool)
223 {
224 svn_fs_x__data_t *ffd = fs->fsap_data;
225 svn_fs_fsx_info_t *info = apr_palloc(result_pool, sizeof(*info));
226 info->fs_type = SVN_FS_TYPE_FSX;
227 info->shard_size = ffd->max_files_per_dir;
228 info->min_unpacked_rev = ffd->min_unpacked_rev;
229 *fsx_info = info;
230 return SVN_NO_ERROR;
231 }
232
233 static svn_error_t *
x_refresh_revprops(svn_fs_t * fs,apr_pool_t * scratch_pool)234 x_refresh_revprops(svn_fs_t *fs,
235 apr_pool_t *scratch_pool)
236 {
237 svn_fs_x__invalidate_revprop_generation(fs);
238 return SVN_NO_ERROR;
239 }
240
241 /* Wrapper around svn_fs_x__get_revision_proplist() adapting between function
242 signatures. */
243 static svn_error_t *
x_revision_proplist(apr_hash_t ** proplist_p,svn_fs_t * fs,svn_revnum_t rev,svn_boolean_t refresh,apr_pool_t * result_pool,apr_pool_t * scratch_pool)244 x_revision_proplist(apr_hash_t **proplist_p,
245 svn_fs_t *fs,
246 svn_revnum_t rev,
247 svn_boolean_t refresh,
248 apr_pool_t *result_pool,
249 apr_pool_t *scratch_pool)
250 {
251 /* No need to bypass the caches for r/o access to revprops. */
252 SVN_ERR(svn_fs_x__get_revision_proplist(proplist_p, fs, rev, FALSE,
253 refresh, result_pool,
254 scratch_pool));
255
256 return SVN_NO_ERROR;
257 }
258
259 /* Wrapper around svn_fs_x__set_uuid() adapting between function
260 signatures. */
261 static svn_error_t *
x_set_uuid(svn_fs_t * fs,const char * uuid,apr_pool_t * scratch_pool)262 x_set_uuid(svn_fs_t *fs,
263 const char *uuid,
264 apr_pool_t *scratch_pool)
265 {
266 /* Whenever we set a new UUID, imply that FS will also be a different
267 * instance (on formats that support this). */
268 return svn_error_trace(svn_fs_x__set_uuid(fs, uuid, NULL, TRUE,
269 scratch_pool));
270 }
271
272 /* Wrapper around svn_fs_x__begin_txn() providing the scratch pool. */
273 static svn_error_t *
x_begin_txn(svn_fs_txn_t ** txn_p,svn_fs_t * fs,svn_revnum_t rev,apr_uint32_t flags,apr_pool_t * pool)274 x_begin_txn(svn_fs_txn_t **txn_p,
275 svn_fs_t *fs,
276 svn_revnum_t rev,
277 apr_uint32_t flags,
278 apr_pool_t *pool)
279 {
280 apr_pool_t *scratch_pool = svn_pool_create(pool);
281 SVN_ERR(svn_fs_x__begin_txn(txn_p, fs, rev, flags, pool, scratch_pool));
282 svn_pool_destroy(scratch_pool);
283
284 return SVN_NO_ERROR;
285 }
286
287
288
289 /* The vtable associated with a specific open filesystem. */
290 static fs_vtable_t fs_vtable = {
291 svn_fs_x__youngest_rev,
292 x_refresh_revprops,
293 svn_fs_x__revision_prop,
294 x_revision_proplist,
295 svn_fs_x__change_rev_prop,
296 x_set_uuid,
297 svn_fs_x__revision_root,
298 x_begin_txn,
299 svn_fs_x__open_txn,
300 svn_fs_x__purge_txn,
301 svn_fs_x__list_transactions,
302 svn_fs_x__deltify,
303 svn_fs_x__lock,
304 svn_fs_x__generate_lock_token,
305 svn_fs_x__unlock,
306 svn_fs_x__get_lock,
307 svn_fs_x__get_locks,
308 svn_fs_x__info_format,
309 svn_fs_x__info_config_files,
310 x_info,
311 svn_fs_x__verify_root,
312 x_freeze,
313 x_set_errcall,
314 NULL /* ioctl */
315 };
316
317
318 /* Creating a new filesystem. */
319
320 /* Set up vtable and fsap_data fields in FS. */
321 static svn_error_t *
initialize_fs_struct(svn_fs_t * fs)322 initialize_fs_struct(svn_fs_t *fs)
323 {
324 svn_fs_x__data_t *ffd = apr_pcalloc(fs->pool, sizeof(*ffd));
325 ffd->revprop_generation = -1;
326 ffd->flush_to_disk = TRUE;
327
328 fs->vtable = &fs_vtable;
329 fs->fsap_data = ffd;
330 return SVN_NO_ERROR;
331 }
332
333 /* Reset vtable and fsap_data fields in FS such that the FS is basically
334 * closed now. Note that FS must not hold locks when you call this. */
335 static void
uninitialize_fs_struct(svn_fs_t * fs)336 uninitialize_fs_struct(svn_fs_t *fs)
337 {
338 fs->vtable = NULL;
339 fs->fsap_data = NULL;
340 }
341
342 /* This implements the fs_library_vtable_t.create() API. Create a new
343 fsx-backed Subversion filesystem at path PATH and link it into
344 *FS.
345
346 Perform temporary allocations in SCRATCH_POOL, and fs-global allocations
347 in COMMON_POOL. The latter must be serialized using COMMON_POOL_LOCK. */
348 static svn_error_t *
x_create(svn_fs_t * fs,const char * path,svn_mutex__t * common_pool_lock,apr_pool_t * scratch_pool,apr_pool_t * common_pool)349 x_create(svn_fs_t *fs,
350 const char *path,
351 svn_mutex__t *common_pool_lock,
352 apr_pool_t *scratch_pool,
353 apr_pool_t *common_pool)
354 {
355 SVN_ERR(svn_fs__check_fs(fs, FALSE));
356
357 SVN_ERR(initialize_fs_struct(fs));
358
359 SVN_ERR(svn_fs_x__create(fs, path, scratch_pool));
360
361 SVN_ERR(svn_fs_x__initialize_caches(fs, scratch_pool));
362 SVN_MUTEX__WITH_LOCK(common_pool_lock,
363 x_serialized_init(fs, common_pool, scratch_pool));
364
365 return SVN_NO_ERROR;
366 }
367
368
369
370 /* Gaining access to an existing filesystem. */
371
372 /* This implements the fs_library_vtable_t.open() API. Open an FSX
373 Subversion filesystem located at PATH, set *FS to point to the
374 correct vtable for the filesystem. Use SCRATCH_POOL for any temporary
375 allocations, and COMMON_POOL for fs-global allocations.
376 The latter must be serialized using COMMON_POOL_LOCK. */
377 static svn_error_t *
x_open(svn_fs_t * fs,const char * path,svn_mutex__t * common_pool_lock,apr_pool_t * scratch_pool,apr_pool_t * common_pool)378 x_open(svn_fs_t *fs,
379 const char *path,
380 svn_mutex__t *common_pool_lock,
381 apr_pool_t *scratch_pool,
382 apr_pool_t *common_pool)
383 {
384 apr_pool_t *subpool = svn_pool_create(scratch_pool);
385
386 SVN_ERR(svn_fs__check_fs(fs, FALSE));
387
388 SVN_ERR(initialize_fs_struct(fs));
389
390 SVN_ERR(svn_fs_x__open(fs, path, subpool));
391
392 SVN_ERR(svn_fs_x__initialize_caches(fs, subpool));
393 SVN_MUTEX__WITH_LOCK(common_pool_lock,
394 x_serialized_init(fs, common_pool, subpool));
395
396 svn_pool_destroy(subpool);
397
398 return SVN_NO_ERROR;
399 }
400
401
402
403 /* This implements the fs_library_vtable_t.open_for_recovery() API. */
404 static svn_error_t *
x_open_for_recovery(svn_fs_t * fs,const char * path,svn_mutex__t * common_pool_lock,apr_pool_t * scratch_pool,apr_pool_t * common_pool)405 x_open_for_recovery(svn_fs_t *fs,
406 const char *path,
407 svn_mutex__t *common_pool_lock,
408 apr_pool_t *scratch_pool,
409 apr_pool_t *common_pool)
410 {
411 svn_error_t * err;
412 svn_revnum_t youngest_rev;
413 apr_pool_t * subpool = svn_pool_create(scratch_pool);
414
415 /* Recovery for FSFS is currently limited to recreating the 'current'
416 file from the latest revision. */
417
418 /* The only thing we have to watch out for is that the 'current' file
419 might not exist or contain garbage. So we'll try to read it here
420 and provide or replace the existing file if we couldn't read it.
421 (We'll also need it to exist later anyway as a source for the new
422 file's permissions). */
423
424 /* Use a partly-filled fs pointer first to create 'current'. */
425 fs->path = apr_pstrdup(fs->pool, path);
426
427 SVN_ERR(initialize_fs_struct(fs));
428
429 /* Figure out the repo format and check that we can even handle it. */
430 SVN_ERR(svn_fs_x__read_format_file(fs, subpool));
431
432 /* Now, read 'current' and try to patch it if necessary. */
433 err = svn_fs_x__youngest_rev(&youngest_rev, fs, subpool);
434 if (err)
435 {
436 const char *file_path;
437
438 /* 'current' file is missing or contains garbage. Since we are trying
439 * to recover from whatever problem there is, being picky about the
440 * error code here won't do us much good. If there is a persistent
441 * problem that we can't fix, it will show up when we try rewrite the
442 * file a few lines further below and we will report the failure back
443 * to the caller.
444 *
445 * Start recovery with HEAD = 0. */
446 svn_error_clear(err);
447 file_path = svn_fs_x__path_current(fs, subpool);
448
449 /* Best effort to ensure the file exists and is valid.
450 * This may fail for r/o filesystems etc. */
451 SVN_ERR(svn_io_remove_file2(file_path, TRUE, subpool));
452 SVN_ERR(svn_io_file_create_empty(file_path, subpool));
453 SVN_ERR(svn_fs_x__write_current(fs, 0, subpool));
454 }
455
456 uninitialize_fs_struct(fs);
457 svn_pool_destroy(subpool);
458
459 /* Now open the filesystem properly by calling the vtable method directly. */
460 return x_open(fs, path, common_pool_lock, scratch_pool, common_pool);
461 }
462
463
464
465 /* This implements the fs_library_vtable_t.upgrade_fs() API. */
466 static svn_error_t *
x_upgrade(svn_fs_t * fs,const char * path,svn_fs_upgrade_notify_t notify_func,void * notify_baton,svn_cancel_func_t cancel_func,void * cancel_baton,svn_mutex__t * common_pool_lock,apr_pool_t * scratch_pool,apr_pool_t * common_pool)467 x_upgrade(svn_fs_t *fs,
468 const char *path,
469 svn_fs_upgrade_notify_t notify_func,
470 void *notify_baton,
471 svn_cancel_func_t cancel_func,
472 void *cancel_baton,
473 svn_mutex__t *common_pool_lock,
474 apr_pool_t *scratch_pool,
475 apr_pool_t *common_pool)
476 {
477 SVN_ERR(x_open(fs, path, common_pool_lock, scratch_pool, common_pool));
478 return svn_fs_x__upgrade(fs, notify_func, notify_baton,
479 cancel_func, cancel_baton, scratch_pool);
480 }
481
482 static svn_error_t *
x_verify(svn_fs_t * fs,const char * path,svn_revnum_t start,svn_revnum_t end,svn_fs_progress_notify_func_t notify_func,void * notify_baton,svn_cancel_func_t cancel_func,void * cancel_baton,svn_mutex__t * common_pool_lock,apr_pool_t * scratch_pool,apr_pool_t * common_pool)483 x_verify(svn_fs_t *fs,
484 const char *path,
485 svn_revnum_t start,
486 svn_revnum_t end,
487 svn_fs_progress_notify_func_t notify_func,
488 void *notify_baton,
489 svn_cancel_func_t cancel_func,
490 void *cancel_baton,
491 svn_mutex__t *common_pool_lock,
492 apr_pool_t *scratch_pool,
493 apr_pool_t *common_pool)
494 {
495 SVN_ERR(x_open(fs, path, common_pool_lock, scratch_pool, common_pool));
496 return svn_fs_x__verify(fs, start, end, notify_func, notify_baton,
497 cancel_func, cancel_baton, scratch_pool);
498 }
499
500 static svn_error_t *
x_pack(svn_fs_t * fs,const char * path,svn_fs_pack_notify_t notify_func,void * notify_baton,svn_cancel_func_t cancel_func,void * cancel_baton,svn_mutex__t * common_pool_lock,apr_pool_t * scratch_pool,apr_pool_t * common_pool)501 x_pack(svn_fs_t *fs,
502 const char *path,
503 svn_fs_pack_notify_t notify_func,
504 void *notify_baton,
505 svn_cancel_func_t cancel_func,
506 void *cancel_baton,
507 svn_mutex__t *common_pool_lock,
508 apr_pool_t *scratch_pool,
509 apr_pool_t *common_pool)
510 {
511 SVN_ERR(x_open(fs, path, common_pool_lock, scratch_pool, common_pool));
512 return svn_fs_x__pack(fs, 0, notify_func, notify_baton,
513 cancel_func, cancel_baton, scratch_pool);
514 }
515
516
517
518
519 /* This implements the fs_library_vtable_t.hotcopy() API. Copy a
520 possibly live Subversion filesystem SRC_FS from SRC_PATH to a
521 DST_FS at DEST_PATH. If INCREMENTAL is TRUE, make an effort not to
522 re-copy data which already exists in DST_FS.
523 The CLEAN_LOGS argument is ignored and included for Subversion
524 1.0.x compatibility. The NOTIFY_FUNC and NOTIFY_BATON arguments
525 are also currently ignored.
526 Perform all temporary allocations in SCRATCH_POOL. */
527 static svn_error_t *
x_hotcopy(svn_fs_t * src_fs,svn_fs_t * dst_fs,const char * src_path,const char * dst_path,svn_boolean_t clean_logs,svn_boolean_t incremental,svn_fs_hotcopy_notify_t notify_func,void * notify_baton,svn_cancel_func_t cancel_func,void * cancel_baton,svn_mutex__t * common_pool_lock,apr_pool_t * scratch_pool,apr_pool_t * common_pool)528 x_hotcopy(svn_fs_t *src_fs,
529 svn_fs_t *dst_fs,
530 const char *src_path,
531 const char *dst_path,
532 svn_boolean_t clean_logs,
533 svn_boolean_t incremental,
534 svn_fs_hotcopy_notify_t notify_func,
535 void *notify_baton,
536 svn_cancel_func_t cancel_func,
537 void *cancel_baton,
538 svn_mutex__t *common_pool_lock,
539 apr_pool_t *scratch_pool,
540 apr_pool_t *common_pool)
541 {
542 /* Open the source repo as usual. */
543 SVN_ERR(x_open(src_fs, src_path, common_pool_lock, scratch_pool,
544 common_pool));
545 if (cancel_func)
546 SVN_ERR(cancel_func(cancel_baton));
547
548 SVN_ERR(svn_fs__check_fs(dst_fs, FALSE));
549 SVN_ERR(initialize_fs_struct(dst_fs));
550
551 /* In INCREMENTAL mode, svn_fs_x__hotcopy() will open DST_FS.
552 Otherwise, it's not an FS yet --- possibly just an empty dir --- so
553 can't be opened.
554 */
555 return svn_fs_x__hotcopy(src_fs, dst_fs, src_path, dst_path,
556 incremental, notify_func, notify_baton,
557 cancel_func, cancel_baton, common_pool_lock,
558 scratch_pool, common_pool);
559 }
560
561
562
563 /* This function is included for Subversion 1.0.x compatibility. It
564 has no effect for fsx backed Subversion filesystems. It conforms
565 to the fs_library_vtable_t.bdb_logfiles() API. */
566 static svn_error_t *
x_logfiles(apr_array_header_t ** logfiles,const char * path,svn_boolean_t only_unused,apr_pool_t * pool)567 x_logfiles(apr_array_header_t **logfiles,
568 const char *path,
569 svn_boolean_t only_unused,
570 apr_pool_t *pool)
571 {
572 /* A no-op for FSX. */
573 *logfiles = apr_array_make(pool, 0, sizeof(const char *));
574
575 return SVN_NO_ERROR;
576 }
577
578
579
580
581
582 /* Delete the filesystem located at path PATH. Perform any temporary
583 allocations in SCRATCH_POOL. */
584 static svn_error_t *
x_delete_fs(const char * path,apr_pool_t * scratch_pool)585 x_delete_fs(const char *path,
586 apr_pool_t *scratch_pool)
587 {
588 /* Remove everything. */
589 return svn_error_trace(svn_io_remove_dir2(path, FALSE, NULL, NULL,
590 scratch_pool));
591 }
592
593 static const svn_version_t *
x_version(void)594 x_version(void)
595 {
596 SVN_VERSION_BODY;
597 }
598
599 static const char *
x_get_description(void)600 x_get_description(void)
601 {
602 return _("Module for working with an experimental (FSX) repository.");
603 }
604
605 static svn_error_t *
x_set_svn_fs_open(svn_fs_t * fs,svn_error_t * (* svn_fs_open_)(svn_fs_t **,const char *,apr_hash_t *,apr_pool_t *,apr_pool_t *))606 x_set_svn_fs_open(svn_fs_t *fs,
607 svn_error_t *(*svn_fs_open_)(svn_fs_t **,
608 const char *,
609 apr_hash_t *,
610 apr_pool_t *,
611 apr_pool_t *))
612 {
613 svn_fs_x__data_t *ffd = fs->fsap_data;
614 ffd->svn_fs_open_ = svn_fs_open_;
615 return SVN_NO_ERROR;
616 }
617
618 static void *
x_info_dup(const void * fsx_info_void,apr_pool_t * result_pool)619 x_info_dup(const void *fsx_info_void,
620 apr_pool_t *result_pool)
621 {
622 /* All fields are either ints or static strings. */
623 const svn_fs_fsx_info_t *fsx_info = fsx_info_void;
624 return apr_pmemdup(result_pool, fsx_info, sizeof(*fsx_info));
625 }
626
627
628 /* Base FS library vtable, used by the FS loader library. */
629
630 static fs_library_vtable_t library_vtable = {
631 x_version,
632 x_create,
633 x_open,
634 x_open_for_recovery,
635 x_upgrade,
636 x_verify,
637 x_delete_fs,
638 x_hotcopy,
639 x_get_description,
640 svn_fs_x__recover,
641 x_pack,
642 x_logfiles,
643 NULL /* parse_id */,
644 x_set_svn_fs_open,
645 x_info_dup,
646 NULL /* ioctl */
647 };
648
649 svn_error_t *
svn_fs_x__init(const svn_version_t * loader_version,fs_library_vtable_t ** vtable,apr_pool_t * common_pool)650 svn_fs_x__init(const svn_version_t *loader_version,
651 fs_library_vtable_t **vtable,
652 apr_pool_t* common_pool)
653 {
654 static const svn_version_checklist_t checklist[] =
655 {
656 { "svn_subr", svn_subr_version },
657 { "svn_delta", svn_delta_version },
658 { "svn_fs_util", svn_fs_util__version },
659 { NULL, NULL }
660 };
661
662 /* Simplified version check to make sure we can safely use the
663 VTABLE parameter. The FS loader does a more exhaustive check. */
664 if (loader_version->major != SVN_VER_MAJOR)
665 return svn_error_createf(SVN_ERR_VERSION_MISMATCH, NULL,
666 _("Unsupported FS loader version (%d) for fsx"),
667 loader_version->major);
668 SVN_ERR(svn_ver_check_list2(x_version(), checklist, svn_ver_equal));
669
670 SVN_ERR(svn_fs_x__batch_fsync_init(common_pool));
671
672 *vtable = &library_vtable;
673 return SVN_NO_ERROR;
674 }
675