commit.c
来自「linux subdivision ying gai ke yi le ba」· C语言 代码 · 共 1,333 行 · 第 1/4 页
C
1,333 行
/*
* commit.c : routines for committing changes to the server
*
* ====================================================================
* 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 <apr_pools.h>
#include <apr_hash.h>
#include <apr_uuid.h>
#include <apr_portable.h>
#define APR_WANT_STDIO
#define APR_WANT_STRFUNC
#include <apr_want.h>
#if APR_HAVE_STDLIB
#include <stdlib.h> /* for free() */
#endif
#include <assert.h>
#include <ne_socket.h>
#include <ne_request.h>
#include <ne_props.h>
#include <ne_basic.h>
#include "svn_pools.h"
#include "svn_error.h"
#include "svn_delta.h"
#include "svn_io.h"
#include "svn_ra.h"
#include "svn_path.h"
#include "svn_xml.h"
#include "svn_dav.h"
#include "svn_base64.h"
#include "svn_private_config.h"
#include "ra_dav.h"
/*
** resource_t: identify the relevant pieces of a resource on the server
**
** REVISION is the resource's revision, or SVN_INVALID_REVNUM if it is
** new or is the HEAD.
**
** URL refers to the public/viewable/original resource.
** VSN_URL refers to the version resource that we stored locally
** WR_URL refers to a working resource for this resource
**
** Note that VSN_URL is NULL if this resource has just been added, and
** WR_URL can be NULL if the resource has not (yet) been checked out.
**
** LOCAL_PATH is relative to the root of the commit. It will be used
** for the get_func, push_func, and close_func callbacks.
*/
typedef struct
{
svn_revnum_t revision;
const char *url;
const char *vsn_url;
const char *wr_url;
const char *local_path;
apr_pool_t *pool; /* pool in which this resource is allocated. */
} resource_t;
typedef struct
{
svn_ra_session_t *ras;
const char *activity_url;
apr_hash_t *valid_targets;
svn_ra_get_wc_prop_func_t get_func;
svn_ra_push_wc_prop_func_t push_func;
void *cb_baton;
svn_boolean_t disable_merge_response;
/* The (potential) author of this commit. */
const char *user;
/* Log message for the commit. */
const char *log_msg;
/* The commit callback and baton */
svn_commit_callback_t callback;
void *callback_baton;
} commit_ctx_t;
typedef struct
{
apr_file_t *tmpfile;
svn_stringbuf_t *fname;
const char *base_checksum; /* hex md5 of base text; may be null */
} put_baton_t;
typedef struct
{
commit_ctx_t *cc;
resource_t *rsrc;
apr_hash_t *prop_changes; /* name/values pairs of new/changed properties. */
apr_array_header_t *prop_deletes; /* names of properties to delete. */
svn_boolean_t created; /* set if this is an add rather than an update */
apr_pool_t *pool; /* the pool from open_foo() / add_foo() */
put_baton_t *put_baton; /* baton for this file's PUT request */
} resource_baton_t;
/* this property will be fetched from the server when we don't find it
cached in the WC property store. */
static const ne_propname fetch_props[] =
{
{ "DAV:", "checked-in" },
{ NULL }
};
static const ne_propname log_message_prop = { SVN_DAV_PROP_NS_SVN, "log" };
/* perform a deep copy of BASE into POOL, and return the result. */
static resource_t * dup_resource(resource_t *base, apr_pool_t *pool)
{
resource_t *rsrc = apr_pcalloc(pool, sizeof(*rsrc));
rsrc->pool = pool;
rsrc->revision = base->revision;
rsrc->url = base->url ?
apr_pstrdup(pool, base->url) : NULL;
rsrc->vsn_url = base->vsn_url ?
apr_pstrdup(pool, base->vsn_url) : NULL;
rsrc->wr_url = base->wr_url ?
apr_pstrdup(pool, base->wr_url) : NULL;
rsrc->local_path = base->local_path ?
apr_pstrdup(pool, base->local_path) : NULL;
return rsrc;
}
static svn_error_t * simple_request(svn_ra_session_t *ras,
const char *method,
const char *url,
int *code,
apr_hash_t *extra_headers,
int okay_1,
int okay_2,
apr_pool_t *pool)
{
ne_request *req;
/* create/prep the request */
req = ne_request_create(ras->sess, method, url);
if (req == NULL)
{
return svn_error_createf(SVN_ERR_RA_DAV_CREATING_REQUEST, NULL,
_("Could not create a request (%s '%s')"),
method, url);
}
/* add any extra headers passed in by caller. */
if (extra_headers != NULL)
{
apr_hash_index_t *hi;
for (hi = apr_hash_first(pool, extra_headers);
hi; hi = apr_hash_next(hi))
{
const void *key;
void *val;
apr_hash_this(hi, &key, NULL, &val);
ne_add_request_header(req, (const char *) key, (const char *) val);
}
}
/* run the request and get the resulting status code (and svn_error_t) */
SVN_ERR( svn_ra_dav__request_dispatch(code, req, ras->sess,
method, url, okay_1, okay_2,
pool) );
return SVN_NO_ERROR;
}
static svn_error_t * delete_activity(void *edit_baton,
apr_pool_t *pool)
{
commit_ctx_t *cc = edit_baton;
return simple_request(cc->ras, "DELETE", cc->activity_url, NULL,
NULL, 204 /* No Content */, 404 /* Not Found */, pool);
}
/* Get the version resource URL for RSRC, storing it in
RSRC->vsn_url. Use POOL for all temporary allocations. */
static svn_error_t * get_version_url(commit_ctx_t *cc,
resource_t *rsrc,
svn_boolean_t force,
apr_pool_t *pool)
{
svn_ra_dav_resource_t *propres;
const char *url;
const svn_string_t *url_str;
if (!force && cc->get_func != NULL)
{
const svn_string_t *vsn_url_value;
SVN_ERR( (*cc->get_func)(cc->cb_baton,
rsrc->local_path,
SVN_RA_DAV__LP_VSN_URL,
&vsn_url_value,
pool) );
if (vsn_url_value != NULL)
{
rsrc->vsn_url = apr_pstrdup (rsrc->pool, vsn_url_value->data);
return SVN_NO_ERROR;
}
/* whoops. it wasn't there. go grab it from the server. */
}
if (rsrc->revision == SVN_INVALID_REVNUM)
{
/* We aren't trying to get a specific version -- use the HEAD. We
fetch the version URL from the public URL. */
url = rsrc->url;
}
else
{
svn_string_t bc_url;
svn_string_t bc_relative;
/* The version URL comes from a resource in the Baseline Collection. */
SVN_ERR( svn_ra_dav__get_baseline_info(NULL,
&bc_url, &bc_relative, NULL,
cc->ras->sess,
rsrc->url,
rsrc->revision,
pool));
url = svn_path_url_add_component(bc_url.data, bc_relative.data, pool);
}
/* Get the DAV:checked-in property, which contains the URL of the
Version Resource */
SVN_ERR( svn_ra_dav__get_props_resource(&propres, cc->ras->sess, url,
NULL, fetch_props, pool) );
url_str = apr_hash_get(propres->propset,
SVN_RA_DAV__PROP_CHECKED_IN,
APR_HASH_KEY_STRING);
if (url_str == NULL)
{
/* ### need a proper SVN_ERR here */
return svn_error_create(APR_EGENERAL, NULL,
"Could not fetch the Version Resource URL "
"(needed during an import or when it is "
"missing from the local, cached props)");
}
/* ensure we get the proper lifetime for this URL since it is going into
a resource object. */
rsrc->vsn_url = apr_pstrdup(rsrc->pool, url_str->data);
if (cc->push_func != NULL)
{
/* Now we can store the new version-url. */
SVN_ERR( (*cc->push_func)(cc->cb_baton,
rsrc->local_path,
SVN_RA_DAV__LP_VSN_URL,
url_str,
pool) );
}
return SVN_NO_ERROR;
}
/* When FORCE is true, then we force a query to the server, ignoring any
cached property. */
static svn_error_t * get_activity_collection(commit_ctx_t *cc,
const svn_string_t **collection,
svn_boolean_t force,
apr_pool_t *pool)
{
if (!force && cc->get_func != NULL)
{
/* with a get_func, we can just ask for the activity URL from the
property store. */
/* get the URL where we should create activities */
SVN_ERR( (*cc->get_func)(cc->cb_baton,
"",
SVN_RA_DAV__LP_ACTIVITY_COLL,
collection,
pool) );
if (*collection != NULL)
{
/* the property was there. return it. */
return SVN_NO_ERROR;
}
/* property not found for some reason. get it from the server. */
}
/* use our utility function to fetch the activity URL */
SVN_ERR( svn_ra_dav__get_activity_collection(collection,
cc->ras,
cc->ras->root.path,
pool) );
if (cc->push_func != NULL)
{
/* save the (new) activity collection URL into the directory */
SVN_ERR( (*cc->push_func)(cc->cb_baton,
"",
SVN_RA_DAV__LP_ACTIVITY_COLL,
*collection,
pool) );
}
return SVN_NO_ERROR;
}
static svn_error_t * create_activity(commit_ctx_t *cc,
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?