1251881Speter/* 2251881Speter * fs_loader.c: Front-end to the various FS back ends 3251881Speter * 4251881Speter * ==================================================================== 5251881Speter * Licensed to the Apache Software Foundation (ASF) under one 6251881Speter * or more contributor license agreements. See the NOTICE file 7251881Speter * distributed with this work for additional information 8251881Speter * regarding copyright ownership. The ASF licenses this file 9251881Speter * to you under the Apache License, Version 2.0 (the 10251881Speter * "License"); you may not use this file except in compliance 11251881Speter * with the License. You may obtain a copy of the License at 12251881Speter * 13251881Speter * http://www.apache.org/licenses/LICENSE-2.0 14251881Speter * 15251881Speter * Unless required by applicable law or agreed to in writing, 16251881Speter * software distributed under the License is distributed on an 17251881Speter * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 18251881Speter * KIND, either express or implied. See the License for the 19251881Speter * specific language governing permissions and limitations 20251881Speter * under the License. 21251881Speter * ==================================================================== 22251881Speter */ 23251881Speter 24251881Speter 25251881Speter#include <string.h> 26251881Speter#include <apr.h> 27251881Speter#include <apr_hash.h> 28251881Speter#include <apr_md5.h> 29251881Speter#include <apr_thread_mutex.h> 30251881Speter#include <apr_uuid.h> 31251881Speter#include <apr_strings.h> 32251881Speter 33251881Speter#include "svn_hash.h" 34251881Speter#include "svn_ctype.h" 35251881Speter#include "svn_types.h" 36251881Speter#include "svn_dso.h" 37251881Speter#include "svn_version.h" 38251881Speter#include "svn_fs.h" 39251881Speter#include "svn_path.h" 40251881Speter#include "svn_xml.h" 41251881Speter#include "svn_pools.h" 42251881Speter#include "svn_string.h" 43251881Speter#include "svn_private_config.h" 44251881Speter 45251881Speter#include "private/svn_fs_private.h" 46251881Speter#include "private/svn_fs_util.h" 47251881Speter#include "private/svn_utf_private.h" 48251881Speter#include "private/svn_mutex.h" 49251881Speter#include "private/svn_subr_private.h" 50251881Speter 51251881Speter#include "fs-loader.h" 52251881Speter 53251881Speter/* This is defined by configure on platforms which use configure, but 54251881Speter we need to define a fallback for Windows. */ 55251881Speter#ifndef DEFAULT_FS_TYPE 56251881Speter#define DEFAULT_FS_TYPE "fsfs" 57251881Speter#endif 58251881Speter 59251881Speter#define FS_TYPE_FILENAME "fs-type" 60251881Speter 61251881Speter/* A pool common to all FS objects. See the documentation on the 62251881Speter open/create functions in fs-loader.h and for svn_fs_initialize(). */ 63251881Speterstatic apr_pool_t *common_pool; 64251881Spetersvn_mutex__t *common_pool_lock; 65251881Speter 66251881Speter 67251881Speter/* --- Utility functions for the loader --- */ 68251881Speter 69251881Speterstruct fs_type_defn { 70251881Speter const char *fs_type; 71251881Speter const char *fsap_name; 72251881Speter fs_init_func_t initfunc; 73251881Speter struct fs_type_defn *next; 74251881Speter}; 75251881Speter 76251881Speterstatic struct fs_type_defn base_defn = 77251881Speter { 78251881Speter SVN_FS_TYPE_BDB, "base", 79251881Speter#ifdef SVN_LIBSVN_FS_LINKS_FS_BASE 80251881Speter svn_fs_base__init, 81251881Speter#else 82251881Speter NULL, 83251881Speter#endif 84262253Speter NULL /* End of static list: this needs to be reset to NULL if the 85262253Speter common_pool used when setting it has been cleared. */ 86251881Speter }; 87251881Speter 88251881Speterstatic struct fs_type_defn fsfs_defn = 89251881Speter { 90251881Speter SVN_FS_TYPE_FSFS, "fs", 91251881Speter#ifdef SVN_LIBSVN_FS_LINKS_FS_FS 92251881Speter svn_fs_fs__init, 93251881Speter#else 94251881Speter NULL, 95251881Speter#endif 96251881Speter &base_defn 97251881Speter }; 98251881Speter 99251881Speterstatic struct fs_type_defn *fs_modules = &fsfs_defn; 100251881Speter 101251881Speter 102251881Speterstatic svn_error_t * 103251881Speterload_module(fs_init_func_t *initfunc, const char *name, apr_pool_t *pool) 104251881Speter{ 105251881Speter *initfunc = NULL; 106251881Speter 107251881Speter#if defined(SVN_USE_DSO) && APR_HAS_DSO 108251881Speter { 109251881Speter apr_dso_handle_t *dso; 110251881Speter apr_dso_handle_sym_t symbol; 111251881Speter const char *libname; 112251881Speter const char *funcname; 113251881Speter apr_status_t status; 114251881Speter const char *p; 115251881Speter 116251881Speter /* Demand a simple alphanumeric name so that the generated DSO 117251881Speter name is sensible. */ 118251881Speter for (p = name; *p; ++p) 119251881Speter if (!svn_ctype_isalnum(*p)) 120251881Speter return svn_error_createf(SVN_ERR_FS_UNKNOWN_FS_TYPE, NULL, 121251881Speter _("Invalid name for FS type '%s'"), 122251881Speter name); 123251881Speter 124251881Speter libname = apr_psprintf(pool, "libsvn_fs_%s-%d.so.%d", 125251881Speter name, SVN_VER_MAJOR, SVN_SOVERSION); 126251881Speter funcname = apr_psprintf(pool, "svn_fs_%s__init", name); 127251881Speter 128251881Speter /* Find/load the specified library. If we get an error, assume 129251881Speter the library doesn't exist. The library will be unloaded when 130251881Speter pool is destroyed. */ 131251881Speter SVN_ERR(svn_dso_load(&dso, libname)); 132251881Speter if (! dso) 133251881Speter return SVN_NO_ERROR; 134251881Speter 135251881Speter /* find the initialization routine */ 136251881Speter status = apr_dso_sym(&symbol, dso, funcname); 137251881Speter if (status) 138251881Speter return svn_error_wrap_apr(status, _("'%s' does not define '%s()'"), 139251881Speter libname, funcname); 140251881Speter 141251881Speter *initfunc = (fs_init_func_t) symbol; 142251881Speter } 143251881Speter#endif /* APR_HAS_DSO */ 144251881Speter 145251881Speter return SVN_NO_ERROR; 146251881Speter} 147251881Speter 148251881Speter/* Fetch a library vtable by a pointer into the library definitions array. */ 149251881Speterstatic svn_error_t * 150251881Speterget_library_vtable_direct(fs_library_vtable_t **vtable, 151251881Speter const struct fs_type_defn *fst, 152251881Speter apr_pool_t *pool) 153251881Speter{ 154251881Speter fs_init_func_t initfunc = NULL; 155251881Speter const svn_version_t *my_version = svn_fs_version(); 156251881Speter const svn_version_t *fs_version; 157251881Speter 158251881Speter initfunc = fst->initfunc; 159251881Speter if (! initfunc) 160251881Speter SVN_ERR(load_module(&initfunc, fst->fsap_name, pool)); 161251881Speter 162251881Speter if (! initfunc) 163251881Speter return svn_error_createf(SVN_ERR_FS_UNKNOWN_FS_TYPE, NULL, 164251881Speter _("Failed to load module for FS type '%s'"), 165251881Speter fst->fs_type); 166251881Speter 167251881Speter { 168251881Speter /* Per our API compatibility rules, we cannot ensure that 169251881Speter svn_fs_initialize is called by the application. If not, we 170251881Speter cannot create the common pool and lock in a thread-safe fashion, 171251881Speter nor can we clean up the common pool if libsvn_fs is dynamically 172251881Speter unloaded. This function makes a best effort by creating the 173251881Speter common pool as a child of the global pool; the window of failure 174251881Speter due to thread collision is small. */ 175251881Speter if (!common_pool) 176251881Speter SVN_ERR(svn_fs_initialize(NULL)); 177251881Speter 178251881Speter /* Invoke the FS module's initfunc function with the common 179251881Speter pool protected by a lock. */ 180251881Speter SVN_MUTEX__WITH_LOCK(common_pool_lock, 181251881Speter initfunc(my_version, vtable, common_pool)); 182251881Speter } 183251881Speter fs_version = (*vtable)->get_version(); 184251881Speter if (!svn_ver_equal(my_version, fs_version)) 185251881Speter return svn_error_createf(SVN_ERR_VERSION_MISMATCH, NULL, 186251881Speter _("Mismatched FS module version for '%s':" 187251881Speter " found %d.%d.%d%s," 188251881Speter " expected %d.%d.%d%s"), 189251881Speter fst->fs_type, 190251881Speter my_version->major, my_version->minor, 191251881Speter my_version->patch, my_version->tag, 192251881Speter fs_version->major, fs_version->minor, 193251881Speter fs_version->patch, fs_version->tag); 194251881Speter return SVN_NO_ERROR; 195251881Speter} 196251881Speter 197251881Speter#if defined(SVN_USE_DSO) && APR_HAS_DSO 198251881Speter/* Return *FST for the third party FS_TYPE */ 199251881Speterstatic svn_error_t * 200251881Speterget_or_allocate_third(struct fs_type_defn **fst, 201251881Speter const char *fs_type) 202251881Speter{ 203251881Speter while (*fst) 204251881Speter { 205251881Speter if (strcmp(fs_type, (*fst)->fs_type) == 0) 206251881Speter return SVN_NO_ERROR; 207251881Speter fst = &(*fst)->next; 208251881Speter } 209251881Speter 210251881Speter *fst = apr_palloc(common_pool, sizeof(struct fs_type_defn)); 211251881Speter (*fst)->fs_type = apr_pstrdup(common_pool, fs_type); 212251881Speter (*fst)->fsap_name = (*fst)->fs_type; 213251881Speter (*fst)->initfunc = NULL; 214251881Speter (*fst)->next = NULL; 215251881Speter 216251881Speter return SVN_NO_ERROR; 217251881Speter} 218251881Speter#endif 219251881Speter 220251881Speter/* Fetch a library vtable by FS type. */ 221251881Speterstatic svn_error_t * 222251881Speterget_library_vtable(fs_library_vtable_t **vtable, const char *fs_type, 223251881Speter apr_pool_t *pool) 224251881Speter{ 225251881Speter struct fs_type_defn **fst = &fs_modules; 226251881Speter svn_boolean_t known = FALSE; 227251881Speter 228251881Speter /* There are two FS module definitions known at compile time. We 229251881Speter want to check these without any locking overhead even when 230251881Speter dynamic third party modules are enabled. The third party modules 231251881Speter cannot be checked until the lock is held. */ 232251881Speter if (strcmp(fs_type, (*fst)->fs_type) == 0) 233251881Speter known = TRUE; 234251881Speter else 235251881Speter { 236251881Speter fst = &(*fst)->next; 237251881Speter if (strcmp(fs_type, (*fst)->fs_type) == 0) 238251881Speter known = TRUE; 239251881Speter } 240251881Speter 241251881Speter#if defined(SVN_USE_DSO) && APR_HAS_DSO 242251881Speter /* Third party FS modules that are unknown at compile time. 243251881Speter 244251881Speter A third party FS is identified by the file fs-type containing a 245251881Speter third party name, say "foo". The loader will load the DSO with 246251881Speter the name "libsvn_fs_foo" and use the entry point with the name 247251881Speter "svn_fs_foo__init". 248251881Speter 249251881Speter Note: the BDB and FSFS modules don't follow this naming scheme 250251881Speter and this allows them to be used to test the third party loader. 251251881Speter Change the content of fs-type to "base" in a BDB filesystem or to 252251881Speter "fs" in an FSFS filesystem and they will be loaded as third party 253251881Speter modules. */ 254251881Speter if (!known) 255251881Speter { 256251881Speter fst = &(*fst)->next; 257251881Speter if (!common_pool) /* Best-effort init, see get_library_vtable_direct. */ 258251881Speter SVN_ERR(svn_fs_initialize(NULL)); 259251881Speter SVN_MUTEX__WITH_LOCK(common_pool_lock, 260251881Speter get_or_allocate_third(fst, fs_type)); 261251881Speter known = TRUE; 262251881Speter } 263251881Speter#endif 264251881Speter if (!known) 265251881Speter return svn_error_createf(SVN_ERR_FS_UNKNOWN_FS_TYPE, NULL, 266251881Speter _("Unknown FS type '%s'"), fs_type); 267251881Speter return get_library_vtable_direct(vtable, *fst, pool); 268251881Speter} 269251881Speter 270251881Spetersvn_error_t * 271251881Spetersvn_fs_type(const char **fs_type, const char *path, apr_pool_t *pool) 272251881Speter{ 273251881Speter const char *filename; 274251881Speter char buf[128]; 275251881Speter svn_error_t *err; 276251881Speter apr_file_t *file; 277251881Speter apr_size_t len; 278251881Speter 279251881Speter /* Read the fsap-name file to get the FSAP name, or assume the (old) 280251881Speter default. For old repositories I suppose we could check some 281251881Speter other file, DB_CONFIG or strings say, but for now just check the 282251881Speter directory exists. */ 283251881Speter filename = svn_dirent_join(path, FS_TYPE_FILENAME, pool); 284251881Speter err = svn_io_file_open(&file, filename, APR_READ|APR_BUFFERED, 0, pool); 285251881Speter if (err && APR_STATUS_IS_ENOENT(err->apr_err)) 286251881Speter { 287251881Speter svn_node_kind_t kind; 288251881Speter svn_error_t *err2 = svn_io_check_path(path, &kind, pool); 289251881Speter if (err2) 290251881Speter { 291251881Speter svn_error_clear(err2); 292251881Speter return err; 293251881Speter } 294251881Speter if (kind == svn_node_dir) 295251881Speter { 296251881Speter svn_error_clear(err); 297251881Speter *fs_type = SVN_FS_TYPE_BDB; 298251881Speter return SVN_NO_ERROR; 299251881Speter } 300251881Speter return err; 301251881Speter } 302251881Speter else if (err) 303251881Speter return err; 304251881Speter 305251881Speter len = sizeof(buf); 306251881Speter SVN_ERR(svn_io_read_length_line(file, buf, &len, pool)); 307251881Speter SVN_ERR(svn_io_file_close(file, pool)); 308251881Speter *fs_type = apr_pstrdup(pool, buf); 309251881Speter 310251881Speter return SVN_NO_ERROR; 311251881Speter} 312251881Speter 313251881Speter/* Fetch the library vtable for an existing FS. */ 314251881Speterstatic svn_error_t * 315251881Speterfs_library_vtable(fs_library_vtable_t **vtable, const char *path, 316251881Speter apr_pool_t *pool) 317251881Speter{ 318251881Speter const char *fs_type; 319251881Speter 320251881Speter SVN_ERR(svn_fs_type(&fs_type, path, pool)); 321251881Speter 322251881Speter /* Fetch the library vtable by name, now that we've chosen one. */ 323251881Speter return svn_error_trace(get_library_vtable(vtable, fs_type, pool)); 324251881Speter} 325251881Speter 326251881Speterstatic svn_error_t * 327251881Speterwrite_fs_type(const char *path, const char *fs_type, apr_pool_t *pool) 328251881Speter{ 329251881Speter const char *filename; 330251881Speter apr_file_t *file; 331251881Speter 332251881Speter filename = svn_dirent_join(path, FS_TYPE_FILENAME, pool); 333251881Speter SVN_ERR(svn_io_file_open(&file, filename, 334251881Speter APR_WRITE|APR_CREATE|APR_TRUNCATE|APR_BUFFERED, 335251881Speter APR_OS_DEFAULT, pool)); 336251881Speter SVN_ERR(svn_io_file_write_full(file, fs_type, strlen(fs_type), NULL, 337251881Speter pool)); 338251881Speter SVN_ERR(svn_io_file_write_full(file, "\n", 1, NULL, pool)); 339251881Speter return svn_error_trace(svn_io_file_close(file, pool)); 340251881Speter} 341251881Speter 342251881Speter 343251881Speter/* --- Functions for operating on filesystems by pathname --- */ 344251881Speter 345251881Speterstatic apr_status_t uninit(void *data) 346251881Speter{ 347251881Speter common_pool = NULL; 348251881Speter return APR_SUCCESS; 349251881Speter} 350251881Speter 351251881Spetersvn_error_t * 352251881Spetersvn_fs_initialize(apr_pool_t *pool) 353251881Speter{ 354251881Speter /* Protect against multiple calls. */ 355251881Speter if (common_pool) 356251881Speter return SVN_NO_ERROR; 357251881Speter 358251881Speter common_pool = svn_pool_create(pool); 359262253Speter base_defn.next = NULL; 360251881Speter SVN_ERR(svn_mutex__init(&common_pool_lock, TRUE, common_pool)); 361251881Speter 362251881Speter /* ### This won't work if POOL is NULL and libsvn_fs is loaded as a DSO 363251881Speter ### (via libsvn_ra_local say) since the global common_pool will live 364251881Speter ### longer than the DSO, which gets unloaded when the pool used to 365251881Speter ### load it is cleared, and so when the handler runs it will refer to 366251881Speter ### a function that no longer exists. libsvn_ra_local attempts to 367251881Speter ### work around this by explicitly calling svn_fs_initialize. */ 368251881Speter apr_pool_cleanup_register(common_pool, NULL, uninit, apr_pool_cleanup_null); 369251881Speter return SVN_NO_ERROR; 370251881Speter} 371251881Speter 372251881Speter/* A default warning handling function. */ 373251881Speterstatic void 374251881Speterdefault_warning_func(void *baton, svn_error_t *err) 375251881Speter{ 376251881Speter /* The one unforgiveable sin is to fail silently. Dumping to stderr 377251881Speter or /dev/tty is not acceptable default behavior for server 378251881Speter processes, since those may both be equivalent to /dev/null. */ 379251881Speter SVN_ERR_MALFUNCTION_NO_RETURN(); 380251881Speter} 381251881Speter 382251881Spetersvn_error_t * 383251881Spetersvn_fs__path_valid(const char *path, apr_pool_t *pool) 384251881Speter{ 385251881Speter /* UTF-8 encoded string without NULs. */ 386251881Speter if (! svn_utf__cstring_is_valid(path)) 387251881Speter { 388251881Speter return svn_error_createf(SVN_ERR_FS_PATH_SYNTAX, NULL, 389251881Speter _("Path '%s' is not in UTF-8"), path); 390251881Speter } 391251881Speter 392251881Speter /* No "." or ".." elements. */ 393251881Speter if (svn_path_is_backpath_present(path) 394251881Speter || svn_path_is_dotpath_present(path)) 395251881Speter { 396251881Speter return svn_error_createf(SVN_ERR_FS_PATH_SYNTAX, NULL, 397251881Speter _("Path '%s' contains '.' or '..' element"), 398251881Speter path); 399251881Speter } 400251881Speter 401251881Speter /* That's good enough. */ 402251881Speter return SVN_NO_ERROR; 403251881Speter} 404251881Speter 405251881Speter/* Allocate svn_fs_t structure. */ 406251881Speterstatic svn_fs_t * 407251881Speterfs_new(apr_hash_t *fs_config, apr_pool_t *pool) 408251881Speter{ 409251881Speter svn_fs_t *fs = apr_palloc(pool, sizeof(*fs)); 410251881Speter fs->pool = pool; 411251881Speter fs->path = NULL; 412251881Speter fs->warning = default_warning_func; 413251881Speter fs->warning_baton = NULL; 414251881Speter fs->config = fs_config; 415251881Speter fs->access_ctx = NULL; 416251881Speter fs->vtable = NULL; 417251881Speter fs->fsap_data = NULL; 418251881Speter fs->uuid = NULL; 419251881Speter return fs; 420251881Speter} 421251881Speter 422251881Spetersvn_fs_t * 423251881Spetersvn_fs_new(apr_hash_t *fs_config, apr_pool_t *pool) 424251881Speter{ 425251881Speter return fs_new(fs_config, pool); 426251881Speter} 427251881Speter 428251881Spetervoid 429251881Spetersvn_fs_set_warning_func(svn_fs_t *fs, svn_fs_warning_callback_t warning, 430251881Speter void *warning_baton) 431251881Speter{ 432251881Speter fs->warning = warning; 433251881Speter fs->warning_baton = warning_baton; 434251881Speter} 435251881Speter 436251881Spetersvn_error_t * 437251881Spetersvn_fs_create(svn_fs_t **fs_p, const char *path, apr_hash_t *fs_config, 438251881Speter apr_pool_t *pool) 439251881Speter{ 440251881Speter fs_library_vtable_t *vtable; 441251881Speter 442251881Speter const char *fs_type = svn_hash__get_cstring(fs_config, 443251881Speter SVN_FS_CONFIG_FS_TYPE, 444251881Speter DEFAULT_FS_TYPE); 445251881Speter SVN_ERR(get_library_vtable(&vtable, fs_type, pool)); 446251881Speter 447251881Speter /* Create the FS directory and write out the fsap-name file. */ 448251881Speter SVN_ERR(svn_io_dir_make_sgid(path, APR_OS_DEFAULT, pool)); 449251881Speter SVN_ERR(write_fs_type(path, fs_type, pool)); 450251881Speter 451251881Speter /* Perform the actual creation. */ 452251881Speter *fs_p = fs_new(fs_config, pool); 453251881Speter 454251881Speter SVN_MUTEX__WITH_LOCK(common_pool_lock, 455251881Speter vtable->create(*fs_p, path, pool, common_pool)); 456251881Speter SVN_ERR(vtable->set_svn_fs_open(*fs_p, svn_fs_open)); 457251881Speter 458251881Speter return SVN_NO_ERROR; 459251881Speter} 460251881Speter 461251881Spetersvn_error_t * 462251881Spetersvn_fs_open(svn_fs_t **fs_p, const char *path, apr_hash_t *fs_config, 463251881Speter apr_pool_t *pool) 464251881Speter{ 465251881Speter fs_library_vtable_t *vtable; 466251881Speter 467251881Speter SVN_ERR(fs_library_vtable(&vtable, path, pool)); 468251881Speter *fs_p = fs_new(fs_config, pool); 469251881Speter SVN_MUTEX__WITH_LOCK(common_pool_lock, 470251881Speter vtable->open_fs(*fs_p, path, pool, common_pool)); 471251881Speter SVN_ERR(vtable->set_svn_fs_open(*fs_p, svn_fs_open)); 472251881Speter 473251881Speter return SVN_NO_ERROR; 474251881Speter} 475251881Speter 476251881Spetersvn_error_t * 477251881Spetersvn_fs_upgrade(const char *path, apr_pool_t *pool) 478251881Speter{ 479251881Speter fs_library_vtable_t *vtable; 480251881Speter svn_fs_t *fs; 481251881Speter 482251881Speter SVN_ERR(fs_library_vtable(&vtable, path, pool)); 483251881Speter fs = fs_new(NULL, pool); 484251881Speter 485251881Speter SVN_MUTEX__WITH_LOCK(common_pool_lock, 486251881Speter vtable->upgrade_fs(fs, path, pool, common_pool)); 487251881Speter return SVN_NO_ERROR; 488251881Speter} 489251881Speter 490251881Spetersvn_error_t * 491251881Spetersvn_fs_verify(const char *path, 492251881Speter apr_hash_t *fs_config, 493251881Speter svn_revnum_t start, 494251881Speter svn_revnum_t end, 495251881Speter svn_fs_progress_notify_func_t notify_func, 496251881Speter void *notify_baton, 497251881Speter svn_cancel_func_t cancel_func, 498251881Speter void *cancel_baton, 499251881Speter apr_pool_t *pool) 500251881Speter{ 501251881Speter fs_library_vtable_t *vtable; 502251881Speter svn_fs_t *fs; 503251881Speter 504251881Speter SVN_ERR(fs_library_vtable(&vtable, path, pool)); 505251881Speter fs = fs_new(fs_config, pool); 506251881Speter 507251881Speter SVN_MUTEX__WITH_LOCK(common_pool_lock, 508251881Speter vtable->verify_fs(fs, path, start, end, 509251881Speter notify_func, notify_baton, 510251881Speter cancel_func, cancel_baton, 511251881Speter pool, common_pool)); 512251881Speter return SVN_NO_ERROR; 513251881Speter} 514251881Speter 515251881Speterconst char * 516251881Spetersvn_fs_path(svn_fs_t *fs, apr_pool_t *pool) 517251881Speter{ 518251881Speter return apr_pstrdup(pool, fs->path); 519251881Speter} 520251881Speter 521251881Speterapr_hash_t * 522251881Spetersvn_fs_config(svn_fs_t *fs, apr_pool_t *pool) 523251881Speter{ 524251881Speter if (fs->config) 525251881Speter return apr_hash_copy(pool, fs->config); 526251881Speter 527251881Speter return NULL; 528251881Speter} 529251881Speter 530251881Spetersvn_error_t * 531251881Spetersvn_fs_delete_fs(const char *path, apr_pool_t *pool) 532251881Speter{ 533251881Speter fs_library_vtable_t *vtable; 534251881Speter 535251881Speter SVN_ERR(fs_library_vtable(&vtable, path, pool)); 536251881Speter return svn_error_trace(vtable->delete_fs(path, pool)); 537251881Speter} 538251881Speter 539251881Spetersvn_error_t * 540251881Spetersvn_fs_hotcopy2(const char *src_path, const char *dst_path, 541251881Speter svn_boolean_t clean, svn_boolean_t incremental, 542251881Speter svn_cancel_func_t cancel_func, void *cancel_baton, 543251881Speter apr_pool_t *scratch_pool) 544251881Speter{ 545251881Speter fs_library_vtable_t *vtable; 546251881Speter const char *src_fs_type; 547251881Speter svn_fs_t *src_fs; 548251881Speter svn_fs_t *dst_fs; 549251881Speter const char *dst_fs_type; 550251881Speter svn_node_kind_t dst_kind; 551251881Speter 552251881Speter if (strcmp(src_path, dst_path) == 0) 553251881Speter return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL, 554251881Speter _("Hotcopy source and destination are equal")); 555251881Speter 556251881Speter SVN_ERR(svn_fs_type(&src_fs_type, src_path, scratch_pool)); 557251881Speter SVN_ERR(get_library_vtable(&vtable, src_fs_type, scratch_pool)); 558251881Speter src_fs = fs_new(NULL, scratch_pool); 559251881Speter dst_fs = fs_new(NULL, scratch_pool); 560251881Speter 561251881Speter SVN_ERR(svn_io_check_path(dst_path, &dst_kind, scratch_pool)); 562251881Speter if (dst_kind == svn_node_file) 563251881Speter return svn_error_createf(SVN_ERR_NODE_UNEXPECTED_KIND, NULL, 564251881Speter _("'%s' already exists and is a file"), 565251881Speter svn_dirent_local_style(dst_path, 566251881Speter scratch_pool)); 567251881Speter if (dst_kind == svn_node_unknown) 568251881Speter return svn_error_createf(SVN_ERR_NODE_UNEXPECTED_KIND, NULL, 569251881Speter _("'%s' already exists and has an unknown " 570251881Speter "node kind"), 571251881Speter svn_dirent_local_style(dst_path, 572251881Speter scratch_pool)); 573251881Speter if (dst_kind == svn_node_dir) 574251881Speter { 575251881Speter svn_node_kind_t type_file_kind; 576251881Speter 577251881Speter SVN_ERR(svn_io_check_path(svn_dirent_join(dst_path, 578251881Speter FS_TYPE_FILENAME, 579251881Speter scratch_pool), 580251881Speter &type_file_kind, scratch_pool)); 581251881Speter if (type_file_kind != svn_node_none) 582251881Speter { 583251881Speter SVN_ERR(svn_fs_type(&dst_fs_type, dst_path, scratch_pool)); 584251881Speter if (strcmp(src_fs_type, dst_fs_type) != 0) 585251881Speter return svn_error_createf( 586251881Speter SVN_ERR_ILLEGAL_TARGET, NULL, 587251881Speter _("The filesystem type of the hotcopy source " 588251881Speter "('%s') does not match the filesystem " 589251881Speter "type of the hotcopy destination ('%s')"), 590251881Speter src_fs_type, dst_fs_type); 591251881Speter } 592251881Speter } 593251881Speter 594251881Speter SVN_ERR(vtable->hotcopy(src_fs, dst_fs, src_path, dst_path, clean, 595251881Speter incremental, cancel_func, cancel_baton, 596251881Speter scratch_pool)); 597251881Speter return svn_error_trace(write_fs_type(dst_path, src_fs_type, scratch_pool)); 598251881Speter} 599251881Speter 600251881Spetersvn_error_t * 601251881Spetersvn_fs_hotcopy(const char *src_path, const char *dest_path, 602251881Speter svn_boolean_t clean, apr_pool_t *pool) 603251881Speter{ 604251881Speter return svn_error_trace(svn_fs_hotcopy2(src_path, dest_path, clean, 605251881Speter FALSE, NULL, NULL, pool)); 606251881Speter} 607251881Speter 608251881Spetersvn_error_t * 609251881Spetersvn_fs_pack(const char *path, 610251881Speter svn_fs_pack_notify_t notify_func, 611251881Speter void *notify_baton, 612251881Speter svn_cancel_func_t cancel_func, 613251881Speter void *cancel_baton, 614251881Speter apr_pool_t *pool) 615251881Speter{ 616251881Speter fs_library_vtable_t *vtable; 617251881Speter svn_fs_t *fs; 618251881Speter 619251881Speter SVN_ERR(fs_library_vtable(&vtable, path, pool)); 620251881Speter fs = fs_new(NULL, pool); 621251881Speter 622251881Speter SVN_MUTEX__WITH_LOCK(common_pool_lock, 623251881Speter vtable->pack_fs(fs, path, notify_func, notify_baton, 624251881Speter cancel_func, cancel_baton, pool, 625251881Speter common_pool)); 626251881Speter return SVN_NO_ERROR; 627251881Speter} 628251881Speter 629251881Spetersvn_error_t * 630251881Spetersvn_fs_recover(const char *path, 631251881Speter svn_cancel_func_t cancel_func, void *cancel_baton, 632251881Speter apr_pool_t *pool) 633251881Speter{ 634251881Speter fs_library_vtable_t *vtable; 635251881Speter svn_fs_t *fs; 636251881Speter 637251881Speter SVN_ERR(fs_library_vtable(&vtable, path, pool)); 638251881Speter fs = fs_new(NULL, pool); 639251881Speter 640251881Speter SVN_MUTEX__WITH_LOCK(common_pool_lock, 641251881Speter vtable->open_fs_for_recovery(fs, path, pool, 642251881Speter common_pool)); 643251881Speter return svn_error_trace(vtable->recover(fs, cancel_func, cancel_baton, 644251881Speter pool)); 645251881Speter} 646251881Speter 647251881Spetersvn_error_t * 648251881Spetersvn_fs_verify_root(svn_fs_root_t *root, 649251881Speter apr_pool_t *scratch_pool) 650251881Speter{ 651251881Speter svn_fs_t *fs = root->fs; 652251881Speter SVN_ERR(fs->vtable->verify_root(root, scratch_pool)); 653251881Speter 654251881Speter return SVN_NO_ERROR; 655251881Speter} 656251881Speter 657251881Spetersvn_error_t * 658251881Spetersvn_fs_freeze(svn_fs_t *fs, 659251881Speter svn_fs_freeze_func_t freeze_func, 660251881Speter void *freeze_baton, 661251881Speter apr_pool_t *pool) 662251881Speter{ 663251881Speter SVN_ERR(fs->vtable->freeze(fs, freeze_func, freeze_baton, pool)); 664251881Speter 665251881Speter return SVN_NO_ERROR; 666251881Speter} 667251881Speter 668251881Speter 669251881Speter/* --- Berkeley-specific functions --- */ 670251881Speter 671251881Spetersvn_error_t * 672251881Spetersvn_fs_create_berkeley(svn_fs_t *fs, const char *path) 673251881Speter{ 674251881Speter fs_library_vtable_t *vtable; 675251881Speter 676251881Speter SVN_ERR(get_library_vtable(&vtable, SVN_FS_TYPE_BDB, fs->pool)); 677251881Speter 678251881Speter /* Create the FS directory and write out the fsap-name file. */ 679251881Speter SVN_ERR(svn_io_dir_make_sgid(path, APR_OS_DEFAULT, fs->pool)); 680251881Speter SVN_ERR(write_fs_type(path, SVN_FS_TYPE_BDB, fs->pool)); 681251881Speter 682251881Speter /* Perform the actual creation. */ 683251881Speter SVN_MUTEX__WITH_LOCK(common_pool_lock, 684251881Speter vtable->create(fs, path, fs->pool, common_pool)); 685251881Speter SVN_ERR(vtable->set_svn_fs_open(fs, svn_fs_open)); 686251881Speter 687251881Speter return SVN_NO_ERROR; 688251881Speter} 689251881Speter 690251881Spetersvn_error_t * 691251881Spetersvn_fs_open_berkeley(svn_fs_t *fs, const char *path) 692251881Speter{ 693251881Speter fs_library_vtable_t *vtable; 694251881Speter 695251881Speter SVN_ERR(fs_library_vtable(&vtable, path, fs->pool)); 696251881Speter SVN_MUTEX__WITH_LOCK(common_pool_lock, 697251881Speter vtable->open_fs(fs, path, fs->pool, common_pool)); 698251881Speter SVN_ERR(vtable->set_svn_fs_open(fs, svn_fs_open)); 699251881Speter 700251881Speter return SVN_NO_ERROR; 701251881Speter} 702251881Speter 703251881Speterconst char * 704251881Spetersvn_fs_berkeley_path(svn_fs_t *fs, apr_pool_t *pool) 705251881Speter{ 706251881Speter return svn_fs_path(fs, pool); 707251881Speter} 708251881Speter 709251881Spetersvn_error_t * 710251881Spetersvn_fs_delete_berkeley(const char *path, apr_pool_t *pool) 711251881Speter{ 712251881Speter return svn_error_trace(svn_fs_delete_fs(path, pool)); 713251881Speter} 714251881Speter 715251881Spetersvn_error_t * 716251881Spetersvn_fs_hotcopy_berkeley(const char *src_path, const char *dest_path, 717251881Speter svn_boolean_t clean_logs, apr_pool_t *pool) 718251881Speter{ 719251881Speter return svn_error_trace(svn_fs_hotcopy2(src_path, dest_path, clean_logs, 720251881Speter FALSE, NULL, NULL, pool)); 721251881Speter} 722251881Speter 723251881Spetersvn_error_t * 724251881Spetersvn_fs_berkeley_recover(const char *path, apr_pool_t *pool) 725251881Speter{ 726251881Speter return svn_error_trace(svn_fs_recover(path, NULL, NULL, pool)); 727251881Speter} 728251881Speter 729251881Spetersvn_error_t * 730251881Spetersvn_fs_set_berkeley_errcall(svn_fs_t *fs, 731251881Speter void (*handler)(const char *errpfx, char *msg)) 732251881Speter{ 733251881Speter return svn_error_trace(fs->vtable->bdb_set_errcall(fs, handler)); 734251881Speter} 735251881Speter 736251881Spetersvn_error_t * 737251881Spetersvn_fs_berkeley_logfiles(apr_array_header_t **logfiles, 738251881Speter const char *path, 739251881Speter svn_boolean_t only_unused, 740251881Speter apr_pool_t *pool) 741251881Speter{ 742251881Speter fs_library_vtable_t *vtable; 743251881Speter 744251881Speter SVN_ERR(fs_library_vtable(&vtable, path, pool)); 745251881Speter return svn_error_trace(vtable->bdb_logfiles(logfiles, path, only_unused, 746251881Speter pool)); 747251881Speter} 748251881Speter 749251881Speter 750251881Speter/* --- Transaction functions --- */ 751251881Speter 752251881Spetersvn_error_t * 753251881Spetersvn_fs_begin_txn2(svn_fs_txn_t **txn_p, svn_fs_t *fs, svn_revnum_t rev, 754251881Speter apr_uint32_t flags, apr_pool_t *pool) 755251881Speter{ 756251881Speter return svn_error_trace(fs->vtable->begin_txn(txn_p, fs, rev, flags, pool)); 757251881Speter} 758251881Speter 759251881Speter 760251881Spetersvn_error_t * 761251881Spetersvn_fs_begin_txn(svn_fs_txn_t **txn_p, svn_fs_t *fs, svn_revnum_t rev, 762251881Speter apr_pool_t *pool) 763251881Speter{ 764251881Speter return svn_error_trace(svn_fs_begin_txn2(txn_p, fs, rev, 0, pool)); 765251881Speter} 766251881Speter 767251881Speter 768251881Spetersvn_error_t * 769251881Spetersvn_fs_commit_txn(const char **conflict_p, svn_revnum_t *new_rev, 770251881Speter svn_fs_txn_t *txn, apr_pool_t *pool) 771251881Speter{ 772251881Speter svn_error_t *err; 773251881Speter 774251881Speter *new_rev = SVN_INVALID_REVNUM; 775251881Speter if (conflict_p) 776251881Speter *conflict_p = NULL; 777251881Speter 778251881Speter err = txn->vtable->commit(conflict_p, new_rev, txn, pool); 779251881Speter 780251881Speter#ifdef SVN_DEBUG 781251881Speter /* Check postconditions. */ 782251881Speter if (conflict_p) 783251881Speter { 784251881Speter SVN_ERR_ASSERT_E(! (SVN_IS_VALID_REVNUM(*new_rev) && *conflict_p != NULL), 785251881Speter err); 786251881Speter SVN_ERR_ASSERT_E((*conflict_p != NULL) 787251881Speter == (err && err->apr_err == SVN_ERR_FS_CONFLICT), 788251881Speter err); 789251881Speter } 790251881Speter#endif 791251881Speter 792251881Speter SVN_ERR(err); 793251881Speter 794251881Speter#ifdef PACK_AFTER_EVERY_COMMIT 795251881Speter { 796251881Speter svn_fs_t *fs = txn->fs; 797251881Speter const char *fs_path = svn_fs_path(fs, pool); 798251881Speter err = svn_fs_pack(fs_path, NULL, NULL, NULL, NULL, pool); 799251881Speter if (err && err->apr_err == SVN_ERR_UNSUPPORTED_FEATURE) 800251881Speter /* Pre-1.6 filesystem. */ 801251881Speter svn_error_clear(err); 802251881Speter else if (err) 803251881Speter /* Real error. */ 804251881Speter return svn_error_trace(err); 805251881Speter } 806251881Speter#endif 807251881Speter 808251881Speter return SVN_NO_ERROR; 809251881Speter} 810251881Speter 811251881Speter 812251881Spetersvn_error_t * 813251881Spetersvn_fs_abort_txn(svn_fs_txn_t *txn, apr_pool_t *pool) 814251881Speter{ 815251881Speter return svn_error_trace(txn->vtable->abort(txn, pool)); 816251881Speter} 817251881Speter 818251881Spetersvn_error_t * 819251881Spetersvn_fs_purge_txn(svn_fs_t *fs, const char *txn_id, apr_pool_t *pool) 820251881Speter{ 821251881Speter return svn_error_trace(fs->vtable->purge_txn(fs, txn_id, pool)); 822251881Speter} 823251881Speter 824251881Spetersvn_error_t * 825251881Spetersvn_fs_txn_name(const char **name_p, svn_fs_txn_t *txn, apr_pool_t *pool) 826251881Speter{ 827251881Speter *name_p = apr_pstrdup(pool, txn->id); 828251881Speter return SVN_NO_ERROR; 829251881Speter} 830251881Speter 831251881Spetersvn_revnum_t 832251881Spetersvn_fs_txn_base_revision(svn_fs_txn_t *txn) 833251881Speter{ 834251881Speter return txn->base_rev; 835251881Speter} 836251881Speter 837251881Spetersvn_error_t * 838251881Spetersvn_fs_open_txn(svn_fs_txn_t **txn, svn_fs_t *fs, const char *name, 839251881Speter apr_pool_t *pool) 840251881Speter{ 841251881Speter return svn_error_trace(fs->vtable->open_txn(txn, fs, name, pool)); 842251881Speter} 843251881Speter 844251881Spetersvn_error_t * 845251881Spetersvn_fs_list_transactions(apr_array_header_t **names_p, svn_fs_t *fs, 846251881Speter apr_pool_t *pool) 847251881Speter{ 848251881Speter return svn_error_trace(fs->vtable->list_transactions(names_p, fs, pool)); 849251881Speter} 850251881Speter 851251881Spetersvn_error_t * 852251881Spetersvn_fs_txn_prop(svn_string_t **value_p, svn_fs_txn_t *txn, 853251881Speter const char *propname, apr_pool_t *pool) 854251881Speter{ 855251881Speter return svn_error_trace(txn->vtable->get_prop(value_p, txn, propname, pool)); 856251881Speter} 857251881Speter 858251881Spetersvn_error_t * 859251881Spetersvn_fs_txn_proplist(apr_hash_t **table_p, svn_fs_txn_t *txn, apr_pool_t *pool) 860251881Speter{ 861251881Speter return svn_error_trace(txn->vtable->get_proplist(table_p, txn, pool)); 862251881Speter} 863251881Speter 864251881Spetersvn_error_t * 865251881Spetersvn_fs_change_txn_prop(svn_fs_txn_t *txn, const char *name, 866251881Speter const svn_string_t *value, apr_pool_t *pool) 867251881Speter{ 868251881Speter return svn_error_trace(txn->vtable->change_prop(txn, name, value, pool)); 869251881Speter} 870251881Speter 871251881Spetersvn_error_t * 872251881Spetersvn_fs_change_txn_props(svn_fs_txn_t *txn, const apr_array_header_t *props, 873251881Speter apr_pool_t *pool) 874251881Speter{ 875251881Speter return svn_error_trace(txn->vtable->change_props(txn, props, pool)); 876251881Speter} 877251881Speter 878251881Speter 879251881Speter/* --- Root functions --- */ 880251881Speter 881251881Spetersvn_error_t * 882251881Spetersvn_fs_revision_root(svn_fs_root_t **root_p, svn_fs_t *fs, svn_revnum_t rev, 883251881Speter apr_pool_t *pool) 884251881Speter{ 885251881Speter /* We create a subpool for each root object to allow us to implement 886251881Speter svn_fs_close_root. */ 887251881Speter apr_pool_t *subpool = svn_pool_create(pool); 888251881Speter return svn_error_trace(fs->vtable->revision_root(root_p, fs, rev, subpool)); 889251881Speter} 890251881Speter 891251881Spetersvn_error_t * 892251881Spetersvn_fs_txn_root(svn_fs_root_t **root_p, svn_fs_txn_t *txn, apr_pool_t *pool) 893251881Speter{ 894251881Speter /* We create a subpool for each root object to allow us to implement 895251881Speter svn_fs_close_root. */ 896251881Speter apr_pool_t *subpool = svn_pool_create(pool); 897251881Speter return svn_error_trace(txn->vtable->root(root_p, txn, subpool)); 898251881Speter} 899251881Speter 900251881Spetervoid 901251881Spetersvn_fs_close_root(svn_fs_root_t *root) 902251881Speter{ 903251881Speter svn_pool_destroy(root->pool); 904251881Speter} 905251881Speter 906251881Spetersvn_fs_t * 907251881Spetersvn_fs_root_fs(svn_fs_root_t *root) 908251881Speter{ 909251881Speter return root->fs; 910251881Speter} 911251881Speter 912251881Spetersvn_boolean_t 913251881Spetersvn_fs_is_txn_root(svn_fs_root_t *root) 914251881Speter{ 915251881Speter return root->is_txn_root; 916251881Speter} 917251881Speter 918251881Spetersvn_boolean_t 919251881Spetersvn_fs_is_revision_root(svn_fs_root_t *root) 920251881Speter{ 921251881Speter return !root->is_txn_root; 922251881Speter} 923251881Speter 924251881Speterconst char * 925251881Spetersvn_fs_txn_root_name(svn_fs_root_t *root, apr_pool_t *pool) 926251881Speter{ 927251881Speter return root->is_txn_root ? apr_pstrdup(pool, root->txn) : NULL; 928251881Speter} 929251881Speter 930251881Spetersvn_revnum_t 931251881Spetersvn_fs_txn_root_base_revision(svn_fs_root_t *root) 932251881Speter{ 933251881Speter return root->is_txn_root ? root->rev : SVN_INVALID_REVNUM; 934251881Speter} 935251881Speter 936251881Spetersvn_revnum_t 937251881Spetersvn_fs_revision_root_revision(svn_fs_root_t *root) 938251881Speter{ 939251881Speter return root->is_txn_root ? SVN_INVALID_REVNUM : root->rev; 940251881Speter} 941251881Speter 942251881Spetersvn_error_t * 943251881Spetersvn_fs_paths_changed2(apr_hash_t **changed_paths_p, svn_fs_root_t *root, 944251881Speter apr_pool_t *pool) 945251881Speter{ 946251881Speter return root->vtable->paths_changed(changed_paths_p, root, pool); 947251881Speter} 948251881Speter 949251881Spetersvn_error_t * 950251881Spetersvn_fs_paths_changed(apr_hash_t **changed_paths_p, svn_fs_root_t *root, 951251881Speter apr_pool_t *pool) 952251881Speter{ 953251881Speter apr_hash_t *changed_paths_new_structs; 954251881Speter apr_hash_index_t *hi; 955251881Speter 956251881Speter SVN_ERR(svn_fs_paths_changed2(&changed_paths_new_structs, root, pool)); 957251881Speter *changed_paths_p = apr_hash_make(pool); 958251881Speter for (hi = apr_hash_first(pool, changed_paths_new_structs); 959251881Speter hi; 960251881Speter hi = apr_hash_next(hi)) 961251881Speter { 962251881Speter const void *vkey; 963251881Speter apr_ssize_t klen; 964251881Speter void *vval; 965251881Speter svn_fs_path_change2_t *val; 966251881Speter svn_fs_path_change_t *change; 967251881Speter apr_hash_this(hi, &vkey, &klen, &vval); 968251881Speter val = vval; 969251881Speter change = apr_palloc(pool, sizeof(*change)); 970251881Speter change->node_rev_id = val->node_rev_id; 971251881Speter change->change_kind = val->change_kind; 972251881Speter change->text_mod = val->text_mod; 973251881Speter change->prop_mod = val->prop_mod; 974251881Speter apr_hash_set(*changed_paths_p, vkey, klen, change); 975251881Speter } 976251881Speter return SVN_NO_ERROR; 977251881Speter} 978251881Speter 979251881Spetersvn_error_t * 980251881Spetersvn_fs_check_path(svn_node_kind_t *kind_p, svn_fs_root_t *root, 981251881Speter const char *path, apr_pool_t *pool) 982251881Speter{ 983251881Speter return svn_error_trace(root->vtable->check_path(kind_p, root, path, pool)); 984251881Speter} 985251881Speter 986251881Spetersvn_error_t * 987251881Spetersvn_fs_node_history(svn_fs_history_t **history_p, svn_fs_root_t *root, 988251881Speter const char *path, apr_pool_t *pool) 989251881Speter{ 990251881Speter return svn_error_trace(root->vtable->node_history(history_p, root, path, 991251881Speter pool)); 992251881Speter} 993251881Speter 994251881Spetersvn_error_t * 995251881Spetersvn_fs_is_dir(svn_boolean_t *is_dir, svn_fs_root_t *root, const char *path, 996251881Speter apr_pool_t *pool) 997251881Speter{ 998251881Speter svn_node_kind_t kind; 999251881Speter 1000251881Speter SVN_ERR(root->vtable->check_path(&kind, root, path, pool)); 1001251881Speter *is_dir = (kind == svn_node_dir); 1002251881Speter return SVN_NO_ERROR; 1003251881Speter} 1004251881Speter 1005251881Spetersvn_error_t * 1006251881Spetersvn_fs_is_file(svn_boolean_t *is_file, svn_fs_root_t *root, const char *path, 1007251881Speter apr_pool_t *pool) 1008251881Speter{ 1009251881Speter svn_node_kind_t kind; 1010251881Speter 1011251881Speter SVN_ERR(root->vtable->check_path(&kind, root, path, pool)); 1012251881Speter *is_file = (kind == svn_node_file); 1013251881Speter return SVN_NO_ERROR; 1014251881Speter} 1015251881Speter 1016251881Spetersvn_error_t * 1017251881Spetersvn_fs_node_id(const svn_fs_id_t **id_p, svn_fs_root_t *root, 1018251881Speter const char *path, apr_pool_t *pool) 1019251881Speter{ 1020251881Speter return svn_error_trace(root->vtable->node_id(id_p, root, path, pool)); 1021251881Speter} 1022251881Speter 1023251881Spetersvn_error_t * 1024251881Spetersvn_fs_node_created_rev(svn_revnum_t *revision, svn_fs_root_t *root, 1025251881Speter const char *path, apr_pool_t *pool) 1026251881Speter{ 1027251881Speter return svn_error_trace(root->vtable->node_created_rev(revision, root, path, 1028251881Speter pool)); 1029251881Speter} 1030251881Speter 1031251881Spetersvn_error_t * 1032251881Spetersvn_fs_node_origin_rev(svn_revnum_t *revision, svn_fs_root_t *root, 1033251881Speter const char *path, apr_pool_t *pool) 1034251881Speter{ 1035251881Speter return svn_error_trace(root->vtable->node_origin_rev(revision, root, path, 1036251881Speter pool)); 1037251881Speter} 1038251881Speter 1039251881Spetersvn_error_t * 1040251881Spetersvn_fs_node_created_path(const char **created_path, svn_fs_root_t *root, 1041251881Speter const char *path, apr_pool_t *pool) 1042251881Speter{ 1043251881Speter return svn_error_trace(root->vtable->node_created_path(created_path, root, 1044251881Speter path, pool)); 1045251881Speter} 1046251881Speter 1047251881Spetersvn_error_t * 1048251881Spetersvn_fs_node_prop(svn_string_t **value_p, svn_fs_root_t *root, 1049251881Speter const char *path, const char *propname, apr_pool_t *pool) 1050251881Speter{ 1051251881Speter return svn_error_trace(root->vtable->node_prop(value_p, root, path, 1052251881Speter propname, pool)); 1053251881Speter} 1054251881Speter 1055251881Spetersvn_error_t * 1056251881Spetersvn_fs_node_proplist(apr_hash_t **table_p, svn_fs_root_t *root, 1057251881Speter const char *path, apr_pool_t *pool) 1058251881Speter{ 1059251881Speter return svn_error_trace(root->vtable->node_proplist(table_p, root, path, 1060251881Speter pool)); 1061251881Speter} 1062251881Speter 1063251881Spetersvn_error_t * 1064251881Spetersvn_fs_change_node_prop(svn_fs_root_t *root, const char *path, 1065251881Speter const char *name, const svn_string_t *value, 1066251881Speter apr_pool_t *pool) 1067251881Speter{ 1068251881Speter return svn_error_trace(root->vtable->change_node_prop(root, path, name, 1069251881Speter value, pool)); 1070251881Speter} 1071251881Speter 1072251881Spetersvn_error_t * 1073251881Spetersvn_fs_props_changed(svn_boolean_t *changed_p, svn_fs_root_t *root1, 1074251881Speter const char *path1, svn_fs_root_t *root2, 1075251881Speter const char *path2, apr_pool_t *pool) 1076251881Speter{ 1077251881Speter return svn_error_trace(root1->vtable->props_changed(changed_p, 1078251881Speter root1, path1, 1079251881Speter root2, path2, 1080251881Speter pool)); 1081251881Speter} 1082251881Speter 1083251881Spetersvn_error_t * 1084251881Spetersvn_fs_copied_from(svn_revnum_t *rev_p, const char **path_p, 1085251881Speter svn_fs_root_t *root, const char *path, apr_pool_t *pool) 1086251881Speter{ 1087251881Speter return svn_error_trace(root->vtable->copied_from(rev_p, path_p, root, path, 1088251881Speter pool)); 1089251881Speter} 1090251881Speter 1091251881Spetersvn_error_t * 1092251881Spetersvn_fs_closest_copy(svn_fs_root_t **root_p, const char **path_p, 1093251881Speter svn_fs_root_t *root, const char *path, apr_pool_t *pool) 1094251881Speter{ 1095251881Speter return svn_error_trace(root->vtable->closest_copy(root_p, path_p, 1096251881Speter root, path, pool)); 1097251881Speter} 1098251881Speter 1099251881Spetersvn_error_t * 1100251881Spetersvn_fs_get_mergeinfo2(svn_mergeinfo_catalog_t *catalog, 1101251881Speter svn_fs_root_t *root, 1102251881Speter const apr_array_header_t *paths, 1103251881Speter svn_mergeinfo_inheritance_t inherit, 1104251881Speter svn_boolean_t include_descendants, 1105251881Speter svn_boolean_t adjust_inherited_mergeinfo, 1106251881Speter apr_pool_t *result_pool, 1107251881Speter apr_pool_t *scratch_pool) 1108251881Speter{ 1109251881Speter return svn_error_trace(root->vtable->get_mergeinfo( 1110251881Speter catalog, root, paths, inherit, include_descendants, 1111251881Speter adjust_inherited_mergeinfo, result_pool, scratch_pool)); 1112251881Speter} 1113251881Speter 1114251881Spetersvn_error_t * 1115251881Spetersvn_fs_get_mergeinfo(svn_mergeinfo_catalog_t *catalog, 1116251881Speter svn_fs_root_t *root, 1117251881Speter const apr_array_header_t *paths, 1118251881Speter svn_mergeinfo_inheritance_t inherit, 1119251881Speter svn_boolean_t include_descendants, 1120251881Speter apr_pool_t *pool) 1121251881Speter{ 1122251881Speter return svn_error_trace(root->vtable->get_mergeinfo(catalog, root, paths, 1123251881Speter inherit, 1124251881Speter include_descendants, 1125251881Speter TRUE, pool, pool)); 1126251881Speter} 1127251881Speter 1128251881Spetersvn_error_t * 1129251881Spetersvn_fs_merge(const char **conflict_p, svn_fs_root_t *source_root, 1130251881Speter const char *source_path, svn_fs_root_t *target_root, 1131251881Speter const char *target_path, svn_fs_root_t *ancestor_root, 1132251881Speter const char *ancestor_path, apr_pool_t *pool) 1133251881Speter{ 1134251881Speter return svn_error_trace(target_root->vtable->merge(conflict_p, 1135251881Speter source_root, source_path, 1136251881Speter target_root, target_path, 1137251881Speter ancestor_root, 1138251881Speter ancestor_path, pool)); 1139251881Speter} 1140251881Speter 1141251881Spetersvn_error_t * 1142251881Spetersvn_fs_dir_entries(apr_hash_t **entries_p, svn_fs_root_t *root, 1143251881Speter const char *path, apr_pool_t *pool) 1144251881Speter{ 1145251881Speter return svn_error_trace(root->vtable->dir_entries(entries_p, root, path, 1146251881Speter pool)); 1147251881Speter} 1148251881Speter 1149251881Spetersvn_error_t * 1150251881Spetersvn_fs_make_dir(svn_fs_root_t *root, const char *path, apr_pool_t *pool) 1151251881Speter{ 1152251881Speter SVN_ERR(svn_fs__path_valid(path, pool)); 1153251881Speter return svn_error_trace(root->vtable->make_dir(root, path, pool)); 1154251881Speter} 1155251881Speter 1156251881Spetersvn_error_t * 1157251881Spetersvn_fs_delete(svn_fs_root_t *root, const char *path, apr_pool_t *pool) 1158251881Speter{ 1159251881Speter return svn_error_trace(root->vtable->delete_node(root, path, pool)); 1160251881Speter} 1161251881Speter 1162251881Spetersvn_error_t * 1163251881Spetersvn_fs_copy(svn_fs_root_t *from_root, const char *from_path, 1164251881Speter svn_fs_root_t *to_root, const char *to_path, apr_pool_t *pool) 1165251881Speter{ 1166251881Speter SVN_ERR(svn_fs__path_valid(to_path, pool)); 1167251881Speter return svn_error_trace(to_root->vtable->copy(from_root, from_path, 1168251881Speter to_root, to_path, pool)); 1169251881Speter} 1170251881Speter 1171251881Spetersvn_error_t * 1172251881Spetersvn_fs_revision_link(svn_fs_root_t *from_root, svn_fs_root_t *to_root, 1173251881Speter const char *path, apr_pool_t *pool) 1174251881Speter{ 1175251881Speter return svn_error_trace(to_root->vtable->revision_link(from_root, to_root, 1176251881Speter path, pool)); 1177251881Speter} 1178251881Speter 1179251881Spetersvn_error_t * 1180251881Spetersvn_fs_file_length(svn_filesize_t *length_p, svn_fs_root_t *root, 1181251881Speter const char *path, apr_pool_t *pool) 1182251881Speter{ 1183251881Speter return svn_error_trace(root->vtable->file_length(length_p, root, path, 1184251881Speter pool)); 1185251881Speter} 1186251881Speter 1187251881Spetersvn_error_t * 1188251881Spetersvn_fs_file_checksum(svn_checksum_t **checksum, 1189251881Speter svn_checksum_kind_t kind, 1190251881Speter svn_fs_root_t *root, 1191251881Speter const char *path, 1192251881Speter svn_boolean_t force, 1193251881Speter apr_pool_t *pool) 1194251881Speter{ 1195251881Speter SVN_ERR(root->vtable->file_checksum(checksum, kind, root, path, pool)); 1196251881Speter 1197251881Speter if (force && (*checksum == NULL || (*checksum)->kind != kind)) 1198251881Speter { 1199251881Speter svn_stream_t *contents, *checksum_contents; 1200251881Speter 1201251881Speter SVN_ERR(svn_fs_file_contents(&contents, root, path, pool)); 1202251881Speter checksum_contents = svn_stream_checksummed2(contents, checksum, NULL, 1203251881Speter kind, TRUE, pool); 1204251881Speter 1205251881Speter /* This will force a read of any remaining data (which is all of it in 1206251881Speter this case) and dump the checksum into checksum->digest. */ 1207251881Speter SVN_ERR(svn_stream_close(checksum_contents)); 1208251881Speter } 1209251881Speter 1210251881Speter return SVN_NO_ERROR; 1211251881Speter} 1212251881Speter 1213251881Spetersvn_error_t * 1214251881Spetersvn_fs_file_md5_checksum(unsigned char digest[], 1215251881Speter svn_fs_root_t *root, 1216251881Speter const char *path, 1217251881Speter apr_pool_t *pool) 1218251881Speter{ 1219251881Speter svn_checksum_t *md5sum; 1220251881Speter 1221251881Speter SVN_ERR(svn_fs_file_checksum(&md5sum, svn_checksum_md5, root, path, TRUE, 1222251881Speter pool)); 1223251881Speter memcpy(digest, md5sum->digest, APR_MD5_DIGESTSIZE); 1224251881Speter 1225251881Speter return SVN_NO_ERROR; 1226251881Speter} 1227251881Speter 1228251881Spetersvn_error_t * 1229251881Spetersvn_fs_file_contents(svn_stream_t **contents, svn_fs_root_t *root, 1230251881Speter const char *path, apr_pool_t *pool) 1231251881Speter{ 1232251881Speter return svn_error_trace(root->vtable->file_contents(contents, root, path, 1233251881Speter pool)); 1234251881Speter} 1235251881Speter 1236251881Spetersvn_error_t * 1237251881Spetersvn_fs_try_process_file_contents(svn_boolean_t *success, 1238251881Speter svn_fs_root_t *root, 1239251881Speter const char *path, 1240251881Speter svn_fs_process_contents_func_t processor, 1241251881Speter void* baton, 1242251881Speter apr_pool_t *pool) 1243251881Speter{ 1244251881Speter /* if the FS doesn't implement this function, report a "failed" attempt */ 1245251881Speter if (root->vtable->try_process_file_contents == NULL) 1246251881Speter { 1247251881Speter *success = FALSE; 1248251881Speter return SVN_NO_ERROR; 1249251881Speter } 1250251881Speter 1251251881Speter return svn_error_trace(root->vtable->try_process_file_contents( 1252251881Speter success, 1253251881Speter root, path, 1254251881Speter processor, baton, pool)); 1255251881Speter} 1256251881Speter 1257251881Spetersvn_error_t * 1258251881Spetersvn_fs_make_file(svn_fs_root_t *root, const char *path, apr_pool_t *pool) 1259251881Speter{ 1260251881Speter SVN_ERR(svn_fs__path_valid(path, pool)); 1261251881Speter return svn_error_trace(root->vtable->make_file(root, path, pool)); 1262251881Speter} 1263251881Speter 1264251881Spetersvn_error_t * 1265251881Spetersvn_fs_apply_textdelta(svn_txdelta_window_handler_t *contents_p, 1266251881Speter void **contents_baton_p, svn_fs_root_t *root, 1267251881Speter const char *path, const char *base_checksum, 1268251881Speter const char *result_checksum, apr_pool_t *pool) 1269251881Speter{ 1270251881Speter svn_checksum_t *base, *result; 1271251881Speter 1272251881Speter /* TODO: If we ever rev this API, we should make the supplied checksums 1273251881Speter svn_checksum_t structs. */ 1274251881Speter SVN_ERR(svn_checksum_parse_hex(&base, svn_checksum_md5, base_checksum, 1275251881Speter pool)); 1276251881Speter SVN_ERR(svn_checksum_parse_hex(&result, svn_checksum_md5, result_checksum, 1277251881Speter pool)); 1278251881Speter 1279251881Speter return svn_error_trace(root->vtable->apply_textdelta(contents_p, 1280251881Speter contents_baton_p, 1281251881Speter root, 1282251881Speter path, 1283251881Speter base, 1284251881Speter result, 1285251881Speter pool)); 1286251881Speter} 1287251881Speter 1288251881Spetersvn_error_t * 1289251881Spetersvn_fs_apply_text(svn_stream_t **contents_p, svn_fs_root_t *root, 1290251881Speter const char *path, const char *result_checksum, 1291251881Speter apr_pool_t *pool) 1292251881Speter{ 1293251881Speter svn_checksum_t *result; 1294251881Speter 1295251881Speter /* TODO: If we ever rev this API, we should make the supplied checksum an 1296251881Speter svn_checksum_t struct. */ 1297251881Speter SVN_ERR(svn_checksum_parse_hex(&result, svn_checksum_md5, result_checksum, 1298251881Speter pool)); 1299251881Speter 1300251881Speter return svn_error_trace(root->vtable->apply_text(contents_p, root, path, 1301251881Speter result, pool)); 1302251881Speter} 1303251881Speter 1304251881Spetersvn_error_t * 1305251881Spetersvn_fs_contents_changed(svn_boolean_t *changed_p, svn_fs_root_t *root1, 1306251881Speter const char *path1, svn_fs_root_t *root2, 1307251881Speter const char *path2, apr_pool_t *pool) 1308251881Speter{ 1309251881Speter return svn_error_trace(root1->vtable->contents_changed(changed_p, 1310251881Speter root1, path1, 1311251881Speter root2, path2, 1312251881Speter pool)); 1313251881Speter} 1314251881Speter 1315251881Spetersvn_error_t * 1316251881Spetersvn_fs_youngest_rev(svn_revnum_t *youngest_p, svn_fs_t *fs, apr_pool_t *pool) 1317251881Speter{ 1318251881Speter return svn_error_trace(fs->vtable->youngest_rev(youngest_p, fs, pool)); 1319251881Speter} 1320251881Speter 1321251881Spetersvn_error_t * 1322251881Spetersvn_fs_deltify_revision(svn_fs_t *fs, svn_revnum_t revision, apr_pool_t *pool) 1323251881Speter{ 1324251881Speter return svn_error_trace(fs->vtable->deltify(fs, revision, pool)); 1325251881Speter} 1326251881Speter 1327251881Spetersvn_error_t * 1328251881Spetersvn_fs_revision_prop(svn_string_t **value_p, svn_fs_t *fs, svn_revnum_t rev, 1329251881Speter const char *propname, apr_pool_t *pool) 1330251881Speter{ 1331251881Speter return svn_error_trace(fs->vtable->revision_prop(value_p, fs, rev, 1332251881Speter propname, pool)); 1333251881Speter} 1334251881Speter 1335251881Spetersvn_error_t * 1336251881Spetersvn_fs_revision_proplist(apr_hash_t **table_p, svn_fs_t *fs, svn_revnum_t rev, 1337251881Speter apr_pool_t *pool) 1338251881Speter{ 1339251881Speter return svn_error_trace(fs->vtable->revision_proplist(table_p, fs, rev, 1340251881Speter pool)); 1341251881Speter} 1342251881Speter 1343251881Spetersvn_error_t * 1344251881Spetersvn_fs_change_rev_prop2(svn_fs_t *fs, svn_revnum_t rev, const char *name, 1345251881Speter const svn_string_t *const *old_value_p, 1346251881Speter const svn_string_t *value, apr_pool_t *pool) 1347251881Speter{ 1348251881Speter return svn_error_trace(fs->vtable->change_rev_prop(fs, rev, name, 1349251881Speter old_value_p, 1350251881Speter value, pool)); 1351251881Speter} 1352251881Speter 1353251881Spetersvn_error_t * 1354251881Spetersvn_fs_change_rev_prop(svn_fs_t *fs, svn_revnum_t rev, const char *name, 1355251881Speter const svn_string_t *value, apr_pool_t *pool) 1356251881Speter{ 1357251881Speter return svn_error_trace( 1358251881Speter svn_fs_change_rev_prop2(fs, rev, name, NULL, value, pool)); 1359251881Speter} 1360251881Speter 1361251881Spetersvn_error_t * 1362251881Spetersvn_fs_get_file_delta_stream(svn_txdelta_stream_t **stream_p, 1363251881Speter svn_fs_root_t *source_root, 1364251881Speter const char *source_path, 1365251881Speter svn_fs_root_t *target_root, 1366251881Speter const char *target_path, apr_pool_t *pool) 1367251881Speter{ 1368251881Speter return svn_error_trace(target_root->vtable->get_file_delta_stream( 1369251881Speter stream_p, 1370251881Speter source_root, source_path, 1371251881Speter target_root, target_path, pool)); 1372251881Speter} 1373251881Speter 1374251881Spetersvn_error_t * 1375251881Spetersvn_fs_get_uuid(svn_fs_t *fs, const char **uuid, apr_pool_t *pool) 1376251881Speter{ 1377251881Speter /* If you change this, consider changing svn_fs__identifier(). */ 1378251881Speter *uuid = apr_pstrdup(pool, fs->uuid); 1379251881Speter return SVN_NO_ERROR; 1380251881Speter} 1381251881Speter 1382251881Spetersvn_error_t * 1383251881Spetersvn_fs_set_uuid(svn_fs_t *fs, const char *uuid, apr_pool_t *pool) 1384251881Speter{ 1385251881Speter if (! uuid) 1386251881Speter { 1387251881Speter uuid = svn_uuid_generate(pool); 1388251881Speter } 1389251881Speter else 1390251881Speter { 1391251881Speter apr_uuid_t parsed_uuid; 1392251881Speter apr_status_t apr_err = apr_uuid_parse(&parsed_uuid, uuid); 1393251881Speter if (apr_err) 1394251881Speter return svn_error_createf(SVN_ERR_BAD_UUID, NULL, 1395251881Speter _("Malformed UUID '%s'"), uuid); 1396251881Speter } 1397251881Speter return svn_error_trace(fs->vtable->set_uuid(fs, uuid, pool)); 1398251881Speter} 1399251881Speter 1400251881Spetersvn_error_t * 1401251881Spetersvn_fs_lock(svn_lock_t **lock, svn_fs_t *fs, const char *path, 1402251881Speter const char *token, const char *comment, 1403251881Speter svn_boolean_t is_dav_comment, apr_time_t expiration_date, 1404251881Speter svn_revnum_t current_rev, svn_boolean_t steal_lock, 1405251881Speter apr_pool_t *pool) 1406251881Speter{ 1407251881Speter /* Enforce that the comment be xml-escapable. */ 1408251881Speter if (comment) 1409251881Speter { 1410251881Speter if (! svn_xml_is_xml_safe(comment, strlen(comment))) 1411251881Speter return svn_error_create 1412251881Speter (SVN_ERR_XML_UNESCAPABLE_DATA, NULL, 1413251881Speter _("Lock comment contains illegal characters")); 1414251881Speter } 1415251881Speter 1416251881Speter /* Enforce that the token be an XML-safe URI. */ 1417251881Speter if (token) 1418251881Speter { 1419251881Speter const char *c; 1420251881Speter 1421251881Speter if (strncmp(token, "opaquelocktoken:", 16)) 1422251881Speter return svn_error_createf(SVN_ERR_FS_BAD_LOCK_TOKEN, NULL, 1423251881Speter _("Lock token URI '%s' has bad scheme; " 1424251881Speter "expected '%s'"), 1425251881Speter token, "opaquelocktoken"); 1426251881Speter 1427251881Speter for (c = token; *c; c++) 1428251881Speter if (! svn_ctype_isascii(*c)) 1429251881Speter return svn_error_createf(SVN_ERR_FS_BAD_LOCK_TOKEN, NULL, 1430251881Speter _("Lock token '%s' is not ASCII " 1431251881Speter "at byte %u"), 1432251881Speter token, (unsigned)(c - token)); 1433251881Speter 1434251881Speter /* strlen(token) == c - token. */ 1435251881Speter if (! svn_xml_is_xml_safe(token, c - token)) 1436251881Speter return svn_error_createf(SVN_ERR_FS_BAD_LOCK_TOKEN, NULL, 1437251881Speter _("Lock token URI '%s' is not XML-safe"), 1438251881Speter token); 1439251881Speter } 1440251881Speter 1441251881Speter if (expiration_date < 0) 1442251881Speter return svn_error_create 1443251881Speter (SVN_ERR_INCORRECT_PARAMS, NULL, 1444251881Speter _("Negative expiration date passed to svn_fs_lock")); 1445251881Speter 1446251881Speter return svn_error_trace(fs->vtable->lock(lock, fs, path, token, comment, 1447251881Speter is_dav_comment, expiration_date, 1448251881Speter current_rev, steal_lock, pool)); 1449251881Speter} 1450251881Speter 1451251881Spetersvn_error_t * 1452251881Spetersvn_fs_generate_lock_token(const char **token, svn_fs_t *fs, apr_pool_t *pool) 1453251881Speter{ 1454251881Speter return svn_error_trace(fs->vtable->generate_lock_token(token, fs, pool)); 1455251881Speter} 1456251881Speter 1457251881Spetersvn_error_t * 1458251881Spetersvn_fs_unlock(svn_fs_t *fs, const char *path, const char *token, 1459251881Speter svn_boolean_t break_lock, apr_pool_t *pool) 1460251881Speter{ 1461251881Speter return svn_error_trace(fs->vtable->unlock(fs, path, token, break_lock, 1462251881Speter pool)); 1463251881Speter} 1464251881Speter 1465251881Spetersvn_error_t * 1466251881Spetersvn_fs_get_lock(svn_lock_t **lock, svn_fs_t *fs, const char *path, 1467251881Speter apr_pool_t *pool) 1468251881Speter{ 1469251881Speter return svn_error_trace(fs->vtable->get_lock(lock, fs, path, pool)); 1470251881Speter} 1471251881Speter 1472251881Spetersvn_error_t * 1473251881Spetersvn_fs_get_locks2(svn_fs_t *fs, const char *path, svn_depth_t depth, 1474251881Speter svn_fs_get_locks_callback_t get_locks_func, 1475251881Speter void *get_locks_baton, apr_pool_t *pool) 1476251881Speter{ 1477251881Speter SVN_ERR_ASSERT((depth == svn_depth_empty) || 1478251881Speter (depth == svn_depth_files) || 1479251881Speter (depth == svn_depth_immediates) || 1480251881Speter (depth == svn_depth_infinity)); 1481251881Speter return svn_error_trace(fs->vtable->get_locks(fs, path, depth, 1482251881Speter get_locks_func, 1483251881Speter get_locks_baton, pool)); 1484251881Speter} 1485251881Speter 1486251881Spetersvn_error_t * 1487251881Spetersvn_fs_get_locks(svn_fs_t *fs, const char *path, 1488251881Speter svn_fs_get_locks_callback_t get_locks_func, 1489251881Speter void *get_locks_baton, apr_pool_t *pool) 1490251881Speter{ 1491251881Speter return svn_error_trace(svn_fs_get_locks2(fs, path, svn_depth_infinity, 1492251881Speter get_locks_func, get_locks_baton, 1493251881Speter pool)); 1494251881Speter} 1495251881Speter 1496251881Speter 1497251881Speter/* --- History functions --- */ 1498251881Speter 1499251881Spetersvn_error_t * 1500251881Spetersvn_fs_history_prev(svn_fs_history_t **prev_history_p, 1501251881Speter svn_fs_history_t *history, svn_boolean_t cross_copies, 1502251881Speter apr_pool_t *pool) 1503251881Speter{ 1504251881Speter return svn_error_trace(history->vtable->prev(prev_history_p, history, 1505251881Speter cross_copies, pool)); 1506251881Speter} 1507251881Speter 1508251881Spetersvn_error_t * 1509251881Spetersvn_fs_history_location(const char **path, svn_revnum_t *revision, 1510251881Speter svn_fs_history_t *history, apr_pool_t *pool) 1511251881Speter{ 1512251881Speter return svn_error_trace(history->vtable->location(path, revision, history, 1513251881Speter pool)); 1514251881Speter} 1515251881Speter 1516251881Speter 1517251881Speter/* --- Node-ID functions --- */ 1518251881Speter 1519251881Spetersvn_fs_id_t * 1520251881Spetersvn_fs_parse_id(const char *data, apr_size_t len, apr_pool_t *pool) 1521251881Speter{ 1522251881Speter fs_library_vtable_t *vtable; 1523251881Speter svn_error_t *err; 1524251881Speter 1525251881Speter err = get_library_vtable(&vtable, SVN_FS_TYPE_BDB, pool); 1526251881Speter if (err) 1527251881Speter { 1528251881Speter svn_error_clear(err); 1529251881Speter return NULL; 1530251881Speter } 1531251881Speter return vtable->parse_id(data, len, pool); 1532251881Speter} 1533251881Speter 1534251881Spetersvn_string_t * 1535251881Spetersvn_fs_unparse_id(const svn_fs_id_t *id, apr_pool_t *pool) 1536251881Speter{ 1537251881Speter return id->vtable->unparse(id, pool); 1538251881Speter} 1539251881Speter 1540251881Spetersvn_boolean_t 1541251881Spetersvn_fs_check_related(const svn_fs_id_t *a, const svn_fs_id_t *b) 1542251881Speter{ 1543251881Speter return (a->vtable->compare(a, b) != -1); 1544251881Speter} 1545251881Speter 1546251881Speterint 1547251881Spetersvn_fs_compare_ids(const svn_fs_id_t *a, const svn_fs_id_t *b) 1548251881Speter{ 1549251881Speter return a->vtable->compare(a, b); 1550251881Speter} 1551251881Speter 1552251881Spetersvn_error_t * 1553251881Spetersvn_fs_print_modules(svn_stringbuf_t *output, 1554251881Speter apr_pool_t *pool) 1555251881Speter{ 1556251881Speter const struct fs_type_defn *defn = fs_modules; 1557251881Speter fs_library_vtable_t *vtable; 1558251881Speter apr_pool_t *iterpool = svn_pool_create(pool); 1559251881Speter 1560251881Speter while (defn) 1561251881Speter { 1562251881Speter char *line; 1563251881Speter svn_error_t *err; 1564251881Speter 1565251881Speter svn_pool_clear(iterpool); 1566251881Speter 1567251881Speter err = get_library_vtable_direct(&vtable, defn, iterpool); 1568251881Speter if (err) 1569251881Speter { 1570251881Speter if (err->apr_err == SVN_ERR_FS_UNKNOWN_FS_TYPE) 1571251881Speter { 1572251881Speter svn_error_clear(err); 1573251881Speter defn = defn->next; 1574251881Speter continue; 1575251881Speter } 1576251881Speter else 1577251881Speter return err; 1578251881Speter } 1579251881Speter 1580251881Speter line = apr_psprintf(iterpool, "* fs_%s : %s\n", 1581251881Speter defn->fsap_name, vtable->get_description()); 1582251881Speter svn_stringbuf_appendcstr(output, line); 1583251881Speter defn = defn->next; 1584251881Speter } 1585251881Speter 1586251881Speter svn_pool_destroy(iterpool); 1587251881Speter 1588251881Speter return SVN_NO_ERROR; 1589251881Speter} 1590251881Speter 1591251881Spetersvn_fs_path_change2_t * 1592251881Spetersvn_fs_path_change2_create(const svn_fs_id_t *node_rev_id, 1593251881Speter svn_fs_path_change_kind_t change_kind, 1594251881Speter apr_pool_t *pool) 1595251881Speter{ 1596251881Speter return svn_fs__path_change_create_internal(node_rev_id, change_kind, pool); 1597251881Speter} 1598251881Speter 1599251881Speter/* Return the library version number. */ 1600251881Speterconst svn_version_t * 1601251881Spetersvn_fs_version(void) 1602251881Speter{ 1603251881Speter SVN_VERSION_BODY; 1604251881Speter} 1605