diff options
author | Peter Wemm <peter@FreeBSD.org> | 2018-05-08 03:44:38 +0000 |
---|---|---|
committer | Peter Wemm <peter@FreeBSD.org> | 2018-05-08 03:44:38 +0000 |
commit | 3faf8d6bffc5d0fb2525ba37bb504c53366caf9d (patch) | |
tree | 7e47911263e75034b767fe34b2f8d3d17e91f66d /subversion/libsvn_repos/replay.c | |
parent | a55fb3c0d5eca7d887798125d5b95942b1f01d4b (diff) |
Diffstat (limited to 'subversion/libsvn_repos/replay.c')
-rw-r--r-- | subversion/libsvn_repos/replay.c | 193 |
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(©from_root, ©from_path, ©from_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. */ |