summaryrefslogtreecommitdiff
path: root/subversion/libsvn_repos/log.c
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/libsvn_repos/log.c')
-rw-r--r--subversion/libsvn_repos/log.c353
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(&copyfrom_rev, &copyfrom_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(&copyfrom_rev, &copyfrom_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));