📄 ra_plugin.c
字号:
/* * ra_plugin.c : the main RA module for local repository access * * ==================================================================== * 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/. * ==================================================================== */#include "ra_local.h"#include "svn_ra.h"#include "svn_fs.h"#include "svn_delta.h"#include "svn_repos.h"#include "svn_pools.h"#include "svn_time.h"#include "svn_props.h"#include "svn_path.h"#include "svn_private_config.h"#include "../libsvn_ra/ra_loader.h"#define APR_WANT_STRFUNC#include <apr_want.h>#include <assert.h>/*----------------------------------------------------------------*//* The reporter vtable needed by do_update() */typedef struct reporter_baton_t{ svn_ra_local__session_baton_t *session; void *report_baton;} reporter_baton_t;static void *make_reporter_baton(svn_ra_local__session_baton_t *session, void *report_baton, apr_pool_t *pool){ reporter_baton_t *rbaton = apr_palloc(pool, sizeof(*rbaton)); rbaton->session = session; rbaton->report_baton = report_baton; return rbaton;}static svn_error_t *reporter_set_path(void *reporter_baton, const char *path, svn_revnum_t revision, svn_boolean_t start_empty, const char *lock_token, apr_pool_t *pool){ reporter_baton_t *rbaton = reporter_baton; return svn_repos_set_path2(rbaton->report_baton, path, revision, start_empty, lock_token, pool);}static svn_error_t *reporter_delete_path(void *reporter_baton, const char *path, apr_pool_t *pool){ reporter_baton_t *rbaton = reporter_baton; return svn_repos_delete_path(rbaton->report_baton, path, pool);}static svn_error_t *reporter_link_path(void *reporter_baton, const char *path, const char *url, svn_revnum_t revision, svn_boolean_t start_empty, const char *lock_token, apr_pool_t *pool){ reporter_baton_t *rbaton = reporter_baton; const char *fs_path = NULL; const char *repos_url_decoded; int repos_url_len; url = svn_path_uri_decode(url, pool); repos_url_decoded = svn_path_uri_decode(rbaton->session->repos_url, pool); repos_url_len = strlen(repos_url_decoded); if (strncmp(url, repos_url_decoded, repos_url_len) != 0) return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL, _("'%s'\n" "is not the same repository as\n" "'%s'"), url, rbaton->session->repos_url); fs_path = url + repos_url_len; return svn_repos_link_path2(rbaton->report_baton, path, fs_path, revision, start_empty, lock_token, pool);}static svn_error_t *reporter_finish_report(void *reporter_baton, apr_pool_t *pool){ reporter_baton_t *rbaton = reporter_baton; return svn_repos_finish_report(rbaton->report_baton, pool);}static svn_error_t *reporter_abort_report(void *reporter_baton, apr_pool_t *pool){ reporter_baton_t *rbaton = reporter_baton; return svn_repos_abort_report(rbaton->report_baton, pool);}static const svn_ra_reporter2_t ra_local_reporter = { reporter_set_path, reporter_delete_path, reporter_link_path, reporter_finish_report, reporter_abort_report};static svn_error_t *svn_ra_local__get_file_revs(svn_ra_session_t *session, const char *path, svn_revnum_t start, svn_revnum_t end, svn_ra_file_rev_handler_t handler, void *handler_baton, apr_pool_t *pool){ svn_ra_local__session_baton_t *sbaton = session->priv; const char *abs_path = sbaton->fs_path->data; /* Concatenate paths */ abs_path = svn_path_join(abs_path, path, pool); return svn_repos_get_file_revs(sbaton->repos, abs_path, start, end, NULL, NULL, handler, handler_baton, pool);}/* Pool cleanup handler: Ensure that the access descriptor of the filesystem DATA is set to NULL. */static apr_status_tcleanup_access(void *data){ svn_error_t *serr; svn_fs_t *fs = data; serr = svn_fs_set_access(fs, NULL); if (serr) { apr_status_t apr_err = serr->apr_err; svn_error_clear(serr); return apr_err; } return APR_SUCCESS;}static svn_error_t *get_username(svn_ra_session_t *session, apr_pool_t *pool){ svn_ra_local__session_baton_t *baton = session->priv; svn_auth_iterstate_t *iterstate; svn_fs_access_t *access_ctx; /* If we've already found the username don't ask for it again. */ if (! baton->username) { /* Get a username somehow, so we have some svn:author property to attach to a commit. */ if (baton->callbacks->auth_baton) { void *creds; svn_auth_cred_username_t *username_creds; SVN_ERR(svn_auth_first_credentials(&creds, &iterstate, SVN_AUTH_CRED_USERNAME, baton->uuid, /* realmstring */ baton->callbacks->auth_baton, pool)); /* No point in calling next_creds(), since that assumes that the first_creds() somehow failed to authenticate. But there's no challenge going on, so we use whatever creds we get back on the first try. */ username_creds = creds; if (username_creds && username_creds->username) { baton->username = apr_pstrdup(session->pool, username_creds->username); svn_error_clear(svn_auth_save_credentials(iterstate, pool)); } else baton->username = ""; } else baton->username = ""; } /* If we have a real username, attach it to the filesystem so that it can be used to validate locks. Even if there already is a user context associated, it may contain irrelevant lock tokens, so always create a new. */ if (*baton->username) { SVN_ERR(svn_fs_create_access(&access_ctx, baton->username, pool)); SVN_ERR(svn_fs_set_access(baton->fs, access_ctx)); /* Make sure this context is disassociated when the pool gets destroyed. */ apr_pool_cleanup_register(pool, baton->fs, cleanup_access, apr_pool_cleanup_null); } return SVN_NO_ERROR;}/*----------------------------------------------------------------*//** The RA vtable routines **/#define RA_LOCAL_DESCRIPTION \ N_("Module for accessing a repository on local disk.")static const char *svn_ra_local__get_description(void){ return _(RA_LOCAL_DESCRIPTION);}static const char * const *svn_ra_local__get_schemes(apr_pool_t *pool){ static const char *schemes[] = { "file", NULL }; return schemes;}static svn_error_t *svn_ra_local__open(svn_ra_session_t *session, const char *repos_URL, const svn_ra_callbacks2_t *callbacks, void *callback_baton, apr_hash_t *config, apr_pool_t *pool){ svn_ra_local__session_baton_t *baton; const char *fs_path; /* Allocate and stash the session_baton args we have already. */ baton = apr_pcalloc(pool, sizeof(*baton)); baton->callbacks = callbacks; baton->callback_baton = callback_baton; /* Look through the URL, figure out which part points to the repository, and which part is the path *within* the repository. */ SVN_ERR_W(svn_ra_local__split_URL(&(baton->repos), &(baton->repos_url), &fs_path, repos_URL, session->pool), _("Unable to open an ra_local session to URL")); baton->fs_path = svn_stringbuf_create(fs_path, session->pool); /* Cache the filesystem object from the repos here for convenience. */ baton->fs = svn_repos_fs(baton->repos); /* Cache the repository UUID as well */ SVN_ERR(svn_fs_get_uuid(baton->fs, &baton->uuid, session->pool)); /* Be sure username is NULL so we know to look it up / ask for it */ baton->username = NULL; session->priv = baton; return SVN_NO_ERROR;}static svn_error_t *svn_ra_local__reparent(svn_ra_session_t *session, const char *url, apr_pool_t *pool){ svn_ra_local__session_baton_t *baton = session->priv; svn_stringbuf_set(baton->fs_path, svn_path_uri_decode(url + strlen(baton->repos_url), pool)); return SVN_NO_ERROR;}static svn_error_t *svn_ra_local__get_latest_revnum(svn_ra_session_t *session, svn_revnum_t *latest_revnum, apr_pool_t *pool){ svn_ra_local__session_baton_t *baton = session->priv; SVN_ERR(svn_fs_youngest_rev(latest_revnum, baton->fs, pool)); return SVN_NO_ERROR;}static svn_error_t *svn_ra_local__get_dated_revision(svn_ra_session_t *session, svn_revnum_t *revision, apr_time_t tm, apr_pool_t *pool){ svn_ra_local__session_baton_t *baton = session->priv; SVN_ERR(svn_repos_dated_revision(revision, baton->repos, tm, pool)); return SVN_NO_ERROR;}static svn_error_t *svn_ra_local__change_rev_prop(svn_ra_session_t *session, svn_revnum_t rev, const char *name, const svn_string_t *value, apr_pool_t *pool){ svn_ra_local__session_baton_t *baton = session->priv; SVN_ERR(get_username(session, pool)); SVN_ERR(svn_repos_fs_change_rev_prop2(baton->repos, rev, baton->username, name, value, NULL, NULL, pool)); return SVN_NO_ERROR;}static svn_error_t *svn_ra_local__get_uuid(svn_ra_session_t *session, const char **uuid, apr_pool_t *pool){ svn_ra_local__session_baton_t *baton = session->priv; *uuid = baton->uuid; return SVN_NO_ERROR;}static svn_error_t *svn_ra_local__get_repos_root(svn_ra_session_t *session, const char **url, apr_pool_t *pool){ svn_ra_local__session_baton_t *baton = session->priv; *url = baton->repos_url; return SVN_NO_ERROR;}static svn_error_t *svn_ra_local__rev_proplist(svn_ra_session_t *session, svn_revnum_t rev, apr_hash_t **props, apr_pool_t *pool){ svn_ra_local__session_baton_t *baton = session->priv; SVN_ERR(svn_repos_fs_revision_proplist(props, baton->repos, rev, NULL, NULL, pool)); return SVN_NO_ERROR;}static svn_error_t *svn_ra_local__rev_prop(svn_ra_session_t *session, svn_revnum_t rev, const char *name, svn_string_t **value, apr_pool_t *pool){ svn_ra_local__session_baton_t *baton = session->priv; SVN_ERR(svn_repos_fs_revision_prop(value, baton->repos, rev, name, NULL, NULL, pool)); return SVN_NO_ERROR;}struct deltify_etc_baton{ svn_fs_t *fs; /* the fs to deltify in */ svn_repos_t *repos; /* repos for unlocking */ const char *fs_path; /* fs-path part of split session URL */ apr_hash_t *lock_tokens; /* tokens to unlock, if any */ apr_pool_t *pool; /* pool for scratch work */ svn_commit_callback2_t callback; /* the original callback */ void *callback_baton; /* the original callback's baton */};/* This implements 'svn_commit_callback_t'. Its invokes the original (wrapped) callback, but also does deltification on the new revision and possibly unlocks committed paths. BATON is 'struct deltify_etc_baton *'. */static svn_error_t * deltify_etc(const svn_commit_info_t *commit_info, void *baton, apr_pool_t *pool){ struct deltify_etc_baton *db = baton; svn_error_t *err1, *err2; apr_hash_index_t *hi; apr_pool_t *iterpool; /* Invoke the original callback first, in case someone's waiting to know the revision number so they can go off and annotate an issue or something. */ err1 = (*db->callback)(commit_info, db->callback_baton, pool); /* Maybe unlock the paths. */ if (db->lock_tokens) { iterpool = svn_pool_create(db->pool); for (hi = apr_hash_first(db->pool, db->lock_tokens); hi; hi = apr_hash_next(hi)) { const void *rel_path; void *val; const char *abs_path, *token;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -