⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 client.c

📁 subversion-1.4.3-1.tar.gz 配置svn的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * client.c :  Functions for repository access via the Subversion protocol * * ==================================================================== * 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_network_io.h>#include <apr_md5.h>#include <apr_uri.h>#include <assert.h>#include "svn_types.h"#include "svn_string.h"#include "svn_error.h"#include "svn_time.h"#include "svn_path.h"#include "svn_pools.h"#include "svn_config.h"#include "svn_private_config.h"#include "svn_ra.h"#include "../libsvn_ra/ra_loader.h"#include "svn_ra_svn.h"#include "svn_md5.h"#include "svn_props.h"#include "ra_svn.h"typedef struct {  apr_pool_t *pool;  svn_ra_svn_conn_t *conn;  int protocol_version;  svn_boolean_t is_tunneled;  svn_auth_baton_t *auth_baton;  const char *user;  const char *realm_prefix;  const char **tunnel_argv;} ra_svn_session_baton_t;typedef struct {  ra_svn_session_baton_t *sess_baton;  apr_pool_t *pool;  svn_revnum_t *new_rev;  svn_commit_callback2_t callback;  void *callback_baton;} ra_svn_commit_callback_baton_t;typedef struct {  ra_svn_session_baton_t *sess_baton;  svn_ra_svn_conn_t *conn;  apr_pool_t *pool;  const svn_delta_editor_t *editor;  void *edit_baton;} ra_svn_reporter_baton_t;/* Parse an svn URL's tunnel portion into tunnel, if there is a tunnel   portion. */static void parse_tunnel(const char *url, const char **tunnel,                         apr_pool_t *pool){  const char *p;  *tunnel = NULL;  if (strncasecmp(url, "svn", 3) != 0)    return;  url += 3;  /* Get the tunnel specification, if any. */  if (*url == '+')    {      url++;      p = strchr(url, ':');      if (!p)        return;      *tunnel = apr_pstrmemdup(pool, url, p - url);      url = p;    }}static svn_error_t *make_connection(const char *hostname, unsigned short port,                                    apr_socket_t **sock, apr_pool_t *pool){  apr_sockaddr_t *sa;  apr_status_t status;  int family = APR_INET;    /* Make sure we have IPV6 support first before giving apr_sockaddr_info_get     APR_UNSPEC, because it may give us back an IPV6 address even if we can't     create IPV6 sockets.  */  #if APR_HAVE_IPV6#ifdef MAX_SECS_TO_LINGER  status = apr_socket_create(sock, APR_INET6, SOCK_STREAM, pool);#else  status = apr_socket_create(sock, APR_INET6, SOCK_STREAM,                             APR_PROTO_TCP, pool);#endif  if (status == 0)    {      apr_socket_close(*sock);      family = APR_UNSPEC;    }#endif  /* Resolve the hostname. */  status = apr_sockaddr_info_get(&sa, hostname, family, port, 0, pool);  if (status)    return svn_error_createf(status, NULL, _("Unknown hostname '%s'"),                             hostname);  /* Create the socket. */#ifdef MAX_SECS_TO_LINGER  /* ### old APR interface */  status = apr_socket_create(sock, sa->family, SOCK_STREAM, pool);#else  status = apr_socket_create(sock, sa->family, SOCK_STREAM, APR_PROTO_TCP,                              pool);#endif  if (status)    return svn_error_wrap_apr(status, _("Can't create socket"));  status = apr_socket_connect(*sock, sa);  if (status)    return svn_error_wrap_apr(status, _("Can't connect to host '%s'"),                              hostname);  return SVN_NO_ERROR;}/* Convert a property list received from the server into a hash table. */static svn_error_t *parse_proplist(apr_array_header_t *list, apr_pool_t *pool,                                   apr_hash_t **props){  char *name;  svn_string_t *value;  svn_ra_svn_item_t *elt;  int i;  *props = apr_hash_make(pool);  for (i = 0; i < list->nelts; i++)    {      elt = &((svn_ra_svn_item_t *) list->elts)[i];      if (elt->kind != SVN_RA_SVN_LIST)        return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,                                _("Proplist element not a list"));      SVN_ERR(svn_ra_svn_parse_tuple(elt->u.list, pool, "cs", &name, &value));      apr_hash_set(*props, name, APR_HASH_KEY_STRING, value);    }  return SVN_NO_ERROR;}/* Set *DIFFS to an array of svn_prop_t, allocated in POOL, based on the   property diffs in LIST, received from the server. */static svn_error_t *parse_prop_diffs(apr_array_header_t *list,                                     apr_pool_t *pool,                                     apr_array_header_t **diffs){  svn_ra_svn_item_t *elt;  svn_prop_t *prop;  int i;  *diffs = apr_array_make(pool, list->nelts, sizeof(svn_prop_t));  for (i = 0; i < list->nelts; i++)    {      elt = &APR_ARRAY_IDX(list, i, svn_ra_svn_item_t);      if (elt->kind != SVN_RA_SVN_LIST)        return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,                                _("Prop diffs element not a list"));      prop = apr_array_push(*diffs);      SVN_ERR(svn_ra_svn_parse_tuple(elt->u.list, pool, "c(?s)", &prop->name,                                     &prop->value));    }  return SVN_NO_ERROR;}/* Parse a lockdesc, provided in LIST as specified by the protocol into   LOCK, allocated in POOL. */static svn_error_t *parse_lock(apr_array_header_t *list, apr_pool_t *pool,                               svn_lock_t **lock){  const char *cdate, *edate;  *lock = svn_lock_create(pool);  SVN_ERR(svn_ra_svn_parse_tuple(list, pool, "ccc(?c)c(?c)", &(*lock)->path,                                 &(*lock)->token, &(*lock)->owner,                                 &(*lock)->comment, &cdate, &edate));  (*lock)->path = svn_path_canonicalize((*lock)->path, pool);  SVN_ERR(svn_time_from_cstring(&(*lock)->creation_date, cdate, pool));  if (edate)    SVN_ERR(svn_time_from_cstring(&(*lock)->expiration_date, edate, pool));  return SVN_NO_ERROR;}static svn_error_t *interpret_kind(const char *str, apr_pool_t *pool,                                   svn_node_kind_t *kind){  if (strcmp(str, "none") == 0)    *kind = svn_node_none;  else if (strcmp(str, "file") == 0)    *kind = svn_node_file;  else if (strcmp(str, "dir") == 0)    *kind = svn_node_dir;  else if (strcmp(str, "unknown") == 0)    *kind = svn_node_unknown;  else    return svn_error_createf(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,                             _("Unrecognized node kind '%s' from server"),                             str);  return SVN_NO_ERROR;}/* --- AUTHENTICATION ROUTINES --- */static svn_boolean_t find_mech(apr_array_header_t *mechlist, const char *mech){  int i;  svn_ra_svn_item_t *elt;  for (i = 0; i < mechlist->nelts; i++)    {      elt = &((svn_ra_svn_item_t *) mechlist->elts)[i];      if (elt->kind == SVN_RA_SVN_WORD && strcmp(elt->u.word, mech) == 0)        return TRUE;    }  return FALSE;}/* Having picked a mechanism, start authentication by writing out an * auth response.  If COMPAT is true, also write out a version number * and capability list.  MECH_ARG may be NULL for mechanisms with no * initial client response. */static svn_error_t *auth_response(svn_ra_svn_conn_t *conn, apr_pool_t *pool,                                  const char *mech, const char *mech_arg,                                  svn_boolean_t compat){  if (compat)    return svn_ra_svn_write_tuple(conn, pool, "nw(?c)(www)", (apr_uint64_t) 1,                                  mech, mech_arg,                                  SVN_RA_SVN_CAP_EDIT_PIPELINE,                                  SVN_RA_SVN_CAP_SVNDIFF1,                                  SVN_RA_SVN_CAP_ABSENT_ENTRIES);  else    return svn_ra_svn_write_tuple(conn, pool, "w(?c)", mech, mech_arg);}/* Read the "success" response to ANONYMOUS or EXTERNAL authentication. */static svn_error_t *read_success(svn_ra_svn_conn_t *conn, apr_pool_t *pool){  const char *status, *arg;  SVN_ERR(svn_ra_svn_read_tuple(conn, pool, "w(?c)", &status, &arg));  if (strcmp(status, "failure") == 0 && arg)    return svn_error_createf(SVN_ERR_RA_NOT_AUTHORIZED, NULL,                             _("Authentication error from server: %s"), arg);  else if (strcmp(status, "success") != 0 || arg)    return svn_error_create(SVN_ERR_RA_NOT_AUTHORIZED, NULL,                            _("Unexpected server response to authentication"));  return SVN_NO_ERROR;}/* Respond to an auth request and perform authentication.  REALM may * be NULL for the initial authentication exchange of protocol version * 1. */static svn_error_t *do_auth(ra_svn_session_baton_t *sess,                            apr_array_header_t *mechlist,                            const char *realm, apr_pool_t *pool){  svn_ra_svn_conn_t *conn = sess->conn;  const char *realmstring, *user, *password, *msg;  svn_auth_iterstate_t *iterstate;  void *creds;  svn_boolean_t compat = (realm == NULL);  realmstring = realm ? apr_psprintf(pool, "%s %s", sess->realm_prefix, realm)    : sess->realm_prefix;  if (sess->is_tunneled && find_mech(mechlist, "EXTERNAL"))    {      /* Ask the server to use the tunnel connection environment (on       * Unix, that means uid) to determine the authentication name. */      SVN_ERR(auth_response(conn, pool, "EXTERNAL", "", compat));      return read_success(conn, pool);    }  else if (find_mech(mechlist, "ANONYMOUS"))    {      SVN_ERR(auth_response(conn, pool, "ANONYMOUS", "", compat));      return read_success(conn, pool);    }  else if (find_mech(mechlist, "CRAM-MD5"))    {      SVN_ERR(svn_auth_first_credentials(&creds, &iterstate,                                         SVN_AUTH_CRED_SIMPLE, realmstring,                                         sess->auth_baton, pool));      if (!creds)        return svn_error_create(SVN_ERR_RA_NOT_AUTHORIZED, NULL,                                _("Can't get password"));      while (creds)        {          user = ((svn_auth_cred_simple_t *) creds)->username;          password = ((svn_auth_cred_simple_t *) creds)->password;          SVN_ERR(auth_response(conn, pool, "CRAM-MD5", NULL, compat));          SVN_ERR(svn_ra_svn__cram_client(conn, pool, user, password, &msg));          if (!msg)            break;          SVN_ERR(svn_auth_next_credentials(&creds, iterstate, pool));        }      if (!creds)        return svn_error_createf(SVN_ERR_RA_NOT_AUTHORIZED, NULL,                                 _("Authentication error from server: %s"),                                 msg);      SVN_ERR(svn_auth_save_credentials(iterstate, pool));      return SVN_NO_ERROR;    }  else    return svn_error_create(SVN_ERR_RA_NOT_AUTHORIZED, NULL,                            _("Cannot negotiate authentication mechanism"));}static svn_error_t *handle_auth_request(ra_svn_session_baton_t *sess,                                        apr_pool_t *pool){  svn_ra_svn_conn_t *conn = sess->conn;  apr_array_header_t *mechlist;  const char *realm;  if (sess->protocol_version < 2)    return SVN_NO_ERROR;  SVN_ERR(svn_ra_svn_read_cmd_response(conn, pool, "lc", &mechlist, &realm));  if (mechlist->nelts == 0)    return SVN_NO_ERROR;  return do_auth(sess, mechlist, realm, pool);}/* --- REPORTER IMPLEMENTATION --- */static svn_error_t *ra_svn_set_path(void *baton, const char *path,                                    svn_revnum_t rev,                                    svn_boolean_t start_empty,                                    const char *lock_token,                                    apr_pool_t *pool){  ra_svn_reporter_baton_t *b = baton;  SVN_ERR(svn_ra_svn_write_cmd(b->conn, pool, "set-path", "crb(?c)", path, rev,                               start_empty, lock_token));

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -