aboutsummaryrefslogtreecommitdiff
path: root/subversion/libsvn_repos/replay.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/libsvn_repos/replay.c
parenta55fb3c0d5eca7d887798125d5b95942b1f01d4b (diff)
Diffstat (limited to 'subversion/libsvn_repos/replay.c')
-rw-r--r--subversion/libsvn_repos/replay.c193
1 files changed, 93 insertions, 100 deletions
diff --git a/subversion/libsvn_repos/replay.c b/subversion/libsvn_repos/replay.c
index bcf260c47a04..9bcc667f6da4 100644
--- a/subversion/libsvn_repos/replay.c
+++ b/subversion/libsvn_repos/replay.c
@@ -198,7 +198,7 @@ add_subdir(svn_fs_root_t *source_root,
for (hi = apr_hash_first(pool, dirents); hi; hi = apr_hash_next(hi))
{
- svn_fs_path_change2_t *change;
+ svn_fs_path_change3_t *change;
svn_boolean_t readable = TRUE;
svn_fs_dirent_t *dent = apr_hash_this_val(hi);
const char *copyfrom_path = NULL;
@@ -412,7 +412,7 @@ fill_copyfrom(svn_fs_root_t **copyfrom_root,
svn_revnum_t *copyfrom_rev,
svn_boolean_t *src_readable,
svn_fs_root_t *root,
- svn_fs_path_change2_t *change,
+ svn_fs_path_change3_t *change,
svn_repos_authz_func_t authz_read_func,
void *authz_read_baton,
const char *path,
@@ -463,7 +463,7 @@ path_driver_cb_func(void **dir_baton,
const svn_delta_editor_t *editor = cb->editor;
void *edit_baton = cb->edit_baton;
svn_fs_root_t *root = cb->root;
- svn_fs_path_change2_t *change;
+ svn_fs_path_change3_t *change;
svn_boolean_t do_add = FALSE, do_delete = FALSE;
void *file_baton = NULL;
svn_revnum_t copyfrom_rev;
@@ -555,10 +555,6 @@ path_driver_cb_func(void **dir_baton,
return svn_error_create(SVN_ERR_FS_ALREADY_EXISTS, NULL,
_("Root directory already exists."));
- /* A NULL parent_baton will cause a segfault. It should never be
- NULL for non-root paths. */
- SVN_ERR_ASSERT(parent_baton);
-
/* Was this node copied? */
SVN_ERR(fill_copyfrom(&copyfrom_root, &copyfrom_path, &copyfrom_rev,
&src_readable, root, change,
@@ -847,6 +843,80 @@ fetch_props_func(apr_hash_t **props,
+/* Retrieve the path changes under ROOT, filter them with AUTHZ_READ_FUNC
+ and AUTHZ_READ_BATON and return those that intersect with BASE_RELPATH.
+
+ The svn_fs_path_change3_t* will be returned in *CHANGED_PATHS, keyed by
+ their path. The paths themselves are additionally returned in *PATHS.
+
+ Allocate the returned data in RESULT_POOL and use SCRATCH_POOL for
+ temporary allocations.
+ */
+static svn_error_t *
+get_relevant_changes(apr_hash_t **changed_paths,
+ apr_array_header_t **paths,
+ svn_fs_root_t *root,
+ const char *base_relpath,
+ svn_repos_authz_func_t authz_read_func,
+ void *authz_read_baton,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ svn_fs_path_change_iterator_t *iterator;
+ svn_fs_path_change3_t *change;
+ apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+
+ /* Fetch the paths changed under ROOT. */
+ SVN_ERR(svn_fs_paths_changed3(&iterator, root, scratch_pool, scratch_pool));
+ SVN_ERR(svn_fs_path_change_get(&change, iterator));
+
+ /* Make an array from the keys of our CHANGED_PATHS hash, and copy
+ the values into a new hash whose keys have no leading slashes. */
+ *paths = apr_array_make(result_pool, 16, sizeof(const char *));
+ *changed_paths = apr_hash_make(result_pool);
+ while (change)
+ {
+ const char *path = change->path.data;
+ apr_ssize_t keylen = change->path.len;
+ svn_boolean_t allowed = TRUE;
+
+ svn_pool_clear(iterpool);
+ if (authz_read_func)
+ SVN_ERR(authz_read_func(&allowed, root, path, authz_read_baton,
+ iterpool));
+
+ if (allowed)
+ {
+ if (path[0] == '/')
+ {
+ path++;
+ keylen--;
+ }
+
+ /* If the base_path doesn't match the top directory of this path
+ we don't want anything to do with it...
+ ...unless this was a change to one of the parent directories of
+ base_path. */
+ if ( svn_relpath_skip_ancestor(base_relpath, path)
+ || svn_relpath_skip_ancestor(path, base_relpath))
+ {
+ change = svn_fs_path_change3_dup(change, result_pool);
+ path = change->path.data;
+ if (path[0] == '/')
+ path++;
+
+ APR_ARRAY_PUSH(*paths, const char *) = path;
+ apr_hash_set(*changed_paths, path, keylen, change);
+ }
+ }
+
+ SVN_ERR(svn_fs_path_change_get(&change, iterator));
+ }
+
+ svn_pool_destroy(iterpool);
+ return SVN_NO_ERROR;
+}
+
svn_error_t *
svn_repos_replay2(svn_fs_root_t *root,
const char *base_path,
@@ -859,9 +929,7 @@ svn_repos_replay2(svn_fs_root_t *root,
apr_pool_t *pool)
{
#ifndef USE_EV2_IMPL
- apr_hash_t *fs_changes;
apr_hash_t *changed_paths;
- apr_hash_index_t *hi;
apr_array_header_t *paths;
struct path_driver_cb_baton cb_baton;
@@ -873,54 +941,15 @@ svn_repos_replay2(svn_fs_root_t *root,
return SVN_NO_ERROR;
}
- /* Fetch the paths changed under ROOT. */
- SVN_ERR(svn_fs_paths_changed2(&fs_changes, root, pool));
-
if (! base_path)
base_path = "";
else if (base_path[0] == '/')
++base_path;
- /* Make an array from the keys of our CHANGED_PATHS hash, and copy
- the values into a new hash whose keys have no leading slashes. */
- paths = apr_array_make(pool, apr_hash_count(fs_changes),
- sizeof(const char *));
- changed_paths = apr_hash_make(pool);
- for (hi = apr_hash_first(pool, fs_changes); hi; hi = apr_hash_next(hi))
- {
- const char *path = apr_hash_this_key(hi);
- apr_ssize_t keylen = apr_hash_this_key_len(hi);
- svn_fs_path_change2_t *change = apr_hash_this_val(hi);
- svn_boolean_t allowed = TRUE;
-
- if (authz_read_func)
- SVN_ERR(authz_read_func(&allowed, root, path, authz_read_baton,
- pool));
-
- if (allowed)
- {
- if (path[0] == '/')
- {
- path++;
- keylen--;
- }
-
- /* If the base_path doesn't match the top directory of this path
- we don't want anything to do with it... */
- if (svn_relpath_skip_ancestor(base_path, path) != NULL)
- {
- APR_ARRAY_PUSH(paths, const char *) = path;
- apr_hash_set(changed_paths, path, keylen, change);
- }
- /* ...unless this was a change to one of the parent directories of
- base_path. */
- else if (svn_relpath_skip_ancestor(path, base_path) != NULL)
- {
- APR_ARRAY_PUSH(paths, const char *) = path;
- apr_hash_set(changed_paths, path, keylen, change);
- }
- }
- }
+ /* Fetch the paths changed under ROOT. */
+ SVN_ERR(get_relevant_changes(&changed_paths, &paths, root, base_path,
+ authz_read_func, authz_read_baton,
+ pool, pool));
/* If we were not given a low water mark, assume that everything is there,
all the way back to revision 0. */
@@ -971,6 +1000,11 @@ svn_repos_replay2(svn_fs_root_t *root,
const char *repos_root = "";
void *unlock_baton;
+ /* If we were not given a low water mark, assume that everything is there,
+ all the way back to revision 0. */
+ if (! SVN_IS_VALID_REVNUM(low_water_mark))
+ low_water_mark = 0;
+
/* Special-case r0, which we know is an empty revision; if we don't
special-case it we might end up trying to compare it to "r-1". */
if (svn_fs_is_revision_root(root)
@@ -1061,7 +1095,7 @@ add_subdir_ev2(svn_fs_root_t *source_root,
for (hi = apr_hash_first(scratch_pool, dirents); hi; hi = apr_hash_next(hi))
{
- svn_fs_path_change2_t *change;
+ svn_fs_path_change3_t *change;
svn_boolean_t readable = TRUE;
svn_fs_dirent_t *dent = apr_hash_this_val(hi);
const char *copyfrom_path = NULL;
@@ -1189,7 +1223,7 @@ replay_node(svn_fs_root_t *root,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
- svn_fs_path_change2_t *change;
+ svn_fs_path_change3_t *change;
svn_boolean_t do_add = FALSE;
svn_boolean_t do_delete = FALSE;
svn_revnum_t copyfrom_rev;
@@ -1484,16 +1518,14 @@ svn_repos__replay_ev2(svn_fs_root_t *root,
void *authz_read_baton,
apr_pool_t *scratch_pool)
{
- apr_hash_t *fs_changes;
apr_hash_t *changed_paths;
- apr_hash_index_t *hi;
apr_array_header_t *paths;
apr_array_header_t *copies;
apr_pool_t *iterpool;
svn_error_t *err = SVN_NO_ERROR;
int i;
- SVN_ERR_ASSERT(!svn_dirent_is_absolute(base_repos_relpath));
+ SVN_ERR_ASSERT(svn_relpath_is_canonical(base_repos_relpath));
/* Special-case r0, which we know is an empty revision; if we don't
special-case it we might end up trying to compare it to "r-1". */
@@ -1504,49 +1536,10 @@ svn_repos__replay_ev2(svn_fs_root_t *root,
}
/* Fetch the paths changed under ROOT. */
- SVN_ERR(svn_fs_paths_changed2(&fs_changes, root, scratch_pool));
-
- /* Make an array from the keys of our CHANGED_PATHS hash, and copy
- the values into a new hash whose keys have no leading slashes. */
- paths = apr_array_make(scratch_pool, apr_hash_count(fs_changes),
- sizeof(const char *));
- changed_paths = apr_hash_make(scratch_pool);
- for (hi = apr_hash_first(scratch_pool, fs_changes); hi;
- hi = apr_hash_next(hi))
- {
- const char *path = apr_hash_this_key(hi);
- apr_ssize_t keylen = apr_hash_this_key_len(hi);
- svn_fs_path_change2_t *change = apr_hash_this_val(hi);
- svn_boolean_t allowed = TRUE;
-
- if (authz_read_func)
- SVN_ERR(authz_read_func(&allowed, root, path, authz_read_baton,
- scratch_pool));
-
- if (allowed)
- {
- if (path[0] == '/')
- {
- path++;
- keylen--;
- }
-
- /* If the base_path doesn't match the top directory of this path
- we don't want anything to do with it... */
- if (svn_relpath_skip_ancestor(base_repos_relpath, path) != NULL)
- {
- APR_ARRAY_PUSH(paths, const char *) = path;
- apr_hash_set(changed_paths, path, keylen, change);
- }
- /* ...unless this was a change to one of the parent directories of
- base_path. */
- else if (svn_relpath_skip_ancestor(path, base_repos_relpath) != NULL)
- {
- APR_ARRAY_PUSH(paths, const char *) = path;
- apr_hash_set(changed_paths, path, keylen, change);
- }
- }
- }
+ SVN_ERR(get_relevant_changes(&changed_paths, &paths, root,
+ base_repos_relpath,
+ authz_read_func, authz_read_baton,
+ scratch_pool, scratch_pool));
/* If we were not given a low water mark, assume that everything is there,
all the way back to revision 0. */