summaryrefslogtreecommitdiff
path: root/subversion/libsvn_fs
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-08-05 16:22:51 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-08-05 16:22:51 +0000
commitcf46733632c7279a9fd0fe6ce26f9185a4ae82a9 (patch)
treeda27775a2161723ef342e91af41a8b51fedef405 /subversion/libsvn_fs
parentbb0ef45f7c46b0ae221b26265ef98a768c33f820 (diff)
downloadsubversion-tarball-master.tar.gz
Diffstat (limited to 'subversion/libsvn_fs')
-rw-r--r--subversion/libsvn_fs/access.c7
-rw-r--r--subversion/libsvn_fs/deprecated.c90
-rw-r--r--subversion/libsvn_fs/editor.c60
-rw-r--r--subversion/libsvn_fs/fs-loader.c735
-rw-r--r--subversion/libsvn_fs/fs-loader.h136
-rw-r--r--subversion/libsvn_fs/libsvn_fs.pc.in12
6 files changed, 797 insertions, 243 deletions
diff --git a/subversion/libsvn_fs/access.c b/subversion/libsvn_fs/access.c
index 9918be4..2b1901f 100644
--- a/subversion/libsvn_fs/access.c
+++ b/subversion/libsvn_fs/access.c
@@ -91,13 +91,6 @@ svn_fs_access_add_lock_token2(svn_fs_access_t *access_ctx,
return SVN_NO_ERROR;
}
-svn_error_t *
-svn_fs_access_add_lock_token(svn_fs_access_t *access_ctx,
- const char *token)
-{
- return svn_fs_access_add_lock_token2(access_ctx, (const char *) 1, token);
-}
-
apr_hash_t *
svn_fs__access_get_lock_tokens(svn_fs_access_t *access_ctx)
{
diff --git a/subversion/libsvn_fs/deprecated.c b/subversion/libsvn_fs/deprecated.c
new file mode 100644
index 0000000..0304577
--- /dev/null
+++ b/subversion/libsvn_fs/deprecated.c
@@ -0,0 +1,90 @@
+/*
+ * deprecated.c: holding file for all deprecated APIs.
+ * "we can't lose 'em, but we can shun 'em!"
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ */
+
+/* We define this here to remove any further warnings about the usage of
+ deprecated functions in this file. */
+#define SVN_DEPRECATED
+
+#include "svn_fs.h"
+
+
+/*** From fs-loader.c ***/
+svn_error_t *
+svn_fs_upgrade(const char *path, apr_pool_t *pool)
+{
+ return svn_error_trace(svn_fs_upgrade2(path, NULL, NULL, NULL, NULL, pool));
+}
+
+svn_error_t *
+svn_fs_hotcopy2(const char *src_path, const char *dest_path,
+ svn_boolean_t clean, svn_boolean_t incremental,
+ svn_cancel_func_t cancel_func, void *cancel_baton,
+ apr_pool_t *scratch_pool)
+{
+ return svn_error_trace(svn_fs_hotcopy3(src_path, dest_path, clean,
+ incremental, NULL, NULL,
+ cancel_func, cancel_baton,
+ scratch_pool));
+}
+
+svn_error_t *
+svn_fs_hotcopy(const char *src_path, const char *dest_path,
+ svn_boolean_t clean, apr_pool_t *pool)
+{
+ return svn_error_trace(svn_fs_hotcopy2(src_path, dest_path, clean,
+ FALSE, NULL, NULL, 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 svn_error_trace(svn_fs_begin_txn2(txn_p, fs, rev, 0, pool));
+}
+
+svn_error_t *
+svn_fs_change_rev_prop(svn_fs_t *fs, svn_revnum_t rev, const char *name,
+ const svn_string_t *value, apr_pool_t *pool)
+{
+ return svn_error_trace(
+ svn_fs_change_rev_prop2(fs, rev, name, NULL, value, pool));
+}
+
+svn_error_t *
+svn_fs_get_locks(svn_fs_t *fs, const char *path,
+ svn_fs_get_locks_callback_t get_locks_func,
+ void *get_locks_baton, apr_pool_t *pool)
+{
+ return svn_error_trace(svn_fs_get_locks2(fs, path, svn_depth_infinity,
+ get_locks_func, get_locks_baton,
+ pool));
+}
+
+/*** From access.c ***/
+svn_error_t *
+svn_fs_access_add_lock_token(svn_fs_access_t *access_ctx,
+ const char *token)
+{
+ return svn_fs_access_add_lock_token2(access_ctx, (const char *) 1, token);
+}
diff --git a/subversion/libsvn_fs/editor.c b/subversion/libsvn_fs/editor.c
index a75f210..b4cd3bc 100644
--- a/subversion/libsvn_fs/editor.c
+++ b/subversion/libsvn_fs/editor.c
@@ -62,9 +62,7 @@ struct edit_baton {
svn_fs_root_t *root;
};
-#define FSPATH(relpath, pool) apr_pstrcat(pool, "/", relpath, NULL)
-#define UNUSED(x) ((void)(x))
-
+#define FSPATH(relpath, pool) apr_pstrcat(pool, "/", relpath, SVN_VA_NULL)
static svn_error_t *
get_root(svn_fs_root_t **root,
@@ -94,8 +92,8 @@ add_new_props(svn_fs_root_t *root,
for (hi = apr_hash_first(scratch_pool, props); hi;
hi = apr_hash_next(hi))
{
- const char *name = svn__apr_hash_index_key(hi);
- const svn_string_t *value = svn__apr_hash_index_val(hi);
+ const char *name = apr_hash_this_key(hi);
+ const svn_string_t *value = apr_hash_this_val(hi);
svn_pool_clear(iterpool);
@@ -177,7 +175,7 @@ can_modify(svn_fs_root_t *txn_root,
SVN_ERR(svn_fs_node_created_rev(&created_rev, txn_root, fspath,
scratch_pool));
- /* Uncommitted nodes (eg. a descendent of a copy/move/rotate destination)
+ /* Uncommitted nodes (eg. a descendant of a copy/move destination)
have no (committed) revision number. Let the caller go ahead and
modify these nodes.
@@ -195,7 +193,7 @@ can_modify(svn_fs_root_t *txn_root,
have supplied a valid revision number [that they expect to change].
The checks further below will determine the out-of-dateness of the
specified revision. */
- /* ### ugh. descendents of copy/move/rotate destinations carry along
+ /* ### ugh. descendants of copy/move destinations carry along
### their original immutable state and (thus) a valid CREATED_REV.
### but they are logically uncommitted, so the caller will pass
### SVN_INVALID_REVNUM. (technically, the caller could provide
@@ -203,9 +201,9 @@ can_modify(svn_fs_root_t *txn_root,
### API).
###
### for now, we will assume the caller knows what they are doing
- ### and an invalid revision implies such a descendent. in the
+ ### and an invalid revision implies such a descendant. in the
### future, we could examine the ancestor chain looking for a
- ### copy/move/rotate-here node and allow the modification (and the
+ ### copy/move-here node and allow the modification (and the
### converse: if no such ancestor, the caller must specify the
### correct/intended revision to modify).
*/
@@ -240,23 +238,18 @@ can_modify(svn_fs_root_t *txn_root,
of those new revisions.
In either case, the node may not have changed in those new
revisions; use the node's ID to determine this case. */
- const svn_fs_id_t *txn_noderev_id;
svn_fs_root_t *rev_root;
- const svn_fs_id_t *new_noderev_id;
-
- /* The ID of the node that we would be modifying in the txn */
- SVN_ERR(svn_fs_node_id(&txn_noderev_id, txn_root, fspath,
- scratch_pool));
+ svn_fs_node_relation_t relation;
/* Get the ID from the future/new revision. */
SVN_ERR(svn_fs_revision_root(&rev_root, svn_fs_root_fs(txn_root),
revision, scratch_pool));
- SVN_ERR(svn_fs_node_id(&new_noderev_id, rev_root, fspath,
- scratch_pool));
+ SVN_ERR(svn_fs_node_relation(&relation, txn_root, fspath, rev_root,
+ fspath, scratch_pool));
svn_fs_close_root(rev_root);
/* Has the target node changed in the future? */
- if (svn_fs_compare_ids(txn_noderev_id, new_noderev_id) != 0)
+ if (relation != svn_fs_node_unchanged)
{
/* Restarting the commit will base the txn on the future/new
revision, allowing the modification at REVISION. */
@@ -299,7 +292,7 @@ can_create(svn_fs_root_t *txn_root,
### test the ancestor to determine if it has been *-here in this
### txn, or just a simple modification. */
- /* Are any of the parents copied/moved/rotated-here? */
+ /* Are any of the parents copied/moved-here? */
for (cur_fspath = fspath;
strlen(cur_fspath) > 1; /* not the root */
cur_fspath = svn_fspath__dirname(cur_fspath, scratch_pool))
@@ -488,9 +481,9 @@ static svn_error_t *
alter_file_cb(void *baton,
const char *relpath,
svn_revnum_t revision,
- apr_hash_t *props,
const svn_checksum_t *checksum,
svn_stream_t *contents,
+ apr_hash_t *props,
apr_pool_t *scratch_pool)
{
struct edit_baton *eb = baton;
@@ -521,13 +514,14 @@ static svn_error_t *
alter_symlink_cb(void *baton,
const char *relpath,
svn_revnum_t revision,
- apr_hash_t *props,
const char *target,
+ apr_hash_t *props,
apr_pool_t *scratch_pool)
{
struct edit_baton *eb = baton;
- UNUSED(eb); SVN__NOT_IMPLEMENTED();
+ SVN_UNUSED(eb);
+ SVN__NOT_IMPLEMENTED();
}
@@ -633,19 +627,6 @@ move_cb(void *baton,
}
-/* This implements svn_editor_cb_rotate_t */
-static svn_error_t *
-rotate_cb(void *baton,
- const apr_array_header_t *relpaths,
- const apr_array_header_t *revisions,
- apr_pool_t *scratch_pool)
-{
- struct edit_baton *eb = baton;
-
- UNUSED(eb); SVN__NOT_IMPLEMENTED();
-}
-
-
/* This implements svn_editor_cb_complete_t */
static svn_error_t *
complete_cb(void *baton,
@@ -714,7 +695,6 @@ make_editor(svn_editor_t **editor,
delete_cb,
copy_cb,
move_cb,
- rotate_cb,
complete_cb,
abort_cb
};
@@ -804,9 +784,9 @@ svn_fs__editor_commit(svn_revnum_t *revision,
if (!err)
err = svn_fs_commit_txn(&inner_conflict_path,
- revision,
- eb->txn,
- scratch_pool);
+ revision,
+ eb->txn,
+ scratch_pool);
if (SVN_IS_VALID_REVNUM(*revision))
{
if (err)
@@ -829,7 +809,7 @@ svn_fs__editor_commit(svn_revnum_t *revision,
/* Copy this into the correct pool (see note above). */
*conflict_path = apr_pstrdup(result_pool, inner_conflict_path);
- /* Return sucess. The caller should inspect CONFLICT_PATH to
+ /* Return success. The caller should inspect CONFLICT_PATH to
determine this particular case. */
svn_error_clear(err);
err = SVN_NO_ERROR;
diff --git a/subversion/libsvn_fs/fs-loader.c b/subversion/libsvn_fs/fs-loader.c
index 336b84f..ba90554 100644
--- a/subversion/libsvn_fs/fs-loader.c
+++ b/subversion/libsvn_fs/fs-loader.c
@@ -24,12 +24,14 @@
#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"
@@ -40,8 +42,9 @@
#include "svn_xml.h"
#include "svn_pools.h"
#include "svn_string.h"
-#include "svn_private_config.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"
@@ -60,8 +63,9 @@
/* A pool common to all FS objects. See the documentation on the
open/create functions in fs-loader.h and for svn_fs_initialize(). */
-static apr_pool_t *common_pool;
-svn_mutex__t *common_pool_lock;
+static apr_pool_t *common_pool = NULL;
+static svn_mutex__t *common_pool_lock = NULL;
+static svn_atomic_t common_pool_initialized = FALSE;
/* --- Utility functions for the loader --- */
@@ -70,6 +74,7 @@ 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;
};
@@ -81,10 +86,23 @@ static struct fs_type_defn base_defn =
#else
NULL,
#endif
+ NULL,
NULL /* End of static list: this needs to be reset to NULL if the
common_pool used when setting it has been cleared. */
};
+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",
@@ -93,7 +111,8 @@ static struct fs_type_defn fsfs_defn =
#else
NULL,
#endif
- &base_defn
+ NULL,
+ &fsx_defn
};
static struct fs_type_defn *fs_modules = &fsfs_defn;
@@ -148,13 +167,20 @@ load_module(fs_init_func_t *initfunc, const char *name, apr_pool_t *pool)
/* 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,
+ 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;
+ /* most times, we get lucky */
+ *vtable = apr_atomic_casptr((volatile void **)&fst->vtable, NULL, NULL);
+ if (*vtable)
+ return SVN_NO_ERROR;
+
+ /* o.k. the first access needs to actually load the module, find the
+ vtable and check for version compatibility. */
initfunc = fst->initfunc;
if (! initfunc)
SVN_ERR(load_module(&initfunc, fst->fsap_name, pool));
@@ -172,8 +198,7 @@ get_library_vtable_direct(fs_library_vtable_t **vtable,
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));
+ SVN_ERR(svn_fs_initialize(NULL));
/* Invoke the FS module's initfunc function with the common
pool protected by a lock. */
@@ -191,6 +216,10 @@ get_library_vtable_direct(fs_library_vtable_t **vtable,
my_version->patch, my_version->tag,
fs_version->major, fs_version->minor,
fs_version->patch, fs_version->tag);
+
+ /* the vtable will not change. Remember it */
+ apr_atomic_casptr((volatile void **)&fst->vtable, *vtable, NULL);
+
return SVN_NO_ERROR;
}
@@ -211,31 +240,37 @@ get_or_allocate_third(struct fs_type_defn **fst,
(*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
-/* Fetch a library vtable by FS type. */
+/* Fetch a library *VTABLE by FS_TYPE.
+ Use POOL for temporary allocations. */
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 = &fs_modules;
+ struct fs_type_defn **fst;
svn_boolean_t known = FALSE;
- /* There are two FS module definitions known at compile time. We
+ /* There are three FS module definitions known at compile time. We
want to check these without any locking overhead even when
dynamic third party modules are enabled. The third party modules
cannot be checked until the lock is held. */
- if (strcmp(fs_type, (*fst)->fs_type) == 0)
- known = TRUE;
- else
+ for (fst = &fs_modules; *fst; fst = &(*fst)->next)
{
- fst = &(*fst)->next;
if (strcmp(fs_type, (*fst)->fs_type) == 0)
- known = TRUE;
+ {
+ known = TRUE;
+ break;
+ }
+ else if (!(*fst)->next)
+ {
+ break;
+ }
}
#if defined(SVN_USE_DSO) && APR_HAS_DSO
@@ -254,8 +289,8 @@ get_library_vtable(fs_library_vtable_t **vtable, const char *fs_type,
if (!known)
{
fst = &(*fst)->next;
- if (!common_pool) /* Best-effort init, see get_library_vtable_direct. */
- SVN_ERR(svn_fs_initialize(NULL));
+ /* Best-effort init, see get_library_vtable_direct. */
+ SVN_ERR(svn_fs_initialize(NULL));
SVN_MUTEX__WITH_LOCK(common_pool_lock,
get_or_allocate_third(fst, fs_type));
known = TRUE;
@@ -320,7 +355,9 @@ fs_library_vtable(fs_library_vtable_t **vtable, const char *path,
SVN_ERR(svn_fs_type(&fs_type, path, pool));
/* Fetch the library vtable by name, now that we've chosen one. */
- return svn_error_trace(get_library_vtable(vtable, fs_type, pool));
+ SVN_ERR(get_library_vtable(vtable, fs_type, pool));
+
+ return SVN_NO_ERROR;
}
static svn_error_t *
@@ -345,16 +382,15 @@ write_fs_type(const char *path, const char *fs_type, apr_pool_t *pool)
static apr_status_t uninit(void *data)
{
common_pool = NULL;
+ common_pool_lock = NULL;
+ common_pool_initialized = 0;
+
return APR_SUCCESS;
}
-svn_error_t *
-svn_fs_initialize(apr_pool_t *pool)
+static svn_error_t *
+synchronized_initialize(void *baton, apr_pool_t *pool)
{
- /* Protect against multiple calls. */
- if (common_pool)
- return SVN_NO_ERROR;
-
common_pool = svn_pool_create(pool);
base_defn.next = NULL;
SVN_ERR(svn_mutex__init(&common_pool_lock, TRUE, common_pool));
@@ -369,19 +405,44 @@ svn_fs_initialize(apr_pool_t *pool)
return SVN_NO_ERROR;
}
+svn_error_t *
+svn_fs_initialize(apr_pool_t *pool)
+{
+#if defined(SVN_USE_DSO) && APR_HAS_DSO
+ /* Ensure that DSO subsystem is initialized early as possible if
+ we're going to use it. */
+ SVN_ERR(svn_dso_initialize2());
+#endif
+ /* Protect against multiple calls. */
+ return svn_error_trace(svn_atomic__init_once(&common_pool_initialized,
+ synchronized_initialize,
+ NULL, pool));
+}
+
/* A default warning handling function. */
static void
default_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. */
+ processes, since those may both be equivalent to /dev/null.
+
+ That said, be a good citizen and print something anyway, in case it goes
+ somewhere, and our caller hasn't overridden the abort() call.
+ */
+ if (svn_error_get_malfunction_handler()
+ == svn_error_abort_on_malfunction)
+ /* ### TODO: extend the malfunction API such that non-abort()ing consumers
+ ### also get the information on ERR. */
+ svn_handle_error2(err, stderr, FALSE /* fatal */, "svn: fs-loader: ");
SVN_ERR_MALFUNCTION_NO_RETURN();
}
svn_error_t *
svn_fs__path_valid(const char *path, apr_pool_t *pool)
{
+ char *c;
+
/* UTF-8 encoded string without NULs. */
if (! svn_utf__cstring_is_valid(path))
{
@@ -398,6 +459,18 @@ svn_fs__path_valid(const char *path, apr_pool_t *pool)
path);
}
+ /* Raise an error if PATH contains a newline because svn:mergeinfo and
+ friends can't handle them. Issue #4340 describes a similar problem
+ in the FSFS code itself.
+ */
+ 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));
+ }
+
/* That's good enough. */
return SVN_NO_ERROR;
}
@@ -451,42 +524,66 @@ svn_fs_create(svn_fs_t **fs_p, const char *path, apr_hash_t *fs_config,
/* Perform the actual creation. */
*fs_p = fs_new(fs_config, pool);
- SVN_MUTEX__WITH_LOCK(common_pool_lock,
- vtable->create(*fs_p, path, pool, common_pool));
- SVN_ERR(vtable->set_svn_fs_open(*fs_p, svn_fs_open));
+ 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_open(svn_fs_t **fs_p, const char *path, apr_hash_t *fs_config,
- apr_pool_t *pool)
+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, pool));
- *fs_p = fs_new(fs_config, pool);
- SVN_MUTEX__WITH_LOCK(common_pool_lock,
- vtable->open_fs(*fs_p, path, pool, common_pool));
- SVN_ERR(vtable->set_svn_fs_open(*fs_p, svn_fs_open));
+ 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_upgrade(const char *path, apr_pool_t *pool)
+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, pool));
- fs = fs_new(NULL, pool);
+ SVN_ERR(fs_library_vtable(&vtable, path, scratch_pool));
+ fs = fs_new(NULL, scratch_pool);
- SVN_MUTEX__WITH_LOCK(common_pool_lock,
- vtable->upgrade_fs(fs, path, pool, common_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;
}
+/* A warning handling function that does not abort on errors,
+ but just lets them be returned normally. */
+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,
@@ -503,12 +600,13 @@ svn_fs_verify(const char *path,
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_MUTEX__WITH_LOCK(common_pool_lock,
- vtable->verify_fs(fs, path, start, end,
- notify_func, notify_baton,
- cancel_func, cancel_baton,
- pool, common_pool));
+ 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;
}
@@ -537,9 +635,12 @@ svn_fs_delete_fs(const char *path, apr_pool_t *pool)
}
svn_error_t *
-svn_fs_hotcopy2(const char *src_path, const char *dst_path,
+svn_fs_hotcopy3(const char *src_path, const char *dst_path,
svn_boolean_t clean, svn_boolean_t incremental,
- svn_cancel_func_t cancel_func, void *cancel_baton,
+ 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;
@@ -592,20 +693,13 @@ svn_fs_hotcopy2(const char *src_path, const char *dst_path,
}
SVN_ERR(vtable->hotcopy(src_fs, dst_fs, src_path, dst_path, clean,
- incremental, cancel_func, cancel_baton,
- scratch_pool));
+ 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_hotcopy(const char *src_path, const char *dest_path,
- svn_boolean_t clean, apr_pool_t *pool)
-{
- return svn_error_trace(svn_fs_hotcopy2(src_path, dest_path, clean,
- FALSE, NULL, NULL, pool));
-}
-
-svn_error_t *
svn_fs_pack(const char *path,
svn_fs_pack_notify_t notify_func,
void *notify_baton,
@@ -619,10 +713,9 @@ svn_fs_pack(const char *path,
SVN_ERR(fs_library_vtable(&vtable, path, pool));
fs = fs_new(NULL, pool);
- SVN_MUTEX__WITH_LOCK(common_pool_lock,
- vtable->pack_fs(fs, path, notify_func, notify_baton,
- cancel_func, cancel_baton, pool,
- common_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;
}
@@ -637,9 +730,8 @@ svn_fs_recover(const char *path,
SVN_ERR(fs_library_vtable(&vtable, path, pool));
fs = fs_new(NULL, pool);
- SVN_MUTEX__WITH_LOCK(common_pool_lock,
- vtable->open_fs_for_recovery(fs, path, pool,
- common_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));
}
@@ -680,9 +772,8 @@ svn_fs_create_berkeley(svn_fs_t *fs, const char *path)
SVN_ERR(write_fs_type(path, SVN_FS_TYPE_BDB, fs->pool));
/* Perform the actual creation. */
- SVN_MUTEX__WITH_LOCK(common_pool_lock,
- vtable->create(fs, path, fs->pool, common_pool));
- SVN_ERR(vtable->set_svn_fs_open(fs, svn_fs_open));
+ 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;
}
@@ -693,9 +784,8 @@ 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_MUTEX__WITH_LOCK(common_pool_lock,
- vtable->open_fs(fs, path, fs->pool, common_pool));
- SVN_ERR(vtable->set_svn_fs_open(fs, svn_fs_open));
+ 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;
}
@@ -716,8 +806,9 @@ 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_hotcopy2(src_path, dest_path, clean_logs,
- FALSE, NULL, NULL, pool));
+ return svn_error_trace(svn_fs_hotcopy3(src_path, dest_path, clean_logs,
+ FALSE, NULL, NULL, NULL, NULL,
+ pool));
}
svn_error_t *
@@ -758,16 +849,8 @@ svn_fs_begin_txn2(svn_fs_txn_t **txn_p, svn_fs_t *fs, svn_revnum_t rev,
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 svn_error_trace(svn_fs_begin_txn2(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)
+ svn_fs_txn_t *txn, apr_pool_t *pool)
{
svn_error_t *err;
@@ -791,24 +874,9 @@ svn_fs_commit_txn(const char **conflict_p, svn_revnum_t *new_rev,
SVN_ERR(err);
-#ifdef PACK_AFTER_EVERY_COMMIT
- {
- svn_fs_t *fs = txn->fs;
- const char *fs_path = svn_fs_path(fs, pool);
- err = svn_fs_pack(fs_path, NULL, NULL, NULL, NULL, pool);
- if (err && err->apr_err == SVN_ERR_UNSUPPORTED_FEATURE)
- /* Pre-1.6 filesystem. */
- svn_error_clear(err);
- else if (err)
- /* Real error. */
- return svn_error_trace(err);
- }
-#endif
-
return SVN_NO_ERROR;
}
-
svn_error_t *
svn_fs_abort_txn(svn_fs_txn_t *txn, apr_pool_t *pool)
{
@@ -848,23 +916,49 @@ svn_fs_list_transactions(apr_array_header_t **names_p, svn_fs_t *fs,
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)
{
- return svn_error_trace(txn->vtable->get_proplist(table_p, txn, pool));
+ SVN_ERR(txn->vtable->get_proplist(table_p, txn, pool));
+
+ /* Don't give away internal transaction properties. */
+ 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));
}
@@ -872,6 +966,18 @@ 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));
}
@@ -940,7 +1046,8 @@ svn_fs_revision_root_revision(svn_fs_root_t *root)
}
svn_error_t *
-svn_fs_paths_changed2(apr_hash_t **changed_paths_p, svn_fs_root_t *root,
+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);
@@ -984,11 +1091,21 @@ svn_fs_check_path(svn_node_kind_t *kind_p, svn_fs_root_t *root,
}
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, pool));
}
svn_error_t *
@@ -1021,6 +1138,25 @@ svn_fs_node_id(const svn_fs_id_t **id_p, svn_fs_root_t *root,
}
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)
+{
+ /* Different repository types? */
+ 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)
{
@@ -1061,6 +1197,16 @@ svn_fs_node_proplist(apr_hash_t **table_p, svn_fs_root_t *root,
}
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)
@@ -1070,6 +1216,17 @@ svn_fs_change_node_prop(svn_fs_root_t *root, const char *path,
}
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)
@@ -1077,7 +1234,7 @@ svn_fs_props_changed(svn_boolean_t *changed_p, svn_fs_root_t *root1,
return svn_error_trace(root1->vtable->props_changed(changed_p,
root1, path1,
root2, path2,
- pool));
+ FALSE, pool));
}
svn_error_t *
@@ -1126,6 +1283,30 @@ svn_fs_get_mergeinfo(svn_mergeinfo_catalog_t *catalog,
}
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 /*include_descendants*/,
+ 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,
@@ -1147,6 +1328,19 @@ svn_fs_dir_entries(apr_hash_t **entries_p, svn_fs_root_t *root,
}
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));
@@ -1302,6 +1496,18 @@ svn_fs_apply_text(svn_stream_t **contents_p, svn_fs_root_t *root,
}
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)
@@ -1309,7 +1515,7 @@ svn_fs_contents_changed(svn_boolean_t *changed_p, svn_fs_root_t *root1,
return svn_error_trace(root1->vtable->contents_changed(changed_p,
root1, path1,
root2, path2,
- pool));
+ FALSE, pool));
}
svn_error_t *
@@ -1319,6 +1525,29 @@ svn_fs_youngest_rev(svn_revnum_t *youngest_p, svn_fs_t *fs, apr_pool_t *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));
@@ -1351,14 +1580,6 @@ svn_fs_change_rev_prop2(svn_fs_t *fs, svn_revnum_t rev, const char *name,
}
svn_error_t *
-svn_fs_change_rev_prop(svn_fs_t *fs, svn_revnum_t rev, const char *name,
- const svn_string_t *value, apr_pool_t *pool)
-{
- return svn_error_trace(
- svn_fs_change_rev_prop2(fs, rev, name, NULL, 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,
@@ -1398,54 +1619,144 @@ svn_fs_set_uuid(svn_fs_t *fs, const char *uuid, apr_pool_t *pool)
}
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)
+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;
+
/* Enforce that the comment be xml-escapable. */
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 (! 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"));
/* Enforce that the token be an XML-safe URI. */
- if (token)
+ for (hi = apr_hash_first(scratch_pool, targets); hi; hi = apr_hash_next(hi))
{
- const char *c;
-
- if (strncmp(token, "opaquelocktoken:", 16))
- return svn_error_createf(SVN_ERR_FS_BAD_LOCK_TOKEN, NULL,
- _("Lock token URI '%s' has bad scheme; "
- "expected '%s'"),
- token, "opaquelocktoken");
-
- for (c = token; *c; c++)
- if (! svn_ctype_isascii(*c))
- return svn_error_createf(SVN_ERR_FS_BAD_LOCK_TOKEN, NULL,
- _("Lock token '%s' is not ASCII "
- "at byte %u"),
- token, (unsigned)(c - token));
-
- /* strlen(token) == c - token. */
- if (! svn_xml_is_xml_safe(token, c - token))
- return svn_error_createf(SVN_ERR_FS_BAD_LOCK_TOKEN, NULL,
- _("Lock token URI '%s' is not XML-safe"),
- token);
+ 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));
+
+ /* strlen(token) == c - 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 (expiration_date < 0)
- return svn_error_create
- (SVN_ERR_INCORRECT_PARAMS, NULL,
- _("Negative expiration date passed to svn_fs_lock"));
+ 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;
+};
+
+/* Implements svn_fs_lock_callback_t. Used by svn_fs_lock and
+ svn_fs_unlock to record the lock and error from svn_fs_lock_many
+ and svn_fs_unlock_many. */
+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);
- return svn_error_trace(fs->vtable->lock(lock, fs, path, token, comment,
- is_dav_comment, expiration_date,
- current_rev, steal_lock, pool));
+ 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 *
@@ -1454,12 +1765,62 @@ 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)
{
- return svn_error_trace(fs->vtable->unlock(fs, path, token, break_lock,
- 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 *
@@ -1483,26 +1844,26 @@ svn_fs_get_locks2(svn_fs_t *fs, const char *path, svn_depth_t depth,
get_locks_baton, pool));
}
+
+/* --- History functions --- */
+
svn_error_t *
-svn_fs_get_locks(svn_fs_t *fs, const char *path,
- svn_fs_get_locks_callback_t get_locks_func,
- void *get_locks_baton, apr_pool_t *pool)
+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(svn_fs_get_locks2(fs, path, svn_depth_infinity,
- get_locks_func, get_locks_baton,
- pool));
+ return svn_error_trace(history->vtable->prev(prev_history_p, history,
+ cross_copies, result_pool,
+ scratch_pool));
}
-
-/* --- History functions --- */
-
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));
+ cross_copies, pool, pool));
}
svn_error_t *
@@ -1540,20 +1901,28 @@ svn_fs_unparse_id(const svn_fs_id_t *id, apr_pool_t *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) != -1);
+ 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)
{
- return a->vtable->compare(a, 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)
{
- const struct fs_type_defn *defn = fs_modules;
+ struct fs_type_defn *defn = fs_modules;
fs_library_vtable_t *vtable;
apr_pool_t *iterpool = svn_pool_create(pool);
@@ -1602,3 +1971,43 @@ svn_fs_version(void)
{
SVN_VERSION_BODY;
}
+
+
+/** info **/
+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));
+ /* ### Ask the disk(!), since svn_fs_t doesn't cache the answer. */
+ 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));
+}
+
diff --git a/subversion/libsvn_fs/fs-loader.h b/subversion/libsvn_fs/fs-loader.h
index 532ff05..db83744 100644
--- a/subversion/libsvn_fs/fs-loader.h
+++ b/subversion/libsvn_fs/fs-loader.h
@@ -27,6 +27,8 @@
#include "svn_types.h"
#include "svn_fs.h"
+#include "svn_props.h"
+#include "private/svn_mutex.h"
#ifdef __cplusplus
extern "C" {
@@ -72,20 +74,32 @@ typedef struct fs_library_vtable_t
this statement, now that the minor version has increased. */
const svn_version_t *(*get_version)(void);
- /* The open_fs/create/open_fs_for_recovery/upgrade_fs functions are
- serialized so that they may use the common_pool parameter to
- allocate fs-global objects such as the bdb env cache. */
- svn_error_t *(*create)(svn_fs_t *fs, const char *path, apr_pool_t *pool,
+ /* The open_fs/create/open_fs_for_recovery/upgrade_fs functions must
+ use the common_pool_lock to serialize the access to the common_pool
+ parameter for allocating fs-global objects such as an env cache. */
+ svn_error_t *(*create)(svn_fs_t *fs, const char *path,
+ svn_mutex__t *common_pool_lock,
+ apr_pool_t *pool,
apr_pool_t *common_pool);
- svn_error_t *(*open_fs)(svn_fs_t *fs, const char *path, apr_pool_t *pool,
+ svn_error_t *(*open_fs)(svn_fs_t *fs, const char *path,
+ svn_mutex__t *common_pool_lock,
+ apr_pool_t *pool,
apr_pool_t *common_pool);
/* open_for_recovery() is like open(), but used to fill in an fs pointer
that will be passed to recover(). We assume that the open() method
might not be immediately appropriate for recovery. */
svn_error_t *(*open_fs_for_recovery)(svn_fs_t *fs, const char *path,
+ svn_mutex__t *common_pool_lock,
apr_pool_t *pool,
apr_pool_t *common_pool);
- svn_error_t *(*upgrade_fs)(svn_fs_t *fs, const char *path, apr_pool_t *pool,
+ svn_error_t *(*upgrade_fs)(svn_fs_t *fs,
+ const char *path,
+ svn_fs_upgrade_notify_t notify_func,
+ void *notify_baton,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ svn_mutex__t *common_pool_lock,
+ apr_pool_t *scratch_pool,
apr_pool_t *common_pool);
svn_error_t *(*verify_fs)(svn_fs_t *fs, const char *path,
svn_revnum_t start,
@@ -94,14 +108,23 @@ typedef struct fs_library_vtable_t
void *notify_baton,
svn_cancel_func_t cancel_func,
void *cancel_baton,
+ svn_mutex__t *common_pool_lock,
apr_pool_t *pool,
apr_pool_t *common_pool);
svn_error_t *(*delete_fs)(const char *path, apr_pool_t *pool);
- svn_error_t *(*hotcopy)(svn_fs_t *src_fs, svn_fs_t *dst_fs,
- const char *src_path, const char *dst_path,
- svn_boolean_t clean, svn_boolean_t incremental,
- svn_cancel_func_t cancel_func, void *cancel_baton,
- apr_pool_t *pool);
+ svn_error_t *(*hotcopy)(svn_fs_t *src_fs,
+ svn_fs_t *dst_fs,
+ 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,
+ svn_mutex__t *common_pool_lock,
+ apr_pool_t *pool,
+ apr_pool_t *common_pool);
const char *(*get_description)(void);
svn_error_t *(*recover)(svn_fs_t *fs,
svn_cancel_func_t cancel_func, void *cancel_baton,
@@ -109,6 +132,7 @@ typedef struct fs_library_vtable_t
svn_error_t *(*pack_fs)(svn_fs_t *fs, const char *path,
svn_fs_pack_notify_t notify_func, void *notify_baton,
svn_cancel_func_t cancel_func, void *cancel_baton,
+ svn_mutex__t *common_pool_lock,
apr_pool_t *pool, apr_pool_t *common_pool);
/* Provider-specific functions should go here, even if they could go
@@ -130,8 +154,11 @@ typedef struct fs_library_vtable_t
svn_error_t *(*svn_fs_open_)(svn_fs_t **,
const char *,
apr_hash_t *,
+ apr_pool_t *,
apr_pool_t *));
-
+ /* For svn_fs_info_fsfs_dup(). */
+ void *(*info_fsap_dup)(const void *fsap_info,
+ apr_pool_t *result_pool);
} fs_library_vtable_t;
/* This is the type of symbol an FS module defines to fetch the
@@ -163,6 +190,9 @@ svn_error_t *svn_fs_base__init(const svn_version_t *loader_version,
svn_error_t *svn_fs_fs__init(const svn_version_t *loader_version,
fs_library_vtable_t **vtable,
apr_pool_t* common_pool);
+svn_error_t *svn_fs_x__init(const svn_version_t *loader_version,
+ fs_library_vtable_t **vtable,
+ apr_pool_t* common_pool);
@@ -196,22 +226,38 @@ typedef struct fs_vtable_t
svn_error_t *(*list_transactions)(apr_array_header_t **names_p,
svn_fs_t *fs, apr_pool_t *pool);
svn_error_t *(*deltify)(svn_fs_t *fs, svn_revnum_t rev, apr_pool_t *pool);
- svn_error_t *(*lock)(svn_lock_t **lock, svn_fs_t *fs,
- const char *path, const char *token,
+ svn_error_t *(*lock)(svn_fs_t *fs,
+ apr_hash_t *targets,
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_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);
svn_error_t *(*generate_lock_token)(const char **token, svn_fs_t *fs,
apr_pool_t *pool);
- svn_error_t *(*unlock)(svn_fs_t *fs, const char *path, const char *token,
- svn_boolean_t break_lock, apr_pool_t *pool);
+ svn_error_t *(*unlock)(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);
svn_error_t *(*get_lock)(svn_lock_t **lock, svn_fs_t *fs,
const char *path, apr_pool_t *pool);
svn_error_t *(*get_locks)(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_error_t *(*info_format)(int *fs_format,
+ svn_version_t **supports_version,
+ svn_fs_t *fs,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
+ svn_error_t *(*info_config_files)(apr_array_header_t **files,
+ svn_fs_t *fs,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
+ svn_error_t *(*info_fsap)(const void **fsap_info,
+ svn_fs_t *fs,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
+ /* info_fsap_dup is in the library vtable. */
svn_error_t *(*verify_root)(svn_fs_root_t *root,
apr_pool_t *pool);
svn_error_t *(*freeze)(svn_fs_t *fs,
@@ -261,9 +307,14 @@ typedef struct root_vtable_t
const char *path, apr_pool_t *pool);
svn_error_t *(*node_history)(svn_fs_history_t **history_p,
svn_fs_root_t *root, const char *path,
- apr_pool_t *pool);
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
svn_error_t *(*node_id)(const svn_fs_id_t **id_p, svn_fs_root_t *root,
const char *path, apr_pool_t *pool);
+ svn_error_t *(*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);
svn_error_t *(*node_created_rev)(svn_revnum_t *revision,
svn_fs_root_t *root, const char *path,
apr_pool_t *pool);
@@ -275,6 +326,13 @@ typedef struct root_vtable_t
apr_pool_t *pool);
svn_error_t *(*delete_node)(svn_fs_root_t *root, const char *path,
apr_pool_t *pool);
+ svn_error_t *(*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_error_t *(*revision_link)(svn_fs_root_t *from_root,
+ svn_fs_root_t *to_root,
+ const char *path,
+ apr_pool_t *pool);
svn_error_t *(*copied_from)(svn_revnum_t *rev_p, const char **path_p,
svn_fs_root_t *root, const char *path,
apr_pool_t *pool);
@@ -288,26 +346,27 @@ typedef struct root_vtable_t
apr_pool_t *pool);
svn_error_t *(*node_proplist)(apr_hash_t **table_p, svn_fs_root_t *root,
const char *path, apr_pool_t *pool);
+ svn_error_t *(*node_has_props)(svn_boolean_t *has_props, svn_fs_root_t *root,
+ const char *path, apr_pool_t *scratch_pool);
svn_error_t *(*change_node_prop)(svn_fs_root_t *root, const char *path,
const char *name,
const svn_string_t *value,
apr_pool_t *pool);
svn_error_t *(*props_changed)(int *changed_p, svn_fs_root_t *root1,
const char *path1, svn_fs_root_t *root2,
- const char *path2, apr_pool_t *pool);
+ const char *path2, svn_boolean_t strict,
+ apr_pool_t *scratch_pool);
/* Directories */
svn_error_t *(*dir_entries)(apr_hash_t **entries_p, svn_fs_root_t *root,
const char *path, apr_pool_t *pool);
+ svn_error_t *(*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);
svn_error_t *(*make_dir)(svn_fs_root_t *root, const char *path,
apr_pool_t *pool);
- svn_error_t *(*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_error_t *(*revision_link)(svn_fs_root_t *from_root,
- svn_fs_root_t *to_root,
- const char *path,
- apr_pool_t *pool);
/* Files */
svn_error_t *(*file_length)(svn_filesize_t *length_p, svn_fs_root_t *root,
@@ -337,7 +396,8 @@ typedef struct root_vtable_t
apr_pool_t *pool);
svn_error_t *(*contents_changed)(int *changed_p, svn_fs_root_t *root1,
const char *path1, svn_fs_root_t *root2,
- const char *path2, apr_pool_t *pool);
+ const char *path2, svn_boolean_t strict,
+ apr_pool_t *scratch_pool);
svn_error_t *(*get_file_delta_stream)(svn_txdelta_stream_t **stream_p,
svn_fs_root_t *source_root,
const char *source_path,
@@ -370,7 +430,7 @@ typedef struct history_vtable_t
{
svn_error_t *(*prev)(svn_fs_history_t **prev_history_p,
svn_fs_history_t *history, svn_boolean_t cross_copies,
- apr_pool_t *pool);
+ apr_pool_t *result_pool, apr_pool_t *scratch_pool);
svn_error_t *(*location)(const char **path, svn_revnum_t *revision,
svn_fs_history_t *history, apr_pool_t *pool);
} history_vtable_t;
@@ -378,8 +438,10 @@ typedef struct history_vtable_t
typedef struct id_vtable_t
{
- svn_string_t *(*unparse)(const svn_fs_id_t *id, apr_pool_t *pool);
- int (*compare)(const svn_fs_id_t *a, const svn_fs_id_t *b);
+ svn_string_t *(*unparse)(const svn_fs_id_t *id,
+ apr_pool_t *pool);
+ svn_fs_node_relation_t (*compare)(const svn_fs_id_t *a,
+ const svn_fs_id_t *b);
} id_vtable_t;
@@ -390,6 +452,8 @@ typedef struct id_vtable_t
in the 'flags' argument to svn_fs_lock(). */
#define SVN_FS__PROP_TXN_CHECK_LOCKS SVN_PROP_PREFIX "check-locks"
#define SVN_FS__PROP_TXN_CHECK_OOD SVN_PROP_PREFIX "check-ood"
+/* Set to "0" at the start of the txn, to "1" when svn:date changes. */
+#define SVN_FS__PROP_TXN_CLIENT_DATE SVN_PROP_PREFIX "client-date"
struct svn_fs_t
{
@@ -487,12 +551,18 @@ struct svn_fs_access_t
const char *username;
/* A collection of lock-tokens supplied by the fs caller.
- Hash maps (const char *) UUID --> (void *) 1
+ Hash maps (const char *) UUID --> path where path can be the
+ magic value (void *) 1 if no path was specified.
fs functions should really only be interested whether a UUID
exists as a hash key at all; the value is irrelevant. */
apr_hash_t *lock_tokens;
};
+struct svn_fs_lock_target_t
+{
+ const char *token;
+ svn_revnum_t current_rev;
+};
#ifdef __cplusplus
diff --git a/subversion/libsvn_fs/libsvn_fs.pc.in b/subversion/libsvn_fs/libsvn_fs.pc.in
new file mode 100644
index 0000000..67154f0
--- /dev/null
+++ b/subversion/libsvn_fs/libsvn_fs.pc.in
@@ -0,0 +1,12 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libsvn_fs
+Description: Subversion Repository Filesystem Library
+Version: @PACKAGE_VERSION@
+Requires: apr-util-@SVN_APR_MAJOR_VERSION@ apr-@SVN_APR_MAJOR_VERSION@
+Requires.private: libsvn_fs_util libsvn_delta libsvn_subr
+Libs: -L${libdir} -lsvn_fs
+Cflags: -I${includedir}