📄 log.c
字号:
/* log.c --- retrieving log messages * * ==================================================================== * Copyright (c) 2000-2004 CollabNet. All rights reserved. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at http://subversion.tigris.org/license-1.html. * If newer versions of this license are posted there, you may use a * newer version instead, at your option. * * This software consists of voluntary contributions made by many * individuals. For exact contribution history, see the revision * history and logs, available at http://subversion.tigris.org/. * ==================================================================== */#define APR_WANT_STRFUNC#include <apr_want.h>#include "svn_private_config.h"#include "svn_pools.h"#include "svn_error.h"#include "svn_path.h"#include "svn_fs.h"#include "svn_repos.h"#include "svn_string.h"#include "svn_sorts.h"#include "svn_props.h"#include "repos.h"/* Store as keys in CHANGED the paths of all node in ROOT that show a * significant change. "Significant" means that the text or * properties of the node were changed, or that the node was added or * deleted. * * 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. * * 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: * * - If some paths are readable and some are not, then silently * omit the unreadable paths from the CHANGED hash, and return * SVN_ERR_AUTHZ_PARTIALLY_READABLE. * * - If absolutely every changed-path (and copyfrom_path) is * unreadable, then return an empty CHANGED hash and * SVN_ERR_AUTHZ_UNREADABLE. (This is to distinguish a revision * which truly has no changed paths from a revision in which all * paths are unreadable.) */static svn_error_t *detect_changed(apr_hash_t **changed, svn_fs_root_t *root, svn_fs_t *fs, svn_repos_authz_func_t authz_read_func, void *authz_read_baton, apr_pool_t *pool){ apr_hash_t *changes; apr_hash_index_t *hi; apr_pool_t *subpool = svn_pool_create(pool); svn_boolean_t found_readable = FALSE; svn_boolean_t found_unreadable = FALSE; *changed = apr_hash_make(pool); SVN_ERR(svn_fs_paths_changed(&changes, root, pool)); if (apr_hash_count(changes) == 0) /* No paths changed in this revision? Uh, sure, I guess the revision is readable, then. */ return SVN_NO_ERROR; for (hi = apr_hash_first(pool, changes); hi; hi = apr_hash_next(hi)) { const void *key; void *val; svn_fs_path_change_t *change; const char *path; char action; svn_log_changed_path_t *item; svn_pool_clear(subpool); /* KEY will be the path, VAL the change. */ apr_hash_this(hi, &key, NULL, &val); path = (const char *) key; change = val; /* Skip path if unreadable. */ if (authz_read_func) { svn_boolean_t readable; SVN_ERR(authz_read_func(&readable, root, path, authz_read_baton, subpool)); if (! readable) { found_unreadable = TRUE; continue; } } /* At least one changed-path was readable. */ found_readable = TRUE; switch (change->change_kind) { case svn_fs_path_change_reset: continue; case svn_fs_path_change_add: action = 'A'; break; case svn_fs_path_change_replace: action = 'R'; break; case svn_fs_path_change_delete: action = 'D'; break; case svn_fs_path_change_modify: default: action = 'M'; break; } item = apr_pcalloc(pool, sizeof(*item)); item->action = action; item->copyfrom_rev = SVN_INVALID_REVNUM; if ((action == 'A') || (action == 'R')) { const char *copyfrom_path; svn_revnum_t copyfrom_rev; SVN_ERR(svn_fs_copied_from(©from_rev, ©from_path, root, path, subpool)); if (copyfrom_path && SVN_IS_VALID_REVNUM(copyfrom_rev)) { svn_boolean_t readable = TRUE; if (authz_read_func) { svn_fs_root_t *copyfrom_root; SVN_ERR(svn_fs_revision_root(©from_root, fs, copyfrom_rev, subpool)); SVN_ERR(authz_read_func(&readable, copyfrom_root, copyfrom_path, authz_read_baton, subpool)); if (! readable) found_unreadable = TRUE; } if (readable) { item->copyfrom_path = apr_pstrdup(pool, copyfrom_path); item->copyfrom_rev = copyfrom_rev; } } } apr_hash_set(*changed, apr_pstrdup(pool, path), APR_HASH_KEY_STRING, item); } svn_pool_destroy(subpool); if (! found_readable) /* Every changed-path was unreadable. */ return svn_error_create(SVN_ERR_AUTHZ_UNREADABLE, NULL, NULL); if (found_unreadable) /* At least one changed-path was unreadable. */ return svn_error_create(SVN_ERR_AUTHZ_PARTIALLY_READABLE, NULL, NULL); /* Every changed-path was readable. */ return SVN_NO_ERROR;}/* This is used by svn_repos_get_logs3 to keep track of multiple * path history information while working through history. * * The two pools are swapped after each iteration through history because * to get the next history requires the previous one. */struct path_info{ svn_stringbuf_t *path; svn_revnum_t history_rev; svn_boolean_t done; svn_boolean_t first_time; /* If possible, we like to keep open the history object for each path, since it avoids needed to open and close it many times as we walk backwards in time. To do so we need two pools, so that we can clear one each time through. If we're not holding the history open for this path then these three pointers will be NULL. */ svn_fs_history_t *hist; apr_pool_t *newpool; apr_pool_t *oldpool;};/* Advance to the next history for the path. * * If INFO->HIST is not NULL we do this using that existing history object, * otherwise we open a new one. * * If no more history is available or the history revision is less * than (earlier) than START, or the history is not available due * to authorization, then INFO->DONE is set to TRUE. * * A STRICT value of FALSE will indicate to follow history across copied * paths. * * If optional AUTHZ_READ_FUNC is non-NULL, then use it (with * AUTHZ_READ_BATON and FS) to check whether INFO->PATH is still readable if * we do indeed find more history for the path. */static svn_error_t *get_history(struct path_info *info, svn_fs_t *fs, svn_boolean_t strict, svn_repos_authz_func_t authz_read_func, void *authz_read_baton, svn_revnum_t start, apr_pool_t *pool){ svn_fs_root_t *history_root = NULL; svn_fs_history_t *hist; apr_pool_t *subpool; const char *path; if (info->hist) { subpool = info->newpool; SVN_ERR(svn_fs_history_prev(&info->hist, info->hist, strict ? FALSE : TRUE, subpool)); hist = info->hist; } else { subpool = svn_pool_create(pool); /* Open the history located at the last rev we were at. */ SVN_ERR(svn_fs_revision_root(&history_root, fs, info->history_rev, subpool)); SVN_ERR(svn_fs_node_history(&hist, history_root, info->path->data, subpool)); SVN_ERR(svn_fs_history_prev(&hist, hist, strict ? FALSE : TRUE, subpool)); if (info->first_time) info->first_time = FALSE; else SVN_ERR(svn_fs_history_prev(&hist, hist, strict ? FALSE : TRUE, subpool)); } if (! hist) { svn_pool_destroy(subpool); if (info->oldpool) svn_pool_destroy(info->oldpool); info->done = TRUE; return SVN_NO_ERROR; } /* Fetch the location information for this history step. */ SVN_ERR(svn_fs_history_location(&path, &info->history_rev, hist, subpool)); svn_stringbuf_set(info->path, path); /* If this history item predates our START revision then don't fetch any more for this path. */ if (info->history_rev < start) { info->done = TRUE; return SVN_NO_ERROR; } /* Is the history item readable? If not, done with path. */ if (authz_read_func) { svn_boolean_t readable; SVN_ERR(svn_fs_revision_root(&history_root, fs, info->history_rev, subpool)); SVN_ERR(authz_read_func(&readable, history_root, info->path->data, authz_read_baton, subpool)); if (! readable) info->done = TRUE; } if (! info->hist) { svn_pool_destroy(subpool); } else { apr_pool_t *temppool = info->oldpool; info->oldpool = info->newpool; svn_pool_clear(temppool); info->newpool = temppool; } return SVN_NO_ERROR;}/* Set INFO->HIST to the next history for the path *if* there is history * available and INFO->HISTORY_REV is equal to or greater than CURRENT. * * *CHANGED is set to TRUE if the path has history in the CURRENT revision, * otherwise it is not touched. * * If we do need to get the next history revision for the path, call * get_history to do it -- see it for details. */static svn_error_t *check_history(svn_boolean_t *changed, struct path_info *info, svn_fs_t *fs, svn_revnum_t current, svn_boolean_t strict, svn_repos_authz_func_t authz_read_func, void *authz_read_baton, svn_revnum_t start, apr_pool_t *pool){ /* If we're already done with histories for this path, don't try to fetch any more. */ if (info->done) return SVN_NO_ERROR; /* If the last rev we got for this path is less than CURRENT, then just return and don't fetch history for this path. The caller will get to this rev eventually or else reach the limit. */ if (info->history_rev < current) return SVN_NO_ERROR; /* If the last rev we got for this path is equal to CURRENT then set *CHANGED to true and get the next history rev where this path was changed. */ *changed = TRUE; SVN_ERR(get_history(info, fs, strict, authz_read_func, authz_read_baton, start, pool)); return SVN_NO_ERROR;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -