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> 27299742Sdim#include <apr_atomic.h> 28251881Speter#include <apr_hash.h> 29251881Speter#include <apr_md5.h> 30251881Speter#include <apr_thread_mutex.h> 31251881Speter#include <apr_uuid.h> 32251881Speter#include <apr_strings.h> 33251881Speter 34299742Sdim#include "svn_private_config.h" 35251881Speter#include "svn_hash.h" 36251881Speter#include "svn_ctype.h" 37251881Speter#include "svn_types.h" 38251881Speter#include "svn_dso.h" 39251881Speter#include "svn_version.h" 40251881Speter#include "svn_fs.h" 41251881Speter#include "svn_path.h" 42251881Speter#include "svn_xml.h" 43251881Speter#include "svn_pools.h" 44251881Speter#include "svn_string.h" 45299742Sdim#include "svn_sorts.h" 46251881Speter 47299742Sdim#include "private/svn_atomic.h" 48251881Speter#include "private/svn_fs_private.h" 49251881Speter#include "private/svn_fs_util.h" 50251881Speter#include "private/svn_utf_private.h" 51251881Speter#include "private/svn_mutex.h" 52251881Speter#include "private/svn_subr_private.h" 53251881Speter 54251881Speter#include "fs-loader.h" 55251881Speter 56251881Speter/* This is defined by configure on platforms which use configure, but 57251881Speter we need to define a fallback for Windows. */ 58251881Speter#ifndef DEFAULT_FS_TYPE 59251881Speter#define DEFAULT_FS_TYPE "fsfs" 60251881Speter#endif 61251881Speter 62251881Speter#define FS_TYPE_FILENAME "fs-type" 63251881Speter 64251881Speter/* A pool common to all FS objects. See the documentation on the 65251881Speter open/create functions in fs-loader.h and for svn_fs_initialize(). */ 66299742Sdimstatic apr_pool_t *common_pool = NULL; 67299742Sdimstatic svn_mutex__t *common_pool_lock = NULL; 68299742Sdimstatic svn_atomic_t common_pool_initialized = FALSE; 69251881Speter 70251881Speter 71251881Speter/* --- Utility functions for the loader --- */ 72251881Speter 73251881Speterstruct fs_type_defn { 74251881Speter const char *fs_type; 75251881Speter const char *fsap_name; 76251881Speter fs_init_func_t initfunc; 77299742Sdim fs_library_vtable_t *vtable; 78251881Speter struct fs_type_defn *next; 79251881Speter}; 80251881Speter 81251881Speterstatic struct fs_type_defn base_defn = 82251881Speter { 83251881Speter SVN_FS_TYPE_BDB, "base", 84251881Speter#ifdef SVN_LIBSVN_FS_LINKS_FS_BASE 85251881Speter svn_fs_base__init, 86251881Speter#else 87251881Speter NULL, 88251881Speter#endif 89299742Sdim NULL, 90262253Speter NULL /* End of static list: this needs to be reset to NULL if the 91262253Speter common_pool used when setting it has been cleared. */ 92251881Speter }; 93251881Speter 94299742Sdimstatic struct fs_type_defn fsx_defn = 95299742Sdim { 96299742Sdim SVN_FS_TYPE_FSX, "x", 97299742Sdim#ifdef SVN_LIBSVN_FS_LINKS_FS_X 98299742Sdim svn_fs_x__init, 99299742Sdim#else 100299742Sdim NULL, 101299742Sdim#endif 102299742Sdim NULL, 103299742Sdim &base_defn 104299742Sdim }; 105299742Sdim 106251881Speterstatic struct fs_type_defn fsfs_defn = 107251881Speter { 108251881Speter SVN_FS_TYPE_FSFS, "fs", 109251881Speter#ifdef SVN_LIBSVN_FS_LINKS_FS_FS 110251881Speter svn_fs_fs__init, 111251881Speter#else 112251881Speter NULL, 113251881Speter#endif 114299742Sdim NULL, 115299742Sdim &fsx_defn 116251881Speter }; 117251881Speter 118251881Speterstatic struct fs_type_defn *fs_modules = &fsfs_defn; 119251881Speter 120251881Speter 121251881Speterstatic svn_error_t * 122251881Speterload_module(fs_init_func_t *initfunc, const char *name, apr_pool_t *pool) 123251881Speter{ 124251881Speter *initfunc = NULL; 125251881Speter 126251881Speter#if defined(SVN_USE_DSO) && APR_HAS_DSO 127251881Speter { 128251881Speter apr_dso_handle_t *dso; 129251881Speter apr_dso_handle_sym_t symbol; 130251881Speter const char *libname; 131251881Speter const char *funcname; 132251881Speter apr_status_t status; 133251881Speter const char *p; 134251881Speter 135251881Speter /* Demand a simple alphanumeric name so that the generated DSO 136251881Speter name is sensible. */ 137251881Speter for (p = name; *p; ++p) 138251881Speter if (!svn_ctype_isalnum(*p)) 139251881Speter return svn_error_createf(SVN_ERR_FS_UNKNOWN_FS_TYPE, NULL, 140251881Speter _("Invalid name for FS type '%s'"), 141251881Speter name); 142251881Speter 143251881Speter libname = apr_psprintf(pool, "libsvn_fs_%s-%d.so.%d", 144251881Speter name, SVN_VER_MAJOR, SVN_SOVERSION); 145251881Speter funcname = apr_psprintf(pool, "svn_fs_%s__init", name); 146251881Speter 147251881Speter /* Find/load the specified library. If we get an error, assume 148251881Speter the library doesn't exist. The library will be unloaded when 149251881Speter pool is destroyed. */ 150251881Speter SVN_ERR(svn_dso_load(&dso, libname)); 151251881Speter if (! dso) 152251881Speter return SVN_NO_ERROR; 153251881Speter 154251881Speter /* find the initialization routine */ 155251881Speter status = apr_dso_sym(&symbol, dso, funcname); 156251881Speter if (status) 157251881Speter return svn_error_wrap_apr(status, _("'%s' does not define '%s()'"), 158251881Speter libname, funcname); 159251881Speter 160251881Speter *initfunc = (fs_init_func_t) symbol; 161251881Speter } 162251881Speter#endif /* APR_HAS_DSO */ 163251881Speter 164251881Speter return SVN_NO_ERROR; 165251881Speter} 166251881Speter 167251881Speter/* Fetch a library vtable by a pointer into the library definitions array. */ 168251881Speterstatic svn_error_t * 169251881Speterget_library_vtable_direct(fs_library_vtable_t **vtable, 170299742Sdim struct fs_type_defn *fst, 171251881Speter apr_pool_t *pool) 172251881Speter{ 173251881Speter fs_init_func_t initfunc = NULL; 174251881Speter const svn_version_t *my_version = svn_fs_version(); 175251881Speter const svn_version_t *fs_version; 176251881Speter 177299742Sdim /* most times, we get lucky */ 178299742Sdim *vtable = apr_atomic_casptr((volatile void **)&fst->vtable, NULL, NULL); 179299742Sdim if (*vtable) 180299742Sdim return SVN_NO_ERROR; 181299742Sdim 182299742Sdim /* o.k. the first access needs to actually load the module, find the 183299742Sdim vtable and check for version compatibility. */ 184251881Speter initfunc = fst->initfunc; 185251881Speter if (! initfunc) 186251881Speter SVN_ERR(load_module(&initfunc, fst->fsap_name, pool)); 187251881Speter 188251881Speter if (! initfunc) 189251881Speter return svn_error_createf(SVN_ERR_FS_UNKNOWN_FS_TYPE, NULL, 190251881Speter _("Failed to load module for FS type '%s'"), 191251881Speter fst->fs_type); 192251881Speter 193251881Speter { 194251881Speter /* Per our API compatibility rules, we cannot ensure that 195251881Speter svn_fs_initialize is called by the application. If not, we 196251881Speter cannot create the common pool and lock in a thread-safe fashion, 197251881Speter nor can we clean up the common pool if libsvn_fs is dynamically 198251881Speter unloaded. This function makes a best effort by creating the 199251881Speter common pool as a child of the global pool; the window of failure 200251881Speter due to thread collision is small. */ 201299742Sdim SVN_ERR(svn_fs_initialize(NULL)); 202251881Speter 203251881Speter /* Invoke the FS module's initfunc function with the common 204251881Speter pool protected by a lock. */ 205251881Speter SVN_MUTEX__WITH_LOCK(common_pool_lock, 206251881Speter initfunc(my_version, vtable, common_pool)); 207251881Speter } 208251881Speter fs_version = (*vtable)->get_version(); 209251881Speter if (!svn_ver_equal(my_version, fs_version)) 210251881Speter return svn_error_createf(SVN_ERR_VERSION_MISMATCH, NULL, 211251881Speter _("Mismatched FS module version for '%s':" 212251881Speter " found %d.%d.%d%s," 213251881Speter " expected %d.%d.%d%s"), 214251881Speter fst->fs_type, 215251881Speter my_version->major, my_version->minor, 216251881Speter my_version->patch, my_version->tag, 217251881Speter fs_version->major, fs_version->minor, 218251881Speter fs_version->patch, fs_version->tag); 219299742Sdim 220299742Sdim /* the vtable will not change. Remember it */ 221299742Sdim apr_atomic_casptr((volatile void **)&fst->vtable, *vtable, NULL); 222299742Sdim 223251881Speter return SVN_NO_ERROR; 224251881Speter} 225251881Speter 226251881Speter#if defined(SVN_USE_DSO) && APR_HAS_DSO 227251881Speter/* Return *FST for the third party FS_TYPE */ 228251881Speterstatic svn_error_t * 229251881Speterget_or_allocate_third(struct fs_type_defn **fst, 230251881Speter const char *fs_type) 231251881Speter{ 232251881Speter while (*fst) 233251881Speter { 234251881Speter if (strcmp(fs_type, (*fst)->fs_type) == 0) 235251881Speter return SVN_NO_ERROR; 236251881Speter fst = &(*fst)->next; 237251881Speter } 238251881Speter 239251881Speter *fst = apr_palloc(common_pool, sizeof(struct fs_type_defn)); 240251881Speter (*fst)->fs_type = apr_pstrdup(common_pool, fs_type); 241251881Speter (*fst)->fsap_name = (*fst)->fs_type; 242251881Speter (*fst)->initfunc = NULL; 243299742Sdim (*fst)->vtable = NULL; 244251881Speter (*fst)->next = NULL; 245251881Speter 246251881Speter return SVN_NO_ERROR; 247251881Speter} 248251881Speter#endif 249251881Speter 250299742Sdim/* Fetch a library *VTABLE by FS_TYPE. 251299742Sdim Use POOL for temporary allocations. */ 252251881Speterstatic svn_error_t * 253251881Speterget_library_vtable(fs_library_vtable_t **vtable, const char *fs_type, 254251881Speter apr_pool_t *pool) 255251881Speter{ 256299742Sdim struct fs_type_defn **fst; 257251881Speter svn_boolean_t known = FALSE; 258251881Speter 259299742Sdim /* There are three FS module definitions known at compile time. We 260251881Speter want to check these without any locking overhead even when 261251881Speter dynamic third party modules are enabled. The third party modules 262251881Speter cannot be checked until the lock is held. */ 263299742Sdim for (fst = &fs_modules; *fst; fst = &(*fst)->next) 264251881Speter { 265251881Speter if (strcmp(fs_type, (*fst)->fs_type) == 0) 266299742Sdim { 267299742Sdim known = TRUE; 268299742Sdim break; 269299742Sdim } 270299742Sdim else if (!(*fst)->next) 271299742Sdim { 272299742Sdim break; 273299742Sdim } 274251881Speter } 275251881Speter 276251881Speter#if defined(SVN_USE_DSO) && APR_HAS_DSO 277251881Speter /* Third party FS modules that are unknown at compile time. 278251881Speter 279251881Speter A third party FS is identified by the file fs-type containing a 280251881Speter third party name, say "foo". The loader will load the DSO with 281251881Speter the name "libsvn_fs_foo" and use the entry point with the name 282251881Speter "svn_fs_foo__init". 283251881Speter 284251881Speter Note: the BDB and FSFS modules don't follow this naming scheme 285251881Speter and this allows them to be used to test the third party loader. 286251881Speter Change the content of fs-type to "base" in a BDB filesystem or to 287251881Speter "fs" in an FSFS filesystem and they will be loaded as third party 288251881Speter modules. */ 289251881Speter if (!known) 290251881Speter { 291251881Speter fst = &(*fst)->next; 292299742Sdim /* Best-effort init, see get_library_vtable_direct. */ 293299742Sdim SVN_ERR(svn_fs_initialize(NULL)); 294251881Speter SVN_MUTEX__WITH_LOCK(common_pool_lock, 295251881Speter get_or_allocate_third(fst, fs_type)); 296251881Speter known = TRUE; 297251881Speter } 298251881Speter#endif 299251881Speter if (!known) 300251881Speter return svn_error_createf(SVN_ERR_FS_UNKNOWN_FS_TYPE, NULL, 301251881Speter _("Unknown FS type '%s'"), fs_type); 302251881Speter return get_library_vtable_direct(vtable, *fst, pool); 303251881Speter} 304251881Speter 305251881Spetersvn_error_t * 306251881Spetersvn_fs_type(const char **fs_type, const char *path, apr_pool_t *pool) 307251881Speter{ 308251881Speter const char *filename; 309251881Speter char buf[128]; 310251881Speter svn_error_t *err; 311251881Speter apr_file_t *file; 312251881Speter apr_size_t len; 313251881Speter 314251881Speter /* Read the fsap-name file to get the FSAP name, or assume the (old) 315251881Speter default. For old repositories I suppose we could check some 316251881Speter other file, DB_CONFIG or strings say, but for now just check the 317251881Speter directory exists. */ 318251881Speter filename = svn_dirent_join(path, FS_TYPE_FILENAME, pool); 319251881Speter err = svn_io_file_open(&file, filename, APR_READ|APR_BUFFERED, 0, pool); 320251881Speter if (err && APR_STATUS_IS_ENOENT(err->apr_err)) 321251881Speter { 322251881Speter svn_node_kind_t kind; 323251881Speter svn_error_t *err2 = svn_io_check_path(path, &kind, pool); 324251881Speter if (err2) 325251881Speter { 326251881Speter svn_error_clear(err2); 327251881Speter return err; 328251881Speter } 329251881Speter if (kind == svn_node_dir) 330251881Speter { 331251881Speter svn_error_clear(err); 332251881Speter *fs_type = SVN_FS_TYPE_BDB; 333251881Speter return SVN_NO_ERROR; 334251881Speter } 335251881Speter return err; 336251881Speter } 337251881Speter else if (err) 338251881Speter return err; 339251881Speter 340251881Speter len = sizeof(buf); 341251881Speter SVN_ERR(svn_io_read_length_line(file, buf, &len, pool)); 342251881Speter SVN_ERR(svn_io_file_close(file, pool)); 343251881Speter *fs_type = apr_pstrdup(pool, buf); 344251881Speter 345251881Speter return SVN_NO_ERROR; 346251881Speter} 347251881Speter 348251881Speter/* Fetch the library vtable for an existing FS. */ 349251881Speterstatic svn_error_t * 350251881Speterfs_library_vtable(fs_library_vtable_t **vtable, const char *path, 351251881Speter apr_pool_t *pool) 352251881Speter{ 353251881Speter const char *fs_type; 354251881Speter 355251881Speter SVN_ERR(svn_fs_type(&fs_type, path, pool)); 356251881Speter 357251881Speter /* Fetch the library vtable by name, now that we've chosen one. */ 358299742Sdim SVN_ERR(get_library_vtable(vtable, fs_type, pool)); 359299742Sdim 360299742Sdim return SVN_NO_ERROR; 361251881Speter} 362251881Speter 363251881Speterstatic svn_error_t * 364251881Speterwrite_fs_type(const char *path, const char *fs_type, apr_pool_t *pool) 365251881Speter{ 366251881Speter const char *filename; 367251881Speter apr_file_t *file; 368251881Speter 369251881Speter filename = svn_dirent_join(path, FS_TYPE_FILENAME, pool); 370251881Speter SVN_ERR(svn_io_file_open(&file, filename, 371251881Speter APR_WRITE|APR_CREATE|APR_TRUNCATE|APR_BUFFERED, 372251881Speter APR_OS_DEFAULT, pool)); 373251881Speter SVN_ERR(svn_io_file_write_full(file, fs_type, strlen(fs_type), NULL, 374251881Speter pool)); 375251881Speter SVN_ERR(svn_io_file_write_full(file, "\n", 1, NULL, pool)); 376251881Speter return svn_error_trace(svn_io_file_close(file, pool)); 377251881Speter} 378251881Speter 379251881Speter 380251881Speter/* --- Functions for operating on filesystems by pathname --- */ 381251881Speter 382251881Speterstatic apr_status_t uninit(void *data) 383251881Speter{ 384251881Speter common_pool = NULL; 385299742Sdim common_pool_lock = NULL; 386299742Sdim common_pool_initialized = 0; 387299742Sdim 388251881Speter return APR_SUCCESS; 389251881Speter} 390251881Speter 391299742Sdimstatic svn_error_t * 392299742Sdimsynchronized_initialize(void *baton, apr_pool_t *pool) 393251881Speter{ 394251881Speter common_pool = svn_pool_create(pool); 395262253Speter base_defn.next = NULL; 396251881Speter SVN_ERR(svn_mutex__init(&common_pool_lock, TRUE, common_pool)); 397251881Speter 398251881Speter /* ### This won't work if POOL is NULL and libsvn_fs is loaded as a DSO 399251881Speter ### (via libsvn_ra_local say) since the global common_pool will live 400251881Speter ### longer than the DSO, which gets unloaded when the pool used to 401251881Speter ### load it is cleared, and so when the handler runs it will refer to 402251881Speter ### a function that no longer exists. libsvn_ra_local attempts to 403251881Speter ### work around this by explicitly calling svn_fs_initialize. */ 404251881Speter apr_pool_cleanup_register(common_pool, NULL, uninit, apr_pool_cleanup_null); 405251881Speter return SVN_NO_ERROR; 406251881Speter} 407251881Speter 408299742Sdimsvn_error_t * 409299742Sdimsvn_fs_initialize(apr_pool_t *pool) 410299742Sdim{ 411299742Sdim#if defined(SVN_USE_DSO) && APR_HAS_DSO 412299742Sdim /* Ensure that DSO subsystem is initialized early as possible if 413299742Sdim we're going to use it. */ 414299742Sdim SVN_ERR(svn_dso_initialize2()); 415299742Sdim#endif 416299742Sdim /* Protect against multiple calls. */ 417299742Sdim return svn_error_trace(svn_atomic__init_once(&common_pool_initialized, 418299742Sdim synchronized_initialize, 419299742Sdim NULL, pool)); 420299742Sdim} 421299742Sdim 422251881Speter/* A default warning handling function. */ 423251881Speterstatic void 424251881Speterdefault_warning_func(void *baton, svn_error_t *err) 425251881Speter{ 426251881Speter /* The one unforgiveable sin is to fail silently. Dumping to stderr 427251881Speter or /dev/tty is not acceptable default behavior for server 428299742Sdim processes, since those may both be equivalent to /dev/null. 429299742Sdim 430299742Sdim That said, be a good citizen and print something anyway, in case it goes 431299742Sdim somewhere, and our caller hasn't overridden the abort() call. 432299742Sdim */ 433299742Sdim if (svn_error_get_malfunction_handler() 434299742Sdim == svn_error_abort_on_malfunction) 435299742Sdim /* ### TODO: extend the malfunction API such that non-abort()ing consumers 436299742Sdim ### also get the information on ERR. */ 437299742Sdim svn_handle_error2(err, stderr, FALSE /* fatal */, "svn: fs-loader: "); 438251881Speter SVN_ERR_MALFUNCTION_NO_RETURN(); 439251881Speter} 440251881Speter 441251881Spetersvn_error_t * 442251881Spetersvn_fs__path_valid(const char *path, apr_pool_t *pool) 443251881Speter{ 444299742Sdim char *c; 445299742Sdim 446251881Speter /* UTF-8 encoded string without NULs. */ 447251881Speter if (! svn_utf__cstring_is_valid(path)) 448251881Speter { 449251881Speter return svn_error_createf(SVN_ERR_FS_PATH_SYNTAX, NULL, 450251881Speter _("Path '%s' is not in UTF-8"), path); 451251881Speter } 452251881Speter 453251881Speter /* No "." or ".." elements. */ 454251881Speter if (svn_path_is_backpath_present(path) 455251881Speter || svn_path_is_dotpath_present(path)) 456251881Speter { 457251881Speter return svn_error_createf(SVN_ERR_FS_PATH_SYNTAX, NULL, 458251881Speter _("Path '%s' contains '.' or '..' element"), 459251881Speter path); 460251881Speter } 461251881Speter 462299742Sdim /* Raise an error if PATH contains a newline because svn:mergeinfo and 463299742Sdim friends can't handle them. Issue #4340 describes a similar problem 464299742Sdim in the FSFS code itself. 465299742Sdim */ 466299742Sdim c = strchr(path, '\n'); 467299742Sdim if (c) 468299742Sdim { 469299742Sdim return svn_error_createf(SVN_ERR_FS_PATH_SYNTAX, NULL, 470299742Sdim _("Invalid control character '0x%02x' in path '%s'"), 471299742Sdim (unsigned char)*c, svn_path_illegal_path_escape(path, pool)); 472299742Sdim } 473299742Sdim 474251881Speter /* That's good enough. */ 475251881Speter return SVN_NO_ERROR; 476251881Speter} 477251881Speter 478251881Speter/* Allocate svn_fs_t structure. */ 479251881Speterstatic svn_fs_t * 480251881Speterfs_new(apr_hash_t *fs_config, apr_pool_t *pool) 481251881Speter{ 482251881Speter svn_fs_t *fs = apr_palloc(pool, sizeof(*fs)); 483251881Speter fs->pool = pool; 484251881Speter fs->path = NULL; 485251881Speter fs->warning = default_warning_func; 486251881Speter fs->warning_baton = NULL; 487251881Speter fs->config = fs_config; 488251881Speter fs->access_ctx = NULL; 489251881Speter fs->vtable = NULL; 490251881Speter fs->fsap_data = NULL; 491251881Speter fs->uuid = NULL; 492251881Speter return fs; 493251881Speter} 494251881Speter 495251881Spetersvn_fs_t * 496251881Spetersvn_fs_new(apr_hash_t *fs_config, apr_pool_t *pool) 497251881Speter{ 498251881Speter return fs_new(fs_config, pool); 499251881Speter} 500251881Speter 501251881Spetervoid 502251881Spetersvn_fs_set_warning_func(svn_fs_t *fs, svn_fs_warning_callback_t warning, 503251881Speter void *warning_baton) 504251881Speter{ 505251881Speter fs->warning = warning; 506251881Speter fs->warning_baton = warning_baton; 507251881Speter} 508251881Speter 509251881Spetersvn_error_t * 510251881Spetersvn_fs_create(svn_fs_t **fs_p, const char *path, apr_hash_t *fs_config, 511251881Speter apr_pool_t *pool) 512251881Speter{ 513251881Speter fs_library_vtable_t *vtable; 514251881Speter 515251881Speter const char *fs_type = svn_hash__get_cstring(fs_config, 516251881Speter SVN_FS_CONFIG_FS_TYPE, 517251881Speter DEFAULT_FS_TYPE); 518251881Speter SVN_ERR(get_library_vtable(&vtable, fs_type, pool)); 519251881Speter 520251881Speter /* Create the FS directory and write out the fsap-name file. */ 521251881Speter SVN_ERR(svn_io_dir_make_sgid(path, APR_OS_DEFAULT, pool)); 522251881Speter SVN_ERR(write_fs_type(path, fs_type, pool)); 523251881Speter 524251881Speter /* Perform the actual creation. */ 525251881Speter *fs_p = fs_new(fs_config, pool); 526251881Speter 527299742Sdim SVN_ERR(vtable->create(*fs_p, path, common_pool_lock, pool, common_pool)); 528299742Sdim SVN_ERR(vtable->set_svn_fs_open(*fs_p, svn_fs_open2)); 529251881Speter 530251881Speter return SVN_NO_ERROR; 531251881Speter} 532251881Speter 533251881Spetersvn_error_t * 534299742Sdimsvn_fs_open2(svn_fs_t **fs_p, const char *path, apr_hash_t *fs_config, 535299742Sdim apr_pool_t *result_pool, 536299742Sdim apr_pool_t *scratch_pool) 537251881Speter{ 538251881Speter fs_library_vtable_t *vtable; 539251881Speter 540299742Sdim SVN_ERR(fs_library_vtable(&vtable, path, scratch_pool)); 541299742Sdim *fs_p = fs_new(fs_config, result_pool); 542299742Sdim SVN_ERR(vtable->open_fs(*fs_p, path, common_pool_lock, scratch_pool, 543299742Sdim common_pool)); 544299742Sdim SVN_ERR(vtable->set_svn_fs_open(*fs_p, svn_fs_open2)); 545251881Speter 546251881Speter return SVN_NO_ERROR; 547251881Speter} 548251881Speter 549251881Spetersvn_error_t * 550299742Sdimsvn_fs_open(svn_fs_t **fs_p, 551299742Sdim const char *path, 552299742Sdim apr_hash_t *fs_config, 553299742Sdim apr_pool_t *pool) 554251881Speter{ 555299742Sdim return svn_fs_open2(fs_p, path, fs_config, pool, pool); 556299742Sdim} 557299742Sdim 558299742Sdimsvn_error_t * 559299742Sdimsvn_fs_upgrade2(const char *path, 560299742Sdim svn_fs_upgrade_notify_t notify_func, 561299742Sdim void *notify_baton, 562299742Sdim svn_cancel_func_t cancel_func, 563299742Sdim void *cancel_baton, 564299742Sdim apr_pool_t *scratch_pool) 565299742Sdim{ 566251881Speter fs_library_vtable_t *vtable; 567251881Speter svn_fs_t *fs; 568251881Speter 569299742Sdim SVN_ERR(fs_library_vtable(&vtable, path, scratch_pool)); 570299742Sdim fs = fs_new(NULL, scratch_pool); 571251881Speter 572299742Sdim SVN_ERR(vtable->upgrade_fs(fs, path, 573299742Sdim notify_func, notify_baton, 574299742Sdim cancel_func, cancel_baton, 575299742Sdim common_pool_lock, 576299742Sdim scratch_pool, common_pool)); 577251881Speter return SVN_NO_ERROR; 578251881Speter} 579251881Speter 580299742Sdim/* A warning handling function that does not abort on errors, 581299742Sdim but just lets them be returned normally. */ 582299742Sdimstatic void 583299742Sdimverify_fs_warning_func(void *baton, svn_error_t *err) 584299742Sdim{ 585299742Sdim} 586299742Sdim 587251881Spetersvn_error_t * 588251881Spetersvn_fs_verify(const char *path, 589251881Speter apr_hash_t *fs_config, 590251881Speter svn_revnum_t start, 591251881Speter svn_revnum_t end, 592251881Speter svn_fs_progress_notify_func_t notify_func, 593251881Speter void *notify_baton, 594251881Speter svn_cancel_func_t cancel_func, 595251881Speter void *cancel_baton, 596251881Speter apr_pool_t *pool) 597251881Speter{ 598251881Speter fs_library_vtable_t *vtable; 599251881Speter svn_fs_t *fs; 600251881Speter 601251881Speter SVN_ERR(fs_library_vtable(&vtable, path, pool)); 602251881Speter fs = fs_new(fs_config, pool); 603299742Sdim svn_fs_set_warning_func(fs, verify_fs_warning_func, NULL); 604251881Speter 605299742Sdim SVN_ERR(vtable->verify_fs(fs, path, start, end, 606299742Sdim notify_func, notify_baton, 607299742Sdim cancel_func, cancel_baton, 608299742Sdim common_pool_lock, 609299742Sdim pool, common_pool)); 610251881Speter return SVN_NO_ERROR; 611251881Speter} 612251881Speter 613251881Speterconst char * 614251881Spetersvn_fs_path(svn_fs_t *fs, apr_pool_t *pool) 615251881Speter{ 616251881Speter return apr_pstrdup(pool, fs->path); 617251881Speter} 618251881Speter 619251881Speterapr_hash_t * 620251881Spetersvn_fs_config(svn_fs_t *fs, apr_pool_t *pool) 621251881Speter{ 622251881Speter if (fs->config) 623251881Speter return apr_hash_copy(pool, fs->config); 624251881Speter 625251881Speter return NULL; 626251881Speter} 627251881Speter 628251881Spetersvn_error_t * 629251881Spetersvn_fs_delete_fs(const char *path, apr_pool_t *pool) 630251881Speter{ 631251881Speter fs_library_vtable_t *vtable; 632251881Speter 633251881Speter SVN_ERR(fs_library_vtable(&vtable, path, pool)); 634251881Speter return svn_error_trace(vtable->delete_fs(path, pool)); 635251881Speter} 636251881Speter 637251881Spetersvn_error_t * 638299742Sdimsvn_fs_hotcopy3(const char *src_path, const char *dst_path, 639251881Speter svn_boolean_t clean, svn_boolean_t incremental, 640299742Sdim svn_fs_hotcopy_notify_t notify_func, 641299742Sdim void *notify_baton, 642299742Sdim svn_cancel_func_t cancel_func, 643299742Sdim void *cancel_baton, 644251881Speter apr_pool_t *scratch_pool) 645251881Speter{ 646251881Speter fs_library_vtable_t *vtable; 647251881Speter const char *src_fs_type; 648251881Speter svn_fs_t *src_fs; 649251881Speter svn_fs_t *dst_fs; 650251881Speter const char *dst_fs_type; 651251881Speter svn_node_kind_t dst_kind; 652251881Speter 653251881Speter if (strcmp(src_path, dst_path) == 0) 654251881Speter return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL, 655251881Speter _("Hotcopy source and destination are equal")); 656251881Speter 657251881Speter SVN_ERR(svn_fs_type(&src_fs_type, src_path, scratch_pool)); 658251881Speter SVN_ERR(get_library_vtable(&vtable, src_fs_type, scratch_pool)); 659251881Speter src_fs = fs_new(NULL, scratch_pool); 660251881Speter dst_fs = fs_new(NULL, scratch_pool); 661251881Speter 662251881Speter SVN_ERR(svn_io_check_path(dst_path, &dst_kind, scratch_pool)); 663251881Speter if (dst_kind == svn_node_file) 664251881Speter return svn_error_createf(SVN_ERR_NODE_UNEXPECTED_KIND, NULL, 665251881Speter _("'%s' already exists and is a file"), 666251881Speter svn_dirent_local_style(dst_path, 667251881Speter scratch_pool)); 668251881Speter if (dst_kind == svn_node_unknown) 669251881Speter return svn_error_createf(SVN_ERR_NODE_UNEXPECTED_KIND, NULL, 670251881Speter _("'%s' already exists and has an unknown " 671251881Speter "node kind"), 672251881Speter svn_dirent_local_style(dst_path, 673251881Speter scratch_pool)); 674251881Speter if (dst_kind == svn_node_dir) 675251881Speter { 676251881Speter svn_node_kind_t type_file_kind; 677251881Speter 678251881Speter SVN_ERR(svn_io_check_path(svn_dirent_join(dst_path, 679251881Speter FS_TYPE_FILENAME, 680251881Speter scratch_pool), 681251881Speter &type_file_kind, scratch_pool)); 682251881Speter if (type_file_kind != svn_node_none) 683251881Speter { 684251881Speter SVN_ERR(svn_fs_type(&dst_fs_type, dst_path, scratch_pool)); 685251881Speter if (strcmp(src_fs_type, dst_fs_type) != 0) 686251881Speter return svn_error_createf( 687251881Speter SVN_ERR_ILLEGAL_TARGET, NULL, 688251881Speter _("The filesystem type of the hotcopy source " 689251881Speter "('%s') does not match the filesystem " 690251881Speter "type of the hotcopy destination ('%s')"), 691251881Speter src_fs_type, dst_fs_type); 692251881Speter } 693251881Speter } 694251881Speter 695251881Speter SVN_ERR(vtable->hotcopy(src_fs, dst_fs, src_path, dst_path, clean, 696299742Sdim incremental, notify_func, notify_baton, 697299742Sdim cancel_func, cancel_baton, common_pool_lock, 698299742Sdim scratch_pool, common_pool)); 699251881Speter return svn_error_trace(write_fs_type(dst_path, src_fs_type, scratch_pool)); 700251881Speter} 701251881Speter 702251881Spetersvn_error_t * 703251881Spetersvn_fs_pack(const char *path, 704251881Speter svn_fs_pack_notify_t notify_func, 705251881Speter void *notify_baton, 706251881Speter svn_cancel_func_t cancel_func, 707251881Speter void *cancel_baton, 708251881Speter apr_pool_t *pool) 709251881Speter{ 710251881Speter fs_library_vtable_t *vtable; 711251881Speter svn_fs_t *fs; 712251881Speter 713251881Speter SVN_ERR(fs_library_vtable(&vtable, path, pool)); 714251881Speter fs = fs_new(NULL, pool); 715251881Speter 716299742Sdim SVN_ERR(vtable->pack_fs(fs, path, notify_func, notify_baton, 717299742Sdim cancel_func, cancel_baton, common_pool_lock, 718299742Sdim pool, common_pool)); 719251881Speter return SVN_NO_ERROR; 720251881Speter} 721251881Speter 722251881Spetersvn_error_t * 723251881Spetersvn_fs_recover(const char *path, 724251881Speter svn_cancel_func_t cancel_func, void *cancel_baton, 725251881Speter apr_pool_t *pool) 726251881Speter{ 727251881Speter fs_library_vtable_t *vtable; 728251881Speter svn_fs_t *fs; 729251881Speter 730251881Speter SVN_ERR(fs_library_vtable(&vtable, path, pool)); 731251881Speter fs = fs_new(NULL, pool); 732251881Speter 733299742Sdim SVN_ERR(vtable->open_fs_for_recovery(fs, path, common_pool_lock, 734299742Sdim pool, common_pool)); 735251881Speter return svn_error_trace(vtable->recover(fs, cancel_func, cancel_baton, 736251881Speter pool)); 737251881Speter} 738251881Speter 739251881Spetersvn_error_t * 740251881Spetersvn_fs_verify_root(svn_fs_root_t *root, 741251881Speter apr_pool_t *scratch_pool) 742251881Speter{ 743251881Speter svn_fs_t *fs = root->fs; 744251881Speter SVN_ERR(fs->vtable->verify_root(root, scratch_pool)); 745251881Speter 746251881Speter return SVN_NO_ERROR; 747251881Speter} 748251881Speter 749251881Spetersvn_error_t * 750251881Spetersvn_fs_freeze(svn_fs_t *fs, 751251881Speter svn_fs_freeze_func_t freeze_func, 752251881Speter void *freeze_baton, 753251881Speter apr_pool_t *pool) 754251881Speter{ 755251881Speter SVN_ERR(fs->vtable->freeze(fs, freeze_func, freeze_baton, pool)); 756251881Speter 757251881Speter return SVN_NO_ERROR; 758251881Speter} 759251881Speter 760251881Speter 761251881Speter/* --- Berkeley-specific functions --- */ 762251881Speter 763251881Spetersvn_error_t * 764251881Spetersvn_fs_create_berkeley(svn_fs_t *fs, const char *path) 765251881Speter{ 766251881Speter fs_library_vtable_t *vtable; 767251881Speter 768251881Speter SVN_ERR(get_library_vtable(&vtable, SVN_FS_TYPE_BDB, fs->pool)); 769251881Speter 770251881Speter /* Create the FS directory and write out the fsap-name file. */ 771251881Speter SVN_ERR(svn_io_dir_make_sgid(path, APR_OS_DEFAULT, fs->pool)); 772251881Speter SVN_ERR(write_fs_type(path, SVN_FS_TYPE_BDB, fs->pool)); 773251881Speter 774251881Speter /* Perform the actual creation. */ 775299742Sdim SVN_ERR(vtable->create(fs, path, common_pool_lock, fs->pool, common_pool)); 776299742Sdim SVN_ERR(vtable->set_svn_fs_open(fs, svn_fs_open2)); 777251881Speter 778251881Speter return SVN_NO_ERROR; 779251881Speter} 780251881Speter 781251881Spetersvn_error_t * 782251881Spetersvn_fs_open_berkeley(svn_fs_t *fs, const char *path) 783251881Speter{ 784251881Speter fs_library_vtable_t *vtable; 785251881Speter 786251881Speter SVN_ERR(fs_library_vtable(&vtable, path, fs->pool)); 787299742Sdim SVN_ERR(vtable->open_fs(fs, path, common_pool_lock, fs->pool, common_pool)); 788299742Sdim SVN_ERR(vtable->set_svn_fs_open(fs, svn_fs_open2)); 789251881Speter 790251881Speter return SVN_NO_ERROR; 791251881Speter} 792251881Speter 793251881Speterconst char * 794251881Spetersvn_fs_berkeley_path(svn_fs_t *fs, apr_pool_t *pool) 795251881Speter{ 796251881Speter return svn_fs_path(fs, pool); 797251881Speter} 798251881Speter 799251881Spetersvn_error_t * 800251881Spetersvn_fs_delete_berkeley(const char *path, apr_pool_t *pool) 801251881Speter{ 802251881Speter return svn_error_trace(svn_fs_delete_fs(path, pool)); 803251881Speter} 804251881Speter 805251881Spetersvn_error_t * 806251881Spetersvn_fs_hotcopy_berkeley(const char *src_path, const char *dest_path, 807251881Speter svn_boolean_t clean_logs, apr_pool_t *pool) 808251881Speter{ 809299742Sdim return svn_error_trace(svn_fs_hotcopy3(src_path, dest_path, clean_logs, 810299742Sdim FALSE, NULL, NULL, NULL, NULL, 811299742Sdim pool)); 812251881Speter} 813251881Speter 814251881Spetersvn_error_t * 815251881Spetersvn_fs_berkeley_recover(const char *path, apr_pool_t *pool) 816251881Speter{ 817251881Speter return svn_error_trace(svn_fs_recover(path, NULL, NULL, pool)); 818251881Speter} 819251881Speter 820251881Spetersvn_error_t * 821251881Spetersvn_fs_set_berkeley_errcall(svn_fs_t *fs, 822251881Speter void (*handler)(const char *errpfx, char *msg)) 823251881Speter{ 824251881Speter return svn_error_trace(fs->vtable->bdb_set_errcall(fs, handler)); 825251881Speter} 826251881Speter 827251881Spetersvn_error_t * 828251881Spetersvn_fs_berkeley_logfiles(apr_array_header_t **logfiles, 829251881Speter const char *path, 830251881Speter svn_boolean_t only_unused, 831251881Speter apr_pool_t *pool) 832251881Speter{ 833251881Speter fs_library_vtable_t *vtable; 834251881Speter 835251881Speter SVN_ERR(fs_library_vtable(&vtable, path, pool)); 836251881Speter return svn_error_trace(vtable->bdb_logfiles(logfiles, path, only_unused, 837251881Speter pool)); 838251881Speter} 839251881Speter 840251881Speter 841251881Speter/* --- Transaction functions --- */ 842251881Speter 843251881Spetersvn_error_t * 844251881Spetersvn_fs_begin_txn2(svn_fs_txn_t **txn_p, svn_fs_t *fs, svn_revnum_t rev, 845251881Speter apr_uint32_t flags, apr_pool_t *pool) 846251881Speter{ 847251881Speter return svn_error_trace(fs->vtable->begin_txn(txn_p, fs, rev, flags, pool)); 848251881Speter} 849251881Speter 850251881Speter 851251881Spetersvn_error_t * 852251881Spetersvn_fs_commit_txn(const char **conflict_p, svn_revnum_t *new_rev, 853299742Sdim svn_fs_txn_t *txn, apr_pool_t *pool) 854251881Speter{ 855251881Speter svn_error_t *err; 856251881Speter 857251881Speter *new_rev = SVN_INVALID_REVNUM; 858251881Speter if (conflict_p) 859251881Speter *conflict_p = NULL; 860251881Speter 861251881Speter err = txn->vtable->commit(conflict_p, new_rev, txn, pool); 862251881Speter 863251881Speter#ifdef SVN_DEBUG 864251881Speter /* Check postconditions. */ 865251881Speter if (conflict_p) 866251881Speter { 867251881Speter SVN_ERR_ASSERT_E(! (SVN_IS_VALID_REVNUM(*new_rev) && *conflict_p != NULL), 868251881Speter err); 869251881Speter SVN_ERR_ASSERT_E((*conflict_p != NULL) 870251881Speter == (err && err->apr_err == SVN_ERR_FS_CONFLICT), 871251881Speter err); 872251881Speter } 873251881Speter#endif 874251881Speter 875251881Speter SVN_ERR(err); 876251881Speter 877251881Speter return SVN_NO_ERROR; 878251881Speter} 879251881Speter 880251881Spetersvn_error_t * 881251881Spetersvn_fs_abort_txn(svn_fs_txn_t *txn, apr_pool_t *pool) 882251881Speter{ 883251881Speter return svn_error_trace(txn->vtable->abort(txn, pool)); 884251881Speter} 885251881Speter 886251881Spetersvn_error_t * 887251881Spetersvn_fs_purge_txn(svn_fs_t *fs, const char *txn_id, apr_pool_t *pool) 888251881Speter{ 889251881Speter return svn_error_trace(fs->vtable->purge_txn(fs, txn_id, pool)); 890251881Speter} 891251881Speter 892251881Spetersvn_error_t * 893251881Spetersvn_fs_txn_name(const char **name_p, svn_fs_txn_t *txn, apr_pool_t *pool) 894251881Speter{ 895251881Speter *name_p = apr_pstrdup(pool, txn->id); 896251881Speter return SVN_NO_ERROR; 897251881Speter} 898251881Speter 899251881Spetersvn_revnum_t 900251881Spetersvn_fs_txn_base_revision(svn_fs_txn_t *txn) 901251881Speter{ 902251881Speter return txn->base_rev; 903251881Speter} 904251881Speter 905251881Spetersvn_error_t * 906251881Spetersvn_fs_open_txn(svn_fs_txn_t **txn, svn_fs_t *fs, const char *name, 907251881Speter apr_pool_t *pool) 908251881Speter{ 909251881Speter return svn_error_trace(fs->vtable->open_txn(txn, fs, name, pool)); 910251881Speter} 911251881Speter 912251881Spetersvn_error_t * 913251881Spetersvn_fs_list_transactions(apr_array_header_t **names_p, svn_fs_t *fs, 914251881Speter apr_pool_t *pool) 915251881Speter{ 916251881Speter return svn_error_trace(fs->vtable->list_transactions(names_p, fs, pool)); 917251881Speter} 918251881Speter 919299742Sdimstatic svn_boolean_t 920299742Sdimis_internal_txn_prop(const char *name) 921299742Sdim{ 922299742Sdim return strcmp(name, SVN_FS__PROP_TXN_CHECK_LOCKS) == 0 || 923299742Sdim strcmp(name, SVN_FS__PROP_TXN_CHECK_OOD) == 0 || 924299742Sdim strcmp(name, SVN_FS__PROP_TXN_CLIENT_DATE) == 0; 925299742Sdim} 926299742Sdim 927251881Spetersvn_error_t * 928251881Spetersvn_fs_txn_prop(svn_string_t **value_p, svn_fs_txn_t *txn, 929251881Speter const char *propname, apr_pool_t *pool) 930251881Speter{ 931299742Sdim if (is_internal_txn_prop(propname)) 932299742Sdim { 933299742Sdim *value_p = NULL; 934299742Sdim return SVN_NO_ERROR; 935299742Sdim } 936299742Sdim 937251881Speter return svn_error_trace(txn->vtable->get_prop(value_p, txn, propname, pool)); 938251881Speter} 939251881Speter 940251881Spetersvn_error_t * 941251881Spetersvn_fs_txn_proplist(apr_hash_t **table_p, svn_fs_txn_t *txn, apr_pool_t *pool) 942251881Speter{ 943299742Sdim SVN_ERR(txn->vtable->get_proplist(table_p, txn, pool)); 944299742Sdim 945299742Sdim /* Don't give away internal transaction properties. */ 946299742Sdim svn_hash_sets(*table_p, SVN_FS__PROP_TXN_CHECK_LOCKS, NULL); 947299742Sdim svn_hash_sets(*table_p, SVN_FS__PROP_TXN_CHECK_OOD, NULL); 948299742Sdim svn_hash_sets(*table_p, SVN_FS__PROP_TXN_CLIENT_DATE, NULL); 949299742Sdim 950299742Sdim return SVN_NO_ERROR; 951251881Speter} 952251881Speter 953251881Spetersvn_error_t * 954251881Spetersvn_fs_change_txn_prop(svn_fs_txn_t *txn, const char *name, 955251881Speter const svn_string_t *value, apr_pool_t *pool) 956251881Speter{ 957299742Sdim if (is_internal_txn_prop(name)) 958299742Sdim return svn_error_createf(SVN_ERR_INCORRECT_PARAMS, NULL, 959299742Sdim _("Attempt to modify internal transaction " 960299742Sdim "property '%s'"), name); 961299742Sdim 962251881Speter return svn_error_trace(txn->vtable->change_prop(txn, name, value, pool)); 963251881Speter} 964251881Speter 965251881Spetersvn_error_t * 966251881Spetersvn_fs_change_txn_props(svn_fs_txn_t *txn, const apr_array_header_t *props, 967251881Speter apr_pool_t *pool) 968251881Speter{ 969299742Sdim int i; 970299742Sdim 971299742Sdim for (i = 0; i < props->nelts; ++i) 972299742Sdim { 973299742Sdim svn_prop_t *prop = &APR_ARRAY_IDX(props, i, svn_prop_t); 974299742Sdim 975299742Sdim if (is_internal_txn_prop(prop->name)) 976299742Sdim return svn_error_createf(SVN_ERR_INCORRECT_PARAMS, NULL, 977299742Sdim _("Attempt to modify internal transaction " 978299742Sdim "property '%s'"), prop->name); 979299742Sdim } 980299742Sdim 981251881Speter return svn_error_trace(txn->vtable->change_props(txn, props, pool)); 982251881Speter} 983251881Speter 984251881Speter 985251881Speter/* --- Root functions --- */ 986251881Speter 987251881Spetersvn_error_t * 988251881Spetersvn_fs_revision_root(svn_fs_root_t **root_p, svn_fs_t *fs, svn_revnum_t rev, 989251881Speter apr_pool_t *pool) 990251881Speter{ 991251881Speter /* We create a subpool for each root object to allow us to implement 992251881Speter svn_fs_close_root. */ 993251881Speter apr_pool_t *subpool = svn_pool_create(pool); 994251881Speter return svn_error_trace(fs->vtable->revision_root(root_p, fs, rev, subpool)); 995251881Speter} 996251881Speter 997251881Spetersvn_error_t * 998251881Spetersvn_fs_txn_root(svn_fs_root_t **root_p, svn_fs_txn_t *txn, apr_pool_t *pool) 999251881Speter{ 1000251881Speter /* We create a subpool for each root object to allow us to implement 1001251881Speter svn_fs_close_root. */ 1002251881Speter apr_pool_t *subpool = svn_pool_create(pool); 1003251881Speter return svn_error_trace(txn->vtable->root(root_p, txn, subpool)); 1004251881Speter} 1005251881Speter 1006251881Spetervoid 1007251881Spetersvn_fs_close_root(svn_fs_root_t *root) 1008251881Speter{ 1009251881Speter svn_pool_destroy(root->pool); 1010251881Speter} 1011251881Speter 1012251881Spetersvn_fs_t * 1013251881Spetersvn_fs_root_fs(svn_fs_root_t *root) 1014251881Speter{ 1015251881Speter return root->fs; 1016251881Speter} 1017251881Speter 1018251881Spetersvn_boolean_t 1019251881Spetersvn_fs_is_txn_root(svn_fs_root_t *root) 1020251881Speter{ 1021251881Speter return root->is_txn_root; 1022251881Speter} 1023251881Speter 1024251881Spetersvn_boolean_t 1025251881Spetersvn_fs_is_revision_root(svn_fs_root_t *root) 1026251881Speter{ 1027251881Speter return !root->is_txn_root; 1028251881Speter} 1029251881Speter 1030251881Speterconst char * 1031251881Spetersvn_fs_txn_root_name(svn_fs_root_t *root, apr_pool_t *pool) 1032251881Speter{ 1033251881Speter return root->is_txn_root ? apr_pstrdup(pool, root->txn) : NULL; 1034251881Speter} 1035251881Speter 1036251881Spetersvn_revnum_t 1037251881Spetersvn_fs_txn_root_base_revision(svn_fs_root_t *root) 1038251881Speter{ 1039251881Speter return root->is_txn_root ? root->rev : SVN_INVALID_REVNUM; 1040251881Speter} 1041251881Speter 1042251881Spetersvn_revnum_t 1043251881Spetersvn_fs_revision_root_revision(svn_fs_root_t *root) 1044251881Speter{ 1045251881Speter return root->is_txn_root ? SVN_INVALID_REVNUM : root->rev; 1046251881Speter} 1047251881Speter 1048251881Spetersvn_error_t * 1049299742Sdimsvn_fs_paths_changed2(apr_hash_t **changed_paths_p, 1050299742Sdim svn_fs_root_t *root, 1051251881Speter apr_pool_t *pool) 1052251881Speter{ 1053251881Speter return root->vtable->paths_changed(changed_paths_p, root, pool); 1054251881Speter} 1055251881Speter 1056251881Spetersvn_error_t * 1057251881Spetersvn_fs_paths_changed(apr_hash_t **changed_paths_p, svn_fs_root_t *root, 1058251881Speter apr_pool_t *pool) 1059251881Speter{ 1060251881Speter apr_hash_t *changed_paths_new_structs; 1061251881Speter apr_hash_index_t *hi; 1062251881Speter 1063251881Speter SVN_ERR(svn_fs_paths_changed2(&changed_paths_new_structs, root, pool)); 1064251881Speter *changed_paths_p = apr_hash_make(pool); 1065251881Speter for (hi = apr_hash_first(pool, changed_paths_new_structs); 1066251881Speter hi; 1067251881Speter hi = apr_hash_next(hi)) 1068251881Speter { 1069251881Speter const void *vkey; 1070251881Speter apr_ssize_t klen; 1071251881Speter void *vval; 1072251881Speter svn_fs_path_change2_t *val; 1073251881Speter svn_fs_path_change_t *change; 1074251881Speter apr_hash_this(hi, &vkey, &klen, &vval); 1075251881Speter val = vval; 1076251881Speter change = apr_palloc(pool, sizeof(*change)); 1077251881Speter change->node_rev_id = val->node_rev_id; 1078251881Speter change->change_kind = val->change_kind; 1079251881Speter change->text_mod = val->text_mod; 1080251881Speter change->prop_mod = val->prop_mod; 1081251881Speter apr_hash_set(*changed_paths_p, vkey, klen, change); 1082251881Speter } 1083251881Speter return SVN_NO_ERROR; 1084251881Speter} 1085251881Speter 1086251881Spetersvn_error_t * 1087251881Spetersvn_fs_check_path(svn_node_kind_t *kind_p, svn_fs_root_t *root, 1088251881Speter const char *path, apr_pool_t *pool) 1089251881Speter{ 1090251881Speter return svn_error_trace(root->vtable->check_path(kind_p, root, path, pool)); 1091251881Speter} 1092251881Speter 1093251881Spetersvn_error_t * 1094299742Sdimsvn_fs_node_history2(svn_fs_history_t **history_p, svn_fs_root_t *root, 1095299742Sdim const char *path, apr_pool_t *result_pool, 1096299742Sdim apr_pool_t *scratch_pool) 1097299742Sdim{ 1098299742Sdim return svn_error_trace(root->vtable->node_history(history_p, root, path, 1099299742Sdim result_pool, 1100299742Sdim scratch_pool)); 1101299742Sdim} 1102299742Sdim 1103299742Sdimsvn_error_t * 1104251881Spetersvn_fs_node_history(svn_fs_history_t **history_p, svn_fs_root_t *root, 1105251881Speter const char *path, apr_pool_t *pool) 1106251881Speter{ 1107251881Speter return svn_error_trace(root->vtable->node_history(history_p, root, path, 1108299742Sdim pool, pool)); 1109251881Speter} 1110251881Speter 1111251881Spetersvn_error_t * 1112251881Spetersvn_fs_is_dir(svn_boolean_t *is_dir, svn_fs_root_t *root, const char *path, 1113251881Speter apr_pool_t *pool) 1114251881Speter{ 1115251881Speter svn_node_kind_t kind; 1116251881Speter 1117251881Speter SVN_ERR(root->vtable->check_path(&kind, root, path, pool)); 1118251881Speter *is_dir = (kind == svn_node_dir); 1119251881Speter return SVN_NO_ERROR; 1120251881Speter} 1121251881Speter 1122251881Spetersvn_error_t * 1123251881Spetersvn_fs_is_file(svn_boolean_t *is_file, svn_fs_root_t *root, const char *path, 1124251881Speter apr_pool_t *pool) 1125251881Speter{ 1126251881Speter svn_node_kind_t kind; 1127251881Speter 1128251881Speter SVN_ERR(root->vtable->check_path(&kind, root, path, pool)); 1129251881Speter *is_file = (kind == svn_node_file); 1130251881Speter return SVN_NO_ERROR; 1131251881Speter} 1132251881Speter 1133251881Spetersvn_error_t * 1134251881Spetersvn_fs_node_id(const svn_fs_id_t **id_p, svn_fs_root_t *root, 1135251881Speter const char *path, apr_pool_t *pool) 1136251881Speter{ 1137251881Speter return svn_error_trace(root->vtable->node_id(id_p, root, path, pool)); 1138251881Speter} 1139251881Speter 1140251881Spetersvn_error_t * 1141299742Sdimsvn_fs_node_relation(svn_fs_node_relation_t *relation, 1142299742Sdim svn_fs_root_t *root_a, const char *path_a, 1143299742Sdim svn_fs_root_t *root_b, const char *path_b, 1144299742Sdim apr_pool_t *scratch_pool) 1145299742Sdim{ 1146299742Sdim /* Different repository types? */ 1147299742Sdim if (root_a->fs != root_b->fs) 1148299742Sdim { 1149299742Sdim *relation = svn_fs_node_unrelated; 1150299742Sdim return SVN_NO_ERROR; 1151299742Sdim } 1152299742Sdim 1153299742Sdim return svn_error_trace(root_a->vtable->node_relation(relation, 1154299742Sdim root_a, path_a, 1155299742Sdim root_b, path_b, 1156299742Sdim scratch_pool)); 1157299742Sdim} 1158299742Sdim 1159299742Sdimsvn_error_t * 1160251881Spetersvn_fs_node_created_rev(svn_revnum_t *revision, svn_fs_root_t *root, 1161251881Speter const char *path, apr_pool_t *pool) 1162251881Speter{ 1163251881Speter return svn_error_trace(root->vtable->node_created_rev(revision, root, path, 1164251881Speter pool)); 1165251881Speter} 1166251881Speter 1167251881Spetersvn_error_t * 1168251881Spetersvn_fs_node_origin_rev(svn_revnum_t *revision, svn_fs_root_t *root, 1169251881Speter const char *path, apr_pool_t *pool) 1170251881Speter{ 1171251881Speter return svn_error_trace(root->vtable->node_origin_rev(revision, root, path, 1172251881Speter pool)); 1173251881Speter} 1174251881Speter 1175251881Spetersvn_error_t * 1176251881Spetersvn_fs_node_created_path(const char **created_path, svn_fs_root_t *root, 1177251881Speter const char *path, apr_pool_t *pool) 1178251881Speter{ 1179251881Speter return svn_error_trace(root->vtable->node_created_path(created_path, root, 1180251881Speter path, pool)); 1181251881Speter} 1182251881Speter 1183251881Spetersvn_error_t * 1184251881Spetersvn_fs_node_prop(svn_string_t **value_p, svn_fs_root_t *root, 1185251881Speter const char *path, const char *propname, apr_pool_t *pool) 1186251881Speter{ 1187251881Speter return svn_error_trace(root->vtable->node_prop(value_p, root, path, 1188251881Speter propname, pool)); 1189251881Speter} 1190251881Speter 1191251881Spetersvn_error_t * 1192251881Spetersvn_fs_node_proplist(apr_hash_t **table_p, svn_fs_root_t *root, 1193251881Speter const char *path, apr_pool_t *pool) 1194251881Speter{ 1195251881Speter return svn_error_trace(root->vtable->node_proplist(table_p, root, path, 1196251881Speter pool)); 1197251881Speter} 1198251881Speter 1199251881Spetersvn_error_t * 1200299742Sdimsvn_fs_node_has_props(svn_boolean_t *has_props, 1201299742Sdim svn_fs_root_t *root, 1202299742Sdim const char *path, 1203299742Sdim apr_pool_t *scratch_pool) 1204299742Sdim{ 1205299742Sdim return svn_error_trace(root->vtable->node_has_props(has_props, root, path, 1206299742Sdim scratch_pool)); 1207299742Sdim} 1208299742Sdim 1209299742Sdimsvn_error_t * 1210251881Spetersvn_fs_change_node_prop(svn_fs_root_t *root, const char *path, 1211251881Speter const char *name, const svn_string_t *value, 1212251881Speter apr_pool_t *pool) 1213251881Speter{ 1214251881Speter return svn_error_trace(root->vtable->change_node_prop(root, path, name, 1215251881Speter value, pool)); 1216251881Speter} 1217251881Speter 1218251881Spetersvn_error_t * 1219299742Sdimsvn_fs_props_different(svn_boolean_t *changed_p, svn_fs_root_t *root1, 1220299742Sdim const char *path1, svn_fs_root_t *root2, 1221299742Sdim const char *path2, apr_pool_t *scratch_pool) 1222299742Sdim{ 1223299742Sdim return svn_error_trace(root1->vtable->props_changed(changed_p, 1224299742Sdim root1, path1, 1225299742Sdim root2, path2, 1226299742Sdim TRUE, scratch_pool)); 1227299742Sdim} 1228299742Sdim 1229299742Sdimsvn_error_t * 1230251881Spetersvn_fs_props_changed(svn_boolean_t *changed_p, svn_fs_root_t *root1, 1231251881Speter const char *path1, svn_fs_root_t *root2, 1232251881Speter const char *path2, apr_pool_t *pool) 1233251881Speter{ 1234251881Speter return svn_error_trace(root1->vtable->props_changed(changed_p, 1235251881Speter root1, path1, 1236251881Speter root2, path2, 1237299742Sdim FALSE, pool)); 1238251881Speter} 1239251881Speter 1240251881Spetersvn_error_t * 1241251881Spetersvn_fs_copied_from(svn_revnum_t *rev_p, const char **path_p, 1242251881Speter svn_fs_root_t *root, const char *path, apr_pool_t *pool) 1243251881Speter{ 1244251881Speter return svn_error_trace(root->vtable->copied_from(rev_p, path_p, root, path, 1245251881Speter pool)); 1246251881Speter} 1247251881Speter 1248251881Spetersvn_error_t * 1249251881Spetersvn_fs_closest_copy(svn_fs_root_t **root_p, const char **path_p, 1250251881Speter svn_fs_root_t *root, const char *path, apr_pool_t *pool) 1251251881Speter{ 1252251881Speter return svn_error_trace(root->vtable->closest_copy(root_p, path_p, 1253251881Speter root, path, pool)); 1254251881Speter} 1255251881Speter 1256251881Spetersvn_error_t * 1257251881Spetersvn_fs_get_mergeinfo2(svn_mergeinfo_catalog_t *catalog, 1258251881Speter svn_fs_root_t *root, 1259251881Speter const apr_array_header_t *paths, 1260251881Speter svn_mergeinfo_inheritance_t inherit, 1261251881Speter svn_boolean_t include_descendants, 1262251881Speter svn_boolean_t adjust_inherited_mergeinfo, 1263251881Speter apr_pool_t *result_pool, 1264251881Speter apr_pool_t *scratch_pool) 1265251881Speter{ 1266251881Speter return svn_error_trace(root->vtable->get_mergeinfo( 1267251881Speter catalog, root, paths, inherit, include_descendants, 1268251881Speter adjust_inherited_mergeinfo, result_pool, scratch_pool)); 1269251881Speter} 1270251881Speter 1271251881Spetersvn_error_t * 1272251881Spetersvn_fs_get_mergeinfo(svn_mergeinfo_catalog_t *catalog, 1273251881Speter svn_fs_root_t *root, 1274251881Speter const apr_array_header_t *paths, 1275251881Speter svn_mergeinfo_inheritance_t inherit, 1276251881Speter svn_boolean_t include_descendants, 1277251881Speter apr_pool_t *pool) 1278251881Speter{ 1279251881Speter return svn_error_trace(root->vtable->get_mergeinfo(catalog, root, paths, 1280251881Speter inherit, 1281251881Speter include_descendants, 1282251881Speter TRUE, pool, pool)); 1283251881Speter} 1284251881Speter 1285251881Spetersvn_error_t * 1286299742Sdimsvn_fs__get_mergeinfo_for_path(svn_mergeinfo_t *mergeinfo, 1287299742Sdim svn_fs_root_t *root, 1288299742Sdim const char *path, 1289299742Sdim svn_mergeinfo_inheritance_t inherit, 1290299742Sdim svn_boolean_t adjust_inherited_mergeinfo, 1291299742Sdim apr_pool_t *result_pool, 1292299742Sdim apr_pool_t *scratch_pool) 1293299742Sdim{ 1294299742Sdim apr_array_header_t *paths 1295299742Sdim = apr_array_make(scratch_pool, 1, sizeof(const char *)); 1296299742Sdim svn_mergeinfo_catalog_t catalog; 1297299742Sdim 1298299742Sdim APR_ARRAY_PUSH(paths, const char *) = path; 1299299742Sdim 1300299742Sdim SVN_ERR(svn_fs_get_mergeinfo2(&catalog, root, paths, 1301299742Sdim inherit, FALSE /*include_descendants*/, 1302299742Sdim adjust_inherited_mergeinfo, 1303299742Sdim result_pool, scratch_pool)); 1304299742Sdim *mergeinfo = svn_hash_gets(catalog, path); 1305299742Sdim 1306299742Sdim return SVN_NO_ERROR; 1307299742Sdim} 1308299742Sdim 1309299742Sdimsvn_error_t * 1310251881Spetersvn_fs_merge(const char **conflict_p, svn_fs_root_t *source_root, 1311251881Speter const char *source_path, svn_fs_root_t *target_root, 1312251881Speter const char *target_path, svn_fs_root_t *ancestor_root, 1313251881Speter const char *ancestor_path, apr_pool_t *pool) 1314251881Speter{ 1315251881Speter return svn_error_trace(target_root->vtable->merge(conflict_p, 1316251881Speter source_root, source_path, 1317251881Speter target_root, target_path, 1318251881Speter ancestor_root, 1319251881Speter ancestor_path, pool)); 1320251881Speter} 1321251881Speter 1322251881Spetersvn_error_t * 1323251881Spetersvn_fs_dir_entries(apr_hash_t **entries_p, svn_fs_root_t *root, 1324251881Speter const char *path, apr_pool_t *pool) 1325251881Speter{ 1326251881Speter return svn_error_trace(root->vtable->dir_entries(entries_p, root, path, 1327251881Speter pool)); 1328251881Speter} 1329251881Speter 1330251881Spetersvn_error_t * 1331299742Sdimsvn_fs_dir_optimal_order(apr_array_header_t **ordered_p, 1332299742Sdim svn_fs_root_t *root, 1333299742Sdim apr_hash_t *entries, 1334299742Sdim apr_pool_t *result_pool, 1335299742Sdim apr_pool_t *scratch_pool) 1336299742Sdim{ 1337299742Sdim return svn_error_trace(root->vtable->dir_optimal_order(ordered_p, root, 1338299742Sdim entries, 1339299742Sdim result_pool, 1340299742Sdim scratch_pool)); 1341299742Sdim} 1342299742Sdim 1343299742Sdimsvn_error_t * 1344251881Spetersvn_fs_make_dir(svn_fs_root_t *root, const char *path, apr_pool_t *pool) 1345251881Speter{ 1346251881Speter SVN_ERR(svn_fs__path_valid(path, pool)); 1347251881Speter return svn_error_trace(root->vtable->make_dir(root, path, pool)); 1348251881Speter} 1349251881Speter 1350251881Spetersvn_error_t * 1351251881Spetersvn_fs_delete(svn_fs_root_t *root, const char *path, apr_pool_t *pool) 1352251881Speter{ 1353251881Speter return svn_error_trace(root->vtable->delete_node(root, path, pool)); 1354251881Speter} 1355251881Speter 1356251881Spetersvn_error_t * 1357251881Spetersvn_fs_copy(svn_fs_root_t *from_root, const char *from_path, 1358251881Speter svn_fs_root_t *to_root, const char *to_path, apr_pool_t *pool) 1359251881Speter{ 1360251881Speter SVN_ERR(svn_fs__path_valid(to_path, pool)); 1361251881Speter return svn_error_trace(to_root->vtable->copy(from_root, from_path, 1362251881Speter to_root, to_path, pool)); 1363251881Speter} 1364251881Speter 1365251881Spetersvn_error_t * 1366251881Spetersvn_fs_revision_link(svn_fs_root_t *from_root, svn_fs_root_t *to_root, 1367251881Speter const char *path, apr_pool_t *pool) 1368251881Speter{ 1369251881Speter return svn_error_trace(to_root->vtable->revision_link(from_root, to_root, 1370251881Speter path, pool)); 1371251881Speter} 1372251881Speter 1373251881Spetersvn_error_t * 1374251881Spetersvn_fs_file_length(svn_filesize_t *length_p, svn_fs_root_t *root, 1375251881Speter const char *path, apr_pool_t *pool) 1376251881Speter{ 1377251881Speter return svn_error_trace(root->vtable->file_length(length_p, root, path, 1378251881Speter pool)); 1379251881Speter} 1380251881Speter 1381251881Spetersvn_error_t * 1382251881Spetersvn_fs_file_checksum(svn_checksum_t **checksum, 1383251881Speter svn_checksum_kind_t kind, 1384251881Speter svn_fs_root_t *root, 1385251881Speter const char *path, 1386251881Speter svn_boolean_t force, 1387251881Speter apr_pool_t *pool) 1388251881Speter{ 1389251881Speter SVN_ERR(root->vtable->file_checksum(checksum, kind, root, path, pool)); 1390251881Speter 1391251881Speter if (force && (*checksum == NULL || (*checksum)->kind != kind)) 1392251881Speter { 1393251881Speter svn_stream_t *contents, *checksum_contents; 1394251881Speter 1395251881Speter SVN_ERR(svn_fs_file_contents(&contents, root, path, pool)); 1396251881Speter checksum_contents = svn_stream_checksummed2(contents, checksum, NULL, 1397251881Speter kind, TRUE, pool); 1398251881Speter 1399251881Speter /* This will force a read of any remaining data (which is all of it in 1400251881Speter this case) and dump the checksum into checksum->digest. */ 1401251881Speter SVN_ERR(svn_stream_close(checksum_contents)); 1402251881Speter } 1403251881Speter 1404251881Speter return SVN_NO_ERROR; 1405251881Speter} 1406251881Speter 1407251881Spetersvn_error_t * 1408251881Spetersvn_fs_file_md5_checksum(unsigned char digest[], 1409251881Speter svn_fs_root_t *root, 1410251881Speter const char *path, 1411251881Speter apr_pool_t *pool) 1412251881Speter{ 1413251881Speter svn_checksum_t *md5sum; 1414251881Speter 1415251881Speter SVN_ERR(svn_fs_file_checksum(&md5sum, svn_checksum_md5, root, path, TRUE, 1416251881Speter pool)); 1417251881Speter memcpy(digest, md5sum->digest, APR_MD5_DIGESTSIZE); 1418251881Speter 1419251881Speter return SVN_NO_ERROR; 1420251881Speter} 1421251881Speter 1422251881Spetersvn_error_t * 1423251881Spetersvn_fs_file_contents(svn_stream_t **contents, svn_fs_root_t *root, 1424251881Speter const char *path, apr_pool_t *pool) 1425251881Speter{ 1426251881Speter return svn_error_trace(root->vtable->file_contents(contents, root, path, 1427251881Speter pool)); 1428251881Speter} 1429251881Speter 1430251881Spetersvn_error_t * 1431251881Spetersvn_fs_try_process_file_contents(svn_boolean_t *success, 1432251881Speter svn_fs_root_t *root, 1433251881Speter const char *path, 1434251881Speter svn_fs_process_contents_func_t processor, 1435251881Speter void* baton, 1436251881Speter apr_pool_t *pool) 1437251881Speter{ 1438251881Speter /* if the FS doesn't implement this function, report a "failed" attempt */ 1439251881Speter if (root->vtable->try_process_file_contents == NULL) 1440251881Speter { 1441251881Speter *success = FALSE; 1442251881Speter return SVN_NO_ERROR; 1443251881Speter } 1444251881Speter 1445251881Speter return svn_error_trace(root->vtable->try_process_file_contents( 1446251881Speter success, 1447251881Speter root, path, 1448251881Speter processor, baton, pool)); 1449251881Speter} 1450251881Speter 1451251881Spetersvn_error_t * 1452251881Spetersvn_fs_make_file(svn_fs_root_t *root, const char *path, apr_pool_t *pool) 1453251881Speter{ 1454251881Speter SVN_ERR(svn_fs__path_valid(path, pool)); 1455251881Speter return svn_error_trace(root->vtable->make_file(root, path, pool)); 1456251881Speter} 1457251881Speter 1458251881Spetersvn_error_t * 1459251881Spetersvn_fs_apply_textdelta(svn_txdelta_window_handler_t *contents_p, 1460251881Speter void **contents_baton_p, svn_fs_root_t *root, 1461251881Speter const char *path, const char *base_checksum, 1462251881Speter const char *result_checksum, apr_pool_t *pool) 1463251881Speter{ 1464251881Speter svn_checksum_t *base, *result; 1465251881Speter 1466251881Speter /* TODO: If we ever rev this API, we should make the supplied checksums 1467251881Speter svn_checksum_t structs. */ 1468251881Speter SVN_ERR(svn_checksum_parse_hex(&base, svn_checksum_md5, base_checksum, 1469251881Speter pool)); 1470251881Speter SVN_ERR(svn_checksum_parse_hex(&result, svn_checksum_md5, result_checksum, 1471251881Speter pool)); 1472251881Speter 1473251881Speter return svn_error_trace(root->vtable->apply_textdelta(contents_p, 1474251881Speter contents_baton_p, 1475251881Speter root, 1476251881Speter path, 1477251881Speter base, 1478251881Speter result, 1479251881Speter pool)); 1480251881Speter} 1481251881Speter 1482251881Spetersvn_error_t * 1483251881Spetersvn_fs_apply_text(svn_stream_t **contents_p, svn_fs_root_t *root, 1484251881Speter const char *path, const char *result_checksum, 1485251881Speter apr_pool_t *pool) 1486251881Speter{ 1487251881Speter svn_checksum_t *result; 1488251881Speter 1489251881Speter /* TODO: If we ever rev this API, we should make the supplied checksum an 1490251881Speter svn_checksum_t struct. */ 1491251881Speter SVN_ERR(svn_checksum_parse_hex(&result, svn_checksum_md5, result_checksum, 1492251881Speter pool)); 1493251881Speter 1494251881Speter return svn_error_trace(root->vtable->apply_text(contents_p, root, path, 1495251881Speter result, pool)); 1496251881Speter} 1497251881Speter 1498251881Spetersvn_error_t * 1499299742Sdimsvn_fs_contents_different(svn_boolean_t *changed_p, svn_fs_root_t *root1, 1500299742Sdim const char *path1, svn_fs_root_t *root2, 1501299742Sdim const char *path2, apr_pool_t *scratch_pool) 1502299742Sdim{ 1503299742Sdim return svn_error_trace(root1->vtable->contents_changed(changed_p, 1504299742Sdim root1, path1, 1505299742Sdim root2, path2, 1506299742Sdim TRUE, 1507299742Sdim scratch_pool)); 1508299742Sdim} 1509299742Sdim 1510299742Sdimsvn_error_t * 1511251881Spetersvn_fs_contents_changed(svn_boolean_t *changed_p, svn_fs_root_t *root1, 1512251881Speter const char *path1, svn_fs_root_t *root2, 1513251881Speter const char *path2, apr_pool_t *pool) 1514251881Speter{ 1515251881Speter return svn_error_trace(root1->vtable->contents_changed(changed_p, 1516251881Speter root1, path1, 1517251881Speter root2, path2, 1518299742Sdim FALSE, pool)); 1519251881Speter} 1520251881Speter 1521251881Spetersvn_error_t * 1522251881Spetersvn_fs_youngest_rev(svn_revnum_t *youngest_p, svn_fs_t *fs, apr_pool_t *pool) 1523251881Speter{ 1524251881Speter return svn_error_trace(fs->vtable->youngest_rev(youngest_p, fs, pool)); 1525251881Speter} 1526251881Speter 1527251881Spetersvn_error_t * 1528299742Sdimsvn_fs_info_format(int *fs_format, 1529299742Sdim svn_version_t **supports_version, 1530299742Sdim svn_fs_t *fs, 1531299742Sdim apr_pool_t *result_pool, 1532299742Sdim apr_pool_t *scratch_pool) 1533299742Sdim{ 1534299742Sdim return svn_error_trace(fs->vtable->info_format(fs_format, supports_version, 1535299742Sdim fs, 1536299742Sdim result_pool, scratch_pool)); 1537299742Sdim} 1538299742Sdim 1539299742Sdimsvn_error_t * 1540299742Sdimsvn_fs_info_config_files(apr_array_header_t **files, 1541299742Sdim svn_fs_t *fs, 1542299742Sdim apr_pool_t *result_pool, 1543299742Sdim apr_pool_t *scratch_pool) 1544299742Sdim{ 1545299742Sdim return svn_error_trace(fs->vtable->info_config_files(files, fs, 1546299742Sdim result_pool, 1547299742Sdim scratch_pool)); 1548299742Sdim} 1549299742Sdim 1550299742Sdimsvn_error_t * 1551251881Spetersvn_fs_deltify_revision(svn_fs_t *fs, svn_revnum_t revision, apr_pool_t *pool) 1552251881Speter{ 1553251881Speter return svn_error_trace(fs->vtable->deltify(fs, revision, pool)); 1554251881Speter} 1555251881Speter 1556251881Spetersvn_error_t * 1557251881Spetersvn_fs_revision_prop(svn_string_t **value_p, svn_fs_t *fs, svn_revnum_t rev, 1558251881Speter const char *propname, apr_pool_t *pool) 1559251881Speter{ 1560251881Speter return svn_error_trace(fs->vtable->revision_prop(value_p, fs, rev, 1561251881Speter propname, pool)); 1562251881Speter} 1563251881Speter 1564251881Spetersvn_error_t * 1565251881Spetersvn_fs_revision_proplist(apr_hash_t **table_p, svn_fs_t *fs, svn_revnum_t rev, 1566251881Speter apr_pool_t *pool) 1567251881Speter{ 1568251881Speter return svn_error_trace(fs->vtable->revision_proplist(table_p, fs, rev, 1569251881Speter pool)); 1570251881Speter} 1571251881Speter 1572251881Spetersvn_error_t * 1573251881Spetersvn_fs_change_rev_prop2(svn_fs_t *fs, svn_revnum_t rev, const char *name, 1574251881Speter const svn_string_t *const *old_value_p, 1575251881Speter const svn_string_t *value, apr_pool_t *pool) 1576251881Speter{ 1577251881Speter return svn_error_trace(fs->vtable->change_rev_prop(fs, rev, name, 1578251881Speter old_value_p, 1579251881Speter value, pool)); 1580251881Speter} 1581251881Speter 1582251881Spetersvn_error_t * 1583251881Spetersvn_fs_get_file_delta_stream(svn_txdelta_stream_t **stream_p, 1584251881Speter svn_fs_root_t *source_root, 1585251881Speter const char *source_path, 1586251881Speter svn_fs_root_t *target_root, 1587251881Speter const char *target_path, apr_pool_t *pool) 1588251881Speter{ 1589251881Speter return svn_error_trace(target_root->vtable->get_file_delta_stream( 1590251881Speter stream_p, 1591251881Speter source_root, source_path, 1592251881Speter target_root, target_path, pool)); 1593251881Speter} 1594251881Speter 1595251881Spetersvn_error_t * 1596251881Spetersvn_fs_get_uuid(svn_fs_t *fs, const char **uuid, apr_pool_t *pool) 1597251881Speter{ 1598251881Speter /* If you change this, consider changing svn_fs__identifier(). */ 1599251881Speter *uuid = apr_pstrdup(pool, fs->uuid); 1600251881Speter return SVN_NO_ERROR; 1601251881Speter} 1602251881Speter 1603251881Spetersvn_error_t * 1604251881Spetersvn_fs_set_uuid(svn_fs_t *fs, const char *uuid, apr_pool_t *pool) 1605251881Speter{ 1606251881Speter if (! uuid) 1607251881Speter { 1608251881Speter uuid = svn_uuid_generate(pool); 1609251881Speter } 1610251881Speter else 1611251881Speter { 1612251881Speter apr_uuid_t parsed_uuid; 1613251881Speter apr_status_t apr_err = apr_uuid_parse(&parsed_uuid, uuid); 1614251881Speter if (apr_err) 1615251881Speter return svn_error_createf(SVN_ERR_BAD_UUID, NULL, 1616251881Speter _("Malformed UUID '%s'"), uuid); 1617251881Speter } 1618251881Speter return svn_error_trace(fs->vtable->set_uuid(fs, uuid, pool)); 1619251881Speter} 1620251881Speter 1621251881Spetersvn_error_t * 1622299742Sdimsvn_fs_lock_many(svn_fs_t *fs, 1623299742Sdim apr_hash_t *targets, 1624299742Sdim const char *comment, 1625299742Sdim svn_boolean_t is_dav_comment, 1626299742Sdim apr_time_t expiration_date, 1627299742Sdim svn_boolean_t steal_lock, 1628299742Sdim svn_fs_lock_callback_t lock_callback, 1629299742Sdim void *lock_baton, 1630299742Sdim apr_pool_t *result_pool, 1631299742Sdim apr_pool_t *scratch_pool) 1632251881Speter{ 1633299742Sdim apr_hash_index_t *hi; 1634299742Sdim apr_hash_t *ok_targets = apr_hash_make(scratch_pool); 1635299742Sdim svn_error_t *err, *cb_err = SVN_NO_ERROR; 1636299742Sdim 1637251881Speter /* Enforce that the comment be xml-escapable. */ 1638251881Speter if (comment) 1639299742Sdim if (! svn_xml_is_xml_safe(comment, strlen(comment))) 1640299742Sdim return svn_error_create(SVN_ERR_XML_UNESCAPABLE_DATA, NULL, 1641299742Sdim _("Lock comment contains illegal characters")); 1642251881Speter 1643299742Sdim if (expiration_date < 0) 1644299742Sdim return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL, 1645299742Sdim _("Negative expiration date passed to svn_fs_lock")); 1646299742Sdim 1647251881Speter /* Enforce that the token be an XML-safe URI. */ 1648299742Sdim for (hi = apr_hash_first(scratch_pool, targets); hi; hi = apr_hash_next(hi)) 1649251881Speter { 1650299742Sdim const svn_fs_lock_target_t *target = apr_hash_this_val(hi); 1651251881Speter 1652299742Sdim err = SVN_NO_ERROR; 1653299742Sdim if (target->token) 1654299742Sdim { 1655299742Sdim const char *c; 1656251881Speter 1657251881Speter 1658299742Sdim if (strncmp(target->token, "opaquelocktoken:", 16)) 1659299742Sdim err = svn_error_createf(SVN_ERR_FS_BAD_LOCK_TOKEN, NULL, 1660299742Sdim _("Lock token URI '%s' has bad scheme; " 1661299742Sdim "expected '%s'"), 1662299742Sdim target->token, "opaquelocktoken"); 1663299742Sdim 1664299742Sdim if (!err) 1665299742Sdim for (c = target->token; *c && !err; c++) 1666299742Sdim if (! svn_ctype_isascii(*c) || svn_ctype_iscntrl(*c)) 1667299742Sdim err = svn_error_createf( 1668299742Sdim SVN_ERR_FS_BAD_LOCK_TOKEN, NULL, 1669299742Sdim _("Lock token '%s' is not ASCII or is a " 1670299742Sdim "control character at byte %u"), 1671299742Sdim target->token, 1672299742Sdim (unsigned)(c - target->token)); 1673299742Sdim 1674299742Sdim /* strlen(token) == c - token. */ 1675299742Sdim if (!err && !svn_xml_is_xml_safe(target->token, c - target->token)) 1676299742Sdim err = svn_error_createf(SVN_ERR_FS_BAD_LOCK_TOKEN, NULL, 1677299742Sdim _("Lock token URI '%s' is not XML-safe"), 1678299742Sdim target->token); 1679299742Sdim } 1680299742Sdim 1681299742Sdim if (err) 1682299742Sdim { 1683299742Sdim if (!cb_err && lock_callback) 1684299742Sdim cb_err = lock_callback(lock_baton, apr_hash_this_key(hi), 1685299742Sdim NULL, err, scratch_pool); 1686299742Sdim svn_error_clear(err); 1687299742Sdim } 1688299742Sdim else 1689299742Sdim svn_hash_sets(ok_targets, apr_hash_this_key(hi), target); 1690251881Speter } 1691251881Speter 1692299742Sdim if (!apr_hash_count(ok_targets)) 1693299742Sdim return svn_error_trace(cb_err); 1694251881Speter 1695299742Sdim err = fs->vtable->lock(fs, ok_targets, comment, is_dav_comment, 1696299742Sdim expiration_date, steal_lock, 1697299742Sdim lock_callback, lock_baton, 1698299742Sdim result_pool, scratch_pool); 1699299742Sdim 1700299742Sdim if (err && cb_err) 1701299742Sdim svn_error_compose(err, cb_err); 1702299742Sdim else if (!err) 1703299742Sdim err = cb_err; 1704299742Sdim 1705299742Sdim return svn_error_trace(err); 1706251881Speter} 1707251881Speter 1708299742Sdimstruct lock_baton_t { 1709299742Sdim const svn_lock_t *lock; 1710299742Sdim svn_error_t *fs_err; 1711299742Sdim}; 1712299742Sdim 1713299742Sdim/* Implements svn_fs_lock_callback_t. Used by svn_fs_lock and 1714299742Sdim svn_fs_unlock to record the lock and error from svn_fs_lock_many 1715299742Sdim and svn_fs_unlock_many. */ 1716299742Sdimstatic svn_error_t * 1717299742Sdimlock_cb(void *lock_baton, 1718299742Sdim const char *path, 1719299742Sdim const svn_lock_t *lock, 1720299742Sdim svn_error_t *fs_err, 1721299742Sdim apr_pool_t *pool) 1722299742Sdim{ 1723299742Sdim struct lock_baton_t *b = lock_baton; 1724299742Sdim 1725299742Sdim b->lock = lock; 1726299742Sdim b->fs_err = svn_error_dup(fs_err); 1727299742Sdim 1728299742Sdim return SVN_NO_ERROR; 1729299742Sdim} 1730299742Sdim 1731251881Spetersvn_error_t * 1732299742Sdimsvn_fs_lock(svn_lock_t **lock, svn_fs_t *fs, const char *path, 1733299742Sdim const char *token, const char *comment, 1734299742Sdim svn_boolean_t is_dav_comment, apr_time_t expiration_date, 1735299742Sdim svn_revnum_t current_rev, svn_boolean_t steal_lock, 1736299742Sdim apr_pool_t *pool) 1737299742Sdim{ 1738299742Sdim apr_hash_t *targets = apr_hash_make(pool); 1739299742Sdim svn_fs_lock_target_t target; 1740299742Sdim svn_error_t *err; 1741299742Sdim struct lock_baton_t baton = {0}; 1742299742Sdim 1743299742Sdim target.token = token; 1744299742Sdim target.current_rev = current_rev; 1745299742Sdim svn_hash_sets(targets, path, &target); 1746299742Sdim 1747299742Sdim err = svn_fs_lock_many(fs, targets, comment, is_dav_comment, 1748299742Sdim expiration_date, steal_lock, lock_cb, &baton, 1749299742Sdim pool, pool); 1750299742Sdim 1751299742Sdim if (baton.lock) 1752299742Sdim *lock = (svn_lock_t*)baton.lock; 1753299742Sdim 1754299742Sdim if (err && baton.fs_err) 1755299742Sdim svn_error_compose(err, baton.fs_err); 1756299742Sdim else if (!err) 1757299742Sdim err = baton.fs_err; 1758299742Sdim 1759299742Sdim return svn_error_trace(err); 1760299742Sdim} 1761299742Sdim 1762299742Sdimsvn_error_t * 1763251881Spetersvn_fs_generate_lock_token(const char **token, svn_fs_t *fs, apr_pool_t *pool) 1764251881Speter{ 1765251881Speter return svn_error_trace(fs->vtable->generate_lock_token(token, fs, pool)); 1766251881Speter} 1767251881Speter 1768299742Sdimsvn_fs_lock_target_t * 1769299742Sdimsvn_fs_lock_target_create(const char *token, 1770299742Sdim svn_revnum_t current_rev, 1771299742Sdim apr_pool_t *result_pool) 1772299742Sdim{ 1773299742Sdim svn_fs_lock_target_t *target = apr_palloc(result_pool, 1774299742Sdim sizeof(svn_fs_lock_target_t)); 1775299742Sdim 1776299742Sdim target->token = token; 1777299742Sdim target->current_rev = current_rev; 1778299742Sdim 1779299742Sdim return target; 1780299742Sdim} 1781299742Sdim 1782299742Sdimvoid 1783299742Sdimsvn_fs_lock_target_set_token(svn_fs_lock_target_t *target, 1784299742Sdim const char *token) 1785299742Sdim{ 1786299742Sdim target->token = token; 1787299742Sdim} 1788299742Sdim 1789251881Spetersvn_error_t * 1790299742Sdimsvn_fs_unlock_many(svn_fs_t *fs, 1791299742Sdim apr_hash_t *targets, 1792299742Sdim svn_boolean_t break_lock, 1793299742Sdim svn_fs_lock_callback_t lock_callback, 1794299742Sdim void *lock_baton, 1795299742Sdim apr_pool_t *result_pool, 1796299742Sdim apr_pool_t *scratch_pool) 1797299742Sdim{ 1798299742Sdim return svn_error_trace(fs->vtable->unlock(fs, targets, break_lock, 1799299742Sdim lock_callback, lock_baton, 1800299742Sdim result_pool, scratch_pool)); 1801299742Sdim} 1802299742Sdim 1803299742Sdimsvn_error_t * 1804251881Spetersvn_fs_unlock(svn_fs_t *fs, const char *path, const char *token, 1805251881Speter svn_boolean_t break_lock, apr_pool_t *pool) 1806251881Speter{ 1807299742Sdim apr_hash_t *targets = apr_hash_make(pool); 1808299742Sdim svn_error_t *err; 1809299742Sdim struct lock_baton_t baton = {0}; 1810299742Sdim 1811299742Sdim if (!token) 1812299742Sdim token = ""; 1813299742Sdim svn_hash_sets(targets, path, token); 1814299742Sdim 1815299742Sdim err = svn_fs_unlock_many(fs, targets, break_lock, lock_cb, &baton, 1816299742Sdim pool, pool); 1817299742Sdim 1818299742Sdim if (err && baton.fs_err) 1819299742Sdim svn_error_compose(err, baton.fs_err); 1820299742Sdim else if (!err) 1821299742Sdim err = baton.fs_err; 1822299742Sdim 1823299742Sdim return svn_error_trace(err); 1824251881Speter} 1825251881Speter 1826251881Spetersvn_error_t * 1827251881Spetersvn_fs_get_lock(svn_lock_t **lock, svn_fs_t *fs, const char *path, 1828251881Speter apr_pool_t *pool) 1829251881Speter{ 1830251881Speter return svn_error_trace(fs->vtable->get_lock(lock, fs, path, pool)); 1831251881Speter} 1832251881Speter 1833251881Spetersvn_error_t * 1834251881Spetersvn_fs_get_locks2(svn_fs_t *fs, const char *path, svn_depth_t depth, 1835251881Speter svn_fs_get_locks_callback_t get_locks_func, 1836251881Speter void *get_locks_baton, apr_pool_t *pool) 1837251881Speter{ 1838251881Speter SVN_ERR_ASSERT((depth == svn_depth_empty) || 1839251881Speter (depth == svn_depth_files) || 1840251881Speter (depth == svn_depth_immediates) || 1841251881Speter (depth == svn_depth_infinity)); 1842251881Speter return svn_error_trace(fs->vtable->get_locks(fs, path, depth, 1843251881Speter get_locks_func, 1844251881Speter get_locks_baton, pool)); 1845251881Speter} 1846251881Speter 1847299742Sdim 1848299742Sdim/* --- History functions --- */ 1849299742Sdim 1850251881Spetersvn_error_t * 1851299742Sdimsvn_fs_history_prev2(svn_fs_history_t **prev_history_p, 1852299742Sdim svn_fs_history_t *history, svn_boolean_t cross_copies, 1853299742Sdim apr_pool_t *result_pool, apr_pool_t *scratch_pool) 1854251881Speter{ 1855299742Sdim return svn_error_trace(history->vtable->prev(prev_history_p, history, 1856299742Sdim cross_copies, result_pool, 1857299742Sdim scratch_pool)); 1858251881Speter} 1859251881Speter 1860251881Spetersvn_error_t * 1861251881Spetersvn_fs_history_prev(svn_fs_history_t **prev_history_p, 1862251881Speter svn_fs_history_t *history, svn_boolean_t cross_copies, 1863251881Speter apr_pool_t *pool) 1864251881Speter{ 1865251881Speter return svn_error_trace(history->vtable->prev(prev_history_p, history, 1866299742Sdim cross_copies, pool, pool)); 1867251881Speter} 1868251881Speter 1869251881Spetersvn_error_t * 1870251881Spetersvn_fs_history_location(const char **path, svn_revnum_t *revision, 1871251881Speter svn_fs_history_t *history, apr_pool_t *pool) 1872251881Speter{ 1873251881Speter return svn_error_trace(history->vtable->location(path, revision, history, 1874251881Speter pool)); 1875251881Speter} 1876251881Speter 1877251881Speter 1878251881Speter/* --- Node-ID functions --- */ 1879251881Speter 1880251881Spetersvn_fs_id_t * 1881251881Spetersvn_fs_parse_id(const char *data, apr_size_t len, apr_pool_t *pool) 1882251881Speter{ 1883251881Speter fs_library_vtable_t *vtable; 1884251881Speter svn_error_t *err; 1885251881Speter 1886251881Speter err = get_library_vtable(&vtable, SVN_FS_TYPE_BDB, pool); 1887251881Speter if (err) 1888251881Speter { 1889251881Speter svn_error_clear(err); 1890251881Speter return NULL; 1891251881Speter } 1892251881Speter return vtable->parse_id(data, len, pool); 1893251881Speter} 1894251881Speter 1895251881Spetersvn_string_t * 1896251881Spetersvn_fs_unparse_id(const svn_fs_id_t *id, apr_pool_t *pool) 1897251881Speter{ 1898251881Speter return id->vtable->unparse(id, pool); 1899251881Speter} 1900251881Speter 1901251881Spetersvn_boolean_t 1902251881Spetersvn_fs_check_related(const svn_fs_id_t *a, const svn_fs_id_t *b) 1903251881Speter{ 1904299742Sdim return (a->vtable->compare(a, b) != svn_fs_node_unrelated); 1905251881Speter} 1906251881Speter 1907251881Speterint 1908251881Spetersvn_fs_compare_ids(const svn_fs_id_t *a, const svn_fs_id_t *b) 1909251881Speter{ 1910299742Sdim switch (a->vtable->compare(a, b)) 1911299742Sdim { 1912299742Sdim case svn_fs_node_unchanged: 1913299742Sdim return 0; 1914299742Sdim case svn_fs_node_common_ancestor: 1915299742Sdim return 1; 1916299742Sdim default: 1917299742Sdim return -1; 1918299742Sdim } 1919251881Speter} 1920251881Speter 1921251881Spetersvn_error_t * 1922251881Spetersvn_fs_print_modules(svn_stringbuf_t *output, 1923251881Speter apr_pool_t *pool) 1924251881Speter{ 1925299742Sdim struct fs_type_defn *defn = fs_modules; 1926251881Speter fs_library_vtable_t *vtable; 1927251881Speter apr_pool_t *iterpool = svn_pool_create(pool); 1928251881Speter 1929251881Speter while (defn) 1930251881Speter { 1931251881Speter char *line; 1932251881Speter svn_error_t *err; 1933251881Speter 1934251881Speter svn_pool_clear(iterpool); 1935251881Speter 1936251881Speter err = get_library_vtable_direct(&vtable, defn, iterpool); 1937251881Speter if (err) 1938251881Speter { 1939251881Speter if (err->apr_err == SVN_ERR_FS_UNKNOWN_FS_TYPE) 1940251881Speter { 1941251881Speter svn_error_clear(err); 1942251881Speter defn = defn->next; 1943251881Speter continue; 1944251881Speter } 1945251881Speter else 1946251881Speter return err; 1947251881Speter } 1948251881Speter 1949251881Speter line = apr_psprintf(iterpool, "* fs_%s : %s\n", 1950251881Speter defn->fsap_name, vtable->get_description()); 1951251881Speter svn_stringbuf_appendcstr(output, line); 1952251881Speter defn = defn->next; 1953251881Speter } 1954251881Speter 1955251881Speter svn_pool_destroy(iterpool); 1956251881Speter 1957251881Speter return SVN_NO_ERROR; 1958251881Speter} 1959251881Speter 1960251881Spetersvn_fs_path_change2_t * 1961251881Spetersvn_fs_path_change2_create(const svn_fs_id_t *node_rev_id, 1962251881Speter svn_fs_path_change_kind_t change_kind, 1963251881Speter apr_pool_t *pool) 1964251881Speter{ 1965251881Speter return svn_fs__path_change_create_internal(node_rev_id, change_kind, pool); 1966251881Speter} 1967251881Speter 1968251881Speter/* Return the library version number. */ 1969251881Speterconst svn_version_t * 1970251881Spetersvn_fs_version(void) 1971251881Speter{ 1972251881Speter SVN_VERSION_BODY; 1973251881Speter} 1974299742Sdim 1975299742Sdim 1976299742Sdim/** info **/ 1977299742Sdimsvn_error_t * 1978299742Sdimsvn_fs_info(const svn_fs_info_placeholder_t **info_p, 1979299742Sdim svn_fs_t *fs, 1980299742Sdim apr_pool_t *result_pool, 1981299742Sdim apr_pool_t *scratch_pool) 1982299742Sdim{ 1983299742Sdim if (fs->vtable->info_fsap) 1984299742Sdim { 1985299742Sdim SVN_ERR(fs->vtable->info_fsap((const void **)info_p, fs, 1986299742Sdim result_pool, scratch_pool)); 1987299742Sdim } 1988299742Sdim else 1989299742Sdim { 1990299742Sdim svn_fs_info_placeholder_t *info = apr_palloc(result_pool, sizeof(*info)); 1991299742Sdim /* ### Ask the disk(!), since svn_fs_t doesn't cache the answer. */ 1992299742Sdim SVN_ERR(svn_fs_type(&info->fs_type, fs->path, result_pool)); 1993299742Sdim *info_p = info; 1994299742Sdim } 1995299742Sdim return SVN_NO_ERROR; 1996299742Sdim} 1997299742Sdim 1998299742Sdimvoid * 1999299742Sdimsvn_fs_info_dup(const void *info_void, 2000299742Sdim apr_pool_t *result_pool, 2001299742Sdim apr_pool_t *scratch_pool) 2002299742Sdim{ 2003299742Sdim const svn_fs_info_placeholder_t *info = info_void; 2004299742Sdim fs_library_vtable_t *vtable; 2005299742Sdim 2006299742Sdim SVN_ERR(get_library_vtable(&vtable, info->fs_type, scratch_pool)); 2007299742Sdim 2008299742Sdim if (vtable->info_fsap_dup) 2009299742Sdim return vtable->info_fsap_dup(info_void, result_pool); 2010299742Sdim else 2011299742Sdim return apr_pmemdup(result_pool, info, sizeof(*info)); 2012299742Sdim} 2013299742Sdim 2014