📄 editorp.c
字号:
/* * editorp.c : Pipelined variation of the ra_svn editor * * ==================================================================== * Copyright (c) 2000-2006 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 <apr_general.h>#include <apr_strings.h>#include <apr_md5.h>#include <assert.h>#include "svn_types.h"#include "svn_string.h"#include "svn_error.h"#include "svn_path.h"#include "svn_delta.h"#include "svn_ra_svn.h"#include "svn_pools.h"#include "svn_private_config.h"#include "ra_svn.h"/* * Both the client and server in the svn protocol need to drive and * consume editors. For a commit, the client drives and the server * consumes; for an update/switch/status/diff, the server drives and * the client consumes. This file provides a generic framework for * marshalling and unmarshalling editor operations over an svn * connection; both ends are useful for both server and client. */typedef struct { svn_ra_svn_conn_t *conn; svn_ra_svn_edit_callback callback; /* Called on successful completion. */ void *callback_baton; int next_token; svn_boolean_t got_status;} ra_svn_edit_baton_t;/* Works for both directories and files. */typedef struct { svn_ra_svn_conn_t *conn; apr_pool_t *pool; ra_svn_edit_baton_t *eb; const char *token;} ra_svn_baton_t;typedef struct { const svn_delta_editor_t *editor; void *edit_baton; apr_hash_t *tokens; svn_boolean_t *aborted; svn_boolean_t done; apr_pool_t *pool; apr_pool_t *file_pool; int file_refs; svn_boolean_t for_replay;} ra_svn_driver_state_t;/* Works for both directories and files; however, the pool handling is different for files. To save space during commits (where file batons generally last until the end of the commit), token entries for files are all created in a single reference-counted pool (the file_pool member of the driver state structure), which is cleared at close_file time when the reference count hits zero. So the pool field in this structure is vestigial for files, and we use it for a different purpose instead: at apply-textdelta time, we set it to a subpool of the file pool, which is destroyed in textdelta-end. */typedef struct { const char *token; void *baton; svn_boolean_t is_file; svn_stream_t *dstream; /* svndiff stream for apply_textdelta */ apr_pool_t *pool;} ra_svn_token_entry_t;/* --- CONSUMING AN EDITOR BY PASSING EDIT OPERATIONS OVER THE NET --- */static const char *make_token(char type, ra_svn_edit_baton_t *eb, apr_pool_t *pool){ return apr_psprintf(pool, "%c%d", type, eb->next_token++);}static ra_svn_baton_t *ra_svn_make_baton(svn_ra_svn_conn_t *conn, apr_pool_t *pool, ra_svn_edit_baton_t *eb, const char *token){ ra_svn_baton_t *b; b = apr_palloc(pool, sizeof(*b)); b->conn = conn; b->pool = pool; b->eb = eb; b->token = token; return b;}/* Check for an early error status report from the consumer. If we * get one, abort the edit and return the error. */static svn_error_t *check_for_error(ra_svn_edit_baton_t *eb, apr_pool_t *pool){ assert(!eb->got_status); if (svn_ra_svn__input_waiting(eb->conn, pool)) { eb->got_status = TRUE; SVN_ERR(svn_ra_svn_write_cmd(eb->conn, pool, "abort-edit", "")); SVN_ERR(svn_ra_svn_read_cmd_response(eb->conn, pool, "")); /* We shouldn't get here if the consumer is doing its job. */ return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL, _("Successful edit status returned too soon")); } return SVN_NO_ERROR;}static svn_error_t *ra_svn_target_rev(void *edit_baton, svn_revnum_t rev, apr_pool_t *pool){ ra_svn_edit_baton_t *eb = edit_baton; SVN_ERR(check_for_error(eb, pool)); SVN_ERR(svn_ra_svn_write_cmd(eb->conn, pool, "target-rev", "r", rev)); return SVN_NO_ERROR;}static svn_error_t *ra_svn_open_root(void *edit_baton, svn_revnum_t rev, apr_pool_t *pool, void **root_baton){ ra_svn_edit_baton_t *eb = edit_baton; const char *token = make_token('d', eb, pool); SVN_ERR(check_for_error(eb, pool)); SVN_ERR(svn_ra_svn_write_cmd(eb->conn, pool, "open-root", "(?r)c", rev, token)); *root_baton = ra_svn_make_baton(eb->conn, pool, eb, token); return SVN_NO_ERROR;}static svn_error_t *ra_svn_delete_entry(const char *path, svn_revnum_t rev, void *parent_baton, apr_pool_t *pool){ ra_svn_baton_t *b = parent_baton; SVN_ERR(check_for_error(b->eb, pool)); SVN_ERR(svn_ra_svn_write_cmd(b->conn, pool, "delete-entry", "c(?r)c", path, rev, b->token)); return SVN_NO_ERROR;}static svn_error_t *ra_svn_add_dir(const char *path, void *parent_baton, const char *copy_path, svn_revnum_t copy_rev, apr_pool_t *pool, void **child_baton){ ra_svn_baton_t *b = parent_baton; const char *token = make_token('d', b->eb, pool); assert((copy_path && SVN_IS_VALID_REVNUM(copy_rev)) || (!copy_path && !SVN_IS_VALID_REVNUM(copy_rev))); SVN_ERR(check_for_error(b->eb, pool)); SVN_ERR(svn_ra_svn_write_cmd(b->conn, pool, "add-dir", "ccc(?cr)", path, b->token, token, copy_path, copy_rev)); *child_baton = ra_svn_make_baton(b->conn, pool, b->eb, token); return SVN_NO_ERROR;}static svn_error_t *ra_svn_open_dir(const char *path, void *parent_baton, svn_revnum_t rev, apr_pool_t *pool, void **child_baton){ ra_svn_baton_t *b = parent_baton; const char *token = make_token('d', b->eb, pool); SVN_ERR(check_for_error(b->eb, pool)); SVN_ERR(svn_ra_svn_write_cmd(b->conn, pool, "open-dir", "ccc(?r)", path, b->token, token, rev)); *child_baton = ra_svn_make_baton(b->conn, pool, b->eb, token); return SVN_NO_ERROR;}static svn_error_t *ra_svn_change_dir_prop(void *dir_baton, const char *name, const svn_string_t *value, apr_pool_t *pool){ ra_svn_baton_t *b = dir_baton; SVN_ERR(check_for_error(b->eb, pool)); SVN_ERR(svn_ra_svn_write_cmd(b->conn, pool, "change-dir-prop", "cc(?s)", b->token, name, value)); return SVN_NO_ERROR;}static svn_error_t *ra_svn_close_dir(void *dir_baton, apr_pool_t *pool){ ra_svn_baton_t *b = dir_baton; SVN_ERR(check_for_error(b->eb, pool)); SVN_ERR(svn_ra_svn_write_cmd(b->conn, pool, "close-dir", "c", b->token)); return SVN_NO_ERROR;}static svn_error_t *ra_svn_absent_dir(const char *path, void *parent_baton, apr_pool_t *pool){ ra_svn_baton_t *b = parent_baton; /* Avoid sending an unknown command if the other end doesn't support absent-dir. */ if (! svn_ra_svn_has_capability(b->conn, SVN_RA_SVN_CAP_ABSENT_ENTRIES)) return SVN_NO_ERROR; SVN_ERR(check_for_error(b->eb, pool)); SVN_ERR(svn_ra_svn_write_cmd(b->conn, pool, "absent-dir", "cc", path, b->token)); return SVN_NO_ERROR;}static svn_error_t *ra_svn_add_file(const char *path, void *parent_baton, const char *copy_path, svn_revnum_t copy_rev, apr_pool_t *pool, void **file_baton){ ra_svn_baton_t *b = parent_baton; const char *token = make_token('c', b->eb, pool); assert((copy_path && SVN_IS_VALID_REVNUM(copy_rev)) || (!copy_path && !SVN_IS_VALID_REVNUM(copy_rev))); SVN_ERR(check_for_error(b->eb, pool)); SVN_ERR(svn_ra_svn_write_cmd(b->conn, pool, "add-file", "ccc(?cr)", path, b->token, token, copy_path, copy_rev)); *file_baton = ra_svn_make_baton(b->conn, pool, b->eb, token); return SVN_NO_ERROR;}static svn_error_t *ra_svn_open_file(const char *path, void *parent_baton, svn_revnum_t rev, apr_pool_t *pool, void **file_baton){ ra_svn_baton_t *b = parent_baton; const char *token = make_token('c', b->eb, pool); SVN_ERR(check_for_error(b->eb, b->pool)); SVN_ERR(svn_ra_svn_write_cmd(b->conn, pool, "open-file", "ccc(?r)", path, b->token, token, rev)); *file_baton = ra_svn_make_baton(b->conn, pool, b->eb, token); return SVN_NO_ERROR;}static svn_error_t *ra_svn_svndiff_handler(void *baton, const char *data, apr_size_t *len){ ra_svn_baton_t *b = baton; svn_string_t str; SVN_ERR(check_for_error(b->eb, b->pool)); str.data = data; str.len = *len; return svn_ra_svn_write_cmd(b->conn, b->pool, "textdelta-chunk", "cs", b->token, &str);}static svn_error_t *ra_svn_svndiff_close_handler(void *baton){ ra_svn_baton_t *b = baton; SVN_ERR(check_for_error(b->eb, b->pool)); SVN_ERR(svn_ra_svn_write_cmd(b->conn, b->pool, "textdelta-end", "c", b->token)); return SVN_NO_ERROR;}static svn_error_t *ra_svn_apply_textdelta(void *file_baton, const char *base_checksum, apr_pool_t *pool, svn_txdelta_window_handler_t *wh, void **wh_baton){ ra_svn_baton_t *b = file_baton; svn_stream_t *diff_stream; /* Tell the other side we're starting a text delta. */ SVN_ERR(check_for_error(b->eb, pool)); SVN_ERR(svn_ra_svn_write_cmd(b->conn, pool, "apply-textdelta", "c(?c)", b->token, base_checksum)); /* Transform the window stream to an svndiff stream. Reuse the * file baton for the stream handler, since it has all the
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -