1251881Speter/* fs.c --- creating, opening and closing filesystems
2251881Speter *
3251881Speter * ====================================================================
4251881Speter *    Licensed to the Apache Software Foundation (ASF) under one
5251881Speter *    or more contributor license agreements.  See the NOTICE file
6251881Speter *    distributed with this work for additional information
7251881Speter *    regarding copyright ownership.  The ASF licenses this file
8251881Speter *    to you under the Apache License, Version 2.0 (the
9251881Speter *    "License"); you may not use this file except in compliance
10251881Speter *    with the License.  You may obtain a copy of the License at
11251881Speter *
12251881Speter *      http://www.apache.org/licenses/LICENSE-2.0
13251881Speter *
14251881Speter *    Unless required by applicable law or agreed to in writing,
15251881Speter *    software distributed under the License is distributed on an
16251881Speter *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17251881Speter *    KIND, either express or implied.  See the License for the
18251881Speter *    specific language governing permissions and limitations
19251881Speter *    under the License.
20251881Speter * ====================================================================
21251881Speter */
22251881Speter
23251881Speter#include <stdlib.h>
24251881Speter#include <stdio.h>
25251881Speter#include <string.h>
26251881Speter
27251881Speter#include <apr_general.h>
28251881Speter#include <apr_pools.h>
29251881Speter#include <apr_file_io.h>
30251881Speter#include <apr_thread_mutex.h>
31251881Speter
32251881Speter#include "svn_fs.h"
33251881Speter#include "svn_delta.h"
34251881Speter#include "svn_version.h"
35251881Speter#include "svn_pools.h"
36251881Speter#include "fs.h"
37251881Speter#include "fs_fs.h"
38251881Speter#include "tree.h"
39251881Speter#include "lock.h"
40299742Sdim#include "hotcopy.h"
41251881Speter#include "id.h"
42299742Sdim#include "pack.h"
43299742Sdim#include "recovery.h"
44251881Speter#include "rep-cache.h"
45299742Sdim#include "revprops.h"
46299742Sdim#include "transaction.h"
47299742Sdim#include "util.h"
48299742Sdim#include "verify.h"
49251881Speter#include "svn_private_config.h"
50251881Speter#include "private/svn_fs_util.h"
51251881Speter
52251881Speter#include "../libsvn_fs/fs-loader.h"
53251881Speter
54251881Speter/* A prefix for the pool userdata variables used to hold
55251881Speter   per-filesystem shared data.  See fs_serialized_init. */
56251881Speter#define SVN_FSFS_SHARED_USERDATA_PREFIX "svn-fsfs-shared-"
57251881Speter
58251881Speter
59251881Speter
60299742Sdim/* Initialize the part of FS that requires global serialization across all
61299742Sdim   instances.  The caller is responsible of ensuring that serialization.
62299742Sdim   Use COMMON_POOL for process-wide and POOL for temporary allocations. */
63251881Speterstatic svn_error_t *
64251881Speterfs_serialized_init(svn_fs_t *fs, apr_pool_t *common_pool, apr_pool_t *pool)
65251881Speter{
66251881Speter  fs_fs_data_t *ffd = fs->fsap_data;
67251881Speter  const char *key;
68251881Speter  void *val;
69251881Speter  fs_fs_shared_data_t *ffsd;
70251881Speter  apr_status_t status;
71251881Speter
72251881Speter  /* Note that we are allocating a small amount of long-lived data for
73251881Speter     each separate repository opened during the lifetime of the
74251881Speter     svn_fs_initialize pool.  It's unlikely that anyone will notice
75251881Speter     the modest expenditure; the alternative is to allocate each structure
76299742Sdim     in a subpool, add a reference-count, and add a serialized destructor
77251881Speter     to the FS vtable.  That's more machinery than it's worth.
78251881Speter
79299742Sdim     Picking an appropriate key for the shared data is tricky, because,
80299742Sdim     unfortunately, a filesystem UUID is not really unique.  It is implicitly
81299742Sdim     shared between hotcopied (1), dump / loaded (2) or naively copied (3)
82299742Sdim     filesystems.  We tackle this problem by using a combination of the UUID
83299742Sdim     and an instance ID as the key.  This allows us to avoid key clashing
84299742Sdim     in (1) and (2) for formats >= SVN_FS_FS__MIN_INSTANCE_ID_FORMAT, which
85299742Sdim     do support instance IDs.  For old formats the shared data (locks, shared
86299742Sdim     transaction data, ...) will still clash.
87251881Speter
88299742Sdim     Speaking of (3), there is not so much we can do about it, except maybe
89299742Sdim     provide a convenient way of fixing things.  Naively copied filesystems
90299742Sdim     have identical filesystem UUIDs *and* instance IDs.  With the key being
91299742Sdim     a combination of these two, clashes can be fixed by changing either of
92299742Sdim     them (or both), e.g. with svn_fs_set_uuid(). */
93299742Sdim
94251881Speter  SVN_ERR_ASSERT(fs->uuid);
95299742Sdim  SVN_ERR_ASSERT(ffd->instance_id);
96299742Sdim
97299742Sdim  key = apr_pstrcat(pool, SVN_FSFS_SHARED_USERDATA_PREFIX,
98299742Sdim                    fs->uuid, ":", ffd->instance_id, SVN_VA_NULL);
99251881Speter  status = apr_pool_userdata_get(&val, key, common_pool);
100251881Speter  if (status)
101251881Speter    return svn_error_wrap_apr(status, _("Can't fetch FSFS shared data"));
102251881Speter  ffsd = val;
103251881Speter
104251881Speter  if (!ffsd)
105251881Speter    {
106251881Speter      ffsd = apr_pcalloc(common_pool, sizeof(*ffsd));
107251881Speter      ffsd->common_pool = common_pool;
108251881Speter
109251881Speter      /* POSIX fcntl locks are per-process, so we need a mutex for
110251881Speter         intra-process synchronization when grabbing the repository write
111251881Speter         lock. */
112251881Speter      SVN_ERR(svn_mutex__init(&ffsd->fs_write_lock,
113251881Speter                              SVN_FS_FS__USE_LOCK_MUTEX, common_pool));
114251881Speter
115299742Sdim      /* ... the pack lock ... */
116299742Sdim      SVN_ERR(svn_mutex__init(&ffsd->fs_pack_lock,
117299742Sdim                              SVN_FS_FS__USE_LOCK_MUTEX, common_pool));
118299742Sdim
119251881Speter      /* ... not to mention locking the txn-current file. */
120251881Speter      SVN_ERR(svn_mutex__init(&ffsd->txn_current_lock,
121251881Speter                              SVN_FS_FS__USE_LOCK_MUTEX, common_pool));
122251881Speter
123269847Speter      /* We also need a mutex for synchronizing access to the active
124299742Sdim         transaction list and free transaction pointer. */
125299742Sdim      SVN_ERR(svn_mutex__init(&ffsd->txn_list_lock, TRUE, common_pool));
126251881Speter
127251881Speter      key = apr_pstrdup(common_pool, key);
128251881Speter      status = apr_pool_userdata_set(ffsd, key, NULL, common_pool);
129251881Speter      if (status)
130251881Speter        return svn_error_wrap_apr(status, _("Can't store FSFS shared data"));
131251881Speter    }
132251881Speter
133251881Speter  ffd->shared = ffsd;
134251881Speter
135251881Speter  return SVN_NO_ERROR;
136251881Speter}
137251881Speter
138251881Speter
139251881Speter
140251881Speter/* This function is provided for Subversion 1.0.x compatibility.  It
141251881Speter   has no effect for fsfs backed Subversion filesystems.  It conforms
142251881Speter   to the fs_library_vtable_t.bdb_set_errcall() API. */
143251881Speterstatic svn_error_t *
144251881Speterfs_set_errcall(svn_fs_t *fs,
145251881Speter               void (*db_errcall_fcn)(const char *errpfx, char *msg))
146251881Speter{
147251881Speter
148251881Speter  return SVN_NO_ERROR;
149251881Speter}
150251881Speter
151251881Speterstruct fs_freeze_baton_t {
152251881Speter  svn_fs_t *fs;
153251881Speter  svn_fs_freeze_func_t freeze_func;
154251881Speter  void *freeze_baton;
155251881Speter};
156251881Speter
157251881Speterstatic svn_error_t *
158251881Speterfs_freeze_body(void *baton,
159251881Speter               apr_pool_t *pool)
160251881Speter{
161251881Speter  struct fs_freeze_baton_t *b = baton;
162251881Speter  svn_boolean_t exists;
163251881Speter
164251881Speter  SVN_ERR(svn_fs_fs__exists_rep_cache(&exists, b->fs, pool));
165251881Speter  if (exists)
166299742Sdim    SVN_ERR(svn_fs_fs__with_rep_cache_lock(b->fs,
167299742Sdim                                           b->freeze_func, b->freeze_baton,
168299742Sdim                                           pool));
169299742Sdim  else
170299742Sdim    SVN_ERR(b->freeze_func(b->freeze_baton, pool));
171251881Speter
172299742Sdim  return SVN_NO_ERROR;
173299742Sdim}
174251881Speter
175299742Sdimstatic svn_error_t *
176299742Sdimfs_freeze_body2(void *baton,
177299742Sdim                apr_pool_t *pool)
178299742Sdim{
179299742Sdim  struct fs_freeze_baton_t *b = baton;
180299742Sdim  SVN_ERR(svn_fs_fs__with_write_lock(b->fs, fs_freeze_body, baton, pool));
181299742Sdim
182251881Speter  return SVN_NO_ERROR;
183251881Speter}
184251881Speter
185251881Speterstatic svn_error_t *
186251881Speterfs_freeze(svn_fs_t *fs,
187251881Speter          svn_fs_freeze_func_t freeze_func,
188251881Speter          void *freeze_baton,
189251881Speter          apr_pool_t *pool)
190251881Speter{
191299742Sdim  fs_fs_data_t *ffd = fs->fsap_data;
192251881Speter  struct fs_freeze_baton_t b;
193251881Speter
194251881Speter  b.fs = fs;
195251881Speter  b.freeze_func = freeze_func;
196251881Speter  b.freeze_baton = freeze_baton;
197251881Speter
198251881Speter  SVN_ERR(svn_fs__check_fs(fs, TRUE));
199251881Speter
200299742Sdim  if (ffd->format >= SVN_FS_FS__MIN_PACK_LOCK_FORMAT)
201299742Sdim    SVN_ERR(svn_fs_fs__with_pack_lock(fs, fs_freeze_body2, &b, pool));
202299742Sdim  else
203299742Sdim    SVN_ERR(fs_freeze_body2(&b, pool));
204299742Sdim
205251881Speter  return SVN_NO_ERROR;
206251881Speter}
207251881Speter
208299742Sdimstatic svn_error_t *
209299742Sdimfs_info(const void **fsfs_info,
210299742Sdim        svn_fs_t *fs,
211299742Sdim        apr_pool_t *result_pool,
212299742Sdim        apr_pool_t *scratch_pool)
213299742Sdim{
214299742Sdim  fs_fs_data_t *ffd = fs->fsap_data;
215299742Sdim  svn_fs_fsfs_info_t *info = apr_palloc(result_pool, sizeof(*info));
216299742Sdim  info->fs_type = SVN_FS_TYPE_FSFS;
217299742Sdim  info->shard_size = ffd->max_files_per_dir;
218299742Sdim  info->min_unpacked_rev = ffd->min_unpacked_rev;
219299742Sdim  info->log_addressing = ffd->use_log_addressing;
220299742Sdim  *fsfs_info = info;
221299742Sdim  return SVN_NO_ERROR;
222299742Sdim}
223299742Sdim
224299742Sdim/* Wrapper around svn_fs_fs__set_uuid() adapting between function
225299742Sdim   signatures. */
226299742Sdimstatic svn_error_t *
227299742Sdimfs_set_uuid(svn_fs_t *fs,
228299742Sdim            const char *uuid,
229299742Sdim            apr_pool_t *pool)
230299742Sdim{
231299742Sdim  /* Whenever we set a new UUID, imply that FS will also be a different
232299742Sdim   * instance (on formats that support this). */
233299742Sdim  return svn_error_trace(svn_fs_fs__set_uuid(fs, uuid, NULL, pool));
234299742Sdim}
235299742Sdim
236251881Speter
237251881Speter
238251881Speter/* The vtable associated with a specific open filesystem. */
239251881Speterstatic fs_vtable_t fs_vtable = {
240251881Speter  svn_fs_fs__youngest_rev,
241251881Speter  svn_fs_fs__revision_prop,
242299742Sdim  svn_fs_fs__get_revision_proplist,
243251881Speter  svn_fs_fs__change_rev_prop,
244299742Sdim  fs_set_uuid,
245251881Speter  svn_fs_fs__revision_root,
246251881Speter  svn_fs_fs__begin_txn,
247251881Speter  svn_fs_fs__open_txn,
248251881Speter  svn_fs_fs__purge_txn,
249251881Speter  svn_fs_fs__list_transactions,
250251881Speter  svn_fs_fs__deltify,
251251881Speter  svn_fs_fs__lock,
252251881Speter  svn_fs_fs__generate_lock_token,
253251881Speter  svn_fs_fs__unlock,
254251881Speter  svn_fs_fs__get_lock,
255251881Speter  svn_fs_fs__get_locks,
256299742Sdim  svn_fs_fs__info_format,
257299742Sdim  svn_fs_fs__info_config_files,
258299742Sdim  fs_info,
259251881Speter  svn_fs_fs__verify_root,
260251881Speter  fs_freeze,
261251881Speter  fs_set_errcall
262251881Speter};
263251881Speter
264251881Speter
265251881Speter/* Creating a new filesystem. */
266251881Speter
267251881Speter/* Set up vtable and fsap_data fields in FS. */
268251881Speterstatic svn_error_t *
269251881Speterinitialize_fs_struct(svn_fs_t *fs)
270251881Speter{
271251881Speter  fs_fs_data_t *ffd = apr_pcalloc(fs->pool, sizeof(*ffd));
272299742Sdim  ffd->use_log_addressing = FALSE;
273299742Sdim
274251881Speter  fs->vtable = &fs_vtable;
275251881Speter  fs->fsap_data = ffd;
276251881Speter  return SVN_NO_ERROR;
277251881Speter}
278251881Speter
279299742Sdim/* Reset vtable and fsap_data fields in FS such that the FS is basically
280299742Sdim * closed now.  Note that FS must not hold locks when you call this. */
281299742Sdimstatic void
282299742Sdimuninitialize_fs_struct(svn_fs_t *fs)
283299742Sdim{
284299742Sdim  fs->vtable = NULL;
285299742Sdim  fs->fsap_data = NULL;
286299742Sdim}
287299742Sdim
288251881Speter/* This implements the fs_library_vtable_t.create() API.  Create a new
289251881Speter   fsfs-backed Subversion filesystem at path PATH and link it into
290251881Speter   *FS.  Perform temporary allocations in POOL, and fs-global allocations
291299742Sdim   in COMMON_POOL.  The latter must be serialized using COMMON_POOL_LOCK. */
292251881Speterstatic svn_error_t *
293299742Sdimfs_create(svn_fs_t *fs,
294299742Sdim          const char *path,
295299742Sdim          svn_mutex__t *common_pool_lock,
296299742Sdim          apr_pool_t *pool,
297251881Speter          apr_pool_t *common_pool)
298251881Speter{
299251881Speter  SVN_ERR(svn_fs__check_fs(fs, FALSE));
300251881Speter
301251881Speter  SVN_ERR(initialize_fs_struct(fs));
302251881Speter
303251881Speter  SVN_ERR(svn_fs_fs__create(fs, path, pool));
304251881Speter
305251881Speter  SVN_ERR(svn_fs_fs__initialize_caches(fs, pool));
306299742Sdim  SVN_MUTEX__WITH_LOCK(common_pool_lock,
307299742Sdim                       fs_serialized_init(fs, common_pool, pool));
308299742Sdim
309299742Sdim  return SVN_NO_ERROR;
310251881Speter}
311251881Speter
312251881Speter
313251881Speter
314251881Speter/* Gaining access to an existing filesystem.  */
315251881Speter
316251881Speter/* This implements the fs_library_vtable_t.open() API.  Open an FSFS
317251881Speter   Subversion filesystem located at PATH, set *FS to point to the
318251881Speter   correct vtable for the filesystem.  Use POOL for any temporary
319299742Sdim   allocations, and COMMON_POOL for fs-global allocations.
320299742Sdim   The latter must be serialized using COMMON_POOL_LOCK. */
321251881Speterstatic svn_error_t *
322299742Sdimfs_open(svn_fs_t *fs,
323299742Sdim        const char *path,
324299742Sdim        svn_mutex__t *common_pool_lock,
325299742Sdim        apr_pool_t *pool,
326251881Speter        apr_pool_t *common_pool)
327251881Speter{
328299742Sdim  apr_pool_t *subpool = svn_pool_create(pool);
329299742Sdim
330299742Sdim  SVN_ERR(svn_fs__check_fs(fs, FALSE));
331299742Sdim
332251881Speter  SVN_ERR(initialize_fs_struct(fs));
333251881Speter
334299742Sdim  SVN_ERR(svn_fs_fs__open(fs, path, subpool));
335251881Speter
336299742Sdim  SVN_ERR(svn_fs_fs__initialize_caches(fs, subpool));
337299742Sdim  SVN_MUTEX__WITH_LOCK(common_pool_lock,
338299742Sdim                       fs_serialized_init(fs, common_pool, subpool));
339299742Sdim
340299742Sdim  svn_pool_destroy(subpool);
341299742Sdim
342299742Sdim  return SVN_NO_ERROR;
343251881Speter}
344251881Speter
345251881Speter
346251881Speter
347251881Speter/* This implements the fs_library_vtable_t.open_for_recovery() API. */
348251881Speterstatic svn_error_t *
349251881Speterfs_open_for_recovery(svn_fs_t *fs,
350251881Speter                     const char *path,
351299742Sdim                     svn_mutex__t *common_pool_lock,
352299742Sdim                     apr_pool_t *pool,
353299742Sdim                     apr_pool_t *common_pool)
354251881Speter{
355299742Sdim  svn_error_t * err;
356299742Sdim  svn_revnum_t youngest_rev;
357299742Sdim  apr_pool_t * subpool = svn_pool_create(pool);
358299742Sdim
359251881Speter  /* Recovery for FSFS is currently limited to recreating the 'current'
360251881Speter     file from the latest revision. */
361251881Speter
362251881Speter  /* The only thing we have to watch out for is that the 'current' file
363299742Sdim     might not exist or contain garbage.  So we'll try to read it here
364299742Sdim     and provide or replace the existing file if we couldn't read it.
365299742Sdim     (We'll also need it to exist later anyway as a source for the new
366299742Sdim     file's permissions). */
367251881Speter
368299742Sdim  /* Use a partly-filled fs pointer first to create 'current'. */
369251881Speter  fs->path = apr_pstrdup(fs->pool, path);
370251881Speter
371299742Sdim  SVN_ERR(initialize_fs_struct(fs));
372299742Sdim
373299742Sdim  /* Figure out the repo format and check that we can even handle it. */
374299742Sdim  SVN_ERR(svn_fs_fs__read_format_file(fs, subpool));
375299742Sdim
376299742Sdim  /* Now, read 'current' and try to patch it if necessary. */
377299742Sdim  err = svn_fs_fs__youngest_rev(&youngest_rev, fs, subpool);
378299742Sdim  if (err)
379299742Sdim    {
380299742Sdim      const char *file_path;
381299742Sdim
382299742Sdim      /* 'current' file is missing or contains garbage.  Since we are trying
383299742Sdim       * to recover from whatever problem there is, being picky about the
384299742Sdim       * error code here won't do us much good.  If there is a persistent
385299742Sdim       * problem that we can't fix, it will show up when we try rewrite the
386299742Sdim       * file a few lines further below and we will report the failure back
387299742Sdim       * to the caller.
388299742Sdim       *
389299742Sdim       * Start recovery with HEAD = 0. */
390299742Sdim      svn_error_clear(err);
391299742Sdim      file_path = svn_fs_fs__path_current(fs, subpool);
392299742Sdim
393299742Sdim      /* Best effort to ensure the file exists and is valid.
394299742Sdim       * This may fail for r/o filesystems etc. */
395299742Sdim      SVN_ERR(svn_io_remove_file2(file_path, TRUE, subpool));
396299742Sdim      SVN_ERR(svn_io_file_create_empty(file_path, subpool));
397299742Sdim      SVN_ERR(svn_fs_fs__write_current(fs, 0, 1, 1, subpool));
398299742Sdim    }
399299742Sdim
400299742Sdim  uninitialize_fs_struct(fs);
401299742Sdim  svn_pool_destroy(subpool);
402299742Sdim
403251881Speter  /* Now open the filesystem properly by calling the vtable method directly. */
404299742Sdim  return fs_open(fs, path, common_pool_lock, pool, common_pool);
405251881Speter}
406251881Speter
407251881Speter
408251881Speter
409251881Speter/* This implements the fs_library_vtable_t.upgrade_fs() API. */
410251881Speterstatic svn_error_t *
411299742Sdimfs_upgrade(svn_fs_t *fs,
412299742Sdim           const char *path,
413299742Sdim           svn_fs_upgrade_notify_t notify_func,
414299742Sdim           void *notify_baton,
415299742Sdim           svn_cancel_func_t cancel_func,
416299742Sdim           void *cancel_baton,
417299742Sdim           svn_mutex__t *common_pool_lock,
418299742Sdim           apr_pool_t *pool,
419251881Speter           apr_pool_t *common_pool)
420251881Speter{
421299742Sdim  SVN_ERR(fs_open(fs, path, common_pool_lock, pool, common_pool));
422299742Sdim  return svn_fs_fs__upgrade(fs, notify_func, notify_baton,
423299742Sdim                            cancel_func, cancel_baton, pool);
424251881Speter}
425251881Speter
426251881Speterstatic svn_error_t *
427251881Speterfs_verify(svn_fs_t *fs, const char *path,
428251881Speter          svn_revnum_t start,
429251881Speter          svn_revnum_t end,
430251881Speter          svn_fs_progress_notify_func_t notify_func,
431251881Speter          void *notify_baton,
432251881Speter          svn_cancel_func_t cancel_func,
433251881Speter          void *cancel_baton,
434299742Sdim          svn_mutex__t *common_pool_lock,
435251881Speter          apr_pool_t *pool,
436251881Speter          apr_pool_t *common_pool)
437251881Speter{
438299742Sdim  SVN_ERR(fs_open(fs, path, common_pool_lock, pool, common_pool));
439251881Speter  return svn_fs_fs__verify(fs, start, end, notify_func, notify_baton,
440251881Speter                           cancel_func, cancel_baton, pool);
441251881Speter}
442251881Speter
443251881Speterstatic svn_error_t *
444251881Speterfs_pack(svn_fs_t *fs,
445251881Speter        const char *path,
446251881Speter        svn_fs_pack_notify_t notify_func,
447251881Speter        void *notify_baton,
448251881Speter        svn_cancel_func_t cancel_func,
449251881Speter        void *cancel_baton,
450299742Sdim        svn_mutex__t *common_pool_lock,
451251881Speter        apr_pool_t *pool,
452251881Speter        apr_pool_t *common_pool)
453251881Speter{
454299742Sdim  SVN_ERR(fs_open(fs, path, common_pool_lock, pool, common_pool));
455309512Speter  return svn_fs_fs__pack(fs, 0, notify_func, notify_baton,
456251881Speter                         cancel_func, cancel_baton, pool);
457251881Speter}
458251881Speter
459251881Speter
460251881Speter
461251881Speter
462251881Speter/* This implements the fs_library_vtable_t.hotcopy() API.  Copy a
463251881Speter   possibly live Subversion filesystem SRC_FS from SRC_PATH to a
464251881Speter   DST_FS at DEST_PATH. If INCREMENTAL is TRUE, make an effort not to
465251881Speter   re-copy data which already exists in DST_FS.
466251881Speter   The CLEAN_LOGS argument is ignored and included for Subversion
467299742Sdim   1.0.x compatibility.  Indicate progress via the optional NOTIFY_FUNC
468299742Sdim   callback using NOTIFY_BATON.  Perform all temporary allocations in POOL. */
469251881Speterstatic svn_error_t *
470251881Speterfs_hotcopy(svn_fs_t *src_fs,
471251881Speter           svn_fs_t *dst_fs,
472251881Speter           const char *src_path,
473251881Speter           const char *dst_path,
474251881Speter           svn_boolean_t clean_logs,
475251881Speter           svn_boolean_t incremental,
476299742Sdim           svn_fs_hotcopy_notify_t notify_func,
477299742Sdim           void *notify_baton,
478251881Speter           svn_cancel_func_t cancel_func,
479251881Speter           void *cancel_baton,
480299742Sdim           svn_mutex__t *common_pool_lock,
481299742Sdim           apr_pool_t *pool,
482299742Sdim           apr_pool_t *common_pool)
483251881Speter{
484299742Sdim  /* Open the source repo as usual. */
485299742Sdim  SVN_ERR(fs_open(src_fs, src_path, common_pool_lock, pool, common_pool));
486299742Sdim  if (cancel_func)
487299742Sdim    SVN_ERR(cancel_func(cancel_baton));
488251881Speter
489299742Sdim  /* Test target repo when in INCREMENTAL mode, initialize it when not.
490299742Sdim   * For this, we need our FS internal data structures to be temporarily
491299742Sdim   * available. */
492251881Speter  SVN_ERR(initialize_fs_struct(dst_fs));
493299742Sdim  SVN_ERR(svn_fs_fs__hotcopy_prepare_target(src_fs, dst_fs, dst_path,
494299742Sdim                                            incremental, pool));
495299742Sdim  uninitialize_fs_struct(dst_fs);
496299742Sdim
497299742Sdim  /* Now, the destination repo should open just fine. */
498299742Sdim  SVN_ERR(fs_open(dst_fs, dst_path, common_pool_lock, pool, common_pool));
499299742Sdim  if (cancel_func)
500299742Sdim    SVN_ERR(cancel_func(cancel_baton));
501299742Sdim
502299742Sdim  /* Now, we may copy data as needed ... */
503299742Sdim  return svn_fs_fs__hotcopy(src_fs, dst_fs, incremental,
504299742Sdim                            notify_func, notify_baton,
505299742Sdim                            cancel_func, cancel_baton, pool);
506251881Speter}
507251881Speter
508251881Speter
509251881Speter
510251881Speter/* This function is included for Subversion 1.0.x compatibility.  It
511251881Speter   has no effect for fsfs backed Subversion filesystems.  It conforms
512251881Speter   to the fs_library_vtable_t.bdb_logfiles() API. */
513251881Speterstatic svn_error_t *
514251881Speterfs_logfiles(apr_array_header_t **logfiles,
515251881Speter            const char *path,
516251881Speter            svn_boolean_t only_unused,
517251881Speter            apr_pool_t *pool)
518251881Speter{
519251881Speter  /* A no-op for FSFS. */
520251881Speter  *logfiles = apr_array_make(pool, 0, sizeof(const char *));
521251881Speter
522251881Speter  return SVN_NO_ERROR;
523251881Speter}
524251881Speter
525251881Speter
526251881Speter
527251881Speter
528251881Speter
529251881Speter/* Delete the filesystem located at path PATH.  Perform any temporary
530251881Speter   allocations in POOL. */
531251881Speterstatic svn_error_t *
532251881Speterfs_delete_fs(const char *path,
533251881Speter             apr_pool_t *pool)
534251881Speter{
535251881Speter  /* Remove everything. */
536299742Sdim  return svn_error_trace(svn_io_remove_dir2(path, FALSE, NULL, NULL, pool));
537251881Speter}
538251881Speter
539251881Speterstatic const svn_version_t *
540251881Speterfs_version(void)
541251881Speter{
542251881Speter  SVN_VERSION_BODY;
543251881Speter}
544251881Speter
545251881Speterstatic const char *
546251881Speterfs_get_description(void)
547251881Speter{
548251881Speter  return _("Module for working with a plain file (FSFS) repository.");
549251881Speter}
550251881Speter
551251881Speterstatic svn_error_t *
552251881Speterfs_set_svn_fs_open(svn_fs_t *fs,
553251881Speter                   svn_error_t *(*svn_fs_open_)(svn_fs_t **,
554251881Speter                                                const char *,
555251881Speter                                                apr_hash_t *,
556299742Sdim                                                apr_pool_t *,
557251881Speter                                                apr_pool_t *))
558251881Speter{
559251881Speter  fs_fs_data_t *ffd = fs->fsap_data;
560251881Speter  ffd->svn_fs_open_ = svn_fs_open_;
561251881Speter  return SVN_NO_ERROR;
562251881Speter}
563251881Speter
564299742Sdimstatic void *
565299742Sdimfs_info_dup(const void *fsfs_info_void,
566299742Sdim            apr_pool_t *result_pool)
567299742Sdim{
568299742Sdim  /* All fields are either ints or static strings. */
569299742Sdim  const svn_fs_fsfs_info_t *fsfs_info = fsfs_info_void;
570299742Sdim  return apr_pmemdup(result_pool, fsfs_info, sizeof(*fsfs_info));
571299742Sdim}
572299742Sdim
573251881Speter
574251881Speter/* Base FS library vtable, used by the FS loader library. */
575251881Speter
576251881Speterstatic fs_library_vtable_t library_vtable = {
577251881Speter  fs_version,
578251881Speter  fs_create,
579251881Speter  fs_open,
580251881Speter  fs_open_for_recovery,
581251881Speter  fs_upgrade,
582251881Speter  fs_verify,
583251881Speter  fs_delete_fs,
584251881Speter  fs_hotcopy,
585251881Speter  fs_get_description,
586251881Speter  svn_fs_fs__recover,
587251881Speter  fs_pack,
588251881Speter  fs_logfiles,
589251881Speter  NULL /* parse_id */,
590299742Sdim  fs_set_svn_fs_open,
591299742Sdim  fs_info_dup
592251881Speter};
593251881Speter
594251881Spetersvn_error_t *
595251881Spetersvn_fs_fs__init(const svn_version_t *loader_version,
596251881Speter                fs_library_vtable_t **vtable, apr_pool_t* common_pool)
597251881Speter{
598251881Speter  static const svn_version_checklist_t checklist[] =
599251881Speter    {
600251881Speter      { "svn_subr",  svn_subr_version },
601251881Speter      { "svn_delta", svn_delta_version },
602299742Sdim      { "svn_fs_util", svn_fs_util__version },
603251881Speter      { NULL, NULL }
604251881Speter    };
605251881Speter
606251881Speter  /* Simplified version check to make sure we can safely use the
607251881Speter     VTABLE parameter. The FS loader does a more exhaustive check. */
608251881Speter  if (loader_version->major != SVN_VER_MAJOR)
609251881Speter    return svn_error_createf(SVN_ERR_VERSION_MISMATCH, NULL,
610251881Speter                             _("Unsupported FS loader version (%d) for fsfs"),
611251881Speter                             loader_version->major);
612262253Speter  SVN_ERR(svn_ver_check_list2(fs_version(), checklist, svn_ver_equal));
613251881Speter
614251881Speter  *vtable = &library_vtable;
615251881Speter  return SVN_NO_ERROR;
616251881Speter}
617