#include <string.h>
#include <apr.h>
#include <apr_atomic.h>
#include <apr_hash.h>
#include <apr_md5.h>
#include <apr_thread_mutex.h>
#include <apr_uuid.h>
#include <apr_strings.h>
#include "svn_private_config.h"
#include "svn_hash.h"
#include "svn_ctype.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_sorts.h"
#include "private/svn_atomic.h"
#include "private/svn_fs_private.h"
#include "private/svn_fs_util.h"
#include "private/svn_utf_private.h"
#include "private/svn_mutex.h"
#include "private/svn_subr_private.h"
#include "fs-loader.h"
#ifndef DEFAULT_FS_TYPE
#define DEFAULT_FS_TYPE "fsfs"
#endif
#define FS_TYPE_FILENAME "fs-type"
static apr_pool_t *common_pool = NULL;
static svn_mutex__t *common_pool_lock = NULL;
static svn_atomic_t common_pool_initialized = FALSE;
struct fs_type_defn {
const char *fs_type;
const char *fsap_name;
fs_init_func_t initfunc;
fs_library_vtable_t *vtable;
struct fs_type_defn *next;
};
static struct fs_type_defn base_defn =
{
SVN_FS_TYPE_BDB, "base",
#ifdef SVN_LIBSVN_FS_LINKS_FS_BASE
svn_fs_base__init,
#else
NULL,
#endif
NULL,
NULL
};
static struct fs_type_defn fsx_defn =
{
SVN_FS_TYPE_FSX, "x",
#ifdef SVN_LIBSVN_FS_LINKS_FS_X
svn_fs_x__init,
#else
NULL,
#endif
NULL,
&base_defn
};
static struct fs_type_defn fsfs_defn =
{
SVN_FS_TYPE_FSFS, "fs",
#ifdef SVN_LIBSVN_FS_LINKS_FS_FS
svn_fs_fs__init,
#else
NULL,
#endif
NULL,
&fsx_defn
};
static struct fs_type_defn *fs_modules = &fsfs_defn;
static svn_error_t *
load_module(fs_init_func_t *initfunc, const char *name, apr_pool_t *pool)
{
*initfunc = NULL;
#if defined(SVN_USE_DSO) && APR_HAS_DSO
{
apr_dso_handle_t *dso;
apr_dso_handle_sym_t symbol;
const char *libname;
const char *funcname;
apr_status_t status;
const char *p;
for (p = name; *p; ++p)
if (!svn_ctype_isalnum(*p))
return svn_error_createf(SVN_ERR_FS_UNKNOWN_FS_TYPE, NULL,
_("Invalid name for FS type '%s'"),
name);
libname = apr_psprintf(pool, "libsvn_fs_%s-%d.so.%d",
name, SVN_VER_MAJOR, SVN_SOVERSION);
funcname = apr_psprintf(pool, "svn_fs_%s__init", name);
SVN_ERR(svn_dso_load(&dso, libname));
if (! dso)
return SVN_NO_ERROR;
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
return SVN_NO_ERROR;
}
static svn_error_t *
get_library_vtable_direct(fs_library_vtable_t **vtable,
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;
*vtable = apr_atomic_casptr((volatile void **)&fst->vtable, NULL, NULL);
if (*vtable)
return SVN_NO_ERROR;
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(svn_fs_initialize(NULL));
SVN_MUTEX__WITH_LOCK(common_pool_lock,
initfunc(my_version, vtable, common_pool));
}
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);
apr_atomic_casptr((volatile void **)&fst->vtable, *vtable, NULL);
return SVN_NO_ERROR;
}
#if defined(SVN_USE_DSO) && APR_HAS_DSO
static svn_error_t *
get_or_allocate_third(struct fs_type_defn **fst,
const char *fs_type)
{
while (*fst)
{
if (strcmp(fs_type, (*fst)->fs_type) == 0)
return SVN_NO_ERROR;
fst = &(*fst)->next;
}
*fst = apr_palloc(common_pool, sizeof(struct fs_type_defn));
(*fst)->fs_type = apr_pstrdup(common_pool, fs_type);
(*fst)->fsap_name = (*fst)->fs_type;
(*fst)->initfunc = NULL;
(*fst)->vtable = NULL;
(*fst)->next = NULL;
return SVN_NO_ERROR;
}
#endif
static svn_error_t *
get_library_vtable(fs_library_vtable_t **vtable, const char *fs_type,
apr_pool_t *pool)
{
struct fs_type_defn **fst;
svn_boolean_t known = FALSE;
for (fst = &fs_modules; *fst; fst = &(*fst)->next)
{
if (strcmp(fs_type, (*fst)->fs_type) == 0)
{
known = TRUE;
break;
}
else if (!(*fst)->next)
{
break;
}
}
#if defined(SVN_USE_DSO) && APR_HAS_DSO
if (!known)
{
fst = &(*fst)->next;
SVN_ERR(svn_fs_initialize(NULL));
SVN_MUTEX__WITH_LOCK(common_pool_lock,
get_or_allocate_third(fst, fs_type));
known = TRUE;
}
#endif
if (!known)
return svn_error_createf(SVN_ERR_FS_UNKNOWN_FS_TYPE, NULL,
_("Unknown FS type '%s'"), fs_type);
return get_library_vtable_direct(vtable, *fst, pool);
}
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;
filename = svn_dirent_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_node_kind_t kind;
svn_error_t *err2 = svn_io_check_path(path, &kind, pool);
if (err2)
{
svn_error_clear(err2);
return err;
}
if (kind == svn_node_dir)
{
svn_error_clear(err);
*fs_type = SVN_FS_TYPE_BDB;
return SVN_NO_ERROR;
}
return err;
}
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;
}
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));
SVN_ERR(get_library_vtable(vtable, fs_type, pool));
return SVN_NO_ERROR;
}
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_dirent_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));
return svn_error_trace(svn_io_file_close(file, pool));
}
static apr_status_t uninit(void *data)
{
common_pool = NULL;
common_pool_lock = NULL;
common_pool_initialized = 0;
return APR_SUCCESS;
}
static svn_error_t *
synchronized_initialize(void *baton, apr_pool_t *pool)
{
common_pool = svn_pool_create(pool);
base_defn.next = NULL;
SVN_ERR(svn_mutex__init(&common_pool_lock, TRUE, common_pool));
apr_pool_cleanup_register(common_pool, NULL, uninit, apr_pool_cleanup_null);
return SVN_NO_ERROR;
}
svn_error_t *
svn_fs_initialize(apr_pool_t *pool)
{
#if defined(SVN_USE_DSO) && APR_HAS_DSO
SVN_ERR(svn_dso_initialize2());
#endif
return svn_error_trace(svn_atomic__init_once(&common_pool_initialized,
synchronized_initialize,
NULL, pool));
}
static void
default_warning_func(void *baton, svn_error_t *err)
{
if (svn_error_get_malfunction_handler()
== svn_error_abort_on_malfunction)
svn_handle_error2(err, stderr, FALSE , "svn: fs-loader: ");
SVN_ERR_MALFUNCTION_NO_RETURN();
}
svn_error_t *
svn_fs__path_valid(const char *path, apr_pool_t *pool)
{
char *c;
if (! svn_utf__cstring_is_valid(path))
{
return svn_error_createf(SVN_ERR_FS_PATH_SYNTAX, NULL,
_("Path '%s' is not in UTF-8"), path);
}
if (svn_path_is_backpath_present(path)
|| svn_path_is_dotpath_present(path))
{
return svn_error_createf(SVN_ERR_FS_PATH_SYNTAX, NULL,
_("Path '%s' contains '.' or '..' element"),
path);
}
c = strchr(path, '\n');
if (c)
{
return svn_error_createf(SVN_ERR_FS_PATH_SYNTAX, NULL,
_("Invalid control character '0x%02x' in path '%s'"),
(unsigned char)*c, svn_path_illegal_path_escape(path, pool));
}
return SVN_NO_ERROR;
}
static svn_fs_t *
fs_new(apr_hash_t *fs_config, apr_pool_t *pool)
{
svn_fs_t *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;
fs->uuid = NULL;
return fs;
}
svn_fs_t *
svn_fs_new(apr_hash_t *fs_config, apr_pool_t *pool)
{
return fs_new(fs_config, pool);
}
void
svn_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 = svn_hash__get_cstring(fs_config,
SVN_FS_CONFIG_FS_TYPE,
DEFAULT_FS_TYPE);
SVN_ERR(get_library_vtable(&vtable, fs_type, pool));
SVN_ERR(svn_io_dir_make_sgid(path, APR_OS_DEFAULT, pool));
SVN_ERR(write_fs_type(path, fs_type, pool));
*fs_p = fs_new(fs_config, pool);
SVN_ERR(vtable->create(*fs_p, path, common_pool_lock, pool, common_pool));
SVN_ERR(vtable->set_svn_fs_open(*fs_p, svn_fs_open2));
return SVN_NO_ERROR;
}
svn_error_t *
svn_fs_open2(svn_fs_t **fs_p, const char *path, apr_hash_t *fs_config,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
fs_library_vtable_t *vtable;
SVN_ERR(fs_library_vtable(&vtable, path, scratch_pool));
*fs_p = fs_new(fs_config, result_pool);
SVN_ERR(vtable->open_fs(*fs_p, path, common_pool_lock, scratch_pool,
common_pool));
SVN_ERR(vtable->set_svn_fs_open(*fs_p, svn_fs_open2));
return SVN_NO_ERROR;
}
svn_error_t *
svn_fs_open(svn_fs_t **fs_p,
const char *path,
apr_hash_t *fs_config,
apr_pool_t *pool)
{
return svn_fs_open2(fs_p, path, fs_config, pool, pool);
}
svn_error_t *
svn_fs_upgrade2(const char *path,
svn_fs_upgrade_notify_t notify_func,
void *notify_baton,
svn_cancel_func_t cancel_func,
void *cancel_baton,
apr_pool_t *scratch_pool)
{
fs_library_vtable_t *vtable;
svn_fs_t *fs;
SVN_ERR(fs_library_vtable(&vtable, path, scratch_pool));
fs = fs_new(NULL, scratch_pool);
SVN_ERR(vtable->upgrade_fs(fs, path,
notify_func, notify_baton,
cancel_func, cancel_baton,
common_pool_lock,
scratch_pool, common_pool));
return SVN_NO_ERROR;
}
static void
verify_fs_warning_func(void *baton, svn_error_t *err)
{
}
svn_error_t *
svn_fs_verify(const char *path,
apr_hash_t *fs_config,
svn_revnum_t start,
svn_revnum_t end,
svn_fs_progress_notify_func_t notify_func,
void *notify_baton,
svn_cancel_func_t cancel_func,
void *cancel_baton,
apr_pool_t *pool)
{
fs_library_vtable_t *vtable;
svn_fs_t *fs;
SVN_ERR(fs_library_vtable(&vtable, path, pool));
fs = fs_new(fs_config, pool);
svn_fs_set_warning_func(fs, verify_fs_warning_func, NULL);
SVN_ERR(vtable->verify_fs(fs, path, start, end,
notify_func, notify_baton,
cancel_func, cancel_baton,
common_pool_lock,
pool, common_pool));
return SVN_NO_ERROR;
}
const char *
svn_fs_path(svn_fs_t *fs, apr_pool_t *pool)
{
return apr_pstrdup(pool, fs->path);
}
apr_hash_t *
svn_fs_config(svn_fs_t *fs, apr_pool_t *pool)
{
if (fs->config)
return apr_hash_copy(pool, fs->config);
return NULL;
}
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 svn_error_trace(vtable->delete_fs(path, pool));
}
svn_error_t *
svn_fs_hotcopy3(const char *src_path, const char *dst_path,
svn_boolean_t clean, svn_boolean_t incremental,
svn_fs_hotcopy_notify_t notify_func,
void *notify_baton,
svn_cancel_func_t cancel_func,
void *cancel_baton,
apr_pool_t *scratch_pool)
{
fs_library_vtable_t *vtable;
const char *src_fs_type;
svn_fs_t *src_fs;
svn_fs_t *dst_fs;
const char *dst_fs_type;
svn_node_kind_t dst_kind;
if (strcmp(src_path, dst_path) == 0)
return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
_("Hotcopy source and destination are equal"));
SVN_ERR(svn_fs_type(&src_fs_type, src_path, scratch_pool));
SVN_ERR(get_library_vtable(&vtable, src_fs_type, scratch_pool));
src_fs = fs_new(NULL, scratch_pool);
dst_fs = fs_new(NULL, scratch_pool);
SVN_ERR(svn_io_check_path(dst_path, &dst_kind, scratch_pool));
if (dst_kind == svn_node_file)
return svn_error_createf(SVN_ERR_NODE_UNEXPECTED_KIND, NULL,
_("'%s' already exists and is a file"),
svn_dirent_local_style(dst_path,
scratch_pool));
if (dst_kind == svn_node_unknown)
return svn_error_createf(SVN_ERR_NODE_UNEXPECTED_KIND, NULL,
_("'%s' already exists and has an unknown "
"node kind"),
svn_dirent_local_style(dst_path,
scratch_pool));
if (dst_kind == svn_node_dir)
{
svn_node_kind_t type_file_kind;
SVN_ERR(svn_io_check_path(svn_dirent_join(dst_path,
FS_TYPE_FILENAME,
scratch_pool),
&type_file_kind, scratch_pool));
if (type_file_kind != svn_node_none)
{
SVN_ERR(svn_fs_type(&dst_fs_type, dst_path, scratch_pool));
if (strcmp(src_fs_type, dst_fs_type) != 0)
return svn_error_createf(
SVN_ERR_ILLEGAL_TARGET, NULL,
_("The filesystem type of the hotcopy source "
"('%s') does not match the filesystem "
"type of the hotcopy destination ('%s')"),
src_fs_type, dst_fs_type);
}
}
SVN_ERR(vtable->hotcopy(src_fs, dst_fs, src_path, dst_path, clean,
incremental, notify_func, notify_baton,
cancel_func, cancel_baton, common_pool_lock,
scratch_pool, common_pool));
return svn_error_trace(write_fs_type(dst_path, src_fs_type, scratch_pool));
}
svn_error_t *
svn_fs_pack(const char *path,
svn_fs_pack_notify_t notify_func,
void *notify_baton,
svn_cancel_func_t cancel_func,
void *cancel_baton,
apr_pool_t *pool)
{
fs_library_vtable_t *vtable;
svn_fs_t *fs;
SVN_ERR(fs_library_vtable(&vtable, path, pool));
fs = fs_new(NULL, pool);
SVN_ERR(vtable->pack_fs(fs, path, notify_func, notify_baton,
cancel_func, cancel_baton, common_pool_lock,
pool, common_pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_fs_recover(const char *path,
svn_cancel_func_t cancel_func, void *cancel_baton,
apr_pool_t *pool)
{
fs_library_vtable_t *vtable;
svn_fs_t *fs;
SVN_ERR(fs_library_vtable(&vtable, path, pool));
fs = fs_new(NULL, pool);
SVN_ERR(vtable->open_fs_for_recovery(fs, path, common_pool_lock,
pool, common_pool));
return svn_error_trace(vtable->recover(fs, cancel_func, cancel_baton,
pool));
}
svn_error_t *
svn_fs_verify_root(svn_fs_root_t *root,
apr_pool_t *scratch_pool)
{
svn_fs_t *fs = root->fs;
SVN_ERR(fs->vtable->verify_root(root, scratch_pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_fs_freeze(svn_fs_t *fs,
svn_fs_freeze_func_t freeze_func,
void *freeze_baton,
apr_pool_t *pool)
{
SVN_ERR(fs->vtable->freeze(fs, freeze_func, freeze_baton, pool));
return SVN_NO_ERROR;
}
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));
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));
SVN_ERR(vtable->create(fs, path, common_pool_lock, fs->pool, common_pool));
SVN_ERR(vtable->set_svn_fs_open(fs, svn_fs_open2));
return SVN_NO_ERROR;
}
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(fs, path, common_pool_lock, fs->pool, common_pool));
SVN_ERR(vtable->set_svn_fs_open(fs, svn_fs_open2));
return SVN_NO_ERROR;
}
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_error_trace(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_error_trace(svn_fs_hotcopy3(src_path, dest_path, clean_logs,
FALSE, NULL, NULL, NULL, NULL,
pool));
}
svn_error_t *
svn_fs_berkeley_recover(const char *path, apr_pool_t *pool)
{
return svn_error_trace(svn_fs_recover(path, NULL, NULL, pool));
}
svn_error_t *
svn_fs_set_berkeley_errcall(svn_fs_t *fs,
void (*handler)(const char *errpfx, char *msg))
{
return svn_error_trace(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 svn_error_trace(vtable->bdb_logfiles(logfiles, path, only_unused,
pool));
}
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 svn_error_trace(fs->vtable->begin_txn(txn_p, fs, rev, flags, 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)
{
svn_error_t *err;
*new_rev = SVN_INVALID_REVNUM;
if (conflict_p)
*conflict_p = NULL;
err = txn->vtable->commit(conflict_p, new_rev, txn, pool);
#ifdef SVN_DEBUG
if (conflict_p)
{
SVN_ERR_ASSERT_E(! (SVN_IS_VALID_REVNUM(*new_rev) && *conflict_p != NULL),
err);
SVN_ERR_ASSERT_E((*conflict_p != NULL)
== (err && err->apr_err == SVN_ERR_FS_CONFLICT),
err);
}
#endif
SVN_ERR(err);
return SVN_NO_ERROR;
}
svn_error_t *
svn_fs_abort_txn(svn_fs_txn_t *txn, apr_pool_t *pool)
{
return svn_error_trace(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 svn_error_trace(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;
}
svn_revnum_t
svn_fs_txn_base_revision(svn_fs_txn_t *txn)
{
return txn->base_rev;
}
svn_error_t *
svn_fs_open_txn(svn_fs_txn_t **txn, svn_fs_t *fs, const char *name,
apr_pool_t *pool)
{
return svn_error_trace(fs->vtable->open_txn(txn, fs, name, pool));
}
svn_error_t *
svn_fs_list_transactions(apr_array_header_t **names_p, svn_fs_t *fs,
apr_pool_t *pool)
{
return svn_error_trace(fs->vtable->list_transactions(names_p, fs, pool));
}
static svn_boolean_t
is_internal_txn_prop(const char *name)
{
return strcmp(name, SVN_FS__PROP_TXN_CHECK_LOCKS) == 0 ||
strcmp(name, SVN_FS__PROP_TXN_CHECK_OOD) == 0 ||
strcmp(name, SVN_FS__PROP_TXN_CLIENT_DATE) == 0;
}
svn_error_t *
svn_fs_txn_prop(svn_string_t **value_p, svn_fs_txn_t *txn,
const char *propname, apr_pool_t *pool)
{
if (is_internal_txn_prop(propname))
{
*value_p = NULL;
return SVN_NO_ERROR;
}
return svn_error_trace(txn->vtable->get_prop(value_p, txn, propname, pool));
}
svn_error_t *
svn_fs_txn_proplist(apr_hash_t **table_p, svn_fs_txn_t *txn, apr_pool_t *pool)
{
SVN_ERR(txn->vtable->get_proplist(table_p, txn, pool));
svn_hash_sets(*table_p, SVN_FS__PROP_TXN_CHECK_LOCKS, NULL);
svn_hash_sets(*table_p, SVN_FS__PROP_TXN_CHECK_OOD, NULL);
svn_hash_sets(*table_p, SVN_FS__PROP_TXN_CLIENT_DATE, NULL);
return SVN_NO_ERROR;
}
svn_error_t *
svn_fs_change_txn_prop(svn_fs_txn_t *txn, const char *name,
const svn_string_t *value, apr_pool_t *pool)
{
if (is_internal_txn_prop(name))
return svn_error_createf(SVN_ERR_INCORRECT_PARAMS, NULL,
_("Attempt to modify internal transaction "
"property '%s'"), name);
return svn_error_trace(txn->vtable->change_prop(txn, name, value, pool));
}
svn_error_t *
svn_fs_change_txn_props(svn_fs_txn_t *txn, const apr_array_header_t *props,
apr_pool_t *pool)
{
int i;
for (i = 0; i < props->nelts; ++i)
{
svn_prop_t *prop = &APR_ARRAY_IDX(props, i, svn_prop_t);
if (is_internal_txn_prop(prop->name))
return svn_error_createf(SVN_ERR_INCORRECT_PARAMS, NULL,
_("Attempt to modify internal transaction "
"property '%s'"), prop->name);
}
return svn_error_trace(txn->vtable->change_props(txn, props, pool));
}
svn_error_t *
svn_fs_revision_root(svn_fs_root_t **root_p, svn_fs_t *fs, svn_revnum_t rev,
apr_pool_t *pool)
{
apr_pool_t *subpool = svn_pool_create(pool);
return svn_error_trace(fs->vtable->revision_root(root_p, fs, rev, subpool));
}
svn_error_t *
svn_fs_txn_root(svn_fs_root_t **root_p, svn_fs_txn_t *txn, apr_pool_t *pool)
{
apr_pool_t *subpool = svn_pool_create(pool);
return svn_error_trace(txn->vtable->root(root_p, txn, subpool));
}
void
svn_fs_close_root(svn_fs_root_t *root)
{
svn_pool_destroy(root->pool);
}
svn_fs_t *
svn_fs_root_fs(svn_fs_root_t *root)
{
return root->fs;
}
svn_boolean_t
svn_fs_is_txn_root(svn_fs_root_t *root)
{
return root->is_txn_root;
}
svn_boolean_t
svn_fs_is_revision_root(svn_fs_root_t *root)
{
return !root->is_txn_root;
}
const char *
svn_fs_txn_root_name(svn_fs_root_t *root, apr_pool_t *pool)
{
return root->is_txn_root ? apr_pstrdup(pool, root->txn) : NULL;
}
svn_revnum_t
svn_fs_txn_root_base_revision(svn_fs_root_t *root)
{
return root->is_txn_root ? root->rev : SVN_INVALID_REVNUM;
}
svn_revnum_t
svn_fs_revision_root_revision(svn_fs_root_t *root)
{
return root->is_txn_root ? SVN_INVALID_REVNUM : root->rev;
}
svn_error_t *
svn_fs_paths_changed2(apr_hash_t **changed_paths_p,
svn_fs_root_t *root,
apr_pool_t *pool)
{
return root->vtable->paths_changed(changed_paths_p, root, pool);
}
svn_error_t *
svn_fs_paths_changed(apr_hash_t **changed_paths_p, svn_fs_root_t *root,
apr_pool_t *pool)
{
apr_hash_t *changed_paths_new_structs;
apr_hash_index_t *hi;
SVN_ERR(svn_fs_paths_changed2(&changed_paths_new_structs, root, pool));
*changed_paths_p = apr_hash_make(pool);
for (hi = apr_hash_first(pool, changed_paths_new_structs);
hi;
hi = apr_hash_next(hi))
{
const void *vkey;
apr_ssize_t klen;
void *vval;
svn_fs_path_change2_t *val;
svn_fs_path_change_t *change;
apr_hash_this(hi, &vkey, &klen, &vval);
val = vval;
change = apr_palloc(pool, sizeof(*change));
change->node_rev_id = val->node_rev_id;
change->change_kind = val->change_kind;
change->text_mod = val->text_mod;
change->prop_mod = val->prop_mod;
apr_hash_set(*changed_paths_p, vkey, klen, change);
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_fs_check_path(svn_node_kind_t *kind_p, svn_fs_root_t *root,
const char *path, apr_pool_t *pool)
{
return svn_error_trace(root->vtable->check_path(kind_p, root, path, pool));
}
svn_error_t *
svn_fs_node_history2(svn_fs_history_t **history_p, svn_fs_root_t *root,
const char *path, apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
return svn_error_trace(root->vtable->node_history(history_p, root, path,
result_pool,
scratch_pool));
}
svn_error_t *
svn_fs_node_history(svn_fs_history_t **history_p, svn_fs_root_t *root,
const char *path, apr_pool_t *pool)
{
return svn_error_trace(root->vtable->node_history(history_p, root, path,
pool, pool));
}
svn_error_t *
svn_fs_is_dir(svn_boolean_t *is_dir, svn_fs_root_t *root, const char *path,
apr_pool_t *pool)
{
svn_node_kind_t kind;
SVN_ERR(root->vtable->check_path(&kind, root, path, pool));
*is_dir = (kind == svn_node_dir);
return SVN_NO_ERROR;
}
svn_error_t *
svn_fs_is_file(svn_boolean_t *is_file, svn_fs_root_t *root, const char *path,
apr_pool_t *pool)
{
svn_node_kind_t kind;
SVN_ERR(root->vtable->check_path(&kind, root, path, pool));
*is_file = (kind == svn_node_file);
return SVN_NO_ERROR;
}
svn_error_t *
svn_fs_node_id(const svn_fs_id_t **id_p, svn_fs_root_t *root,
const char *path, apr_pool_t *pool)
{
return svn_error_trace(root->vtable->node_id(id_p, root, path, pool));
}
svn_error_t *
svn_fs_node_relation(svn_fs_node_relation_t *relation,
svn_fs_root_t *root_a, const char *path_a,
svn_fs_root_t *root_b, const char *path_b,
apr_pool_t *scratch_pool)
{
if (root_a->fs != root_b->fs)
{
*relation = svn_fs_node_unrelated;
return SVN_NO_ERROR;
}
return svn_error_trace(root_a->vtable->node_relation(relation,
root_a, path_a,
root_b, path_b,
scratch_pool));
}
svn_error_t *
svn_fs_node_created_rev(svn_revnum_t *revision, svn_fs_root_t *root,
const char *path, apr_pool_t *pool)
{
return svn_error_trace(root->vtable->node_created_rev(revision, root, path,
pool));
}
svn_error_t *
svn_fs_node_origin_rev(svn_revnum_t *revision, svn_fs_root_t *root,
const char *path, apr_pool_t *pool)
{
return svn_error_trace(root->vtable->node_origin_rev(revision, root, path,
pool));
}
svn_error_t *
svn_fs_node_created_path(const char **created_path, svn_fs_root_t *root,
const char *path, apr_pool_t *pool)
{
return svn_error_trace(root->vtable->node_created_path(created_path, root,
path, pool));
}
svn_error_t *
svn_fs_node_prop(svn_string_t **value_p, svn_fs_root_t *root,
const char *path, const char *propname, apr_pool_t *pool)
{
return svn_error_trace(root->vtable->node_prop(value_p, root, path,
propname, pool));
}
svn_error_t *
svn_fs_node_proplist(apr_hash_t **table_p, svn_fs_root_t *root,
const char *path, apr_pool_t *pool)
{
return svn_error_trace(root->vtable->node_proplist(table_p, root, path,
pool));
}
svn_error_t *
svn_fs_node_has_props(svn_boolean_t *has_props,
svn_fs_root_t *root,
const char *path,
apr_pool_t *scratch_pool)
{
return svn_error_trace(root->vtable->node_has_props(has_props, root, path,
scratch_pool));
}
svn_error_t *
svn_fs_change_node_prop(svn_fs_root_t *root, const char *path,
const char *name, const svn_string_t *value,
apr_pool_t *pool)
{
return svn_error_trace(root->vtable->change_node_prop(root, path, name,
value, pool));
}
svn_error_t *
svn_fs_props_different(svn_boolean_t *changed_p, svn_fs_root_t *root1,
const char *path1, svn_fs_root_t *root2,
const char *path2, apr_pool_t *scratch_pool)
{
return svn_error_trace(root1->vtable->props_changed(changed_p,
root1, path1,
root2, path2,
TRUE, scratch_pool));
}
svn_error_t *
svn_fs_props_changed(svn_boolean_t *changed_p, svn_fs_root_t *root1,
const char *path1, svn_fs_root_t *root2,
const char *path2, apr_pool_t *pool)
{
return svn_error_trace(root1->vtable->props_changed(changed_p,
root1, path1,
root2, path2,
FALSE, pool));
}
svn_error_t *
svn_fs_copied_from(svn_revnum_t *rev_p, const char **path_p,
svn_fs_root_t *root, const char *path, apr_pool_t *pool)
{
return svn_error_trace(root->vtable->copied_from(rev_p, path_p, root, path,
pool));
}
svn_error_t *
svn_fs_closest_copy(svn_fs_root_t **root_p, const char **path_p,
svn_fs_root_t *root, const char *path, apr_pool_t *pool)
{
return svn_error_trace(root->vtable->closest_copy(root_p, path_p,
root, path, pool));
}
svn_error_t *
svn_fs_get_mergeinfo2(svn_mergeinfo_catalog_t *catalog,
svn_fs_root_t *root,
const apr_array_header_t *paths,
svn_mergeinfo_inheritance_t inherit,
svn_boolean_t include_descendants,
svn_boolean_t adjust_inherited_mergeinfo,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
return svn_error_trace(root->vtable->get_mergeinfo(
catalog, root, paths, inherit, include_descendants,
adjust_inherited_mergeinfo, result_pool, scratch_pool));
}
svn_error_t *
svn_fs_get_mergeinfo(svn_mergeinfo_catalog_t *catalog,
svn_fs_root_t *root,
const apr_array_header_t *paths,
svn_mergeinfo_inheritance_t inherit,
svn_boolean_t include_descendants,
apr_pool_t *pool)
{
return svn_error_trace(root->vtable->get_mergeinfo(catalog, root, paths,
inherit,
include_descendants,
TRUE, pool, pool));
}
svn_error_t *
svn_fs__get_mergeinfo_for_path(svn_mergeinfo_t *mergeinfo,
svn_fs_root_t *root,
const char *path,
svn_mergeinfo_inheritance_t inherit,
svn_boolean_t adjust_inherited_mergeinfo,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
apr_array_header_t *paths
= apr_array_make(scratch_pool, 1, sizeof(const char *));
svn_mergeinfo_catalog_t catalog;
APR_ARRAY_PUSH(paths, const char *) = path;
SVN_ERR(svn_fs_get_mergeinfo2(&catalog, root, paths,
inherit, FALSE ,
adjust_inherited_mergeinfo,
result_pool, scratch_pool));
*mergeinfo = svn_hash_gets(catalog, path);
return SVN_NO_ERROR;
}
svn_error_t *
svn_fs_merge(const char **conflict_p, svn_fs_root_t *source_root,
const char *source_path, svn_fs_root_t *target_root,
const char *target_path, svn_fs_root_t *ancestor_root,
const char *ancestor_path, apr_pool_t *pool)
{
return svn_error_trace(target_root->vtable->merge(conflict_p,
source_root, source_path,
target_root, target_path,
ancestor_root,
ancestor_path, pool));
}
svn_error_t *
svn_fs_dir_entries(apr_hash_t **entries_p, svn_fs_root_t *root,
const char *path, apr_pool_t *pool)
{
return svn_error_trace(root->vtable->dir_entries(entries_p, root, path,
pool));
}
svn_error_t *
svn_fs_dir_optimal_order(apr_array_header_t **ordered_p,
svn_fs_root_t *root,
apr_hash_t *entries,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
return svn_error_trace(root->vtable->dir_optimal_order(ordered_p, root,
entries,
result_pool,
scratch_pool));
}
svn_error_t *
svn_fs_make_dir(svn_fs_root_t *root, const char *path, apr_pool_t *pool)
{
SVN_ERR(svn_fs__path_valid(path, pool));
return svn_error_trace(root->vtable->make_dir(root, path, pool));
}
svn_error_t *
svn_fs_delete(svn_fs_root_t *root, const char *path, apr_pool_t *pool)
{
return svn_error_trace(root->vtable->delete_node(root, path, pool));
}
svn_error_t *
svn_fs_copy(svn_fs_root_t *from_root, const char *from_path,
svn_fs_root_t *to_root, const char *to_path, apr_pool_t *pool)
{
SVN_ERR(svn_fs__path_valid(to_path, pool));
return svn_error_trace(to_root->vtable->copy(from_root, from_path,
to_root, to_path, pool));
}
svn_error_t *
svn_fs_revision_link(svn_fs_root_t *from_root, svn_fs_root_t *to_root,
const char *path, apr_pool_t *pool)
{
return svn_error_trace(to_root->vtable->revision_link(from_root, to_root,
path, pool));
}
svn_error_t *
svn_fs_file_length(svn_filesize_t *length_p, svn_fs_root_t *root,
const char *path, apr_pool_t *pool)
{
return svn_error_trace(root->vtable->file_length(length_p, root, path,
pool));
}
svn_error_t *
svn_fs_file_checksum(svn_checksum_t **checksum,
svn_checksum_kind_t kind,
svn_fs_root_t *root,
const char *path,
svn_boolean_t force,
apr_pool_t *pool)
{
SVN_ERR(root->vtable->file_checksum(checksum, kind, root, path, pool));
if (force && (*checksum == NULL || (*checksum)->kind != kind))
{
svn_stream_t *contents, *checksum_contents;
SVN_ERR(svn_fs_file_contents(&contents, root, path, pool));
checksum_contents = svn_stream_checksummed2(contents, checksum, NULL,
kind, TRUE, pool);
SVN_ERR(svn_stream_close(checksum_contents));
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_fs_file_md5_checksum(unsigned char digest[],
svn_fs_root_t *root,
const char *path,
apr_pool_t *pool)
{
svn_checksum_t *md5sum;
SVN_ERR(svn_fs_file_checksum(&md5sum, svn_checksum_md5, root, path, TRUE,
pool));
memcpy(digest, md5sum->digest, APR_MD5_DIGESTSIZE);
return SVN_NO_ERROR;
}
svn_error_t *
svn_fs_file_contents(svn_stream_t **contents, svn_fs_root_t *root,
const char *path, apr_pool_t *pool)
{
return svn_error_trace(root->vtable->file_contents(contents, root, path,
pool));
}
svn_error_t *
svn_fs_try_process_file_contents(svn_boolean_t *success,
svn_fs_root_t *root,
const char *path,
svn_fs_process_contents_func_t processor,
void* baton,
apr_pool_t *pool)
{
if (root->vtable->try_process_file_contents == NULL)
{
*success = FALSE;
return SVN_NO_ERROR;
}
return svn_error_trace(root->vtable->try_process_file_contents(
success,
root, path,
processor, baton, pool));
}
svn_error_t *
svn_fs_make_file(svn_fs_root_t *root, const char *path, apr_pool_t *pool)
{
SVN_ERR(svn_fs__path_valid(path, pool));
return svn_error_trace(root->vtable->make_file(root, path, pool));
}
svn_error_t *
svn_fs_apply_textdelta(svn_txdelta_window_handler_t *contents_p,
void **contents_baton_p, svn_fs_root_t *root,
const char *path, const char *base_checksum,
const char *result_checksum, apr_pool_t *pool)
{
svn_checksum_t *base, *result;
SVN_ERR(svn_checksum_parse_hex(&base, svn_checksum_md5, base_checksum,
pool));
SVN_ERR(svn_checksum_parse_hex(&result, svn_checksum_md5, result_checksum,
pool));
return svn_error_trace(root->vtable->apply_textdelta(contents_p,
contents_baton_p,
root,
path,
base,
result,
pool));
}
svn_error_t *
svn_fs_apply_text(svn_stream_t **contents_p, svn_fs_root_t *root,
const char *path, const char *result_checksum,
apr_pool_t *pool)
{
svn_checksum_t *result;
SVN_ERR(svn_checksum_parse_hex(&result, svn_checksum_md5, result_checksum,
pool));
return svn_error_trace(root->vtable->apply_text(contents_p, root, path,
result, pool));
}
svn_error_t *
svn_fs_contents_different(svn_boolean_t *changed_p, svn_fs_root_t *root1,
const char *path1, svn_fs_root_t *root2,
const char *path2, apr_pool_t *scratch_pool)
{
return svn_error_trace(root1->vtable->contents_changed(changed_p,
root1, path1,
root2, path2,
TRUE,
scratch_pool));
}
svn_error_t *
svn_fs_contents_changed(svn_boolean_t *changed_p, svn_fs_root_t *root1,
const char *path1, svn_fs_root_t *root2,
const char *path2, apr_pool_t *pool)
{
return svn_error_trace(root1->vtable->contents_changed(changed_p,
root1, path1,
root2, path2,
FALSE, pool));
}
svn_error_t *
svn_fs_youngest_rev(svn_revnum_t *youngest_p, svn_fs_t *fs, apr_pool_t *pool)
{
return svn_error_trace(fs->vtable->youngest_rev(youngest_p, fs, pool));
}
svn_error_t *
svn_fs_info_format(int *fs_format,
svn_version_t **supports_version,
svn_fs_t *fs,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
return svn_error_trace(fs->vtable->info_format(fs_format, supports_version,
fs,
result_pool, scratch_pool));
}
svn_error_t *
svn_fs_info_config_files(apr_array_header_t **files,
svn_fs_t *fs,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
return svn_error_trace(fs->vtable->info_config_files(files, fs,
result_pool,
scratch_pool));
}
svn_error_t *
svn_fs_deltify_revision(svn_fs_t *fs, svn_revnum_t revision, apr_pool_t *pool)
{
return svn_error_trace(fs->vtable->deltify(fs, revision, pool));
}
svn_error_t *
svn_fs_revision_prop(svn_string_t **value_p, svn_fs_t *fs, svn_revnum_t rev,
const char *propname, apr_pool_t *pool)
{
return svn_error_trace(fs->vtable->revision_prop(value_p, fs, rev,
propname, pool));
}
svn_error_t *
svn_fs_revision_proplist(apr_hash_t **table_p, svn_fs_t *fs, svn_revnum_t rev,
apr_pool_t *pool)
{
return svn_error_trace(fs->vtable->revision_proplist(table_p, fs, rev,
pool));
}
svn_error_t *
svn_fs_change_rev_prop2(svn_fs_t *fs, svn_revnum_t rev, const char *name,
const svn_string_t *const *old_value_p,
const svn_string_t *value, apr_pool_t *pool)
{
return svn_error_trace(fs->vtable->change_rev_prop(fs, rev, name,
old_value_p,
value, pool));
}
svn_error_t *
svn_fs_get_file_delta_stream(svn_txdelta_stream_t **stream_p,
svn_fs_root_t *source_root,
const char *source_path,
svn_fs_root_t *target_root,
const char *target_path, apr_pool_t *pool)
{
return svn_error_trace(target_root->vtable->get_file_delta_stream(
stream_p,
source_root, source_path,
target_root, target_path, pool));
}
svn_error_t *
svn_fs_get_uuid(svn_fs_t *fs, const char **uuid, apr_pool_t *pool)
{
*uuid = apr_pstrdup(pool, fs->uuid);
return SVN_NO_ERROR;
}
svn_error_t *
svn_fs_set_uuid(svn_fs_t *fs, const char *uuid, apr_pool_t *pool)
{
if (! uuid)
{
uuid = svn_uuid_generate(pool);
}
else
{
apr_uuid_t parsed_uuid;
apr_status_t apr_err = apr_uuid_parse(&parsed_uuid, uuid);
if (apr_err)
return svn_error_createf(SVN_ERR_BAD_UUID, NULL,
_("Malformed UUID '%s'"), uuid);
}
return svn_error_trace(fs->vtable->set_uuid(fs, uuid, pool));
}
svn_error_t *
svn_fs_lock_many(svn_fs_t *fs,
apr_hash_t *targets,
const char *comment,
svn_boolean_t is_dav_comment,
apr_time_t expiration_date,
svn_boolean_t steal_lock,
svn_fs_lock_callback_t lock_callback,
void *lock_baton,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
apr_hash_index_t *hi;
apr_hash_t *ok_targets = apr_hash_make(scratch_pool);
svn_error_t *err, *cb_err = SVN_NO_ERROR;
if (comment)
if (! svn_xml_is_xml_safe(comment, strlen(comment)))
return svn_error_create(SVN_ERR_XML_UNESCAPABLE_DATA, NULL,
_("Lock comment contains illegal characters"));
if (expiration_date < 0)
return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
_("Negative expiration date passed to svn_fs_lock"));
for (hi = apr_hash_first(scratch_pool, targets); hi; hi = apr_hash_next(hi))
{
const svn_fs_lock_target_t *target = apr_hash_this_val(hi);
err = SVN_NO_ERROR;
if (target->token)
{
const char *c;
if (strncmp(target->token, "opaquelocktoken:", 16))
err = svn_error_createf(SVN_ERR_FS_BAD_LOCK_TOKEN, NULL,
_("Lock token URI '%s' has bad scheme; "
"expected '%s'"),
target->token, "opaquelocktoken");
if (!err)
for (c = target->token; *c && !err; c++)
if (! svn_ctype_isascii(*c) || svn_ctype_iscntrl(*c))
err = svn_error_createf(
SVN_ERR_FS_BAD_LOCK_TOKEN, NULL,
_("Lock token '%s' is not ASCII or is a "
"control character at byte %u"),
target->token,
(unsigned)(c - target->token));
if (!err && !svn_xml_is_xml_safe(target->token, c - target->token))
err = svn_error_createf(SVN_ERR_FS_BAD_LOCK_TOKEN, NULL,
_("Lock token URI '%s' is not XML-safe"),
target->token);
}
if (err)
{
if (!cb_err && lock_callback)
cb_err = lock_callback(lock_baton, apr_hash_this_key(hi),
NULL, err, scratch_pool);
svn_error_clear(err);
}
else
svn_hash_sets(ok_targets, apr_hash_this_key(hi), target);
}
if (!apr_hash_count(ok_targets))
return svn_error_trace(cb_err);
err = fs->vtable->lock(fs, ok_targets, comment, is_dav_comment,
expiration_date, steal_lock,
lock_callback, lock_baton,
result_pool, scratch_pool);
if (err && cb_err)
svn_error_compose(err, cb_err);
else if (!err)
err = cb_err;
return svn_error_trace(err);
}
struct lock_baton_t {
const svn_lock_t *lock;
svn_error_t *fs_err;
};
static svn_error_t *
lock_cb(void *lock_baton,
const char *path,
const svn_lock_t *lock,
svn_error_t *fs_err,
apr_pool_t *pool)
{
struct lock_baton_t *b = lock_baton;
b->lock = lock;
b->fs_err = svn_error_dup(fs_err);
return SVN_NO_ERROR;
}
svn_error_t *
svn_fs_lock(svn_lock_t **lock, svn_fs_t *fs, const char *path,
const char *token, const char *comment,
svn_boolean_t is_dav_comment, apr_time_t expiration_date,
svn_revnum_t current_rev, svn_boolean_t steal_lock,
apr_pool_t *pool)
{
apr_hash_t *targets = apr_hash_make(pool);
svn_fs_lock_target_t target;
svn_error_t *err;
struct lock_baton_t baton = {0};
target.token = token;
target.current_rev = current_rev;
svn_hash_sets(targets, path, &target);
err = svn_fs_lock_many(fs, targets, comment, is_dav_comment,
expiration_date, steal_lock, lock_cb, &baton,
pool, pool);
if (baton.lock)
*lock = (svn_lock_t*)baton.lock;
if (err && baton.fs_err)
svn_error_compose(err, baton.fs_err);
else if (!err)
err = baton.fs_err;
return svn_error_trace(err);
}
svn_error_t *
svn_fs_generate_lock_token(const char **token, svn_fs_t *fs, apr_pool_t *pool)
{
return svn_error_trace(fs->vtable->generate_lock_token(token, fs, pool));
}
svn_fs_lock_target_t *
svn_fs_lock_target_create(const char *token,
svn_revnum_t current_rev,
apr_pool_t *result_pool)
{
svn_fs_lock_target_t *target = apr_palloc(result_pool,
sizeof(svn_fs_lock_target_t));
target->token = token;
target->current_rev = current_rev;
return target;
}
void
svn_fs_lock_target_set_token(svn_fs_lock_target_t *target,
const char *token)
{
target->token = token;
}
svn_error_t *
svn_fs_unlock_many(svn_fs_t *fs,
apr_hash_t *targets,
svn_boolean_t break_lock,
svn_fs_lock_callback_t lock_callback,
void *lock_baton,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
return svn_error_trace(fs->vtable->unlock(fs, targets, break_lock,
lock_callback, lock_baton,
result_pool, scratch_pool));
}
svn_error_t *
svn_fs_unlock(svn_fs_t *fs, const char *path, const char *token,
svn_boolean_t break_lock, apr_pool_t *pool)
{
apr_hash_t *targets = apr_hash_make(pool);
svn_error_t *err;
struct lock_baton_t baton = {0};
if (!token)
token = "";
svn_hash_sets(targets, path, token);
err = svn_fs_unlock_many(fs, targets, break_lock, lock_cb, &baton,
pool, pool);
if (err && baton.fs_err)
svn_error_compose(err, baton.fs_err);
else if (!err)
err = baton.fs_err;
return svn_error_trace(err);
}
svn_error_t *
svn_fs_get_lock(svn_lock_t **lock, svn_fs_t *fs, const char *path,
apr_pool_t *pool)
{
return svn_error_trace(fs->vtable->get_lock(lock, fs, path, pool));
}
svn_error_t *
svn_fs_get_locks2(svn_fs_t *fs, const char *path, svn_depth_t depth,
svn_fs_get_locks_callback_t get_locks_func,
void *get_locks_baton, apr_pool_t *pool)
{
SVN_ERR_ASSERT((depth == svn_depth_empty) ||
(depth == svn_depth_files) ||
(depth == svn_depth_immediates) ||
(depth == svn_depth_infinity));
return svn_error_trace(fs->vtable->get_locks(fs, path, depth,
get_locks_func,
get_locks_baton, pool));
}
svn_error_t *
svn_fs_history_prev2(svn_fs_history_t **prev_history_p,
svn_fs_history_t *history, svn_boolean_t cross_copies,
apr_pool_t *result_pool, apr_pool_t *scratch_pool)
{
return svn_error_trace(history->vtable->prev(prev_history_p, history,
cross_copies, result_pool,
scratch_pool));
}
svn_error_t *
svn_fs_history_prev(svn_fs_history_t **prev_history_p,
svn_fs_history_t *history, svn_boolean_t cross_copies,
apr_pool_t *pool)
{
return svn_error_trace(history->vtable->prev(prev_history_p, history,
cross_copies, pool, pool));
}
svn_error_t *
svn_fs_history_location(const char **path, svn_revnum_t *revision,
svn_fs_history_t *history, apr_pool_t *pool)
{
return svn_error_trace(history->vtable->location(path, revision, history,
pool));
}
svn_fs_id_t *
svn_fs_parse_id(const char *data, apr_size_t len, apr_pool_t *pool)
{
fs_library_vtable_t *vtable;
svn_error_t *err;
err = get_library_vtable(&vtable, SVN_FS_TYPE_BDB, pool);
if (err)
{
svn_error_clear(err);
return NULL;
}
return vtable->parse_id(data, len, pool);
}
svn_string_t *
svn_fs_unparse_id(const svn_fs_id_t *id, apr_pool_t *pool)
{
return id->vtable->unparse(id, pool);
}
svn_boolean_t
svn_fs_check_related(const svn_fs_id_t *a, const svn_fs_id_t *b)
{
return (a->vtable->compare(a, b) != svn_fs_node_unrelated);
}
int
svn_fs_compare_ids(const svn_fs_id_t *a, const svn_fs_id_t *b)
{
switch (a->vtable->compare(a, b))
{
case svn_fs_node_unchanged:
return 0;
case svn_fs_node_common_ancestor:
return 1;
default:
return -1;
}
}
svn_error_t *
svn_fs_print_modules(svn_stringbuf_t *output,
apr_pool_t *pool)
{
struct fs_type_defn *defn = fs_modules;
fs_library_vtable_t *vtable;
apr_pool_t *iterpool = svn_pool_create(pool);
while (defn)
{
char *line;
svn_error_t *err;
svn_pool_clear(iterpool);
err = get_library_vtable_direct(&vtable, defn, iterpool);
if (err)
{
if (err->apr_err == SVN_ERR_FS_UNKNOWN_FS_TYPE)
{
svn_error_clear(err);
defn = defn->next;
continue;
}
else
return err;
}
line = apr_psprintf(iterpool, "* fs_%s : %s\n",
defn->fsap_name, vtable->get_description());
svn_stringbuf_appendcstr(output, line);
defn = defn->next;
}
svn_pool_destroy(iterpool);
return SVN_NO_ERROR;
}
svn_fs_path_change2_t *
svn_fs_path_change2_create(const svn_fs_id_t *node_rev_id,
svn_fs_path_change_kind_t change_kind,
apr_pool_t *pool)
{
return svn_fs__path_change_create_internal(node_rev_id, change_kind, pool);
}
const svn_version_t *
svn_fs_version(void)
{
SVN_VERSION_BODY;
}
svn_error_t *
svn_fs_info(const svn_fs_info_placeholder_t **info_p,
svn_fs_t *fs,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
if (fs->vtable->info_fsap)
{
SVN_ERR(fs->vtable->info_fsap((const void **)info_p, fs,
result_pool, scratch_pool));
}
else
{
svn_fs_info_placeholder_t *info = apr_palloc(result_pool, sizeof(*info));
SVN_ERR(svn_fs_type(&info->fs_type, fs->path, result_pool));
*info_p = info;
}
return SVN_NO_ERROR;
}
void *
svn_fs_info_dup(const void *info_void,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
const svn_fs_info_placeholder_t *info = info_void;
fs_library_vtable_t *vtable;
SVN_ERR(get_library_vtable(&vtable, info->fs_type, scratch_pool));
if (vtable->info_fsap_dup)
return vtable->info_fsap_dup(info_void, result_pool);
else
return apr_pmemdup(result_pool, info, sizeof(*info));
}