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