summaryrefslogtreecommitdiff
path: root/subversion/libsvn_repos/repos.c
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/libsvn_repos/repos.c')
-rw-r--r--subversion/libsvn_repos/repos.c349
1 files changed, 295 insertions, 54 deletions
diff --git a/subversion/libsvn_repos/repos.c b/subversion/libsvn_repos/repos.c
index a22ca23..9f10c06 100644
--- a/subversion/libsvn_repos/repos.c
+++ b/subversion/libsvn_repos/repos.c
@@ -34,8 +34,10 @@
#include "svn_repos.h"
#include "svn_hash.h"
#include "svn_version.h"
+#include "svn_config.h"
#include "private/svn_repos_private.h"
+#include "private/svn_subr_private.h"
#include "svn_private_config.h" /* for SVN_TEMPLATE_ROOT_DIR */
#include "repos.h"
@@ -165,7 +167,6 @@ svn_repos_post_revprop_change_hook(svn_repos_t *repos, apr_pool_t *pool)
pool);
}
-
static svn_error_t *
create_repos_dir(const char *path, apr_pool_t *pool)
{
@@ -304,16 +305,17 @@ create_hooks(svn_repos_t *repos, apr_pool_t *pool)
"" NL
"# START-COMMIT HOOK" NL
"#" NL
-"# The start-commit hook is invoked before a Subversion txn is created" NL
-"# in the process of doing a commit. Subversion runs this hook" NL
-"# by invoking a program (script, executable, binary, etc.) named" NL
-"# '"SCRIPT_NAME"' (for which this file is a template)" NL
-"# with the following ordered arguments:" NL
+"# The start-commit hook is invoked immediately after a Subversion txn is" NL
+"# created and populated with initial revprops in the process of doing a" NL
+"# commit. Subversion runs this hook by invoking a program (script, " NL
+"# executable, binary, etc.) named '"SCRIPT_NAME"' (for which this file" NL
+"# is a template) with the following ordered arguments:" NL
"#" NL
"# [1] REPOS-PATH (the path to this repository)" NL
"# [2] USER (the authenticated user attempting to commit)" NL
"# [3] CAPABILITIES (a colon-separated list of capabilities reported" NL
"# by the client; see note below)" NL
+"# [4] TXN-NAME (the name of the commit txn just created)" NL
"#" NL
"# Note: The CAPABILITIES parameter is new in Subversion 1.5, and 1.5" NL
"# clients will typically report at least the \"" \
@@ -322,6 +324,11 @@ create_hooks(svn_repos_t *repos, apr_pool_t *pool)
"# e.g.: \"" SVN_RA_CAPABILITY_MERGEINFO ":some-other-capability\" " \
"(the order is undefined)." NL
"#" NL
+"# Note: The TXN-NAME parameter is new in Subversion 1.8. Prior to version" NL
+"# 1.8, the start-commit hook was invoked before the commit txn was even" NL
+"# created, so the ability to inspect the commit txn and its metadata from" NL
+"# within the start-commit hook was not possible." NL
+"# " NL
"# The list is self-reported by the client. Therefore, you should not" NL
"# make security assumptions based on the capabilities list, nor should" NL
"# you assume that clients reliably report every capability they have." NL
@@ -364,6 +371,8 @@ PREWRITTEN_HOOKS_TEXT
SVN_ERR_W(svn_io_file_create(this_path, contents, pool),
_("Creating start-commit hook"));
+
+ SVN_ERR(svn_io_set_file_executable(this_path, TRUE, FALSE, pool));
} /* end start-commit hook */
/* Pre-commit hook. */
@@ -454,6 +463,8 @@ PREWRITTEN_HOOKS_TEXT
SVN_ERR_W(svn_io_file_create(this_path, contents, pool),
_("Creating pre-commit hook"));
+
+ SVN_ERR(svn_io_set_file_executable(this_path, TRUE, FALSE, pool));
} /* end pre-commit hook */
@@ -530,6 +541,8 @@ PREWRITTEN_HOOKS_TEXT
SVN_ERR_W(svn_io_file_create(this_path, contents, pool),
_("Creating pre-revprop-change hook"));
+
+ SVN_ERR(svn_io_set_file_executable(this_path, TRUE, FALSE, pool));
} /* end pre-revprop-change hook */
@@ -620,6 +633,8 @@ PREWRITTEN_HOOKS_TEXT
SVN_ERR_W(svn_io_file_create(this_path, contents, pool),
"Creating pre-lock hook");
+
+ SVN_ERR(svn_io_set_file_executable(this_path, TRUE, FALSE, pool));
} /* end pre-lock hook */
@@ -702,6 +717,8 @@ PREWRITTEN_HOOKS_TEXT
SVN_ERR_W(svn_io_file_create(this_path, contents, pool),
"Creating pre-unlock hook");
+
+ SVN_ERR(svn_io_set_file_executable(this_path, TRUE, FALSE, pool));
} /* end pre-unlock hook */
@@ -726,6 +743,7 @@ PREWRITTEN_HOOKS_TEXT
"#" NL
"# [1] REPOS-PATH (the path to this repository)" NL
"# [2] REV (the number of the revision just committed)" NL
+"# [3] TXN-NAME (the name of the transaction that has become REV)" NL
"#" NL
"# The default working directory for the invocation is undefined, so" NL
"# the program should set one explicitly if it cares." NL
@@ -755,6 +773,7 @@ PREWRITTEN_HOOKS_TEXT
"" NL
"REPOS=\"$1\"" NL
"REV=\"$2\"" NL
+"TXN_NAME=\"$3\"" NL
NL
"mailer.py commit \"$REPOS\" \"$REV\" /path/to/mailer.conf" NL;
@@ -762,6 +781,8 @@ PREWRITTEN_HOOKS_TEXT
SVN_ERR_W(svn_io_file_create(this_path, contents, pool),
_("Creating post-commit hook"));
+
+ SVN_ERR(svn_io_set_file_executable(this_path, TRUE, FALSE, pool));
} /* end post-commit hook */
@@ -823,6 +844,8 @@ PREWRITTEN_HOOKS_TEXT
SVN_ERR_W(svn_io_file_create(this_path, contents, pool),
"Creating post-lock hook");
+
+ SVN_ERR(svn_io_set_file_executable(this_path, TRUE, FALSE, pool));
} /* end post-lock hook */
@@ -882,6 +905,8 @@ PREWRITTEN_HOOKS_TEXT
SVN_ERR_W(svn_io_file_create(this_path, contents, pool),
"Creating post-unlock hook");
+
+ SVN_ERR(svn_io_set_file_executable(this_path, TRUE, FALSE, pool));
} /* end post-unlock hook */
@@ -948,6 +973,8 @@ PREWRITTEN_HOOKS_TEXT
SVN_ERR_W(svn_io_file_create(this_path, contents, pool),
_("Creating post-revprop-change hook"));
+
+ SVN_ERR(svn_io_set_file_executable(this_path, TRUE, FALSE, pool));
} /* end post-revprop-change hook */
return SVN_NO_ERROR;
@@ -991,11 +1018,19 @@ create_conf(svn_repos_t *repos, apr_pool_t *pool)
"# password-db = passwd" NL
"### The authz-db option controls the location of the authorization" NL
"### rules for path-based access control. Unless you specify a path" NL
-"### starting with a /, the file's location is relative to the the" NL
-"### directory containing this file. If you don't specify an" NL
-"### authz-db, no path-based access control is done." NL
+"### starting with a /, the file's location is relative to the" NL
+"### directory containing this file. The specified path may be a" NL
+"### repository relative URL (^/) or an absolute file:// URL to a text" NL
+"### file in a Subversion repository. If you don't specify an authz-db," NL
+"### no path-based access control is done." NL
"### Uncomment the line below to use the default authorization file." NL
"# authz-db = " SVN_REPOS__CONF_AUTHZ NL
+"### The groups-db option controls the location of the groups file." NL
+"### Unless you specify a path starting with a /, the file's location is" NL
+"### relative to the directory containing this file. The specified path" NL
+"### may be a repository relative URL (^/) or an absolute file:// URL to a" NL
+"### text file in a Subversion repository." NL
+"# groups-db = " SVN_REPOS__CONF_GROUPS NL
"### This option specifies the authentication realm of the repository." NL
"### If two repositories have the same authentication realm, they should" NL
"### have the same password database, and vice versa. The default realm" NL
@@ -1008,6 +1043,13 @@ create_conf(svn_repos_t *repos, apr_pool_t *pool)
"### \"none\" (to compare usernames as-is without case conversion, which" NL
"### is the default behavior)." NL
"# force-username-case = none" NL
+"### The hooks-env options specifies a path to the hook script environment " NL
+"### configuration file. This option overrides the per-repository default" NL
+"### and can be used to configure the hook script environment for multiple " NL
+"### repositories in a single file, if an absolute path is specified." NL
+"### Unless you specify an absolute path, the file's location is relative" NL
+"### to the directory containing this file." NL
+"# hooks-env = " SVN_REPOS__CONF_HOOKS_ENV NL
"" NL
"[sasl]" NL
"### This option specifies whether you want to use the Cyrus SASL" NL
@@ -1089,6 +1131,55 @@ create_conf(svn_repos_t *repos, apr_pool_t *pool)
_("Creating authz file"));
}
+ {
+ static const char * const hooks_env_contents =
+"### This file is an example hook script environment configuration file." NL
+"### Hook scripts run in an empty environment by default." NL
+"### As shown below each section defines environment variables for a" NL
+"### particular hook script. The [default] section defines environment" NL
+"### variables for all hook scripts, unless overridden by a hook-specific" NL
+"### section." NL
+"" NL
+"### This example configures a UTF-8 locale for all hook scripts, so that " NL
+"### special characters, such as umlauts, may be printed to stderr." NL
+"### If UTF-8 is used with a mod_dav_svn server, the SVNUseUTF8 option must" NL
+"### also be set to 'yes' in httpd.conf." NL
+"### With svnserve, the LANG environment variable of the svnserve process" NL
+"### must be set to the same value as given here." NL
+"[default]" NL
+"LANG = en_US.UTF-8" NL
+"" NL
+"### This sets the PATH environment variable for the pre-commit hook." NL
+"[pre-commit]" NL
+"PATH = /usr/local/bin:/usr/bin:/usr/sbin" NL;
+
+ SVN_ERR_W(svn_io_file_create(svn_dirent_join(repos->conf_path,
+ SVN_REPOS__CONF_HOOKS_ENV \
+ SVN_REPOS__HOOK_DESC_EXT,
+ pool),
+ hooks_env_contents, pool),
+ _("Creating hooks-env file"));
+ }
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_repos_hooks_setenv(svn_repos_t *repos,
+ const char *hooks_env_path,
+ apr_pool_t *scratch_pool)
+{
+ if (hooks_env_path == NULL)
+ repos->hooks_env_path = svn_dirent_join(repos->conf_path,
+ SVN_REPOS__CONF_HOOKS_ENV,
+ repos->pool);
+ else if (!svn_dirent_is_absolute(hooks_env_path))
+ repos->hooks_env_path = svn_dirent_join(repos->conf_path,
+ hooks_env_path,
+ repos->pool);
+ else
+ repos->hooks_env_path = apr_pstrdup(repos->pool, hooks_env_path);
+
return SVN_NO_ERROR;
}
@@ -1107,7 +1198,9 @@ create_svn_repos_t(const char *path, apr_pool_t *pool)
repos->conf_path = svn_dirent_join(path, SVN_REPOS__CONF_DIR, pool);
repos->hook_path = svn_dirent_join(path, SVN_REPOS__HOOK_DIR, pool);
repos->lock_path = svn_dirent_join(path, SVN_REPOS__LOCK_DIR, pool);
+ repos->hooks_env_path = NULL;
repos->repository_capabilities = apr_hash_make(pool);
+ repos->pool = pool;
return repos;
}
@@ -1125,10 +1218,8 @@ create_repos_structure(svn_repos_t *repos,
/* Create the DAV sandbox directory if pre-1.4 or pre-1.5-compatible. */
if (fs_config
- && (apr_hash_get(fs_config, SVN_FS_CONFIG_PRE_1_4_COMPATIBLE,
- APR_HASH_KEY_STRING)
- || apr_hash_get(fs_config, SVN_FS_CONFIG_PRE_1_5_COMPATIBLE,
- APR_HASH_KEY_STRING)))
+ && (svn_hash_gets(fs_config, SVN_FS_CONFIG_PRE_1_4_COMPATIBLE)
+ || svn_hash_gets(fs_config, SVN_FS_CONFIG_PRE_1_5_COMPATIBLE)))
{
const char *dav_path = svn_dirent_join(repos->path,
SVN_REPOS__DAV_DIR, pool);
@@ -1148,9 +1239,9 @@ create_repos_structure(svn_repos_t *repos,
/* Write the top-level README file. */
{
const char * const readme_header =
- "This is a Subversion repository; use the 'svnadmin' tool to examine" NL
- "it. Do not add, delete, or modify files here unless you know how" NL
- "to avoid corrupting the repository." NL
+ "This is a Subversion repository; use the 'svnadmin' and 'svnlook' " NL
+ "tools to examine it. Do not add, delete, or modify files here " NL
+ "unless you know how to avoid corrupting the repository." NL
"" NL;
const char * const readme_bdb_insert =
"The directory \"" SVN_REPOS__DB_DIR "\" contains a Berkeley DB environment." NL
@@ -1379,6 +1470,23 @@ get_repos(svn_repos_t **repos_p,
if (open_fs)
SVN_ERR(svn_fs_open(&repos->fs, repos->db_path, fs_config, pool));
+#ifdef SVN_DEBUG_CRASH_AT_REPOS_OPEN
+ /* If $PATH/config/debug-abort exists, crash the server here.
+ This debugging feature can be used to test client recovery
+ when the server crashes.
+
+ See: Issue #4274 */
+ {
+ svn_node_kind_t kind;
+ svn_error_t *err = svn_io_check_path(
+ svn_dirent_join(repos->conf_path, "debug-abort", pool),
+ &kind, pool);
+ svn_error_clear(err);
+ if (!err && kind == svn_node_file)
+ SVN_ERR_MALFUNCTION_NO_RETURN();
+ }
+#endif /* SVN_DEBUG_CRASH_AT_REPOS_OPEN */
+
*repos_p = repos;
return SVN_NO_ERROR;
}
@@ -1505,8 +1613,7 @@ svn_repos_has_capability(svn_repos_t *repos,
const char *capability,
apr_pool_t *pool)
{
- const char *val = apr_hash_get(repos->repository_capabilities,
- capability, APR_HASH_KEY_STRING);
+ const char *val = svn_hash_gets(repos->repository_capabilities, capability);
if (val == capability_yes)
{
@@ -1527,16 +1634,16 @@ svn_repos_has_capability(svn_repos_t *repos,
SVN_ERR(svn_fs_revision_root(&root, repos->fs, 0, pool));
APR_ARRAY_PUSH(paths, const char *) = "";
- err = svn_fs_get_mergeinfo(&ignored, root, paths, FALSE, FALSE, pool);
+ err = svn_fs_get_mergeinfo2(&ignored, root, paths, FALSE, FALSE,
+ TRUE, pool, pool);
if (err)
{
if (err->apr_err == SVN_ERR_UNSUPPORTED_FEATURE)
{
svn_error_clear(err);
- apr_hash_set(repos->repository_capabilities,
- SVN_REPOS_CAPABILITY_MERGEINFO,
- APR_HASH_KEY_STRING, capability_no);
+ svn_hash_sets(repos->repository_capabilities,
+ SVN_REPOS_CAPABILITY_MERGEINFO, capability_no);
*has = FALSE;
}
else if (err->apr_err == SVN_ERR_FS_NOT_FOUND)
@@ -1545,9 +1652,8 @@ svn_repos_has_capability(svn_repos_t *repos,
in r0, so we're likely to get this error -- but it
means the repository supports mergeinfo! */
svn_error_clear(err);
- apr_hash_set(repos->repository_capabilities,
- SVN_REPOS_CAPABILITY_MERGEINFO,
- APR_HASH_KEY_STRING, capability_yes);
+ svn_hash_sets(repos->repository_capabilities,
+ SVN_REPOS_CAPABILITY_MERGEINFO, capability_yes);
*has = TRUE;
}
else
@@ -1557,9 +1663,8 @@ svn_repos_has_capability(svn_repos_t *repos,
}
else
{
- apr_hash_set(repos->repository_capabilities,
- SVN_REPOS_CAPABILITY_MERGEINFO,
- APR_HASH_KEY_STRING, capability_yes);
+ svn_hash_sets(repos->repository_capabilities,
+ SVN_REPOS_CAPABILITY_MERGEINFO, capability_yes);
*has = TRUE;
}
}
@@ -1572,7 +1677,6 @@ svn_repos_has_capability(svn_repos_t *repos,
return SVN_NO_ERROR;
}
-
svn_fs_t *
svn_repos_fs(svn_repos_t *repos)
{
@@ -1647,6 +1751,86 @@ svn_repos_recover4(const char *path,
return SVN_NO_ERROR;
}
+struct freeze_baton_t {
+ apr_array_header_t *paths;
+ int counter;
+ svn_repos_freeze_func_t freeze_func;
+ void *freeze_baton;
+};
+
+static svn_error_t *
+multi_freeze(void *baton,
+ apr_pool_t *pool)
+{
+ struct freeze_baton_t *fb = baton;
+
+ if (fb->counter == fb->paths->nelts)
+ {
+ SVN_ERR(fb->freeze_func(fb->freeze_baton, pool));
+ return SVN_NO_ERROR;
+ }
+ else
+ {
+ /* Using a subpool as the only way to unlock the repos lock used
+ by BDB is to clear the pool used to take the lock. */
+ apr_pool_t *subpool = svn_pool_create(pool);
+ const char *path = APR_ARRAY_IDX(fb->paths, fb->counter, const char *);
+ svn_repos_t *repos;
+
+ ++fb->counter;
+
+ SVN_ERR(get_repos(&repos, path,
+ TRUE /* exclusive (only applies to BDB) */,
+ FALSE /* non-blocking */,
+ FALSE /* open-fs */,
+ NULL, subpool));
+
+
+ if (strcmp(repos->fs_type, SVN_FS_TYPE_BDB) == 0)
+ {
+ svn_error_t *err = multi_freeze(fb, subpool);
+
+ svn_pool_destroy(subpool);
+
+ return err;
+ }
+ else
+ {
+ SVN_ERR(svn_fs_open(&repos->fs, repos->db_path, NULL, subpool));
+ SVN_ERR(svn_fs_freeze(svn_repos_fs(repos), multi_freeze, fb,
+ subpool));
+ }
+
+ svn_pool_destroy(subpool);
+ }
+
+ return SVN_NO_ERROR;
+}
+
+/* For BDB we fall back on BDB's repos layer lock which means that the
+ repository is unreadable while frozen.
+
+ For FSFS we delegate to the FS layer which uses the FSFS write-lock
+ and an SQLite reserved lock which means the repository is readable
+ while frozen. */
+svn_error_t *
+svn_repos_freeze(apr_array_header_t *paths,
+ svn_repos_freeze_func_t freeze_func,
+ void *freeze_baton,
+ apr_pool_t *pool)
+{
+ struct freeze_baton_t fb;
+
+ fb.paths = paths;
+ fb.counter = 0;
+ fb.freeze_func = freeze_func;
+ fb.freeze_baton = freeze_baton;
+
+ SVN_ERR(multi_freeze(&fb, pool));
+
+ return SVN_NO_ERROR;
+}
+
svn_error_t *svn_repos_db_logfiles(apr_array_header_t **logfiles,
const char *path,
svn_boolean_t only_unused,
@@ -1676,31 +1860,38 @@ svn_error_t *svn_repos_db_logfiles(apr_array_header_t **logfiles,
return SVN_NO_ERROR;
}
-/** Hot copy structure copy context.
- */
+/* Baton for hotcopy_structure(). */
struct hotcopy_ctx_t {
const char *dest; /* target location to construct */
size_t src_len; /* len of the source path*/
+
+ /* As in svn_repos_hotcopy2() */
+ svn_boolean_t incremental;
+ svn_cancel_func_t cancel_func;
+ void *cancel_baton;
};
-/** Called by (svn_io_dir_walk2).
- * Copies the repository structure with exception of @c SVN_REPOS__DB_DIR,
- * @c SVN_REPOS__LOCK_DIR and @c SVN_REPOS__FORMAT.
- * Those directories and files are handled separetly.
- * @a baton is a pointer to (struct hotcopy_ctx_t) specifying
- * destination path to copy to and the length of the source path.
+/* Copy the repository structure of PATH to BATON->DEST, with exception of
+ * @c SVN_REPOS__DB_DIR, @c SVN_REPOS__LOCK_DIR and @c SVN_REPOS__FORMAT;
+ * those directories and files are handled separately.
+ *
+ * BATON is a (struct hotcopy_ctx_t *). BATON->SRC_LEN is the length
+ * of PATH.
*
- * @copydoc svn_io_dir_walk2()
+ * Implements svn_io_walk_func_t.
*/
static svn_error_t *hotcopy_structure(void *baton,
const char *path,
const apr_finfo_t *finfo,
apr_pool_t *pool)
{
- const struct hotcopy_ctx_t *ctx = ((struct hotcopy_ctx_t *) baton);
+ const struct hotcopy_ctx_t *ctx = baton;
const char *sub_path;
const char *target;
+ if (ctx->cancel_func)
+ SVN_ERR(ctx->cancel_func(ctx->cancel_baton));
+
if (strlen(path) == ctx->src_len)
{
sub_path = "";
@@ -1730,7 +1921,17 @@ static svn_error_t *hotcopy_structure(void *baton,
target = svn_dirent_join(ctx->dest, sub_path, pool);
if (finfo->filetype == APR_DIR)
- return create_repos_dir(target, pool);
+ {
+ svn_error_t *err;
+
+ err = create_repos_dir(target, pool);
+ if (ctx->incremental && err && err->apr_err == SVN_ERR_DIR_NOT_EMPTY)
+ {
+ svn_error_clear(err);
+ err = SVN_NO_ERROR;
+ }
+ return svn_error_trace(err);
+ }
else if (finfo->filetype == APR_REG)
return svn_io_copy_file(path, target, TRUE, pool);
else if (finfo->filetype == APR_LNK)
@@ -1759,17 +1960,29 @@ lock_db_logs_file(svn_repos_t *repos,
/* Make a copy of a repository with hot backup of fs. */
svn_error_t *
-svn_repos_hotcopy(const char *src_path,
- const char *dst_path,
- svn_boolean_t clean_logs,
- apr_pool_t *pool)
+svn_repos_hotcopy2(const char *src_path,
+ const char *dst_path,
+ svn_boolean_t clean_logs,
+ svn_boolean_t incremental,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ apr_pool_t *pool)
{
svn_repos_t *src_repos;
svn_repos_t *dst_repos;
struct hotcopy_ctx_t hotcopy_context;
+ svn_error_t *err;
+ const char *src_abspath;
+ const char *dst_abspath;
+
+ SVN_ERR(svn_dirent_get_absolute(&src_abspath, src_path, pool));
+ SVN_ERR(svn_dirent_get_absolute(&dst_abspath, dst_path, pool));
+ if (strcmp(src_abspath, dst_abspath) == 0)
+ return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
+ _("Hotcopy source and destination are equal"));
/* Try to open original repository */
- SVN_ERR(get_repos(&src_repos, src_path,
+ SVN_ERR(get_repos(&src_repos, src_abspath,
FALSE, FALSE,
FALSE, /* don't try to open the db yet. */
NULL,
@@ -1786,9 +1999,12 @@ svn_repos_hotcopy(const char *src_path,
/* Copy the repository to a new path, with exception of
specially handled directories */
- hotcopy_context.dest = dst_path;
- hotcopy_context.src_len = strlen(src_path);
- SVN_ERR(svn_io_dir_walk2(src_path,
+ hotcopy_context.dest = dst_abspath;
+ hotcopy_context.src_len = strlen(src_abspath);
+ hotcopy_context.incremental = incremental;
+ hotcopy_context.cancel_func = cancel_func;
+ hotcopy_context.cancel_baton = cancel_baton;
+ SVN_ERR(svn_io_dir_walk2(src_abspath,
0,
hotcopy_structure,
&hotcopy_context,
@@ -1797,20 +2013,35 @@ svn_repos_hotcopy(const char *src_path,
/* Prepare dst_repos object so that we may create locks,
so that we may open repository */
- dst_repos = create_svn_repos_t(dst_path, pool);
+ dst_repos = create_svn_repos_t(dst_abspath, pool);
dst_repos->fs_type = src_repos->fs_type;
dst_repos->format = src_repos->format;
- SVN_ERR(create_locks(dst_repos, pool));
+ err = create_locks(dst_repos, pool);
+ if (err)
+ {
+ if (incremental && err->apr_err == SVN_ERR_DIR_NOT_EMPTY)
+ svn_error_clear(err);
+ else
+ return svn_error_trace(err);
+ }
- SVN_ERR(svn_io_dir_make_sgid(dst_repos->db_path, APR_OS_DEFAULT, pool));
+ err = svn_io_dir_make_sgid(dst_repos->db_path, APR_OS_DEFAULT, pool);
+ if (err)
+ {
+ if (incremental && APR_STATUS_IS_EEXIST(err->apr_err))
+ svn_error_clear(err);
+ else
+ return svn_error_trace(err);
+ }
/* Exclusively lock the new repository.
No one should be accessing it at the moment */
SVN_ERR(lock_repos(dst_repos, TRUE, FALSE, pool));
- SVN_ERR(svn_fs_hotcopy(src_repos->db_path, dst_repos->db_path,
- clean_logs, pool));
+ SVN_ERR(svn_fs_hotcopy2(src_repos->db_path, dst_repos->db_path,
+ clean_logs, incremental,
+ cancel_func, cancel_baton, pool));
/* Destination repository is ready. Stamp it with a format number. */
return svn_io_write_version_file
@@ -1818,6 +2049,16 @@ svn_repos_hotcopy(const char *src_path,
dst_repos->format, pool);
}
+svn_error_t *
+svn_repos_hotcopy(const char *src_path,
+ const char *dst_path,
+ svn_boolean_t clean_logs,
+ apr_pool_t *pool)
+{
+ return svn_error_trace(svn_repos_hotcopy2(src_path, dst_path, clean_logs,
+ FALSE, NULL, NULL, pool));
+}
+
/* Return the library version number. */
const svn_version_t *
svn_repos_version(void)
@@ -1846,7 +2087,7 @@ svn_repos_stat(svn_dirent_t **dirent,
return SVN_NO_ERROR;
}
- ent = apr_pcalloc(pool, sizeof(*ent));
+ ent = svn_dirent_create(pool);
ent->kind = kind;
if (kind == svn_node_file)