diff options
author | Lorry Tar Creator <lorry-tar-importer@baserock.org> | 2015-03-18 13:33:26 +0000 |
---|---|---|
committer | <> | 2015-07-08 14:41:01 +0000 |
commit | bb0ef45f7c46b0ae221b26265ef98a768c33f820 (patch) | |
tree | 98bae10dde41c746c51ae97ec4f879e330415aa7 /subversion/libsvn_repos/log.c | |
parent | 239dfafe71711b2f4c43d7b90a1228d7bdc5195e (diff) | |
download | subversion-tarball-subversion-1.8.13.tar.gz |
Imported from /home/lorry/working-area/delta_subversion-tarball/subversion-1.8.13.tar.gz.subversion-1.8.13
Diffstat (limited to 'subversion/libsvn_repos/log.c')
-rw-r--r-- | subversion/libsvn_repos/log.c | 353 |
1 files changed, 244 insertions, 109 deletions
diff --git a/subversion/libsvn_repos/log.c b/subversion/libsvn_repos/log.c index c0d00d6..8ca870b 100644 --- a/subversion/libsvn_repos/log.c +++ b/subversion/libsvn_repos/log.c @@ -27,6 +27,7 @@ #include "svn_compat.h" #include "svn_private_config.h" +#include "svn_hash.h" #include "svn_pools.h" #include "svn_error.h" #include "svn_path.h" @@ -39,6 +40,7 @@ #include "repos.h" #include "private/svn_fspath.h" #include "private/svn_mergeinfo_private.h" +#include "private/svn_subr_private.h" @@ -159,6 +161,10 @@ svn_repos_check_revision_access(svn_repos_revision_access_level_t *access_level, * The CHANGED hash set and its keys and values are allocated in POOL; * keys are const char * paths and values are svn_log_changed_path_t. * + * To prevent changes from being processed over and over again, the + * changed paths for ROOT may be passed in PREFETCHED_CHANGES. If the + * latter is NULL, we will request the list inside this function. + * * If optional AUTHZ_READ_FUNC is non-NULL, then use it (with * AUTHZ_READ_BATON and FS) to check whether each changed-path (and * copyfrom_path) is readable: @@ -177,18 +183,20 @@ static svn_error_t * detect_changed(apr_hash_t **changed, svn_fs_root_t *root, svn_fs_t *fs, + apr_hash_t *prefetched_changes, svn_repos_authz_func_t authz_read_func, void *authz_read_baton, apr_pool_t *pool) { - apr_hash_t *changes; + apr_hash_t *changes = prefetched_changes; apr_hash_index_t *hi; apr_pool_t *subpool; svn_boolean_t found_readable = FALSE; svn_boolean_t found_unreadable = FALSE; - *changed = apr_hash_make(pool); - SVN_ERR(svn_fs_paths_changed2(&changes, root, pool)); + *changed = svn_hash__make(pool); + if (changes == NULL) + SVN_ERR(svn_fs_paths_changed2(&changes, root, pool)); if (apr_hash_count(changes) == 0) /* No paths changed in this revision? Uh, sure, I guess the @@ -264,13 +272,54 @@ detect_changed(apr_hash_t **changed, : svn_tristate_false; item->props_modified = change->prop_mod ? svn_tristate_true : svn_tristate_false; + + /* Pre-1.6 revision files don't store the change path kind, so fetch + it manually. */ + if (item->node_kind == svn_node_unknown) + { + svn_fs_root_t *check_root = root; + const char *check_path = path; + + /* Deleted items don't exist so check earlier revision. We + know the parent must exist and could be a copy */ + if (change->change_kind == svn_fs_path_change_delete) + { + svn_fs_history_t *history; + svn_revnum_t prev_rev; + const char *parent_path, *name; + + svn_fspath__split(&parent_path, &name, path, subpool); + + SVN_ERR(svn_fs_node_history(&history, root, parent_path, + subpool)); + + /* Two calls because the first call returns the original + revision as the deleted child means it is 'interesting' */ + SVN_ERR(svn_fs_history_prev(&history, history, TRUE, subpool)); + SVN_ERR(svn_fs_history_prev(&history, history, TRUE, subpool)); + + SVN_ERR(svn_fs_history_location(&parent_path, &prev_rev, history, + subpool)); + SVN_ERR(svn_fs_revision_root(&check_root, fs, prev_rev, subpool)); + check_path = svn_fspath__join(parent_path, name, subpool); + } + + SVN_ERR(svn_fs_check_path(&item->node_kind, check_root, check_path, + subpool)); + } + + if ((action == 'A') || (action == 'R')) { - const char *copyfrom_path; - svn_revnum_t copyfrom_rev; + const char *copyfrom_path = change->copyfrom_path; + svn_revnum_t copyfrom_rev = change->copyfrom_rev; - SVN_ERR(svn_fs_copied_from(©from_rev, ©from_path, - root, path, subpool)); + /* the following is a potentially expensive operation since on FSFS + we will follow the DAG from ROOT to PATH and that requires + actually reading the directories along the way. */ + if (!change->copyfrom_known) + SVN_ERR(svn_fs_copied_from(©from_rev, ©from_path, + root, path, subpool)); if (copyfrom_path && SVN_IS_VALID_REVNUM(copyfrom_rev)) { @@ -296,8 +345,7 @@ detect_changed(apr_hash_t **changed, } } } - apr_hash_set(*changed, apr_pstrdup(pool, path), - APR_HASH_KEY_STRING, item); + svn_hash_sets(*changed, apr_pstrdup(pool, path), item); } svn_pool_destroy(subpool); @@ -514,26 +562,28 @@ next_history_rev(const apr_array_header_t *histories) /* Set *DELETED_MERGEINFO_CATALOG and *ADDED_MERGEINFO_CATALOG to catalogs describing how mergeinfo values on paths (which are the - keys of those catalogs) were changed in REV. */ + keys of those catalogs) were changed in REV. If *PREFETCHED_CAHNGES + already contains the changed paths for REV, use that. Otherwise, + request that data and return it in *PREFETCHED_CHANGES. */ /* ### TODO: This would make a *great*, useful public function, ### svn_repos_fs_mergeinfo_changed()! -- cmpilato */ static svn_error_t * fs_mergeinfo_changed(svn_mergeinfo_catalog_t *deleted_mergeinfo_catalog, svn_mergeinfo_catalog_t *added_mergeinfo_catalog, + apr_hash_t **prefetched_changes, svn_fs_t *fs, svn_revnum_t rev, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { - apr_hash_t *changes; svn_fs_root_t *root; apr_pool_t *iterpool; apr_hash_index_t *hi; /* Initialize return variables. */ - *deleted_mergeinfo_catalog = apr_hash_make(result_pool); - *added_mergeinfo_catalog = apr_hash_make(result_pool); + *deleted_mergeinfo_catalog = svn_hash__make(result_pool); + *added_mergeinfo_catalog = svn_hash__make(result_pool); /* Revision 0 has no mergeinfo and no mergeinfo changes. */ if (rev == 0) @@ -542,17 +592,20 @@ fs_mergeinfo_changed(svn_mergeinfo_catalog_t *deleted_mergeinfo_catalog, /* We're going to use the changed-paths information for REV to narrow down our search. */ SVN_ERR(svn_fs_revision_root(&root, fs, rev, scratch_pool)); - SVN_ERR(svn_fs_paths_changed2(&changes, root, scratch_pool)); + if (*prefetched_changes == NULL) + SVN_ERR(svn_fs_paths_changed2(prefetched_changes, root, scratch_pool)); /* No changed paths? We're done. */ - if (apr_hash_count(changes) == 0) + if (apr_hash_count(*prefetched_changes) == 0) return SVN_NO_ERROR; /* Loop over changes, looking for anything that might carry an svn:mergeinfo change and is one of our paths of interest, or a child or [grand]parent directory thereof. */ iterpool = svn_pool_create(scratch_pool); - for (hi = apr_hash_first(scratch_pool, changes); hi; hi = apr_hash_next(hi)) + for (hi = apr_hash_first(scratch_pool, *prefetched_changes); + hi; + hi = apr_hash_next(hi)) { const void *key; void *val; @@ -663,11 +716,10 @@ fs_mergeinfo_changed(svn_mergeinfo_catalog_t *deleted_mergeinfo_catalog, svn_mergeinfo_catalog_t tmp_catalog; APR_ARRAY_PUSH(query_paths, const char *) = changed_path; - SVN_ERR(svn_fs_get_mergeinfo(&tmp_catalog, root, - query_paths, svn_mergeinfo_inherited, - FALSE, iterpool)); - tmp_mergeinfo = apr_hash_get(tmp_catalog, changed_path, - APR_HASH_KEY_STRING); + SVN_ERR(svn_fs_get_mergeinfo2(&tmp_catalog, root, + query_paths, svn_mergeinfo_inherited, + FALSE, TRUE, iterpool, iterpool)); + tmp_mergeinfo = svn_hash_gets(tmp_catalog, changed_path); if (tmp_mergeinfo) SVN_ERR(svn_mergeinfo_to_string(&mergeinfo_value, tmp_mergeinfo, @@ -682,11 +734,10 @@ fs_mergeinfo_changed(svn_mergeinfo_catalog_t *deleted_mergeinfo_catalog, svn_mergeinfo_catalog_t tmp_catalog; APR_ARRAY_PUSH(query_paths, const char *) = base_path; - SVN_ERR(svn_fs_get_mergeinfo(&tmp_catalog, base_root, - query_paths, svn_mergeinfo_inherited, - FALSE, iterpool)); - tmp_mergeinfo = apr_hash_get(tmp_catalog, base_path, - APR_HASH_KEY_STRING); + SVN_ERR(svn_fs_get_mergeinfo2(&tmp_catalog, base_root, + query_paths, svn_mergeinfo_inherited, + FALSE, TRUE, iterpool, iterpool)); + tmp_mergeinfo = svn_hash_gets(tmp_catalog, base_path); if (tmp_mergeinfo) SVN_ERR(svn_mergeinfo_to_string(&prev_mergeinfo_value, tmp_mergeinfo, @@ -711,17 +762,14 @@ fs_mergeinfo_changed(svn_mergeinfo_catalog_t *deleted_mergeinfo_catalog, if (prev_mergeinfo_value) SVN_ERR(svn_mergeinfo_parse(&prev_mergeinfo, prev_mergeinfo_value->data, iterpool)); - SVN_ERR(svn_mergeinfo_diff(&deleted, &added, prev_mergeinfo, - mergeinfo, FALSE, iterpool)); + SVN_ERR(svn_mergeinfo_diff2(&deleted, &added, prev_mergeinfo, + mergeinfo, FALSE, result_pool, + iterpool)); /* Toss interesting stuff into our return catalogs. */ hash_path = apr_pstrdup(result_pool, changed_path); - apr_hash_set(*deleted_mergeinfo_catalog, hash_path, - APR_HASH_KEY_STRING, svn_mergeinfo_dup(deleted, - result_pool)); - apr_hash_set(*added_mergeinfo_catalog, hash_path, - APR_HASH_KEY_STRING, svn_mergeinfo_dup(added, - result_pool)); + svn_hash_sets(*deleted_mergeinfo_catalog, hash_path, deleted); + svn_hash_sets(*added_mergeinfo_catalog, hash_path, added); } } @@ -733,10 +781,14 @@ fs_mergeinfo_changed(svn_mergeinfo_catalog_t *deleted_mergeinfo_catalog, /* Determine what (if any) mergeinfo for PATHS was modified in revision REV, returning the differences for added mergeinfo in *ADDED_MERGEINFO and deleted mergeinfo in *DELETED_MERGEINFO. + If *PREFETCHED_CAHNGES already contains the changed paths for + REV, use that. Otherwise, request that data and return it in + *PREFETCHED_CHANGES. Use POOL for all allocations. */ static svn_error_t * get_combined_mergeinfo_changes(svn_mergeinfo_t *added_mergeinfo, svn_mergeinfo_t *deleted_mergeinfo, + apr_hash_t **prefetched_changes, svn_fs_t *fs, const apr_array_header_t *paths, svn_revnum_t rev, @@ -751,8 +803,8 @@ get_combined_mergeinfo_changes(svn_mergeinfo_t *added_mergeinfo, svn_error_t *err; /* Initialize return value. */ - *added_mergeinfo = apr_hash_make(result_pool); - *deleted_mergeinfo = apr_hash_make(result_pool); + *added_mergeinfo = svn_hash__make(result_pool); + *deleted_mergeinfo = svn_hash__make(result_pool); /* If we're asking about revision 0, there's no mergeinfo to be found. */ if (rev == 0) @@ -768,6 +820,7 @@ get_combined_mergeinfo_changes(svn_mergeinfo_t *added_mergeinfo, /* Fetch the mergeinfo changes for REV. */ err = fs_mergeinfo_changed(&deleted_mergeinfo_catalog, &added_mergeinfo_catalog, + prefetched_changes, fs, rev, scratch_pool, scratch_pool); if (err) { @@ -785,6 +838,11 @@ get_combined_mergeinfo_changes(svn_mergeinfo_t *added_mergeinfo, } } + /* In most revisions, there will be no mergeinfo change at all. */ + if ( apr_hash_count(deleted_mergeinfo_catalog) == 0 + && apr_hash_count(added_mergeinfo_catalog) == 0) + return SVN_NO_ERROR; + /* Check our PATHS for any changes to their inherited mergeinfo. (We deal with changes to mergeinfo directly *on* the paths in the following loop.) */ @@ -793,17 +851,19 @@ get_combined_mergeinfo_changes(svn_mergeinfo_t *added_mergeinfo, { const char *path = APR_ARRAY_IDX(paths, i, const char *); const char *prev_path; + apr_ssize_t klen; svn_revnum_t appeared_rev, prev_rev; svn_fs_root_t *prev_root; - svn_mergeinfo_catalog_t catalog; - svn_mergeinfo_t prev_mergeinfo, mergeinfo, deleted, added; + svn_mergeinfo_catalog_t catalog, inherited_catalog; + svn_mergeinfo_t prev_mergeinfo, mergeinfo, deleted, added, + prev_inherited_mergeinfo, inherited_mergeinfo; apr_array_header_t *query_paths; svn_pool_clear(iterpool); /* If this path is represented in the changed-mergeinfo hashes, we'll deal with it in the loop below. */ - if (apr_hash_get(deleted_mergeinfo_catalog, path, APR_HASH_KEY_STRING)) + if (svn_hash_gets(deleted_mergeinfo_catalog, path)) continue; /* Figure out what path/rev to compare against. Ignore @@ -835,8 +895,9 @@ get_combined_mergeinfo_changes(svn_mergeinfo_t *added_mergeinfo, SVN_ERR(svn_fs_revision_root(&prev_root, fs, prev_rev, iterpool)); query_paths = apr_array_make(iterpool, 1, sizeof(const char *)); APR_ARRAY_PUSH(query_paths, const char *) = prev_path; - err = svn_fs_get_mergeinfo(&catalog, prev_root, query_paths, - svn_mergeinfo_inherited, FALSE, iterpool); + err = svn_fs_get_mergeinfo2(&catalog, prev_root, query_paths, + svn_mergeinfo_inherited, FALSE, TRUE, + iterpool, iterpool); if (err && (err->apr_err == SVN_ERR_FS_NOT_FOUND || err->apr_err == SVN_ERR_FS_NOT_DIRECTORY || err->apr_err == SVN_ERR_MERGEINFO_PARSE_ERROR)) @@ -846,29 +907,78 @@ get_combined_mergeinfo_changes(svn_mergeinfo_t *added_mergeinfo, continue; } SVN_ERR(err); - prev_mergeinfo = apr_hash_get(catalog, prev_path, APR_HASH_KEY_STRING); + + /* Issue #4022 'svn log -g interprets change in inherited mergeinfo due + to move as a merge': A copy where the source and destination inherit + mergeinfo from the same parent means the inherited mergeinfo of the + source and destination will differ, but this diffrence is not + indicative of a merge unless the mergeinfo on the inherited parent + has actually changed. + + To check for this we must fetch the "raw" previous inherited + mergeinfo and the "raw" mergeinfo @REV then compare these. */ + SVN_ERR(svn_fs_get_mergeinfo2(&inherited_catalog, prev_root, query_paths, + svn_mergeinfo_nearest_ancestor, FALSE, + FALSE, /* adjust_inherited_mergeinfo */ + iterpool, iterpool)); + + klen = strlen(prev_path); + prev_mergeinfo = apr_hash_get(catalog, prev_path, klen); + prev_inherited_mergeinfo = apr_hash_get(inherited_catalog, prev_path, klen); /* Fetch the current mergeinfo (as of REV, and including inherited stuff) for this path. */ APR_ARRAY_IDX(query_paths, 0, const char *) = path; - SVN_ERR(svn_fs_get_mergeinfo(&catalog, root, query_paths, - svn_mergeinfo_inherited, FALSE, iterpool)); - mergeinfo = apr_hash_get(catalog, path, APR_HASH_KEY_STRING); + SVN_ERR(svn_fs_get_mergeinfo2(&catalog, root, query_paths, + svn_mergeinfo_inherited, FALSE, TRUE, + iterpool, iterpool)); + + /* Issue #4022 again, fetch the raw inherited mergeinfo. */ + SVN_ERR(svn_fs_get_mergeinfo2(&inherited_catalog, root, query_paths, + svn_mergeinfo_nearest_ancestor, FALSE, + FALSE, /* adjust_inherited_mergeinfo */ + iterpool, iterpool)); + + klen = strlen(path); + mergeinfo = apr_hash_get(catalog, path, klen); + inherited_mergeinfo = apr_hash_get(inherited_catalog, path, klen); if (!prev_mergeinfo && !mergeinfo) continue; + /* Last bit of issue #4022 checking. */ + if (prev_inherited_mergeinfo && inherited_mergeinfo) + { + svn_boolean_t inherits_same_mergeinfo; + + SVN_ERR(svn_mergeinfo__equals(&inherits_same_mergeinfo, + prev_inherited_mergeinfo, + inherited_mergeinfo, + TRUE, iterpool)); + /* If a copy rather than an actual merge brought about an + inherited mergeinfo change then we are finished. */ + if (inherits_same_mergeinfo) + continue; + } + else + { + svn_boolean_t same_mergeinfo; + SVN_ERR(svn_mergeinfo__equals(&same_mergeinfo, + prev_inherited_mergeinfo, + FALSE, + TRUE, iterpool)); + if (same_mergeinfo) + continue; + } + /* Compare, constrast, and combine the results. */ - SVN_ERR(svn_mergeinfo_diff(&deleted, &added, prev_mergeinfo, - mergeinfo, FALSE, iterpool)); - SVN_ERR(svn_mergeinfo_merge(*deleted_mergeinfo, - svn_mergeinfo_dup(deleted, result_pool), - result_pool)); - SVN_ERR(svn_mergeinfo_merge(*added_mergeinfo, - svn_mergeinfo_dup(added, result_pool), - result_pool)); + SVN_ERR(svn_mergeinfo_diff2(&deleted, &added, prev_mergeinfo, + mergeinfo, FALSE, result_pool, iterpool)); + SVN_ERR(svn_mergeinfo_merge2(*deleted_mergeinfo, deleted, + result_pool, iterpool)); + SVN_ERR(svn_mergeinfo_merge2(*added_mergeinfo, added, + result_pool, iterpool)); } - svn_pool_destroy(iterpool); /* Merge all the mergeinfos which are, or are children of, one of our paths of interest into one giant delta mergeinfo. */ @@ -889,20 +999,22 @@ get_combined_mergeinfo_changes(svn_mergeinfo_t *added_mergeinfo, for (i = 0; i < paths->nelts; i++) { const char *path = APR_ARRAY_IDX(paths, i, const char *); - if (! svn_dirent_is_ancestor(path, changed_path)) + if (! svn_fspath__skip_ancestor(path, changed_path)) continue; + svn_pool_clear(iterpool); deleted = apr_hash_get(deleted_mergeinfo_catalog, key, klen); - SVN_ERR(svn_mergeinfo_merge(*deleted_mergeinfo, - svn_mergeinfo_dup(deleted, result_pool), - result_pool)); - SVN_ERR(svn_mergeinfo_merge(*added_mergeinfo, - svn_mergeinfo_dup(added, result_pool), - result_pool)); + SVN_ERR(svn_mergeinfo_merge2(*deleted_mergeinfo, + svn_mergeinfo_dup(deleted, result_pool), + result_pool, iterpool)); + SVN_ERR(svn_mergeinfo_merge2(*added_mergeinfo, + svn_mergeinfo_dup(added, result_pool), + result_pool, iterpool)); break; } } + svn_pool_destroy(iterpool); return SVN_NO_ERROR; } @@ -912,6 +1024,7 @@ static svn_error_t * fill_log_entry(svn_log_entry_t *log_entry, svn_revnum_t rev, svn_fs_t *fs, + apr_hash_t *prefetched_changes, svn_boolean_t discover_changed_paths, const apr_array_header_t *revprops, svn_repos_authz_func_t authz_read_func, @@ -931,7 +1044,7 @@ fill_log_entry(svn_log_entry_t *log_entry, SVN_ERR(svn_fs_revision_root(&newroot, fs, rev, pool)); patherr = detect_changed(&changed_paths, - newroot, fs, + newroot, fs, prefetched_changes, authz_read_func, authz_read_baton, pool); @@ -971,15 +1084,11 @@ fill_log_entry(svn_log_entry_t *log_entry, if (censor_revprops) { /* ... but we can only return author/date. */ - log_entry->revprops = apr_hash_make(pool); - apr_hash_set(log_entry->revprops, SVN_PROP_REVISION_AUTHOR, - APR_HASH_KEY_STRING, - apr_hash_get(r_props, SVN_PROP_REVISION_AUTHOR, - APR_HASH_KEY_STRING)); - apr_hash_set(log_entry->revprops, SVN_PROP_REVISION_DATE, - APR_HASH_KEY_STRING, - apr_hash_get(r_props, SVN_PROP_REVISION_DATE, - APR_HASH_KEY_STRING)); + log_entry->revprops = svn_hash__make(pool); + svn_hash_sets(log_entry->revprops, SVN_PROP_REVISION_AUTHOR, + svn_hash_gets(r_props, SVN_PROP_REVISION_AUTHOR)); + svn_hash_sets(log_entry->revprops, SVN_PROP_REVISION_DATE, + svn_hash_gets(r_props, SVN_PROP_REVISION_DATE)); } else /* ... so return all we got. */ @@ -992,17 +1101,15 @@ fill_log_entry(svn_log_entry_t *log_entry, for (i = 0; i < revprops->nelts; i++) { char *name = APR_ARRAY_IDX(revprops, i, char *); - svn_string_t *value = apr_hash_get(r_props, name, - APR_HASH_KEY_STRING); + svn_string_t *value = svn_hash_gets(r_props, name); if (censor_revprops && !(strcmp(name, SVN_PROP_REVISION_AUTHOR) == 0 || strcmp(name, SVN_PROP_REVISION_DATE) == 0)) /* ... but we can only return author/date. */ continue; if (log_entry->revprops == NULL) - log_entry->revprops = apr_hash_make(pool); - apr_hash_set(log_entry->revprops, name, - APR_HASH_KEY_STRING, value); + log_entry->revprops = svn_hash__make(pool); + svn_hash_sets(log_entry->revprops, name, value); } } } @@ -1024,8 +1131,9 @@ fill_log_entry(svn_log_entry_t *log_entry, If DESCENDING_ORDER is true, send child messages in descending order. - If REVPROPS is NULL, retrieve all revprops; else, retrieve only the - revprops named in the array (i.e. retrieve none if the array is empty). + If REVPROPS is NULL, retrieve all revision properties; else, retrieve + only the revision properties named by the (const char *) array elements + (i.e. retrieve none if the array is empty). LOG_TARGET_HISTORY_AS_MERGEINFO, HANDLING_MERGED_REVISION, and NESTED_MERGES are as per the arguments of the same name to DO_LOGS. If @@ -1041,6 +1149,7 @@ fill_log_entry(svn_log_entry_t *log_entry, static svn_error_t * send_log(svn_revnum_t rev, svn_fs_t *fs, + apr_hash_t *prefetched_changes, svn_mergeinfo_t log_target_history_as_mergeinfo, apr_hash_t *nested_merges, svn_boolean_t discover_changed_paths, @@ -1059,7 +1168,7 @@ send_log(svn_revnum_t rev, svn_boolean_t found_rev_of_interest = TRUE; log_entry = svn_log_entry_create(pool); - SVN_ERR(fill_log_entry(log_entry, rev, fs, + SVN_ERR(fill_log_entry(log_entry, rev, fs, prefetched_changes, discover_changed_paths || handling_merged_revision, revprops, authz_read_func, authz_read_baton, pool)); @@ -1091,6 +1200,7 @@ send_log(svn_revnum_t rev, apr_hash_index_t *hi2; apr_pool_t *inner_subpool = svn_pool_create(subpool); + /* Look at each path on the log target's mergeinfo. */ for (hi2 = apr_hash_first(inner_subpool, log_target_history_as_mergeinfo); hi2; @@ -1098,11 +1208,12 @@ send_log(svn_revnum_t rev, { const char *mergeinfo_path = svn__apr_hash_index_key(hi2); - apr_array_header_t *rangelist = + svn_rangelist_t *rangelist = svn__apr_hash_index_val(hi2); - if (svn_fspath__is_ancestor(mergeinfo_path, - changed_path)) + /* Check whether CHANGED_PATH at revision REV is a child of + a (path, revision) tuple in LOG_TARGET_HISTORY_AS_MERGEINFO. */ + if (svn_fspath__skip_ancestor(mergeinfo_path, changed_path)) { int i; @@ -1317,7 +1428,7 @@ struct path_list_range the paths can be accessed by revision. */ struct rangelist_path { - apr_array_header_t *rangelist; + svn_rangelist_t *rangelist; const char *path; }; @@ -1655,14 +1766,13 @@ reduce_search(apr_array_header_t *paths, for (i = 0; i < paths->nelts; ++i) { const char *path = APR_ARRAY_IDX(paths, i, const char *); - apr_array_header_t *ranges = apr_hash_get(processed, path, - APR_HASH_KEY_STRING); + svn_rangelist_t *ranges = svn_hash_gets(processed, path); int j; if (!ranges) continue; - /* ranges is ordered, could we use some sort of binay search + /* ranges is ordered, could we use some sort of binary search rather than iterating? */ for (j = 0; j < ranges->nelts; ++j) { @@ -1720,27 +1830,26 @@ store_search(svn_mergeinfo_t processed, singe revisions where HIST_START is equal to HIST_END. */ svn_revnum_t start = hist_start <= hist_end ? hist_start : hist_end; svn_revnum_t end = hist_start <= hist_end ? hist_end + 1 : hist_start + 1; - svn_mergeinfo_t mergeinfo = apr_hash_make(scratch_pool); + svn_mergeinfo_t mergeinfo = svn_hash__make(scratch_pool); apr_pool_t *processed_pool = apr_hash_pool_get(processed); int i; for (i = 0; i < paths->nelts; ++i) { const char *path = APR_ARRAY_IDX(paths, i, const char *); - apr_array_header_t *ranges = apr_array_make(processed_pool, 1, - sizeof(svn_merge_range_t*)); + svn_rangelist_t *ranges = apr_array_make(processed_pool, 1, + sizeof(svn_merge_range_t*)); svn_merge_range_t *range = apr_palloc(processed_pool, sizeof(svn_merge_range_t)); - + range->start = start; range->end = end; range->inheritable = TRUE; APR_ARRAY_PUSH(ranges, svn_merge_range_t *) = range; - apr_hash_set(mergeinfo, apr_pstrdup(processed_pool, path), - APR_HASH_KEY_STRING, ranges); + svn_hash_sets(mergeinfo, apr_pstrdup(processed_pool, path), ranges); } - SVN_ERR(svn_mergeinfo_merge(processed, mergeinfo, - apr_hash_pool_get(processed))); + SVN_ERR(svn_mergeinfo_merge2(processed, mergeinfo, + apr_hash_pool_get(processed), scratch_pool)); return SVN_NO_ERROR; } @@ -1769,7 +1878,7 @@ store_search(svn_mergeinfo_t processed, do_logs()/send_logs()/handle_merge_revisions() recursions, see also the argument of the same name in send_logs(). - If PROCESSED is a mergeinfo hash that represents the paths and + PROCESSED is a mergeinfo hash that represents the paths and revisions that have already been searched. Allocated like NESTED_MERGES above. @@ -1861,6 +1970,7 @@ do_logs(svn_fs_t *fs, svn_mergeinfo_t added_mergeinfo = NULL; svn_mergeinfo_t deleted_mergeinfo = NULL; svn_boolean_t has_children = FALSE; + apr_hash_t *changes = NULL; /* If we're including merged revisions, we need to calculate the mergeinfo deltas committed in this revision to our @@ -1881,6 +1991,7 @@ do_logs(svn_fs_t *fs, } SVN_ERR(get_combined_mergeinfo_changes(&added_mergeinfo, &deleted_mergeinfo, + &changes, fs, cur_paths, current, iterpool, iterpool)); @@ -1893,7 +2004,7 @@ do_logs(svn_fs_t *fs, in anyway). */ if (descending_order) { - SVN_ERR(send_log(current, fs, + SVN_ERR(send_log(current, fs, changes, log_target_history_as_mergeinfo, nested_merges, discover_changed_paths, subtractive_merge, handling_merged_revisions, @@ -1909,8 +2020,8 @@ do_logs(svn_fs_t *fs, single hash to be shared across all of the merged recursions so we can track and squelch duplicates. */ subpool = svn_pool_create(pool); - nested_merges = apr_hash_make(subpool); - processed = apr_hash_make(subpool); + nested_merges = svn_hash__make(subpool); + processed = svn_hash__make(subpool); } SVN_ERR(handle_merged_revisions( @@ -1955,7 +2066,7 @@ do_logs(svn_fs_t *fs, *cur_rev = current; if (! rev_mergeinfo) - rev_mergeinfo = apr_hash_make(pool); + rev_mergeinfo = svn_hash__make(pool); apr_hash_set(rev_mergeinfo, cur_rev, sizeof(*cur_rev), add_and_del_mergeinfo); } @@ -1998,8 +2109,8 @@ do_logs(svn_fs_t *fs, || apr_hash_count(deleted_mergeinfo) > 0); } - SVN_ERR(send_log(current, fs, log_target_history_as_mergeinfo, - nested_merges, + SVN_ERR(send_log(current, fs, NULL, + log_target_history_as_mergeinfo, nested_merges, discover_changed_paths, subtractive_merge, handling_merged_revisions, revprops, has_children, receiver, receiver_baton, authz_read_func, @@ -2009,7 +2120,7 @@ do_logs(svn_fs_t *fs, if (!nested_merges) { subpool = svn_pool_create(pool); - nested_merges = apr_hash_make(subpool); + nested_merges = svn_hash__make(subpool); } SVN_ERR(handle_merged_revisions(current, fs, @@ -2089,7 +2200,7 @@ get_paths_history_as_mergeinfo(svn_mergeinfo_t *paths_history_mergeinfo, end_rev = tmp_rev; } - *paths_history_mergeinfo = apr_hash_make(result_pool); + *paths_history_mergeinfo = svn_hash__make(result_pool); for (i = 0; i < paths->nelts; i++) { @@ -2111,10 +2222,10 @@ get_paths_history_as_mergeinfo(svn_mergeinfo_t *paths_history_mergeinfo, SVN_ERR(svn_mergeinfo__mergeinfo_from_segments( &path_history_mergeinfo, loc_seg_baton.history_segments, iterpool)); - SVN_ERR(svn_mergeinfo_merge(*paths_history_mergeinfo, - svn_mergeinfo_dup(path_history_mergeinfo, - result_pool), - result_pool)); + SVN_ERR(svn_mergeinfo_merge2(*paths_history_mergeinfo, + svn_mergeinfo_dup(path_history_mergeinfo, + result_pool), + result_pool, iterpool)); } svn_pool_destroy(iterpool); return SVN_NO_ERROR; @@ -2188,18 +2299,42 @@ svn_repos_get_logs4(svn_repos_t *repos, int i; apr_pool_t *iterpool = svn_pool_create(pool); + /* If we are provided an authz callback function, use it to + verify that the user has read access to the root path in the + first of our revisions. + + ### FIXME: Strictly speaking, we should be checking this + ### access in every revision along the line. But currently, + ### there are no known authz implementations which concern + ### themselves with per-revision access. */ + if (authz_read_func) + { + svn_boolean_t readable; + svn_fs_root_t *rev_root; + + SVN_ERR(svn_fs_revision_root(&rev_root, fs, + descending_order ? end : start, pool)); + SVN_ERR(authz_read_func(&readable, rev_root, "", + authz_read_baton, pool)); + if (! readable) + return svn_error_create(SVN_ERR_AUTHZ_UNREADABLE, NULL, NULL); + } + send_count = end - start + 1; if (limit && send_count > limit) send_count = limit; for (i = 0; i < send_count; ++i) { - svn_revnum_t rev = start + i; + svn_revnum_t rev; svn_pool_clear(iterpool); if (descending_order) rev = end - i; - SVN_ERR(send_log(rev, fs, NULL, NULL, discover_changed_paths, FALSE, + else + rev = start + i; + SVN_ERR(send_log(rev, fs, NULL, NULL, NULL, + discover_changed_paths, FALSE, FALSE, revprops, FALSE, receiver, receiver_baton, authz_read_func, authz_read_baton, iterpool)); |