fetch.c
来自「linux subdivision ying gai ke yi le ba」· C语言 代码 · 共 1,814 行 · 第 1/5 页
C
1,814 行
/*
* fetch.c : routines for fetching updates and checkouts
*
* ====================================================================
* 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/.
* ====================================================================
*/
#define APR_WANT_STRFUNC
#include <apr_want.h> /* for strcmp() */
#include <apr_pools.h>
#include <apr_tables.h>
#include <apr_strings.h>
#include <apr_md5.h>
#include <apr_portable.h>
#include <apr_xml.h>
#include <ne_socket.h>
#include <ne_basic.h>
#include <ne_utils.h>
#include <ne_basic.h>
#include <ne_207.h>
#include <ne_props.h>
#include <ne_xml.h>
#include <ne_request.h>
#include <ne_compress.h>
#include "svn_error.h"
#include "svn_pools.h"
#include "svn_delta.h"
#include "svn_io.h"
#include "svn_md5.h"
#include "svn_base64.h"
#include "svn_ra.h"
#include "svn_path.h"
#include "svn_xml.h"
#include "svn_dav.h"
#include "svn_time.h"
#include "svn_private_config.h"
#include "ra_dav.h"
#define CHKERR(e) \
do { \
if ((rb->err = (e)) != NULL) \
return NE_XML_ABORT; \
} while(0)
typedef struct {
/* the information for this subdir. if rsrc==NULL, then this is a sentinel
record in fetch_ctx_t.subdirs to close the directory implied by the
parent_baton member. */
svn_ra_dav_resource_t *rsrc;
/* the directory containing this subdirectory. */
void *parent_baton;
} subdir_t;
typedef struct {
apr_pool_t *pool;
/* these two are the handler that the editor gave us */
svn_txdelta_window_handler_t handler;
void *handler_baton;
/* if we're receiving an svndiff, this is a parser which places the
resulting windows into the above handler/baton. */
svn_stream_t *stream;
} file_read_ctx_t;
typedef struct {
svn_boolean_t do_checksum; /* only accumulate checksum if set */
apr_md5_ctx_t md5_context; /* accumulating checksum of file contents */
svn_stream_t *stream; /* stream to write file contents to */
} file_write_ctx_t;
typedef struct {
svn_error_t *err; /* propagate an error out of the reader */
int checked_type; /* have we processed ctype yet? */
ne_content_type ctype; /* the Content-Type header */
void *subctx;
} custom_get_ctx_t;
#define POP_SUBDIR(sds) (((subdir_t **)(sds)->elts)[--(sds)->nelts])
#define PUSH_SUBDIR(sds,s) (*(subdir_t **)apr_array_push(sds) = (s))
typedef svn_error_t * (*prop_setter_t)(void *baton,
const char *name,
const svn_string_t *value,
apr_pool_t *pool);
typedef struct {
/* The baton returned by the editor's open_root/open_dir */
void *baton;
/* Should we fetch properties for this directory when the close tag
is found? */
svn_boolean_t fetch_props;
/* The version resource URL for this directory. */
const char *vsn_url;
/* A buffer which stores the relative directory name. We also use this
for temporary construction of relative file names. */
svn_stringbuf_t *pathbuf;
/* If a directory, this may contain a hash of prophashes returned
from doing a depth 1 PROPFIND. */
apr_hash_t *children;
/* A subpool. It's about memory. Ya dig? */
apr_pool_t *pool;
} dir_item_t;
typedef struct {
svn_ra_session_t *ras;
apr_file_t *tmpfile;
/* Pool initialized when the report_baton is created, and meant for
quick scratchwork. This is like a loop pool, but since the loop
that drives ra_dav callbacks is in the wrong scope for us to use
the normal loop pool idiom, we must resort to this. Always clear
this pool right after using it; only YOU can prevent forest fires. */
apr_pool_t *scratch_pool;
svn_boolean_t fetch_content;
svn_boolean_t fetch_props;
const svn_delta_editor_t *editor;
void *edit_baton;
apr_array_header_t *dirs; /* stack of directory batons/vsn_urls */
#define TOP_DIR(rb) (((dir_item_t *)(rb)->dirs->elts)[(rb)->dirs->nelts - 1])
#define PUSH_BATON(rb,b) (*(void **)apr_array_push((rb)->dirs) = (b))
/* These items are only valid inside add- and open-file tags! */
void *file_baton;
apr_pool_t *file_pool;
const char *result_checksum; /* hex md5 digest of result; may be null */
svn_stringbuf_t *namestr;
svn_stringbuf_t *cpathstr;
svn_stringbuf_t *href;
/* Empty string means no encoding, "base64" means base64. */
svn_stringbuf_t *encoding;
/* These are used when receiving an inline txdelta, and null at all
other times. */
svn_txdelta_window_handler_t whandler;
void *whandler_baton;
svn_stream_t *svndiff_decoder;
svn_stream_t *base64_decoder;
/* A generic accumulator for elements that have small bits of cdata,
like md5_checksum, href, etc. Uh, or where our own API gives us
no choice about holding them in memory, as with prop values, ahem.
This is always the empty stringbuf when not in use. */
svn_stringbuf_t *cdata_accum;
const char *current_wcprop_path;
svn_boolean_t is_switch;
/* Named target, or NULL if none. For example, in 'svn up wc/foo',
this is "wc/foo", but in 'svn up' it is "".
The target helps us determine whether a response received from
the server should be acted on. Take 'svn up wc/foo': the server
may send back a new vsn-rsrc-url wcprop for 'wc' (because the
report had to be anchored there just in case the update deletes
wc/foo). While this is correct behavior for the server, the
client should ignore the new wcprop, because the client knows
it's not really updating the top level directory. */
const char *target;
/* A modern server will understand our "send-all" attribute on the
update report request, and will put a "send-all" attribute on
its response. If we see that attribute, we set this to true,
otherwise, it stays false (i.e., it's not a modern server). */
svn_boolean_t receiving_all;
svn_error_t *err;
} report_baton_t;
static const char report_head[]
= "<S:update-report send-all=\"true\" xmlns:S=\""
SVN_XML_NAMESPACE "\">" DEBUG_CR;
static const char report_tail[] = "</S:update-report>" DEBUG_CR;
static const svn_ra_dav__xml_elm_t report_elements[] =
{
{ SVN_XML_NAMESPACE, "update-report", ELEM_update_report, 0 },
{ SVN_XML_NAMESPACE, "resource-walk", ELEM_resource_walk, 0 },
{ SVN_XML_NAMESPACE, "resource", ELEM_resource, 0 },
{ SVN_XML_NAMESPACE, "target-revision", ELEM_target_revision, 0 },
{ SVN_XML_NAMESPACE, "open-directory", ELEM_open_directory, 0 },
{ SVN_XML_NAMESPACE, "add-directory", ELEM_add_directory, 0 },
{ SVN_XML_NAMESPACE, "absent-directory", ELEM_absent_directory, 0 },
{ SVN_XML_NAMESPACE, "open-file", ELEM_open_file, 0 },
{ SVN_XML_NAMESPACE, "add-file", ELEM_add_file, 0 },
{ SVN_XML_NAMESPACE, "txdelta", ELEM_txdelta, 0 },
{ SVN_XML_NAMESPACE, "absent-file", ELEM_absent_file, 0 },
{ SVN_XML_NAMESPACE, "delete-entry", ELEM_delete_entry, 0 },
{ SVN_XML_NAMESPACE, "fetch-props", ELEM_fetch_props, 0 },
{ SVN_XML_NAMESPACE, "set-prop", ELEM_set_prop, 0 },
{ SVN_XML_NAMESPACE, "remove-prop", ELEM_remove_prop, 0 },
{ SVN_XML_NAMESPACE, "fetch-file", ELEM_fetch_file, 0 },
{ SVN_XML_NAMESPACE, "prop", ELEM_SVN_prop, 0 },
{ SVN_DAV_PROP_NS_DAV, "repository-uuid",
ELEM_repository_uuid, SVN_RA_DAV__XML_CDATA },
{ SVN_DAV_PROP_NS_DAV, "md5-checksum", ELEM_md5_checksum,
SVN_RA_DAV__XML_CDATA },
{ "DAV:", "version-name", ELEM_version_name, SVN_RA_DAV__XML_CDATA },
{ "DAV:", "creationdate", ELEM_creationdate, SVN_RA_DAV__XML_CDATA },
{ "DAV:", "creator-displayname", ELEM_creator_displayname,
SVN_RA_DAV__XML_CDATA },
{ "DAV:", "checked-in", ELEM_checked_in, 0 },
{ "DAV:", "href", ELEM_href, SVN_RA_DAV__XML_CDATA },
{ NULL }
};
/* Elements used in a dated-rev-report response */
static const svn_ra_dav__xml_elm_t drev_report_elements[] =
{
{ SVN_XML_NAMESPACE, "dated-rev-report", ELEM_dated_rev_report, 0 },
{ "DAV:", "version-name", ELEM_version_name, SVN_RA_DAV__XML_CDATA },
{ NULL }
};
static svn_error_t *simple_store_vsn_url(const char *vsn_url,
void *baton,
prop_setter_t setter,
apr_pool_t *pool)
{
/* store the version URL as a property */
SVN_ERR_W( (*setter)(baton, SVN_RA_DAV__LP_VSN_URL,
svn_string_create(vsn_url, pool), pool),
_("Could not save the URL of the version resource") );
return NULL;
}
static svn_error_t *get_delta_base(const char **delta_base,
const char *relpath,
svn_ra_get_wc_prop_func_t get_wc_prop,
void *cb_baton,
apr_pool_t *pool)
{
const svn_string_t *value;
if (relpath == NULL || get_wc_prop == NULL)
{
*delta_base = NULL;
return SVN_NO_ERROR;
}
SVN_ERR( (*get_wc_prop)(cb_baton, relpath, SVN_RA_DAV__LP_VSN_URL,
&value, pool) );
*delta_base = value ? value->data : NULL;
return SVN_NO_ERROR;
}
/* helper func which maps certain DAV: properties to svn:wc:
properties. Used during checkouts and updates. */
static svn_error_t *set_special_wc_prop (const char *key,
const svn_string_t *val,
prop_setter_t setter,
void *baton,
apr_pool_t *pool)
{
const char *name = NULL;
if (strcmp(key, SVN_RA_DAV__PROP_VERSION_NAME) == 0)
name = SVN_PROP_ENTRY_COMMITTED_REV;
else if (strcmp(key, SVN_RA_DAV__PROP_CREATIONDATE) == 0)
name = SVN_PROP_ENTRY_COMMITTED_DATE;
else if (strcmp(key, SVN_RA_DAV__PROP_CREATOR_DISPLAYNAME) == 0)
name = SVN_PROP_ENTRY_LAST_AUTHOR;
else if (strcmp(key, SVN_RA_DAV__PROP_REPOSITORY_UUID) == 0)
name = SVN_PROP_ENTRY_UUID;
/* If we got a name we care about it, call the setter function. */
if (name)
SVN_ERR( (*setter)(baton, name, val, pool) );
return SVN_NO_ERROR;
}
static void add_props(apr_hash_t *props,
prop_setter_t setter,
void *baton,
apr_pool_t *pool)
{
apr_hash_index_t *hi;
for (hi = apr_hash_first(pool, props); hi; hi = apr_hash_next(hi))
{
const void *vkey;
void *vval;
const char *key;
const svn_string_t *val;
apr_hash_this(hi, &vkey, NULL, &vval);
key = vkey;
val = vval;
#define NSLEN (sizeof(SVN_DAV_PROP_NS_CUSTOM) - 1)
if (strncmp(key, SVN_DAV_PROP_NS_CUSTOM, NSLEN) == 0)
{
/* for props in the 'custom' namespace, we strip the
namespace and just use whatever name the user gave the
property. */
(*setter)(baton, key + NSLEN, val, pool);
continue;
}
#undef NSLEN
#define NSLEN (sizeof(SVN_DAV_PROP_NS_SVN) - 1)
if (strncmp(key, SVN_DAV_PROP_NS_SVN, NSLEN) == 0)
{
/* This property is an 'svn:' prop, recognized by client, or
server, or both. Convert the URI namespace into normal
'svn:' prefix again before pushing it at the wc. */
(*setter)(baton,
apr_pstrcat(pool, SVN_PROP_PREFIX, key + NSLEN, NULL),
val, pool);
}
#undef NSLEN
else
{
/* If we get here, then we have a property that is neither
in the 'custom' space, nor in the 'svn' space. So it
must be either in the 'network' space or 'DAV:' space.
The following routine converts a handful of DAV: props
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?