summaryrefslogtreecommitdiff
path: root/subversion/svnadmin/svnadmin.c
diff options
context:
space:
mode:
authorPeter Wemm <peter@FreeBSD.org>2018-05-08 03:44:38 +0000
committerPeter Wemm <peter@FreeBSD.org>2018-05-08 03:44:38 +0000
commit3faf8d6bffc5d0fb2525ba37bb504c53366caf9d (patch)
tree7e47911263e75034b767fe34b2f8d3d17e91f66d /subversion/svnadmin/svnadmin.c
parenta55fb3c0d5eca7d887798125d5b95942b1f01d4b (diff)
Notes
Diffstat (limited to 'subversion/svnadmin/svnadmin.c')
-rw-r--r--subversion/svnadmin/svnadmin.c823
1 files changed, 593 insertions, 230 deletions
diff --git a/subversion/svnadmin/svnadmin.c b/subversion/svnadmin/svnadmin.c
index 2ee5410d24e3..eb26c5a8f0fc 100644
--- a/subversion/svnadmin/svnadmin.c
+++ b/subversion/svnadmin/svnadmin.c
@@ -23,7 +23,6 @@
#include <apr_file_io.h>
-#include <apr_signal.h>
#include "svn_hash.h"
#include "svn_pools.h"
@@ -48,6 +47,8 @@
#include "private/svn_opt_private.h"
#include "private/svn_sorts_private.h"
#include "private/svn_subr_private.h"
+#include "private/svn_cmdline_private.h"
+#include "private/svn_fspath.h"
#include "svn_private_config.h"
@@ -59,46 +60,7 @@
* The current threshold is 64MB. */
#define BLOCK_READ_CACHE_THRESHOLD (0x40 * 0x100000)
-/* A flag to see if we've been cancelled by the client or not. */
-static volatile sig_atomic_t cancelled = FALSE;
-
-/* A signal handler to support cancellation. */
-static void
-signal_handler(int signum)
-{
- apr_signal(signum, SIG_IGN);
- cancelled = TRUE;
-}
-
-
-/* A helper to set up the cancellation signal handlers. */
-static void
-setup_cancellation_signals(void (*handler)(int signum))
-{
- apr_signal(SIGINT, handler);
-#ifdef SIGBREAK
- /* SIGBREAK is a Win32 specific signal generated by ctrl-break. */
- apr_signal(SIGBREAK, handler);
-#endif
-#ifdef SIGHUP
- apr_signal(SIGHUP, handler);
-#endif
-#ifdef SIGTERM
- apr_signal(SIGTERM, handler);
-#endif
-}
-
-
-/* Our cancellation callback. */
-static svn_error_t *
-check_cancel(void *baton)
-{
- if (cancelled)
- return svn_error_create(SVN_ERR_CANCELLED, NULL, _("Caught signal"));
- else
- return SVN_NO_ERROR;
-}
-
+static svn_cancel_func_t check_cancel = NULL;
/* Custom filesystem warning function. */
static void
@@ -111,34 +73,6 @@ warning_func(void *baton,
}
-/* Helper to open a repository and set a warning func (so we don't
- * SEGFAULT when libsvn_fs's default handler gets run). */
-static svn_error_t *
-open_repos(svn_repos_t **repos,
- const char *path,
- apr_pool_t *pool)
-{
- /* Enable the "block-read" feature (where it applies)? */
- svn_boolean_t use_block_read
- = svn_cache_config_get()->cache_size > BLOCK_READ_CACHE_THRESHOLD;
-
- /* construct FS configuration parameters: enable caches for r/o data */
- apr_hash_t *fs_config = apr_hash_make(pool);
- svn_hash_sets(fs_config, SVN_FS_CONFIG_FSFS_CACHE_DELTAS, "1");
- svn_hash_sets(fs_config, SVN_FS_CONFIG_FSFS_CACHE_FULLTEXTS, "1");
- svn_hash_sets(fs_config, SVN_FS_CONFIG_FSFS_CACHE_REVPROPS, "2");
- svn_hash_sets(fs_config, SVN_FS_CONFIG_FSFS_CACHE_NS,
- svn_uuid_generate(pool));
- svn_hash_sets(fs_config, SVN_FS_CONFIG_FSFS_BLOCK_READ,
- use_block_read ? "1" : "0");
-
- /* now, open the requested repository */
- SVN_ERR(svn_repos_open3(repos, path, fs_config, pool, pool));
- svn_fs_set_warning_func(svn_repos_fs(*repos), warning_func, NULL);
- return SVN_NO_ERROR;
-}
-
-
/* Version compatibility check */
static svn_error_t *
check_lib_versions(void)
@@ -166,11 +100,13 @@ static svn_opt_subcommand_t
subcommand_delrevprop,
subcommand_deltify,
subcommand_dump,
+ subcommand_dump_revprops,
subcommand_freeze,
subcommand_help,
subcommand_hotcopy,
subcommand_info,
subcommand_load,
+ subcommand_load_revprops,
subcommand_list_dblogs,
subcommand_list_unused_dblogs,
subcommand_lock,
@@ -214,7 +150,12 @@ enum svnadmin__cmdline_options_t
svnadmin__pre_1_6_compatible,
svnadmin__compatible_version,
svnadmin__check_normalization,
- svnadmin__metadata_only
+ svnadmin__metadata_only,
+ svnadmin__no_flush_to_disk,
+ svnadmin__normalize_props,
+ svnadmin__exclude,
+ svnadmin__include,
+ svnadmin__glob
};
/* Option codes and descriptions.
@@ -333,6 +274,26 @@ static const apr_getopt_option_t options_table[] =
" checking against external corruption in\n"
" Subversion 1.9+ format repositories.\n")},
+ {"no-flush-to-disk", svnadmin__no_flush_to_disk, 0,
+ N_("disable flushing to disk during the operation\n"
+ " (faster, but unsafe on power off)")},
+
+ {"normalize-props", svnadmin__normalize_props, 0,
+ N_("normalize property values found in the dumpstream\n"
+ " (currently, only translates non-LF line endings)")},
+
+ {"exclude", svnadmin__exclude, 1,
+ N_("filter out nodes with given prefix(es) from dump")},
+
+ {"include", svnadmin__include, 1,
+ N_("filter out nodes without given prefix(es) from dump")},
+
+ {"pattern", svnadmin__glob, 0,
+ N_("treat the path prefixes as file glob patterns.\n"
+ " Glob special characters are '*' '?' '[]' and '\\'.\n"
+ " Character '/' is not treated specially, so\n"
+ " pattern /*/foo matches paths /a/foo and /a/b/foo.") },
+
{NULL}
};
@@ -359,7 +320,7 @@ static const svn_opt_subcommand_desc2_t cmd_table[] =
{"delrevprop", subcommand_delrevprop, {0}, N_
("usage: 1. svnadmin delrevprop REPOS_PATH -r REVISION NAME\n"
- " 2. svnadmin delrevprop REPO_PATH -t TXN NAME\n\n"
+ " 2. svnadmin delrevprop REPOS_PATH -t TXN NAME\n\n"
"1. Delete the property NAME on revision REVISION.\n\n"
"Use --use-pre-revprop-change-hook/--use-post-revprop-change-hook to\n"
"trigger the revision property-related hooks (for example, if you want\n"
@@ -389,8 +350,24 @@ static const svn_opt_subcommand_desc2_t cmd_table[] =
"only the paths changed in that revision; otherwise it will describe\n"
"every path present in the repository as of that revision. (In either\n"
"case, the second and subsequent revisions, if any, describe only paths\n"
- "changed in those revisions.)\n"),
- {'r', svnadmin__incremental, svnadmin__deltas, 'q', 'M'} },
+ "changed in those revisions.)\n"
+ "\n"
+ "Using --exclude or --include gives results equivalent to authz-based\n"
+ "path exclusions. In particular, when the source of a copy is\n"
+ "excluded, the copy is transformed into an add (unlike in 'svndumpfilter').\n"),
+ {'r', svnadmin__incremental, svnadmin__deltas, 'q', 'M', 'F',
+ svnadmin__exclude, svnadmin__include, svnadmin__glob },
+ {{'F', N_("write to file ARG instead of stdout")}} },
+
+ {"dump-revprops", subcommand_dump_revprops, {0}, N_
+ ("usage: svnadmin dump-revprops REPOS_PATH [-r LOWER[:UPPER]]\n\n"
+ "Dump the revision properties of filesystem to stdout in a 'dumpfile'\n"
+ "portable format, sending feedback to stderr. Dump revisions\n"
+ "LOWER rev through UPPER rev. If no revisions are given, dump the\n"
+ "properties for all revisions. If only LOWER is given, dump the\n"
+ "properties for that one revision.\n"),
+ {'r', 'q', 'F'},
+ {{'F', N_("write to file ARG instead of stdout")}} },
{"freeze", subcommand_freeze, {0}, N_
("usage: 1. svnadmin freeze REPOS_PATH PROGRAM [ARG...]\n"
@@ -401,7 +378,8 @@ static const svn_opt_subcommand_desc2_t cmd_table[] =
"2. Like 1 except all repositories listed in FILE are locked. The file\n"
" format is repository paths separated by newlines. Repositories are\n"
" locked in the same order as they are listed in the file.\n"),
- {'F'} },
+ {'F'},
+ {{'F', N_("read repository paths from file ARG")}} },
{"help", subcommand_help, {"?", "h"}, N_
("usage: svnadmin help [SUBCOMMAND...]\n\n"
@@ -443,14 +421,28 @@ static const svn_opt_subcommand_desc2_t cmd_table[] =
{'q', 'r', svnadmin__ignore_uuid, svnadmin__force_uuid,
svnadmin__ignore_dates,
svnadmin__use_pre_commit_hook, svnadmin__use_post_commit_hook,
- svnadmin__parent_dir, svnadmin__bypass_prop_validation, 'M'} },
+ svnadmin__parent_dir, svnadmin__normalize_props,
+ svnadmin__bypass_prop_validation, 'M',
+ svnadmin__no_flush_to_disk, 'F'},
+ {{'F', N_("read from file ARG instead of stdin")}} },
+
+ {"load-revprops", subcommand_load_revprops, {0}, N_
+ ("usage: svnadmin load-revprops REPOS_PATH\n\n"
+ "Read a 'dumpfile'-formatted stream from stdin, setting the revision\n"
+ "properties in the repository's filesystem. Revisions not found in the\n"
+ "repository will cause an error. Progress feedback is sent to stdout.\n"
+ "If --revision is specified, limit the loaded revisions to only those\n"
+ "in the dump stream whose revision numbers match the specified range.\n"),
+ {'q', 'r', svnadmin__force_uuid, svnadmin__normalize_props,
+ svnadmin__bypass_prop_validation, svnadmin__no_flush_to_disk, 'F'},
+ {{'F', N_("read from file ARG instead of stdin")}} },
{"lock", subcommand_lock, {0}, N_
("usage: svnadmin lock REPOS_PATH PATH USERNAME COMMENT-FILE [TOKEN]\n\n"
"Lock PATH by USERNAME setting comments from COMMENT-FILE.\n"
"If provided, use TOKEN as lock token. Use --bypass-hooks to avoid\n"
"triggering the pre-lock and post-lock hook scripts.\n"),
- {svnadmin__bypass_hooks} },
+ {svnadmin__bypass_hooks, 'q'} },
{"lslocks", subcommand_lslocks, {0}, N_
("usage: svnadmin lslocks REPOS_PATH [PATH-IN-REPOS]\n\n"
@@ -460,8 +452,12 @@ static const svn_opt_subcommand_desc2_t cmd_table[] =
{"lstxns", subcommand_lstxns, {0}, N_
("usage: svnadmin lstxns REPOS_PATH\n\n"
- "Print the names of all uncommitted transactions.\n"),
- {0} },
+ "Print the names of uncommitted transactions. With -rN skip the output\n"
+ "of those that have a base revision more recent than rN. Transactions\n"
+ "with base revisions much older than HEAD are likely to have been\n"
+ "abandonded and are candidates to be removed.\n"),
+ {'r'},
+ { {'r', "transaction base revision ARG"} } },
{"pack", subcommand_pack, {0}, N_
("usage: svnadmin pack REPOS_PATH\n\n"
@@ -480,7 +476,7 @@ static const svn_opt_subcommand_desc2_t cmd_table[] =
{"rmlocks", subcommand_rmlocks, {0}, N_
("usage: svnadmin rmlocks REPOS_PATH LOCKED_PATH...\n\n"
"Unconditionally remove lock from each LOCKED_PATH.\n"),
- {0} },
+ {'q'} },
{"rmtxns", subcommand_rmtxns, {0}, N_
("usage: svnadmin rmtxns REPOS_PATH TXN_NAME...\n\n"
@@ -524,7 +520,7 @@ static const svn_opt_subcommand_desc2_t cmd_table[] =
"Unlock LOCKED_PATH (as USERNAME) after verifying that the token\n"
"associated with the lock matches TOKEN. Use --bypass-hooks to avoid\n"
"triggering the pre-unlock and post-unlock hook scripts.\n"),
- {svnadmin__bypass_hooks} },
+ {svnadmin__bypass_hooks, 'q'} },
{"upgrade", subcommand_upgrade, {0}, N_
("usage: svnadmin upgrade REPOS_PATH\n\n"
@@ -576,16 +572,53 @@ struct svnadmin_opt_state
svn_boolean_t metadata_only; /* --metadata-only */
svn_boolean_t bypass_prop_validation; /* --bypass-prop-validation */
svn_boolean_t ignore_dates; /* --ignore-dates */
+ svn_boolean_t no_flush_to_disk; /* --no-flush-to-disk */
+ svn_boolean_t normalize_props; /* --normalize_props */
enum svn_repos_load_uuid uuid_action; /* --ignore-uuid,
--force-uuid */
apr_uint64_t memory_cache_size; /* --memory-cache-size M */
const char *parent_dir; /* --parent-dir */
- svn_stringbuf_t *filedata; /* --file */
+ const char *file; /* --file */
+ apr_array_header_t *exclude; /* --exclude */
+ apr_array_header_t *include; /* --include */
+ svn_boolean_t glob; /* --pattern */
const char *config_dir; /* Overriding Configuration Directory */
};
+/* Helper to open a repository and set a warning func (so we don't
+ * SEGFAULT when libsvn_fs's default handler gets run). */
+static svn_error_t *
+open_repos(svn_repos_t **repos,
+ const char *path,
+ struct svnadmin_opt_state *opt_state,
+ apr_pool_t *pool)
+{
+ /* Enable the "block-read" feature (where it applies)? */
+ svn_boolean_t use_block_read
+ = svn_cache_config_get()->cache_size > BLOCK_READ_CACHE_THRESHOLD;
+
+ /* construct FS configuration parameters: enable caches for r/o data */
+ apr_hash_t *fs_config = apr_hash_make(pool);
+ svn_hash_sets(fs_config, SVN_FS_CONFIG_FSFS_CACHE_DELTAS, "1");
+ svn_hash_sets(fs_config, SVN_FS_CONFIG_FSFS_CACHE_FULLTEXTS, "1");
+ svn_hash_sets(fs_config, SVN_FS_CONFIG_FSFS_CACHE_NODEPROPS, "1");
+ svn_hash_sets(fs_config, SVN_FS_CONFIG_FSFS_CACHE_REVPROPS, "2");
+ svn_hash_sets(fs_config, SVN_FS_CONFIG_FSFS_CACHE_NS,
+ svn_uuid_generate(pool));
+ svn_hash_sets(fs_config, SVN_FS_CONFIG_FSFS_BLOCK_READ,
+ use_block_read ? "1" : "0");
+ svn_hash_sets(fs_config, SVN_FS_CONFIG_NO_FLUSH_TO_DISK,
+ opt_state->no_flush_to_disk ? "1" : "0");
+
+ /* now, open the requested repository */
+ SVN_ERR(svn_repos_open3(repos, path, fs_config, pool, pool));
+ svn_fs_set_warning_func(svn_repos_fs(*repos), warning_func, NULL);
+ return SVN_NO_ERROR;
+}
+
+
/* Set *REVNUM to the revision specified by REVISION (or to
SVN_INVALID_REVNUM if that has the type 'unspecified'),
possibly making use of the YOUNGEST revision number in REPOS. */
@@ -614,16 +647,25 @@ get_revnum(svn_revnum_t *revnum, const svn_opt_revision_t *revision,
return SVN_NO_ERROR;
}
-/* Set *PATH to an internal-style, UTF8-encoded, local dirent path
- allocated from POOL and parsed from raw command-line argument ARG. */
+/* Set *FSPATH to an internal-style fspath parsed from ARG. */
static svn_error_t *
-target_arg_to_dirent(const char **dirent,
+target_arg_to_fspath(const char **fspath,
const char *arg,
- apr_pool_t *pool)
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
- const char *path;
+ /* ### Using a private API. This really shouldn't be needed. */
+ *fspath = svn_fspath__canonicalize(arg, result_pool);
+ return SVN_NO_ERROR;
+}
- SVN_ERR(svn_utf_cstring_to_utf8(&path, arg, pool));
+/* Set *DIRENT to an internal-style, local dirent path
+ allocated from POOL and parsed from PATH. */
+static svn_error_t *
+target_arg_to_dirent(const char **dirent,
+ const char *path,
+ apr_pool_t *pool)
+{
if (svn_path_is_url(path))
return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
_("Path '%s' is not a local path"), path);
@@ -665,8 +707,12 @@ parse_args(apr_array_header_t **args,
if (num_args)
while (os->ind < os->argc)
- APR_ARRAY_PUSH(*args, const char *) =
- apr_pstrdup(pool, os->argv[os->ind++]);
+ {
+ const char *arg;
+
+ SVN_ERR(svn_utf_cstring_to_utf8(&arg, os->argv[os->ind++], pool));
+ APR_ARRAY_PUSH(*args, const char *) = arg;
+ }
}
return SVN_NO_ERROR;
@@ -692,7 +738,7 @@ subcommand_crashtest(apr_getopt_t *os, void *baton, apr_pool_t *pool)
svn_repos_t *repos;
(void)svn_error_set_malfunction_handler(crashtest_malfunction_handler);
- SVN_ERR(open_repos(&repos, opt_state->repository_path, pool));
+ SVN_ERR(open_repos(&repos, opt_state->repository_path, opt_state, pool));
SVN_ERR(svn_cmdline_printf(pool,
_("Successfully opened repository '%s'.\n"
"Will now crash to simulate a crashing "
@@ -809,7 +855,7 @@ subcommand_deltify(apr_getopt_t *os, void *baton, apr_pool_t *pool)
/* Expect no more arguments. */
SVN_ERR(parse_args(NULL, os, 0, 0, pool));
- SVN_ERR(open_repos(&repos, opt_state->repository_path, pool));
+ SVN_ERR(open_repos(&repos, opt_state->repository_path, opt_state, pool));
fs = svn_repos_fs(repos);
SVN_ERR(svn_fs_youngest_rev(&youngest, fs, pool));
@@ -1066,8 +1112,7 @@ repos_notify_handler(void *baton,
return;
case svn_repos_notify_mutex_acquired:
- /* Enable cancellation signal handlers. */
- setup_cancellation_signals(signal_handler);
+ svn_cmdline__setup_cancellation_handler();
return;
case svn_repos_notify_recover_start:
@@ -1126,6 +1171,24 @@ repos_notify_handler(void *baton,
_("* Copied revisions from %ld to %ld.\n"),
notify->start_revision, notify->end_revision));
}
+ return;
+
+ case svn_repos_notify_pack_noop:
+ /* For best backward compatibility, we keep silent if there were just
+ no more shards to pack. */
+ if (notify->shard == -1)
+ {
+ svn_error_clear(svn_stream_printf(feedback_stream, scratch_pool,
+ _("svnadmin: Warning - this repository is not sharded."
+ " Packing has no effect.\n")));
+ }
+ return;
+
+ case svn_repos_notify_load_revprop_set:
+ svn_error_clear(svn_stream_printf(feedback_stream, scratch_pool,
+ _("Properties set on revision %ld.\n"),
+ notify->new_revision));
+ return;
default:
return;
@@ -1172,57 +1235,207 @@ recode_stream_create(FILE *std_stream, apr_pool_t *pool)
return rw_stream;
}
-
-/* This implements `svn_opt_subcommand_t'. */
+/* Read the min / max revision from the OPT_STATE, verify them against REPOS
+ and return them in *LOWER and *UPPER, respectively. Use SCRATCH_POOL
+ for temporary allocations. */
static svn_error_t *
-subcommand_dump(apr_getopt_t *os, void *baton, apr_pool_t *pool)
+get_dump_range(svn_revnum_t *lower,
+ svn_revnum_t *upper,
+ svn_repos_t *repos,
+ struct svnadmin_opt_state *opt_state,
+ apr_pool_t *scratch_pool)
{
- struct svnadmin_opt_state *opt_state = baton;
- svn_repos_t *repos;
svn_fs_t *fs;
- svn_stream_t *stdout_stream;
- svn_revnum_t lower = SVN_INVALID_REVNUM, upper = SVN_INVALID_REVNUM;
svn_revnum_t youngest;
- svn_stream_t *feedback_stream = NULL;
- /* Expect no more arguments. */
- SVN_ERR(parse_args(NULL, os, 0, 0, pool));
+ *lower = SVN_INVALID_REVNUM;
+ *upper = SVN_INVALID_REVNUM;
- SVN_ERR(open_repos(&repos, opt_state->repository_path, pool));
fs = svn_repos_fs(repos);
- SVN_ERR(svn_fs_youngest_rev(&youngest, fs, pool));
+ SVN_ERR(svn_fs_youngest_rev(&youngest, fs, scratch_pool));
/* Find the revision numbers at which to start and end. */
- SVN_ERR(get_revnum(&lower, &opt_state->start_revision,
- youngest, repos, pool));
- SVN_ERR(get_revnum(&upper, &opt_state->end_revision,
- youngest, repos, pool));
+ SVN_ERR(get_revnum(lower, &opt_state->start_revision,
+ youngest, repos, scratch_pool));
+ SVN_ERR(get_revnum(upper, &opt_state->end_revision,
+ youngest, repos, scratch_pool));
/* Fill in implied revisions if necessary. */
- if (lower == SVN_INVALID_REVNUM)
+ if (*lower == SVN_INVALID_REVNUM)
{
- lower = 0;
- upper = youngest;
+ *lower = 0;
+ *upper = youngest;
}
- else if (upper == SVN_INVALID_REVNUM)
+ else if (*upper == SVN_INVALID_REVNUM)
{
- upper = lower;
+ *upper = *lower;
}
- if (lower > upper)
+ if (*lower > *upper)
return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
_("First revision cannot be higher than second"));
- SVN_ERR(svn_stream_for_stdout(&stdout_stream, pool));
+ return SVN_NO_ERROR;
+}
+
+/* Compare the node-path PATH with the (const char *) prefixes in PFXLIST.
+ * Return TRUE if any prefix is a prefix of PATH (matching whole path
+ * components); FALSE otherwise.
+ * PATH starts with a '/', as do the (const char *) paths in PREFIXES. */
+/* This function is a duplicate of svndumpfilter.c:ary_prefix_match(). */
+static svn_boolean_t
+ary_prefix_match(const apr_array_header_t *pfxlist, const char *path)
+{
+ int i;
+ size_t path_len = strlen(path);
+
+ for (i = 0; i < pfxlist->nelts; i++)
+ {
+ const char *pfx = APR_ARRAY_IDX(pfxlist, i, const char *);
+ size_t pfx_len = strlen(pfx);
+
+ if (path_len < pfx_len)
+ continue;
+ if (strncmp(path, pfx, pfx_len) == 0
+ && (pfx_len == 1 || path[pfx_len] == '\0' || path[pfx_len] == '/'))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/* Baton for dump_filter_func(). */
+struct dump_filter_baton_t
+{
+ apr_array_header_t *prefixes;
+ svn_boolean_t glob;
+ svn_boolean_t do_exclude;
+};
+
+/* Implements svn_repos_dump_filter_func_t. */
+static svn_error_t *
+dump_filter_func(svn_boolean_t *include,
+ svn_fs_root_t *root,
+ const char *path,
+ void *baton,
+ apr_pool_t *scratch_pool)
+{
+ struct dump_filter_baton_t *b = baton;
+ const svn_boolean_t matches =
+ (b->glob
+ ? svn_cstring_match_glob_list(path, b->prefixes)
+ : ary_prefix_match(b->prefixes, path));
+
+ *include = b->do_exclude ? !matches : matches;
+ return SVN_NO_ERROR;
+}
+
+/* This implements `svn_opt_subcommand_t'. */
+static svn_error_t *
+subcommand_dump(apr_getopt_t *os, void *baton, apr_pool_t *pool)
+{
+ struct svnadmin_opt_state *opt_state = baton;
+ svn_repos_t *repos;
+ svn_stream_t *out_stream;
+ svn_revnum_t lower, upper;
+ svn_stream_t *feedback_stream = NULL;
+ struct dump_filter_baton_t filter_baton = {0};
+
+ /* Expect no more arguments. */
+ SVN_ERR(parse_args(NULL, os, 0, 0, pool));
+
+ SVN_ERR(open_repos(&repos, opt_state->repository_path, opt_state, pool));
+ SVN_ERR(get_dump_range(&lower, &upper, repos, opt_state, pool));
+
+ /* Open the file or STDOUT, depending on whether -F was specified. */
+ if (opt_state->file)
+ {
+ apr_file_t *file;
+
+ /* Overwrite existing files, same as with > redirection. */
+ SVN_ERR(svn_io_file_open(&file, opt_state->file,
+ APR_WRITE | APR_CREATE | APR_TRUNCATE
+ | APR_BUFFERED, APR_OS_DEFAULT, pool));
+ out_stream = svn_stream_from_aprfile2(file, FALSE, pool);
+ }
+ else
+ SVN_ERR(svn_stream_for_stdout(&out_stream, pool));
/* Progress feedback goes to STDERR, unless they asked to suppress it. */
if (! opt_state->quiet)
feedback_stream = recode_stream_create(stderr, pool);
- SVN_ERR(svn_repos_dump_fs3(repos, stdout_stream, lower, upper,
+ /* Initialize the filter baton. */
+ filter_baton.glob = opt_state->glob;
+
+ if (opt_state->exclude && !opt_state->include)
+ {
+ filter_baton.prefixes = opt_state->exclude;
+ filter_baton.do_exclude = TRUE;
+ }
+ else if (opt_state->include && !opt_state->exclude)
+ {
+ filter_baton.prefixes = opt_state->include;
+ filter_baton.do_exclude = FALSE;
+ }
+ else if (opt_state->include && opt_state->exclude)
+ {
+ return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("'--exclude' and '--include' options "
+ "cannot be used simultaneously"));
+ }
+
+ SVN_ERR(svn_repos_dump_fs4(repos, out_stream, lower, upper,
opt_state->incremental, opt_state->use_deltas,
+ TRUE, TRUE,
!opt_state->quiet ? repos_notify_handler : NULL,
- feedback_stream, check_cancel, NULL, pool));
+ feedback_stream,
+ filter_baton.prefixes ? dump_filter_func : NULL,
+ &filter_baton,
+ check_cancel, NULL, pool));
+
+ return SVN_NO_ERROR;
+}
+
+/* This implements `svn_opt_subcommand_t'. */
+static svn_error_t *
+subcommand_dump_revprops(apr_getopt_t *os, void *baton, apr_pool_t *pool)
+{
+ struct svnadmin_opt_state *opt_state = baton;
+ svn_repos_t *repos;
+ svn_stream_t *out_stream;
+ svn_revnum_t lower, upper;
+ svn_stream_t *feedback_stream = NULL;
+
+ /* Expect no more arguments. */
+ SVN_ERR(parse_args(NULL, os, 0, 0, pool));
+
+ SVN_ERR(open_repos(&repos, opt_state->repository_path, opt_state, pool));
+ SVN_ERR(get_dump_range(&lower, &upper, repos, opt_state, pool));
+
+ /* Open the file or STDOUT, depending on whether -F was specified. */
+ if (opt_state->file)
+ {
+ apr_file_t *file;
+
+ /* Overwrite existing files, same as with > redirection. */
+ SVN_ERR(svn_io_file_open(&file, opt_state->file,
+ APR_WRITE | APR_CREATE | APR_TRUNCATE
+ | APR_BUFFERED, APR_OS_DEFAULT, pool));
+ out_stream = svn_stream_from_aprfile2(file, FALSE, pool);
+ }
+ else
+ SVN_ERR(svn_stream_for_stdout(&out_stream, pool));
+
+ /* Progress feedback goes to STDERR, unless they asked to suppress it. */
+ if (! opt_state->quiet)
+ feedback_stream = recode_stream_create(stderr, pool);
+
+ SVN_ERR(svn_repos_dump_fs4(repos, out_stream, lower, upper,
+ FALSE, FALSE, TRUE, FALSE,
+ !opt_state->quiet ? repos_notify_handler : NULL,
+ feedback_stream, NULL, NULL,
+ check_cancel, NULL, pool));
return SVN_NO_ERROR;
}
@@ -1268,13 +1481,13 @@ subcommand_freeze(apr_getopt_t *os, void *baton, apr_pool_t *pool)
int i;
struct freeze_baton_t b;
- SVN_ERR(svn_opt_parse_all_args(&args, os, pool));
+ SVN_ERR(parse_args(&args, os, -1, -1, pool));
if (!args->nelts)
return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, 0,
_("No program provided"));
- if (!opt_state->filedata)
+ if (!opt_state->file)
{
/* One repository on the command line. */
paths = apr_array_make(pool, 1, sizeof(const char *));
@@ -1282,9 +1495,11 @@ subcommand_freeze(apr_getopt_t *os, void *baton, apr_pool_t *pool)
}
else
{
+ svn_stringbuf_t *buf;
const char *utf8;
- /* All repositories in filedata. */
- SVN_ERR(svn_utf_cstring_to_utf8(&utf8, opt_state->filedata->data, pool));
+ /* Read repository paths from the -F file. */
+ SVN_ERR(svn_stringbuf_from_file2(&buf, opt_state->file, pool));
+ SVN_ERR(svn_utf_cstring_to_utf8(&utf8, buf->data, pool));
paths = svn_cstring_split(utf8, "\r\n", FALSE, pool);
}
@@ -1362,69 +1577,156 @@ optrev_to_revnum(svn_revnum_t *revnum, const svn_opt_revision_t *opt_rev)
return SVN_NO_ERROR;
}
-
-/* This implements `svn_opt_subcommand_t'. */
+/* Read the min / max revision from the OPT_STATE, verify them and return
+ them in *LOWER and *UPPER, respectively. */
static svn_error_t *
-subcommand_load(apr_getopt_t *os, void *baton, apr_pool_t *pool)
+get_load_range(svn_revnum_t *lower,
+ svn_revnum_t *upper,
+ struct svnadmin_opt_state *opt_state)
{
- svn_error_t *err;
- struct svnadmin_opt_state *opt_state = baton;
- svn_repos_t *repos;
- svn_revnum_t lower = SVN_INVALID_REVNUM, upper = SVN_INVALID_REVNUM;
- svn_stream_t *stdin_stream;
- svn_stream_t *feedback_stream = NULL;
-
- /* Expect no more arguments. */
- SVN_ERR(parse_args(NULL, os, 0, 0, pool));
-
/* Find the revision numbers at which to start and end. We only
support a limited set of revision kinds: number and unspecified. */
- SVN_ERR(optrev_to_revnum(&lower, &opt_state->start_revision));
- SVN_ERR(optrev_to_revnum(&upper, &opt_state->end_revision));
+ SVN_ERR(optrev_to_revnum(lower, &opt_state->start_revision));
+ SVN_ERR(optrev_to_revnum(upper, &opt_state->end_revision));
/* Fill in implied revisions if necessary. */
- if ((upper == SVN_INVALID_REVNUM) && (lower != SVN_INVALID_REVNUM))
+ if ((*upper == SVN_INVALID_REVNUM) && (*lower != SVN_INVALID_REVNUM))
{
- upper = lower;
+ *upper = *lower;
}
- else if ((upper != SVN_INVALID_REVNUM) && (lower == SVN_INVALID_REVNUM))
+ else if ((*upper != SVN_INVALID_REVNUM) && (*lower == SVN_INVALID_REVNUM))
{
- lower = upper;
+ *lower = *upper;
}
/* Ensure correct range ordering. */
- if (lower > upper)
+ if (*lower > *upper)
{
return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
_("First revision cannot be higher than second"));
}
- SVN_ERR(open_repos(&repos, opt_state->repository_path, pool));
+ return SVN_NO_ERROR;
+}
- /* Read the stream from STDIN. Users can redirect a file. */
- SVN_ERR(svn_stream_for_stdin(&stdin_stream, pool));
+
+/* This implements `svn_opt_subcommand_t'. */
+static svn_error_t *
+subcommand_load(apr_getopt_t *os, void *baton, apr_pool_t *pool)
+{
+ svn_error_t *err;
+ struct svnadmin_opt_state *opt_state = baton;
+ svn_repos_t *repos;
+ svn_revnum_t lower, upper;
+ svn_stream_t *in_stream;
+ svn_stream_t *feedback_stream = NULL;
+
+ /* Expect no more arguments. */
+ SVN_ERR(parse_args(NULL, os, 0, 0, pool));
+
+ /* Find the revision numbers at which to start and end. We only
+ support a limited set of revision kinds: number and unspecified. */
+ SVN_ERR(get_load_range(&lower, &upper, opt_state));
+
+ SVN_ERR(open_repos(&repos, opt_state->repository_path, opt_state, pool));
+
+ /* Open the file or STDIN, depending on whether -F was specified. */
+ if (opt_state->file)
+ SVN_ERR(svn_stream_open_readonly(&in_stream, opt_state->file,
+ pool, pool));
+ else
+ SVN_ERR(svn_stream_for_stdin2(&in_stream, TRUE, pool));
/* Progress feedback goes to STDOUT, unless they asked to suppress it. */
if (! opt_state->quiet)
feedback_stream = recode_stream_create(stdout, pool);
- err = svn_repos_load_fs5(repos, stdin_stream, lower, upper,
+ err = svn_repos_load_fs6(repos, in_stream, lower, upper,
opt_state->uuid_action, opt_state->parent_dir,
opt_state->use_pre_commit_hook,
opt_state->use_post_commit_hook,
!opt_state->bypass_prop_validation,
opt_state->ignore_dates,
+ opt_state->normalize_props,
opt_state->quiet ? NULL : repos_notify_handler,
feedback_stream, check_cancel, NULL, pool);
- if (err && err->apr_err == SVN_ERR_BAD_PROPERTY_VALUE)
- return svn_error_quick_wrap(err,
- _("Invalid property value found in "
- "dumpstream; consider repairing the source "
- "or using --bypass-prop-validation while "
- "loading."));
+
+ if (svn_error_find_cause(err, SVN_ERR_BAD_PROPERTY_VALUE_EOL))
+ {
+ return svn_error_quick_wrap(err,
+ _("A property with invalid line ending "
+ "found in dumpstream; consider using "
+ "--normalize-props while loading."));
+ }
+ else if (err && err->apr_err == SVN_ERR_BAD_PROPERTY_VALUE)
+ {
+ return svn_error_quick_wrap(err,
+ _("Invalid property value found in "
+ "dumpstream; consider repairing the "
+ "source or using --bypass-prop-validation "
+ "while loading."));
+ }
+
return err;
}
+static svn_error_t *
+subcommand_load_revprops(apr_getopt_t *os, void *baton, apr_pool_t *pool)
+{
+ svn_error_t *err;
+ struct svnadmin_opt_state *opt_state = baton;
+ svn_repos_t *repos;
+ svn_revnum_t lower, upper;
+ svn_stream_t *in_stream;
+
+ svn_stream_t *feedback_stream = NULL;
+
+ /* Expect no more arguments. */
+ SVN_ERR(parse_args(NULL, os, 0, 0, pool));
+
+ /* Find the revision numbers at which to start and end. We only
+ support a limited set of revision kinds: number and unspecified. */
+ SVN_ERR(get_load_range(&lower, &upper, opt_state));
+
+ SVN_ERR(open_repos(&repos, opt_state->repository_path, opt_state, pool));
+
+ /* Open the file or STDIN, depending on whether -F was specified. */
+ if (opt_state->file)
+ SVN_ERR(svn_stream_open_readonly(&in_stream, opt_state->file,
+ pool, pool));
+ else
+ SVN_ERR(svn_stream_for_stdin2(&in_stream, TRUE, pool));
+
+ /* Progress feedback goes to STDOUT, unless they asked to suppress it. */
+ if (! opt_state->quiet)
+ feedback_stream = recode_stream_create(stdout, pool);
+
+ err = svn_repos_load_fs_revprops(repos, in_stream, lower, upper,
+ !opt_state->bypass_prop_validation,
+ opt_state->ignore_dates,
+ opt_state->normalize_props,
+ opt_state->quiet ? NULL
+ : repos_notify_handler,
+ feedback_stream, check_cancel, NULL, pool);
+
+ if (svn_error_find_cause(err, SVN_ERR_BAD_PROPERTY_VALUE_EOL))
+ {
+ return svn_error_quick_wrap(err,
+ _("A property with invalid line ending "
+ "found in dumpstream; consider using "
+ "--normalize-props while loading."));
+ }
+ else if (err && err->apr_err == SVN_ERR_BAD_PROPERTY_VALUE)
+ {
+ return svn_error_quick_wrap(err,
+ _("Invalid property value found in "
+ "dumpstream; consider repairing the "
+ "source or using --bypass-prop-validation "
+ "while loading."));
+ }
+
+ return err;
+}
/* This implements `svn_opt_subcommand_t'. */
static svn_error_t *
@@ -1434,21 +1736,46 @@ subcommand_lstxns(apr_getopt_t *os, void *baton, apr_pool_t *pool)
svn_repos_t *repos;
svn_fs_t *fs;
apr_array_header_t *txns;
+ apr_pool_t *iterpool;
+ svn_revnum_t youngest, limit;
int i;
/* Expect no more arguments. */
SVN_ERR(parse_args(NULL, os, 0, 0, pool));
+ if (opt_state->end_revision.kind != svn_opt_revision_unspecified)
+ return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("Revision range is not allowed"));
- SVN_ERR(open_repos(&repos, opt_state->repository_path, pool));
+ SVN_ERR(open_repos(&repos, opt_state->repository_path, opt_state, pool));
fs = svn_repos_fs(repos);
SVN_ERR(svn_fs_list_transactions(&txns, fs, pool));
- /* Loop, printing revisions. */
+ SVN_ERR(svn_fs_youngest_rev(&youngest, fs, pool));
+ SVN_ERR(get_revnum(&limit, &opt_state->start_revision, youngest, repos,
+ pool));
+
+ iterpool = svn_pool_create(pool);
for (i = 0; i < txns->nelts; i++)
{
- SVN_ERR(svn_cmdline_printf(pool, "%s\n",
- APR_ARRAY_IDX(txns, i, const char *)));
+ const char *name = APR_ARRAY_IDX(txns, i, const char *);
+ svn_boolean_t show = TRUE;
+
+ svn_pool_clear(iterpool);
+ if (limit != SVN_INVALID_REVNUM)
+ {
+ svn_fs_txn_t *txn;
+ svn_revnum_t base;
+
+ SVN_ERR(svn_fs_open_txn(&txn, fs, name, iterpool));
+ base = svn_fs_txn_base_revision(txn);
+
+ if (base > limit)
+ show = FALSE;
+ }
+ if (show)
+ SVN_ERR(svn_cmdline_printf(pool, "%s\n", name));
}
+ svn_pool_destroy(iterpool);
return SVN_NO_ERROR;
}
@@ -1472,7 +1799,7 @@ subcommand_recover(apr_getopt_t *os, void *baton, apr_pool_t *pool)
/* Restore default signal handlers until after we have acquired the
* exclusive lock so that the user interrupt before we actually
* touch the repository. */
- setup_cancellation_signals(SIG_DFL);
+ svn_cmdline__disable_cancellation_handler();
err = svn_repos_recover4(opt_state->repository_path, TRUE,
repos_notify_handler, feedback_stream,
@@ -1502,7 +1829,7 @@ subcommand_recover(apr_getopt_t *os, void *baton, apr_pool_t *pool)
/* Since db transactions may have been replayed, it's nice to tell
people what the latest revision is. It also proves that the
recovery actually worked. */
- SVN_ERR(open_repos(&repos, opt_state->repository_path, pool));
+ SVN_ERR(open_repos(&repos, opt_state->repository_path, opt_state, pool));
SVN_ERR(svn_fs_youngest_rev(&youngest_rev, svn_repos_fs(repos), pool));
SVN_ERR(svn_cmdline_printf(pool, _("The latest repos revision is %ld.\n"),
youngest_rev));
@@ -1533,12 +1860,12 @@ list_dblogs(apr_getopt_t *os, void *baton, svn_boolean_t only_unused,
style before printing. */
for (i = 0; i < logfiles->nelts; i++)
{
- const char *log_utf8;
- log_utf8 = svn_dirent_join(opt_state->repository_path,
+ const char *log_path;
+ log_path = svn_dirent_join(opt_state->repository_path,
APR_ARRAY_IDX(logfiles, i, const char *),
pool);
- log_utf8 = svn_dirent_local_style(log_utf8, pool);
- SVN_ERR(svn_cmdline_printf(pool, "%s\n", log_utf8));
+ log_path = svn_dirent_local_style(log_path, pool);
+ SVN_ERR(svn_cmdline_printf(pool, "%s\n", log_path));
}
return SVN_NO_ERROR;
@@ -1578,24 +1905,21 @@ subcommand_rmtxns(apr_getopt_t *os, void *baton, apr_pool_t *pool)
int i;
apr_pool_t *subpool = svn_pool_create(pool);
- SVN_ERR(svn_opt_parse_all_args(&args, os, pool));
+ SVN_ERR(parse_args(&args, os, -1, -1, pool));
- SVN_ERR(open_repos(&repos, opt_state->repository_path, pool));
+ SVN_ERR(open_repos(&repos, opt_state->repository_path, opt_state, pool));
fs = svn_repos_fs(repos);
/* All the rest of the arguments are transaction names. */
for (i = 0; i < args->nelts; i++)
{
const char *txn_name = APR_ARRAY_IDX(args, i, const char *);
- const char *txn_name_utf8;
svn_error_t *err;
svn_pool_clear(subpool);
- SVN_ERR(svn_utf_cstring_to_utf8(&txn_name_utf8, txn_name, subpool));
-
/* Try to open the txn. If that succeeds, try to abort it. */
- err = svn_fs_open_txn(&txn, fs, txn_name_utf8, subpool);
+ err = svn_fs_open_txn(&txn, fs, txn_name, subpool);
if (! err)
err = svn_fs_abort_txn(txn, subpool);
@@ -1606,7 +1930,7 @@ subcommand_rmtxns(apr_getopt_t *os, void *baton, apr_pool_t *pool)
if (err && (err->apr_err == SVN_ERR_FS_TRANSACTION_DEAD))
{
svn_error_clear(err);
- err = svn_fs_purge_txn(fs, txn_name_utf8, subpool);
+ err = svn_fs_purge_txn(fs, txn_name, subpool);
}
/* If we had a real from the txn open, abort, or purge, we clear
@@ -1660,7 +1984,7 @@ set_revprop(const char *prop_name, const char *filename,
}
/* Open the filesystem */
- SVN_ERR(open_repos(&repos, opt_state->repository_path, pool));
+ SVN_ERR(open_repos(&repos, opt_state->repository_path, opt_state, pool));
if (opt_state->txn_id)
{
@@ -1736,7 +2060,7 @@ subcommand_setuuid(apr_getopt_t *os, void *baton, apr_pool_t *pool)
if (args->nelts == 1)
uuid = APR_ARRAY_IDX(args, 0, const char *);
- SVN_ERR(open_repos(&repos, opt_state->repository_path, pool));
+ SVN_ERR(open_repos(&repos, opt_state->repository_path, opt_state, pool));
fs = svn_repos_fs(repos);
return svn_fs_set_uuid(fs, uuid, pool);
}
@@ -1784,7 +2108,7 @@ subcommand_pack(apr_getopt_t *os, void *baton, apr_pool_t *pool)
/* Expect no more arguments. */
SVN_ERR(parse_args(NULL, os, 0, 0, pool));
- SVN_ERR(open_repos(&repos, opt_state->repository_path, pool));
+ SVN_ERR(open_repos(&repos, opt_state->repository_path, opt_state, pool));
/* Progress feedback goes to STDOUT, unless they asked to suppress it. */
if (! opt_state->quiet)
@@ -1819,7 +2143,7 @@ subcommand_verify(apr_getopt_t *os, void *baton, apr_pool_t *pool)
"are mutually exclusive"));
}
- SVN_ERR(open_repos(&repos, opt_state->repository_path, pool));
+ SVN_ERR(open_repos(&repos, opt_state->repository_path, opt_state, pool));
fs = svn_repos_fs(repos);
SVN_ERR(svn_fs_youngest_rev(&youngest, fs, pool));
@@ -1970,11 +2294,12 @@ subcommand_info(apr_getopt_t *os, void *baton, apr_pool_t *pool)
svn_fs_t *fs;
int fs_format;
const char *uuid;
+ svn_revnum_t head_rev;
/* Expect no more arguments. */
SVN_ERR(parse_args(NULL, os, 0, 0, pool));
- SVN_ERR(open_repos(&repos, opt_state->repository_path, pool));
+ SVN_ERR(open_repos(&repos, opt_state->repository_path, opt_state, pool));
fs = svn_repos_fs(repos);
SVN_ERR(svn_cmdline_printf(pool, _("Path: %s\n"),
svn_dirent_local_style(svn_repos_path(repos, pool),
@@ -1982,6 +2307,9 @@ subcommand_info(apr_getopt_t *os, void *baton, apr_pool_t *pool)
SVN_ERR(svn_fs_get_uuid(fs, &uuid, pool));
SVN_ERR(svn_cmdline_printf(pool, _("UUID: %s\n"), uuid));
+
+ SVN_ERR(svn_fs_youngest_rev(&head_rev, fs, pool));
+ SVN_ERR(svn_cmdline_printf(pool, _("Revisions: %ld\n"), head_rev));
{
int repos_format, minor;
svn_version_t *repos_version, *fs_version;
@@ -2036,8 +2364,6 @@ subcommand_info(apr_getopt_t *os, void *baton, apr_pool_t *pool)
if (!strcmp(info->fs_type, SVN_FS_TYPE_FSFS))
{
const svn_fs_fsfs_info_t *fsfs_info = (const void *)info;
- svn_revnum_t youngest;
- SVN_ERR(svn_fs_youngest_rev(&youngest, fs, pool));
if (fsfs_info->shard_size)
SVN_ERR(svn_cmdline_printf(pool, _("FSFS Sharded: yes\n")));
@@ -2053,7 +2379,7 @@ subcommand_info(apr_getopt_t *os, void *baton, apr_pool_t *pool)
{
const int shard_size = fsfs_info->shard_size;
const long shards_packed = fsfs_info->min_unpacked_rev / shard_size;
- const long shards_full = (youngest + 1) / shard_size;
+ const long shards_full = (head_rev + 1) / shard_size;
SVN_ERR(svn_cmdline_printf(pool, _("FSFS Shards Packed: %ld/%ld\n"),
shards_packed, shards_full));
}
@@ -2063,6 +2389,19 @@ subcommand_info(apr_getopt_t *os, void *baton, apr_pool_t *pool)
else
SVN_ERR(svn_cmdline_printf(pool, _("FSFS Logical Addressing: no\n")));
}
+ else if (!strcmp(info->fs_type, SVN_FS_TYPE_FSX))
+ {
+ const svn_fs_fsx_info_t *fsx_info = (const void *)info;
+
+ const int shard_size = fsx_info->shard_size;
+ const long shards_packed = fsx_info->min_unpacked_rev / shard_size;
+ long shards_full = (head_rev + 1) / shard_size;
+
+ SVN_ERR(svn_cmdline_printf(pool, _("FSX Shard Size: %d\n"),
+ shard_size));
+ SVN_ERR(svn_cmdline_printf(pool, _("FSX Shards Packed: %ld/%ld\n"),
+ shards_packed, shards_full));
+ }
}
{
@@ -2097,7 +2436,6 @@ subcommand_lock(apr_getopt_t *os, void *baton, apr_pool_t *pool)
const char *lock_path;
const char *comment_file_name;
svn_stringbuf_t *file_contents;
- const char *lock_path_utf8;
svn_lock_t *lock;
const char *lock_token = NULL;
@@ -2113,7 +2451,7 @@ subcommand_lock(apr_getopt_t *os, void *baton, apr_pool_t *pool)
SVN_ERR(target_arg_to_dirent(&comment_file_name, comment_file_name, pool));
- SVN_ERR(open_repos(&repos, opt_state->repository_path, pool));
+ SVN_ERR(open_repos(&repos, opt_state->repository_path, opt_state, pool));
fs = svn_repos_fs(repos);
/* Create an access context describing the user. */
@@ -2124,10 +2462,10 @@ subcommand_lock(apr_getopt_t *os, void *baton, apr_pool_t *pool)
SVN_ERR(svn_stringbuf_from_file2(&file_contents, comment_file_name, pool));
- SVN_ERR(svn_utf_cstring_to_utf8(&lock_path_utf8, lock_path, pool));
+ SVN_ERR(target_arg_to_fspath(&lock_path, lock_path, pool, pool));
if (opt_state->bypass_hooks)
- SVN_ERR(svn_fs_lock(&lock, fs, lock_path_utf8,
+ SVN_ERR(svn_fs_lock(&lock, fs, lock_path,
lock_token,
file_contents->data, /* comment */
0, /* is_dav_comment */
@@ -2135,7 +2473,7 @@ subcommand_lock(apr_getopt_t *os, void *baton, apr_pool_t *pool)
SVN_INVALID_REVNUM,
FALSE, pool));
else
- SVN_ERR(svn_repos_fs_lock(&lock, repos, lock_path_utf8,
+ SVN_ERR(svn_repos_fs_lock(&lock, repos, lock_path,
lock_token,
file_contents->data, /* comment */
0, /* is_dav_comment */
@@ -2143,8 +2481,10 @@ subcommand_lock(apr_getopt_t *os, void *baton, apr_pool_t *pool)
SVN_INVALID_REVNUM,
FALSE, pool));
- SVN_ERR(svn_cmdline_printf(pool, _("'%s' locked by user '%s'.\n"),
- lock_path, username));
+ if (! opt_state->quiet)
+ SVN_ERR(svn_cmdline_printf(pool, _("'%s' locked by user '%s'.\n"),
+ lock_path, username));
+
return SVN_NO_ERROR;
}
@@ -2154,7 +2494,7 @@ subcommand_lslocks(apr_getopt_t *os, void *baton, apr_pool_t *pool)
struct svnadmin_opt_state *opt_state = baton;
apr_array_header_t *targets;
svn_repos_t *repos;
- const char *fs_path = "/";
+ const char *fs_path;
apr_hash_t *locks;
apr_hash_index_t *hi;
apr_pool_t *iterpool = svn_pool_create(pool);
@@ -2168,8 +2508,11 @@ subcommand_lslocks(apr_getopt_t *os, void *baton, apr_pool_t *pool)
_("Too many arguments given"));
if (targets->nelts)
fs_path = APR_ARRAY_IDX(targets, 0, const char *);
+ else
+ fs_path = "/";
+ SVN_ERR(target_arg_to_fspath(&fs_path, fs_path, pool, pool));
- SVN_ERR(open_repos(&repos, opt_state->repository_path, pool));
+ SVN_ERR(open_repos(&repos, opt_state->repository_path, opt_state, pool));
/* Fetch all locks on or below the root directory. */
SVN_ERR(svn_repos_fs_get_locks2(&locks, repos, fs_path, svn_depth_infinity,
@@ -2227,7 +2570,7 @@ subcommand_rmlocks(apr_getopt_t *os, void *baton, apr_pool_t *pool)
const char *username;
apr_pool_t *subpool = svn_pool_create(pool);
- SVN_ERR(open_repos(&repos, opt_state->repository_path, pool));
+ SVN_ERR(open_repos(&repos, opt_state->repository_path, opt_state, pool));
fs = svn_repos_fs(repos);
/* svn_fs_unlock() demands that some username be associated with the
@@ -2243,7 +2586,7 @@ subcommand_rmlocks(apr_getopt_t *os, void *baton, apr_pool_t *pool)
SVN_ERR(svn_fs_set_access(fs, access));
/* Parse out any options. */
- SVN_ERR(svn_opt_parse_all_args(&args, os, pool));
+ SVN_ERR(parse_args(&args, os, -1, -1, pool));
/* Our usage requires at least one FS path. */
if (args->nelts == 0)
@@ -2254,31 +2597,34 @@ subcommand_rmlocks(apr_getopt_t *os, void *baton, apr_pool_t *pool)
for (i = 0; i < args->nelts; i++)
{
const char *lock_path = APR_ARRAY_IDX(args, i, const char *);
- const char *lock_path_utf8;
svn_lock_t *lock;
- SVN_ERR(svn_utf_cstring_to_utf8(&lock_path_utf8, lock_path, subpool));
+ SVN_ERR(target_arg_to_fspath(&lock_path, lock_path, subpool, subpool));
/* Fetch the path's svn_lock_t. */
- err = svn_fs_get_lock(&lock, fs, lock_path_utf8, subpool);
+ err = svn_fs_get_lock(&lock, fs, lock_path, subpool);
if (err)
goto move_on;
if (! lock)
{
- SVN_ERR(svn_cmdline_printf(subpool,
- _("Path '%s' isn't locked.\n"),
- lock_path));
+ if (! opt_state->quiet)
+ SVN_ERR(svn_cmdline_printf(subpool,
+ _("Path '%s' isn't locked.\n"),
+ lock_path));
continue;
}
+ lock = NULL; /* Don't access LOCK after this point. */
/* Now forcibly destroy the lock. */
- err = svn_fs_unlock(fs, lock_path_utf8,
- lock->token, 1 /* force */, subpool);
+ err = svn_fs_unlock(fs, lock_path,
+ NULL, 1 /* force */, subpool);
if (err)
goto move_on;
- SVN_ERR(svn_cmdline_printf(subpool,
- _("Removed lock on '%s'.\n"), lock->path));
+ if (! opt_state->quiet)
+ SVN_ERR(svn_cmdline_printf(subpool,
+ _("Removed lock on '%s'.\n"),
+ lock_path));
move_on:
if (err)
@@ -2307,7 +2653,6 @@ subcommand_unlock(apr_getopt_t *os, void *baton, apr_pool_t *pool)
apr_array_header_t *args;
const char *username;
const char *lock_path;
- const char *lock_path_utf8;
const char *lock_token = NULL;
/* Expect three more arguments: PATH USERNAME TOKEN */
@@ -2318,21 +2663,23 @@ subcommand_unlock(apr_getopt_t *os, void *baton, apr_pool_t *pool)
/* Open the repos/FS, and associate an access context containing
USERNAME. */
- SVN_ERR(open_repos(&repos, opt_state->repository_path, pool));
+ SVN_ERR(open_repos(&repos, opt_state->repository_path, opt_state, pool));
fs = svn_repos_fs(repos);
SVN_ERR(svn_fs_create_access(&access, username, pool));
SVN_ERR(svn_fs_set_access(fs, access));
- SVN_ERR(svn_utf_cstring_to_utf8(&lock_path_utf8, lock_path, pool));
+ SVN_ERR(target_arg_to_fspath(&lock_path, lock_path, pool, pool));
if (opt_state->bypass_hooks)
- SVN_ERR(svn_fs_unlock(fs, lock_path_utf8, lock_token,
+ SVN_ERR(svn_fs_unlock(fs, lock_path, lock_token,
FALSE, pool));
else
- SVN_ERR(svn_repos_fs_unlock(repos, lock_path_utf8, lock_token,
+ SVN_ERR(svn_repos_fs_unlock(repos, lock_path, lock_token,
FALSE, pool));
- SVN_ERR(svn_cmdline_printf(pool, _("'%s' unlocked by user '%s'.\n"),
- lock_path, username));
+ if (! opt_state->quiet)
+ SVN_ERR(svn_cmdline_printf(pool, _("'%s' unlocked by user '%s'.\n"),
+ lock_path, username));
+
return SVN_NO_ERROR;
}
@@ -2351,7 +2698,7 @@ subcommand_upgrade(apr_getopt_t *os, void *baton, apr_pool_t *pool)
SVN_ERR(svn_stream_for_stdout(&feedback_stream, pool));
/* Restore default signal handlers. */
- setup_cancellation_signals(SIG_DFL);
+ svn_cmdline__disable_cancellation_handler();
err = svn_repos_upgrade2(opt_state->repository_path, TRUE,
repos_notify_handler, feedback_stream, pool);
@@ -2532,14 +2879,17 @@ sub_main(int *exit_code, int argc, const char *argv[], apr_pool_t *pool)
opt_state.help = TRUE;
break;
case 'M':
- opt_state.memory_cache_size
- = 0x100000 * apr_strtoi64(opt_arg, NULL, 0);
+ {
+ apr_uint64_t sz_val;
+ SVN_ERR(svn_cstring_atoui64(&sz_val, opt_arg));
+
+ opt_state.memory_cache_size = 0x100000 * sz_val;
+ }
break;
case 'F':
- SVN_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
- SVN_ERR(svn_stringbuf_from_file2(&(opt_state.filedata),
- utf8_opt_arg, pool));
+ SVN_ERR(svn_utf_cstring_to_utf8(&(opt_state.file), opt_arg, pool));
dash_F_arg = TRUE;
+ break;
case svnadmin__version:
opt_state.version = TRUE;
break;
@@ -2662,6 +3012,29 @@ sub_main(int *exit_code, int argc, const char *argv[], apr_pool_t *pool)
case svnadmin__wait:
opt_state.wait = TRUE;
break;
+ case svnadmin__no_flush_to_disk:
+ opt_state.no_flush_to_disk = TRUE;
+ break;
+ case svnadmin__normalize_props:
+ opt_state.normalize_props = TRUE;
+ break;
+ case svnadmin__exclude:
+ SVN_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
+
+ if (! opt_state.exclude)
+ opt_state.exclude = apr_array_make(pool, 1, sizeof(const char *));
+ APR_ARRAY_PUSH(opt_state.exclude, const char *) = utf8_opt_arg;
+ break;
+ case svnadmin__include:
+ SVN_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
+
+ if (! opt_state.include)
+ opt_state.include = apr_array_make(pool, 1, sizeof(const char *));
+ APR_ARRAY_PUSH(opt_state.include, const char *) = utf8_opt_arg;
+ break;
+ case svnadmin__glob:
+ opt_state.glob = TRUE;
+ break;
default:
{
SVN_ERR(subcommand_help(NULL, NULL, pool));
@@ -2706,17 +3079,17 @@ sub_main(int *exit_code, int argc, const char *argv[], apr_pool_t *pool)
}
else
{
- const char *first_arg = os->argv[os->ind++];
+ const char *first_arg;
+
+ SVN_ERR(svn_utf_cstring_to_utf8(&first_arg, os->argv[os->ind++],
+ pool));
subcommand = svn_opt_get_canonical_subcommand2(cmd_table, first_arg);
if (subcommand == NULL)
{
- const char *first_arg_utf8;
- SVN_ERR(svn_utf_cstring_to_utf8(&first_arg_utf8,
- first_arg, pool));
svn_error_clear(
svn_cmdline_fprintf(stderr, pool,
_("Unknown subcommand: '%s'\n"),
- first_arg_utf8));
+ first_arg));
SVN_ERR(subcommand_help(NULL, NULL, pool));
*exit_code = EXIT_FAILURE;
return SVN_NO_ERROR;
@@ -2781,20 +3154,7 @@ sub_main(int *exit_code, int argc, const char *argv[], apr_pool_t *pool)
}
}
- /* Set up our cancellation support. */
- setup_cancellation_signals(signal_handler);
-
-#ifdef SIGPIPE
- /* Disable SIGPIPE generation for the platforms that have it. */
- apr_signal(SIGPIPE, SIG_IGN);
-#endif
-
-#ifdef SIGXFSZ
- /* Disable SIGXFSZ generation for the platforms that have it, otherwise
- * working with large files when compiled against an APR that doesn't have
- * large file support will crash the program, which is uncool. */
- apr_signal(SIGXFSZ, SIG_IGN);
-#endif
+ check_cancel = svn_cmdline__setup_cancellation_handler();
/* Configure FSFS caches for maximum efficiency with svnadmin.
* Also, apply the respective command line parameters, if given. */
@@ -2854,5 +3214,8 @@ main(int argc, const char *argv[])
}
svn_pool_destroy(pool);
+
+ svn_cmdline__cancellation_exit();
+
return exit_code;
}