📄 fs-loader.c
字号:
/* * fs_loader.c: Front-end to the various FS back ends * * ==================================================================== * Copyright (c) 2000-2004 CollabNet. All rights reserved. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at http://subversion.tigris.org/license-1.html. * If newer versions of this license are posted there, you may use a * newer version instead, at your option. * * This software consists of voluntary contributions made by many * individuals. For exact contribution history, see the revision * history and logs, available at http://subversion.tigris.org/. * ==================================================================== */#include <string.h>#include <apr.h>#include <apr_hash.h>#include <apr_thread_mutex.h>#include "svn_types.h"#include "svn_dso.h"#include "svn_version.h"#include "svn_fs.h"#include "svn_path.h"#include "svn_xml.h"#include "svn_pools.h"#include "svn_string.h"#include "svn_private_config.h"#include "fs-loader.h"/* This is defined by configure on platforms which use configure, but we need to define a fallback for Windows. */#ifndef DEFAULT_FS_TYPE#define DEFAULT_FS_TYPE "fsfs"#endif#define FS_TYPE_FILENAME "fs-type"/* A pool common to all FS objects. See the documentation on the serialized_init function in fs-loader.h and for svn_fs_initialize(). */static apr_pool_t *common_pool;#if APR_HAS_THREADSstatic apr_thread_mutex_t *common_pool_lock;#endif/* --- Utility functions for the loader --- */static const struct fs_type_defn { const char *fs_type; const char *fsap_name; fs_init_func_t initfunc;} fs_modules[] = { { SVN_FS_TYPE_BDB, "base",#ifdef SVN_LIBSVN_FS_LINKS_FS_BASE svn_fs_base__init#endif }, { SVN_FS_TYPE_FSFS, "fs",#ifdef SVN_LIBSVN_FS_LINKS_FS_FS svn_fs_fs__init#endif }, { NULL }};static svn_error_t *load_module(fs_init_func_t *initfunc, const char *name, apr_pool_t *pool){ *initfunc = NULL;#if APR_HAS_DSO { apr_dso_handle_t *dso; apr_dso_handle_sym_t symbol; const char *libname; const char *funcname; apr_status_t status; libname = apr_psprintf(pool, "libsvn_fs_%s-%d.so.0", name, SVN_VER_MAJOR); funcname = apr_psprintf(pool, "svn_fs_%s__init", name); /* Find/load the specified library. If we get an error, assume the library doesn't exist. The library will be unloaded when pool is destroyed. */ SVN_ERR(svn_dso_load(&dso, libname)); if (! dso) return SVN_NO_ERROR; /* find the initialization routine */ status = apr_dso_sym(&symbol, dso, funcname); if (status) return svn_error_wrap_apr(status, _("'%s' does not define '%s()'"), libname, funcname); *initfunc = (fs_init_func_t) symbol; }#endif /* APR_HAS_DSO */ return SVN_NO_ERROR;}/* Fetch a library vtable by a pointer into the library definitions array. */static svn_error_t *get_library_vtable_direct(fs_library_vtable_t **vtable, const struct fs_type_defn *fst, apr_pool_t *pool){ fs_init_func_t initfunc = NULL; const svn_version_t *my_version = svn_fs_version(); const svn_version_t *fs_version; initfunc = fst->initfunc; if (! initfunc) SVN_ERR(load_module(&initfunc, fst->fsap_name, pool)); if (! initfunc) return svn_error_createf(SVN_ERR_FS_UNKNOWN_FS_TYPE, NULL, _("Failed to load module for FS type '%s'"), fst->fs_type); SVN_ERR(initfunc(my_version, vtable)); fs_version = (*vtable)->get_version(); if (!svn_ver_equal(my_version, fs_version)) return svn_error_createf(SVN_ERR_VERSION_MISMATCH, NULL, _("Mismatched FS module version for '%s':" " found %d.%d.%d%s," " expected %d.%d.%d%s"), fst->fs_type, my_version->major, my_version->minor, my_version->patch, my_version->tag, fs_version->major, fs_version->minor, fs_version->patch, fs_version->tag); return SVN_NO_ERROR;}/* Fetch a library vtable by FS type. */static svn_error_t *get_library_vtable(fs_library_vtable_t **vtable, const char *fs_type, apr_pool_t *pool){ const struct fs_type_defn *fst; for (fst = fs_modules; fst->fs_type; fst++) { if (strcmp(fs_type, fst->fs_type) == 0) return get_library_vtable_direct(vtable, fst, pool); } return svn_error_createf(SVN_ERR_FS_UNKNOWN_FS_TYPE, NULL, _("Unknown FS type '%s'"), fs_type);}svn_error_t *svn_fs_type(const char **fs_type, const char *path, apr_pool_t *pool){ const char *filename; char buf[128]; svn_error_t *err; apr_file_t *file; apr_size_t len; /* Read the fsap-name file to get the FSAP name, or assume the default. */ filename = svn_path_join(path, FS_TYPE_FILENAME, pool); err = svn_io_file_open(&file, filename, APR_READ|APR_BUFFERED, 0, pool); if (err && APR_STATUS_IS_ENOENT(err->apr_err)) { svn_error_clear(err); *fs_type = apr_pstrdup(pool, SVN_FS_TYPE_BDB); return SVN_NO_ERROR; } else if (err) return err; len = sizeof(buf); SVN_ERR(svn_io_read_length_line(file, buf, &len, pool)); SVN_ERR(svn_io_file_close(file, pool)); *fs_type = apr_pstrdup(pool, buf); return SVN_NO_ERROR;}/* Fetch the library vtable for an existing FS. */static svn_error_t *fs_library_vtable(fs_library_vtable_t **vtable, const char *path, apr_pool_t *pool){ const char *fs_type; SVN_ERR(svn_fs_type(&fs_type, path, pool)); /* Fetch the library vtable by name, now that we've chosen one. */ return get_library_vtable(vtable, fs_type, pool);}static svn_error_t *write_fs_type(const char *path, const char *fs_type, apr_pool_t *pool){ const char *filename; apr_file_t *file; filename = svn_path_join(path, FS_TYPE_FILENAME, pool); SVN_ERR(svn_io_file_open(&file, filename, APR_WRITE|APR_CREATE|APR_TRUNCATE|APR_BUFFERED, APR_OS_DEFAULT, pool)); SVN_ERR(svn_io_file_write_full(file, fs_type, strlen(fs_type), NULL, pool)); SVN_ERR(svn_io_file_write_full(file, "\n", 1, NULL, pool)); SVN_ERR(svn_io_file_close(file, pool)); return SVN_NO_ERROR;}/* --- Functions for operating on filesystems by pathname --- */static apr_status_t uninit(void *data){ common_pool = NULL;#if APR_HAS_THREADS common_pool_lock = NULL;#endif return APR_SUCCESS;}svn_error_t *svn_fs_initialize(apr_pool_t *pool){#if APR_HAS_THREADS apr_status_t status;#endif /* Protect against multiple calls. */ if (common_pool) return SVN_NO_ERROR; common_pool = svn_pool_create(pool);#if APR_HAS_THREADS status = apr_thread_mutex_create(&common_pool_lock, APR_THREAD_MUTEX_DEFAULT, common_pool); if (status) return svn_error_wrap_apr(status, _("Can't allocate FS mutex"));#endif /* ### This won't work if POOL is NULL and libsvn_fs is loaded as a DSO ### (via libsvn_ra_local say) since the global common_pool will live ### longer than the DSO, which gets unloaded when the pool used to ### load it is cleared, and so when the handler runs it will refer to ### a function that no longer exists. libsvn_ra_local attempts to ### work around this by explicitly calling svn_fs_initialize. */ apr_pool_cleanup_register(common_pool, NULL, uninit, apr_pool_cleanup_null); return SVN_NO_ERROR;}static svn_error_t *serialized_init(svn_fs_t *fs, apr_pool_t *pool){ svn_error_t *err;#if APR_HAS_THREADS apr_status_t status;#endif /* Per our API compatibility rules, we cannot ensure that svn_fs_initialize is called by the application. If not, we cannot create the common pool and lock in a thread-safe fashion, nor can we clean up the common pool if libsvn_fs is dynamically unloaded. This function makes a best effort by creating the common pool as a child of the global pool; the window of failure due to thread collision is small. */ if (!common_pool) SVN_ERR(svn_fs_initialize(NULL)); /* Invoke the FS module's serialized_init function with the common pool protected by a lock. */#if APR_HAS_THREADS status = apr_thread_mutex_lock(common_pool_lock); if (status) return svn_error_wrap_apr(status, _("Can't grab FS mutex"));#endif err = fs->vtable->serialized_init(fs, common_pool, pool);#if APR_HAS_THREADS status = apr_thread_mutex_unlock(common_pool_lock); if (status && !err) return svn_error_wrap_apr(status, _("Can't ungrab FS mutex"));#endif return err;}/* A default warning handling function. */static voiddefault_warning_func(void *baton, svn_error_t *err){ /* The one unforgiveable sin is to fail silently. Dumping to stderr or /dev/tty is not acceptable default behavior for server processes, since those may both be equivalent to /dev/null. */ abort();}svn_fs_t *svn_fs_new(apr_hash_t *fs_config, apr_pool_t *pool){ svn_fs_t *fs; fs = apr_palloc(pool, sizeof(*fs)); fs->pool = pool; fs->path = NULL; fs->warning = default_warning_func; fs->warning_baton = NULL; fs->config = fs_config; fs->access_ctx = NULL; fs->vtable = NULL; fs->fsap_data = NULL; return fs;}voidsvn_fs_set_warning_func(svn_fs_t *fs, svn_fs_warning_callback_t warning, void *warning_baton){ fs->warning = warning; fs->warning_baton = warning_baton;}svn_error_t *svn_fs_create(svn_fs_t **fs_p, const char *path, apr_hash_t *fs_config, apr_pool_t *pool){ fs_library_vtable_t *vtable; const char *fs_type = NULL; if (fs_config) fs_type = apr_hash_get(fs_config, SVN_FS_CONFIG_FS_TYPE, APR_HASH_KEY_STRING); if (fs_type == NULL) fs_type = DEFAULT_FS_TYPE; SVN_ERR(get_library_vtable(&vtable, fs_type, pool)); /* Create the FS directory and write out the fsap-name file. */ SVN_ERR(svn_io_dir_make_sgid(path, APR_OS_DEFAULT, pool)); SVN_ERR(write_fs_type(path, fs_type, pool)); /* Perform the actual creation. */ *fs_p = svn_fs_new(fs_config, pool); SVN_ERR(vtable->create(*fs_p, path, pool)); return serialized_init(*fs_p, pool);}svn_error_t *svn_fs_open(svn_fs_t **fs_p, const char *path, apr_hash_t *fs_config, apr_pool_t *pool){ fs_library_vtable_t *vtable; SVN_ERR(fs_library_vtable(&vtable, path, pool)); *fs_p = svn_fs_new(fs_config, pool); SVN_ERR(vtable->open(*fs_p, path, pool)); return serialized_init(*fs_p, pool);}const char *svn_fs_path(svn_fs_t *fs, apr_pool_t *pool){ return apr_pstrdup(pool, fs->path);}svn_error_t *svn_fs_delete_fs(const char *path, apr_pool_t *pool){ fs_library_vtable_t *vtable; SVN_ERR(fs_library_vtable(&vtable, path, pool)); return vtable->delete_fs(path, pool);}svn_error_t *svn_fs_hotcopy(const char *src_path, const char *dest_path, svn_boolean_t clean, apr_pool_t *pool){ fs_library_vtable_t *vtable; const char *fs_type; SVN_ERR(svn_fs_type(&fs_type, src_path, pool)); SVN_ERR(get_library_vtable(&vtable, fs_type, pool)); SVN_ERR(vtable->hotcopy(src_path, dest_path, clean, pool)); SVN_ERR(write_fs_type(dest_path, fs_type, pool)); return SVN_NO_ERROR;}/* --- Berkeley-specific functions --- */svn_error_t *svn_fs_create_berkeley(svn_fs_t *fs, const char *path){ fs_library_vtable_t *vtable; SVN_ERR(get_library_vtable(&vtable, SVN_FS_TYPE_BDB, fs->pool)); /* Create the FS directory and write out the fsap-name file. */ SVN_ERR(svn_io_dir_make_sgid(path, APR_OS_DEFAULT, fs->pool)); SVN_ERR(write_fs_type(path, SVN_FS_TYPE_BDB, fs->pool)); /* Perform the actual creation. */ SVN_ERR(vtable->create(fs, path, fs->pool)); return serialized_init(fs, fs->pool);}svn_error_t *svn_fs_open_berkeley(svn_fs_t *fs, const char *path){ fs_library_vtable_t *vtable; SVN_ERR(fs_library_vtable(&vtable, path, fs->pool)); SVN_ERR(vtable->open(fs, path, fs->pool)); return serialized_init(fs, fs->pool);}const char *svn_fs_berkeley_path(svn_fs_t *fs, apr_pool_t *pool){ return svn_fs_path(fs, pool);}svn_error_t *svn_fs_delete_berkeley(const char *path, apr_pool_t *pool){ return svn_fs_delete_fs(path, pool);}svn_error_t *svn_fs_hotcopy_berkeley(const char *src_path, const char *dest_path, svn_boolean_t clean_logs, apr_pool_t *pool){ return svn_fs_hotcopy(src_path, dest_path, clean_logs, pool);}svn_error_t *svn_fs_berkeley_recover(const char *path, apr_pool_t *pool){ fs_library_vtable_t *vtable; SVN_ERR(fs_library_vtable(&vtable, path, pool)); return vtable->bdb_recover(path, pool);}svn_error_t *svn_fs_set_berkeley_errcall(svn_fs_t *fs, void (*handler)(const char *errpfx, char *msg)){ return fs->vtable->bdb_set_errcall(fs, handler);}svn_error_t *svn_fs_berkeley_logfiles(apr_array_header_t **logfiles, const char *path, svn_boolean_t only_unused, apr_pool_t *pool){ fs_library_vtable_t *vtable; SVN_ERR(fs_library_vtable(&vtable, path, pool)); return vtable->bdb_logfiles(logfiles, path, only_unused, pool);}/* --- Transaction functions --- */svn_error_t *svn_fs_begin_txn2(svn_fs_txn_t **txn_p, svn_fs_t *fs, svn_revnum_t rev, apr_uint32_t flags, apr_pool_t *pool){ return fs->vtable->begin_txn(txn_p, fs, rev, flags, pool);}svn_error_t *svn_fs_begin_txn(svn_fs_txn_t **txn_p, svn_fs_t *fs, svn_revnum_t rev, apr_pool_t *pool){ return fs->vtable->begin_txn(txn_p, fs, rev, 0, pool);}svn_error_t *svn_fs_commit_txn(const char **conflict_p, svn_revnum_t *new_rev, svn_fs_txn_t *txn, apr_pool_t *pool){ return txn->vtable->commit(conflict_p, new_rev, txn, pool);}svn_error_t *svn_fs_abort_txn(svn_fs_txn_t *txn, apr_pool_t *pool){ return txn->vtable->abort(txn, pool);}svn_error_t *svn_fs_purge_txn(svn_fs_t *fs, const char *txn_id, apr_pool_t *pool){ return fs->vtable->purge_txn(fs, txn_id, pool);}svn_error_t *svn_fs_txn_name(const char **name_p, svn_fs_txn_t *txn, apr_pool_t *pool){ *name_p = apr_pstrdup(pool, txn->id); return SVN_NO_ERROR;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -