📄 rev_hunt.c
字号:
svn_fs_root_t *root;
svn_fs_history_t *history;
const char *path;
svn_revnum_t revision;
apr_pool_t *lastpool, *currpool;
lastpool = svn_pool_create (pool);
currpool = svn_pool_create (pool);
SVN_ERR (svn_fs_revision_root (&root, fs, future_revision, pool));
SVN_ERR (svn_fs_node_history (&history, root, fs_path, lastpool));
/* Since paths that are different according to strcmp may still be
equivalent (due to number of consecutive slashes and the fact that
"" is the same as "/"), we get the "canonical" path in the first
iteration below so that the comparison after the loop will work
correctly. */
fs_path = NULL;
while (1)
{
apr_pool_t *tmppool;
SVN_ERR (svn_fs_history_prev (&history, history, TRUE, currpool));
if (!history)
break;
SVN_ERR (svn_fs_history_location (&path, &revision, history, currpool));
if (!fs_path)
fs_path = apr_pstrdup (pool, path);
if (revision <= peg_revision)
break;
/* Clear old pool and flip. */
svn_pool_clear (lastpool);
tmppool = lastpool;
lastpool = currpool;
currpool = tmppool;
}
/* We must have had at least one iteration above where we
reassigned fs_path. Else, the path wouldn't have existed at
future_revision and svn_fs_history would have thrown. */
assert (fs_path != NULL);
*is_ancestor = (history && strcmp (path, fs_path) == 0);
return SVN_NO_ERROR;
}
svn_error_t *
svn_repos_trace_node_locations (svn_fs_t *fs,
apr_hash_t **locations,
const char *fs_path,
svn_revnum_t peg_revision,
apr_array_header_t *location_revisions_orig,
svn_repos_authz_func_t authz_read_func,
void *authz_read_baton,
apr_pool_t *pool)
{
apr_array_header_t *location_revisions;
svn_revnum_t *revision_ptr, *revision_ptr_end;
svn_fs_root_t *root;
svn_fs_history_t *history;
const char *path;
svn_revnum_t revision;
svn_boolean_t is_ancestor;
apr_pool_t *lastpool, *currpool;
/* Sanity check. */
assert (location_revisions_orig->elt_size == sizeof(svn_revnum_t));
/* Another sanity check. */
if (authz_read_func)
{
svn_fs_root_t *peg_root;
SVN_ERR (svn_fs_revision_root (&peg_root, fs, peg_revision, pool));
SVN_ERR (check_readability (peg_root, fs_path,
authz_read_func, authz_read_baton, pool));
}
*locations = apr_hash_make (pool);
/* We flip between two pools in the second loop below. */
lastpool = svn_pool_create (pool);
currpool = svn_pool_create (pool);
/* First - let's sort the array of the revisions from the greatest revision
* downward, so it will be easier to search on. */
location_revisions = apr_array_copy (pool, location_revisions_orig);
qsort (location_revisions->elts, location_revisions->nelts,
sizeof (*revision_ptr), svn_sort_compare_revisions);
revision_ptr = (svn_revnum_t *)location_revisions->elts;
revision_ptr_end = revision_ptr + location_revisions->nelts;
/* Ignore revisions R that are younger than the peg_revisions where
path@peg_revision is not an ancestor of path@R. */
is_ancestor = FALSE;
while (revision_ptr < revision_ptr_end && *revision_ptr > peg_revision)
{
svn_pool_clear (currpool);
SVN_ERR (check_ancestry_of_peg_path (&is_ancestor, fs, fs_path,
peg_revision, *revision_ptr,
currpool));
if (is_ancestor)
break;
++revision_ptr;
}
SVN_ERR (svn_fs_revision_root (&root, fs,
(is_ancestor ?
(*revision_ptr) :
peg_revision), pool));
if (authz_read_func)
SVN_ERR (check_readability (root, fs_path, authz_read_func,
authz_read_baton, pool));
SVN_ERR (svn_fs_node_history (&history, root, fs_path, lastpool));
while (revision_ptr < revision_ptr_end)
{
apr_pool_t *tmppool;
SVN_ERR (svn_fs_history_prev (&history, history, TRUE, currpool));
if (!history)
break;
SVN_ERR (svn_fs_history_location (&path, &revision, history, currpool));
if (authz_read_func)
{
svn_boolean_t readable;
svn_fs_root_t *tmp_root;
SVN_ERR (svn_fs_revision_root (&tmp_root, fs, revision, currpool));
SVN_ERR (authz_read_func (&readable, tmp_root, path,
authz_read_baton, currpool));
if (! readable)
{
return SVN_NO_ERROR;
}
}
/* Assign the current path to all younger revisions until we reach
the current one. */
while ((revision_ptr < revision_ptr_end) && (*revision_ptr >= revision))
{
/* *revision_ptr is allocated out of pool, so we can point
to in the hash table. */
apr_hash_set (*locations, revision_ptr, sizeof (*revision_ptr),
apr_pstrdup (pool, path));
revision_ptr++;
}
/* Clear last pool and switch. */
svn_pool_clear (lastpool);
tmppool = lastpool;
lastpool = currpool;
currpool = tmppool;
}
svn_pool_destroy (lastpool);
svn_pool_destroy (currpool);
return SVN_NO_ERROR;
}
svn_error_t *
svn_repos_get_file_revs (svn_repos_t *repos,
const char *path,
svn_revnum_t start,
svn_revnum_t end,
svn_repos_authz_func_t authz_read_func,
void *authz_read_baton,
svn_repos_file_rev_handler_t handler,
void *handler_baton,
apr_pool_t *pool)
{
apr_pool_t *iter_pool, *last_pool;
svn_fs_history_t *history;
apr_array_header_t *revnums = apr_array_make (pool, 0,
sizeof (svn_revnum_t));
apr_array_header_t *paths = apr_array_make (pool, 0, sizeof (char *));
apr_hash_t *last_props;
svn_fs_root_t *root, *last_root;
const char *last_path;
int i;
/* We switch betwwen two pools while looping, since we need information from
the last iteration to be available. */
iter_pool = svn_pool_create (pool);
last_pool = svn_pool_create (pool);
/* Open revision root for path@end. */
/* ### Can we use last_pool for this? How long does the history
object need the root? */
SVN_ERR (svn_fs_revision_root (&root, repos->fs, end, pool));
/* Open a history object. */
SVN_ERR (svn_fs_node_history (&history, root, path, last_pool));
/* Get the revisions we are interested in. */
while (1)
{
const char* rev_path;
svn_revnum_t rev;
apr_pool_t *tmp_pool;
svn_pool_clear (iter_pool);
SVN_ERR (svn_fs_history_prev (&history, history, TRUE, iter_pool));
if (!history)
break;
SVN_ERR (svn_fs_history_location (&rev_path, &rev, history, iter_pool));
if (authz_read_func)
{
svn_boolean_t readable;
svn_fs_root_t *tmp_root;
SVN_ERR (svn_fs_revision_root (&tmp_root, repos->fs, rev, iter_pool));
SVN_ERR (authz_read_func (&readable, tmp_root, rev_path,
authz_read_baton, iter_pool));
if (! readable)
{
break;
}
}
*(svn_revnum_t*) apr_array_push (revnums) = rev;
*(char **) apr_array_push (paths) = apr_pstrdup (pool, rev_path);
if (rev <= start)
break;
/* Swap pools. */
tmp_pool = iter_pool;
iter_pool = last_pool;
last_pool = tmp_pool;
}
/* We must have at least one revision to get. */
assert (revnums->nelts > 0);
/* We want the first txdelta to be against the empty file. */
last_root = NULL;
last_path = NULL;
/* Create an empty hash table for the first property diff. */
last_props = apr_hash_make (last_pool);
/* Walk through the revisions in chronological order. */
for (i = revnums->nelts; i > 0; --i)
{
svn_revnum_t rev = APR_ARRAY_IDX (revnums, i - 1, svn_revnum_t);
const char *rev_path = APR_ARRAY_IDX (paths, i - 1, const char *);
apr_hash_t *rev_props;
apr_hash_t *props;
apr_array_header_t *prop_diffs;
svn_txdelta_stream_t *delta_stream;
svn_txdelta_window_handler_t delta_handler = NULL;
void *delta_baton = NULL;
apr_pool_t *tmp_pool; /* For swapping */
svn_boolean_t contents_changed;
svn_pool_clear (iter_pool);
/* Get the revision properties. */
SVN_ERR (svn_fs_revision_proplist (&rev_props, repos->fs,
rev, iter_pool));
/* Open the revision root. */
SVN_ERR (svn_fs_revision_root (&root, repos->fs, rev, iter_pool));
/* Get the file's properties for this revision and compute the diffs. */
SVN_ERR (svn_fs_node_proplist (&props, root, rev_path, iter_pool));
SVN_ERR (svn_prop_diffs (&prop_diffs, props, last_props, pool));
/* Check if the contents changed. */
/* Special case: In the first revision, we always provide a delta. */
if (last_root)
SVN_ERR (svn_fs_contents_changed (&contents_changed,
last_root, last_path,
root, rev_path, iter_pool));
else
contents_changed = TRUE;
/* We have all we need, give to the handler. */
SVN_ERR (handler (handler_baton, rev_path, rev, rev_props,
contents_changed ? &delta_handler : NULL,
contents_changed ? &delta_baton : NULL,
prop_diffs, iter_pool));
/* Compute and send delta if client asked for it.
Note that this was initialized to NULL, so if !contents_changed,
no deltas will be computed. */
if (delta_handler)
{
/* Get the content delta. */
SVN_ERR (svn_fs_get_file_delta_stream (&delta_stream,
last_root, last_path,
root, rev_path,
iter_pool));
/* And send. */
SVN_ERR (svn_txdelta_send_txstream (delta_stream,
delta_handler, delta_baton,
iter_pool));
}
/* Remember root, path and props for next iteration. */
last_root = root;
last_path = rev_path;
last_props = props;
/* Swap the pools. */
tmp_pool = iter_pool;
iter_pool = last_pool;
last_pool = tmp_pool;
}
svn_pool_destroy (last_pool);
svn_pool_destroy (iter_pool);
return SVN_NO_ERROR;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -