📄 ra_plugin.c
字号:
/* Open the revision's root. */ if (! SVN_IS_VALID_REVNUM(revision)) { SVN_ERR(svn_fs_youngest_rev(&youngest_rev, sbaton->fs, pool)); SVN_ERR(svn_fs_revision_root(&root, sbaton->fs, youngest_rev, pool)); if (fetched_rev != NULL) *fetched_rev = youngest_rev; } else SVN_ERR(svn_fs_revision_root(&root, sbaton->fs, revision, pool)); if (stream) { /* Get a stream representing the file's contents. */ SVN_ERR(svn_fs_file_contents(&contents, root, abs_path, pool)); /* Now push data from the fs stream back at the caller's stream. Note that this particular RA layer does not computing a checksum as we go, and confirming it against the repository's checksum when done. That's because it calls svn_fs_file_contents() directly, which already checks the stored checksum, and all we're doing here is writing bytes in a loop. Truly, Nothing Can Go Wrong :-). But RA layers that go over a network should confirm the checksum. */ SVN_ERR(svn_stream_copy(contents, stream, pool)); SVN_ERR(svn_stream_close(contents)); } /* Handle props if requested. */ if (props) SVN_ERR(get_node_props(props, sbaton, root, abs_path, pool)); return SVN_NO_ERROR;}/* Getting a directory's entries */static svn_error_t *svn_ra_local__get_dir(svn_ra_session_t *session, apr_hash_t **dirents, svn_revnum_t *fetched_rev, apr_hash_t **props, const char *path, svn_revnum_t revision, apr_uint32_t dirent_fields, apr_pool_t *pool){ svn_fs_root_t *root; svn_revnum_t youngest_rev; apr_hash_t *entries; apr_hash_index_t *hi; svn_ra_local__session_baton_t *sbaton = session->priv; const char *abs_path = sbaton->fs_path->data; apr_pool_t *subpool; /* ### Not sure if this counts as a workaround or not. The session baton uses the empty string to mean root, and not sure that should change. However, it would be better to use a path library function to add this separator -- hardcoding it is totally bogus. See issue #559, though it may be only tangentially related. */ if (abs_path[0] == '\0') abs_path = "/"; /* If we were given a relative path to append, append it. */ if (path) abs_path = svn_path_join(abs_path, path, pool); /* Open the revision's root. */ if (! SVN_IS_VALID_REVNUM(revision)) { SVN_ERR(svn_fs_youngest_rev(&youngest_rev, sbaton->fs, pool)); SVN_ERR(svn_fs_revision_root(&root, sbaton->fs, youngest_rev, pool)); if (fetched_rev != NULL) *fetched_rev = youngest_rev; } else SVN_ERR(svn_fs_revision_root(&root, sbaton->fs, revision, pool)); if (dirents) { /* Get the dir's entries. */ SVN_ERR(svn_fs_dir_entries(&entries, root, abs_path, pool)); /* Loop over the fs dirents, and build a hash of general svn_dirent_t's. */ *dirents = apr_hash_make(pool); subpool = svn_pool_create(pool); for (hi = apr_hash_first(pool, entries); hi; hi = apr_hash_next(hi)) { const void *key; void *val; apr_hash_t *prophash; const char *datestring, *entryname, *fullpath; svn_fs_dirent_t *fs_entry; svn_dirent_t *entry = apr_pcalloc(pool, sizeof(*entry)); svn_pool_clear(subpool); apr_hash_this(hi, &key, NULL, &val); entryname = (const char *) key; fs_entry = (svn_fs_dirent_t *) val; fullpath = svn_path_join(abs_path, entryname, subpool); if (dirent_fields & SVN_DIRENT_KIND) { /* node kind */ entry->kind = fs_entry->kind; } if (dirent_fields & SVN_DIRENT_SIZE) { /* size */ if (entry->kind == svn_node_dir) entry->size = 0; else SVN_ERR(svn_fs_file_length(&(entry->size), root, fullpath, subpool)); } if (dirent_fields & SVN_DIRENT_HAS_PROPS) { /* has_props? */ SVN_ERR(svn_fs_node_proplist(&prophash, root, fullpath, subpool)); entry->has_props = (apr_hash_count(prophash)) ? TRUE : FALSE; } if ((dirent_fields & SVN_DIRENT_TIME) || (dirent_fields & SVN_DIRENT_LAST_AUTHOR) || (dirent_fields & SVN_DIRENT_CREATED_REV)) { /* created_rev & friends */ SVN_ERR(svn_repos_get_committed_info(&(entry->created_rev), &datestring, &(entry->last_author), root, fullpath, subpool)); if (datestring) SVN_ERR(svn_time_from_cstring(&(entry->time), datestring, pool)); if (entry->last_author) entry->last_author = apr_pstrdup(pool, entry->last_author); } /* Store. */ apr_hash_set(*dirents, entryname, APR_HASH_KEY_STRING, entry); } svn_pool_destroy(subpool); } /* Handle props if requested. */ if (props) SVN_ERR(get_node_props(props, sbaton, root, abs_path, pool)); return SVN_NO_ERROR;}static svn_error_t *svn_ra_local__get_locations(svn_ra_session_t *session, apr_hash_t **locations, const char *relative_path, svn_revnum_t peg_revision, apr_array_header_t *location_revisions, apr_pool_t *pool){ svn_ra_local__session_baton_t *sbaton = session->priv; const char *abs_path; /* Append the relative path to the base FS path to get an absolute repository path. */ abs_path = svn_path_join(sbaton->fs_path->data, relative_path, pool); SVN_ERR(svn_repos_trace_node_locations(sbaton->fs, locations, abs_path, peg_revision, location_revisions, NULL, NULL, pool)); return SVN_NO_ERROR;}static svn_error_t *svn_ra_local__lock(svn_ra_session_t *session, apr_hash_t *path_revs, const char *comment, svn_boolean_t force, svn_ra_lock_callback_t lock_func, void *lock_baton, apr_pool_t *pool){ svn_ra_local__session_baton_t *sess = session->priv; apr_hash_index_t *hi; apr_pool_t *iterpool = svn_pool_create(pool); /* A username is absolutely required to lock a path. */ SVN_ERR(get_username(session, pool)); for (hi = apr_hash_first(pool, path_revs); hi; hi = apr_hash_next(hi)) { svn_lock_t *lock; const void *key; const char *path; void *val; svn_revnum_t *revnum; const char *abs_path; svn_error_t *err, *callback_err = NULL; svn_pool_clear(iterpool); apr_hash_this(hi, &key, NULL, &val); path = key; revnum = val; abs_path = svn_path_join(sess->fs_path->data, path, iterpool); /* This wrapper will call pre- and post-lock hooks. */ err = svn_repos_fs_lock(&lock, sess->repos, abs_path, NULL, comment, FALSE /* not DAV comment */, 0 /* no expiration */, *revnum, force, iterpool); if (err && !SVN_ERR_IS_LOCK_ERROR(err)) return err; if (lock_func) callback_err = lock_func(lock_baton, path, TRUE, err ? NULL : lock, err, iterpool); svn_error_clear(err); if (callback_err) return callback_err; } svn_pool_destroy(iterpool); return SVN_NO_ERROR;}static svn_error_t *svn_ra_local__unlock(svn_ra_session_t *session, apr_hash_t *path_tokens, svn_boolean_t force, svn_ra_lock_callback_t lock_func, void *lock_baton, apr_pool_t *pool){ svn_ra_local__session_baton_t *sess = session->priv; apr_hash_index_t *hi; apr_pool_t *iterpool = svn_pool_create(pool); /* A username is absolutely required to unlock a path. */ SVN_ERR(get_username(session, pool)); for (hi = apr_hash_first(pool, path_tokens); hi; hi = apr_hash_next(hi)) { const void *key; const char *path; void *val; const char *abs_path, *token; svn_error_t *err, *callback_err = NULL; svn_pool_clear(iterpool); apr_hash_this(hi, &key, NULL, &val); path = key; /* Since we can't store NULL values in a hash, we turn "" to NULL here. */ if (strcmp(val, "") != 0) token = val; else token = NULL; abs_path = svn_path_join(sess->fs_path->data, path, iterpool); /* This wrapper will call pre- and post-unlock hooks. */ err = svn_repos_fs_unlock(sess->repos, abs_path, token, force, iterpool); if (err && !SVN_ERR_IS_UNLOCK_ERROR(err)) return err; if (lock_func) callback_err = lock_func(lock_baton, path, FALSE, NULL, err, iterpool); svn_error_clear(err); if (callback_err) return callback_err; } svn_pool_destroy(iterpool); return SVN_NO_ERROR;}static svn_error_t *svn_ra_local__get_lock(svn_ra_session_t *session, svn_lock_t **lock, const char *path, apr_pool_t *pool){ svn_ra_local__session_baton_t *sess = session->priv; const char *abs_path; /* Get the absolute path. */ abs_path = svn_path_join(sess->fs_path->data, path, pool); SVN_ERR(svn_fs_get_lock(lock, sess->fs, abs_path, pool)); return SVN_NO_ERROR;}static svn_error_t *svn_ra_local__get_locks(svn_ra_session_t *session, apr_hash_t **locks, const char *path, apr_pool_t *pool){ svn_ra_local__session_baton_t *sess = session->priv; const char *abs_path; /* Get the absolute path. */ abs_path = svn_path_join(sess->fs_path->data, path, pool); /* Kinda silly to call the repos wrapper, since we have no authz func to give it. But heck, why not. */ SVN_ERR(svn_repos_fs_get_locks(locks, sess->repos, abs_path, NULL, NULL, pool)); return SVN_NO_ERROR;}static svn_error_t *svn_ra_local__replay(svn_ra_session_t *session, svn_revnum_t revision, svn_revnum_t low_water_mark, svn_boolean_t send_deltas, const svn_delta_editor_t *editor, void *edit_baton, apr_pool_t *pool){ svn_ra_local__session_baton_t *sess = session->priv; svn_fs_root_t *root; SVN_ERR(svn_fs_revision_root(&root, svn_repos_fs(sess->repos), revision, pool)); SVN_ERR(svn_repos_replay2(root, sess->fs_path->data, low_water_mark, send_deltas, editor, edit_baton, NULL, NULL, pool)); return SVN_NO_ERROR;}/*----------------------------------------------------------------*/static const svn_version_t *ra_local_version(void){ SVN_VERSION_BODY;}/** The ra_vtable **/static const svn_ra__vtable_t ra_local_vtable ={ ra_local_version, svn_ra_local__get_description, svn_ra_local__get_schemes, svn_ra_local__open, svn_ra_local__reparent, svn_ra_local__get_latest_revnum, svn_ra_local__get_dated_revision, svn_ra_local__change_rev_prop, svn_ra_local__rev_proplist, svn_ra_local__rev_prop, svn_ra_local__get_commit_editor, svn_ra_local__get_file, svn_ra_local__get_dir, svn_ra_local__do_update, svn_ra_local__do_switch, svn_ra_local__do_status, svn_ra_local__do_diff, svn_ra_local__get_log, svn_ra_local__do_check_path, svn_ra_local__stat, svn_ra_local__get_uuid, svn_ra_local__get_repos_root, svn_ra_local__get_locations, svn_ra_local__get_file_revs, svn_ra_local__lock, svn_ra_local__unlock, svn_ra_local__get_lock, svn_ra_local__get_locks, svn_ra_local__replay,};/*----------------------------------------------------------------*//** The One Public Routine, called by libsvn_ra **/svn_error_t *svn_ra_local__init(const svn_version_t *loader_version, const svn_ra__vtable_t **vtable, apr_pool_t *pool){ static const svn_version_checklist_t checklist[] = { { "svn_subr", svn_subr_version }, { "svn_delta", svn_delta_version }, { "svn_repos", svn_repos_version }, { "svn_fs", svn_fs_version }, { NULL, NULL } }; /* Simplified version check to make sure we can safely use the VTABLE parameter. The RA loader does a more exhaustive check. */ if (loader_version->major != SVN_VER_MAJOR) return svn_error_createf(SVN_ERR_VERSION_MISMATCH, NULL, _("Unsupported RA loader version (%d) for " "ra_local"), loader_version->major); SVN_ERR(svn_ver_check_list(ra_local_version(), checklist));#ifndef SVN_LIBSVN_CLIENT_LINKS_RA_LOCAL /* This assumes that POOL was the pool used to load the dso. */ SVN_ERR(svn_fs_initialize(pool));#endif *vtable = &ra_local_vtable; return SVN_NO_ERROR;}/* Compatibility wrapper for the 1.1 and before API. */#define NAME "ra_local"#define DESCRIPTION RA_LOCAL_DESCRIPTION#define VTBL ra_local_vtable#define INITFUNC svn_ra_local__init#define COMPAT_INITFUNC svn_ra_local_init#include "../libsvn_ra/wrapper_template.h"
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -