📄 update.c
字号:
const char *path;
svn_revnum_t revision;
/* Try to use the CR, assuming the path exists in CR. */
path = get_real_fs_path(baton, pool);
revision = dav_svn_get_safe_cr(baton->uc->rev_root, path, pool);
href = dav_svn_build_uri(baton->uc->resource->info->repos,
DAV_SVN_BUILD_URI_VERSION,
revision, path, 0 /* add_href */, pool);
return send_xml(baton->uc, "<D:checked-in><D:href>%s</D:href></D:checked-in>"
DEBUG_CR, apr_xml_quote_string (pool, href, 1));
}
static svn_error_t * absent_helper(svn_boolean_t is_dir,
const char *path,
item_baton_t *parent,
apr_pool_t *pool)
{
update_ctx_t *uc = parent->uc;
if (! uc->resource_walk)
{
const char *elt = apr_psprintf(pool,
"<S:absent-%s name=\"%s\"/>" DEBUG_CR,
DIR_OR_FILE(is_dir),
svn_path_basename(path, pool));
SVN_ERR( send_xml(uc, "%s", elt) );
}
return SVN_NO_ERROR;
}
static svn_error_t * upd_absent_directory(const char *path,
void *parent_baton,
apr_pool_t *pool)
{
return absent_helper(TRUE, path, parent_baton, pool);
}
static svn_error_t * upd_absent_file(const char *path,
void *parent_baton,
apr_pool_t *pool)
{
return absent_helper(FALSE, path, parent_baton, pool);
}
static svn_error_t * add_helper(svn_boolean_t is_dir,
const char *path,
item_baton_t *parent,
const char *copyfrom_path,
svn_revnum_t copyfrom_revision,
apr_pool_t *pool,
void **child_baton)
{
item_baton_t *child;
update_ctx_t *uc = parent->uc;
const char *bc_url = NULL;
child = make_child_baton(parent, path, pool);
child->added = TRUE;
if (uc->resource_walk)
{
SVN_ERR( send_xml(child->uc, "<S:resource path=\"%s\">" DEBUG_CR,
apr_xml_quote_string(pool, child->path3, 1)) );
}
else
{
const char *qname = apr_xml_quote_string(pool, child->name, 1);
const char *elt;
const char *real_path = get_real_fs_path(child, pool);
if (! is_dir)
{
/* files have checksums */
unsigned char digest[APR_MD5_DIGESTSIZE];
SVN_ERR (svn_fs_file_md5_checksum
(digest, uc->rev_root, real_path, pool));
child->text_checksum = svn_md5_digest_to_cstring(digest, pool);
}
else
{
/* we send baseline-collection urls when we add a directory */
svn_revnum_t revision;
revision = dav_svn_get_safe_cr(child->uc->rev_root, real_path, pool);
bc_url = dav_svn_build_uri(child->uc->resource->info->repos,
DAV_SVN_BUILD_URI_BC,
revision, real_path,
0 /* add_href */, pool);
/* ugh, build_uri ignores the path and just builds the root
of the baseline collection. we have to tack the
real_path on manually, ignoring its leading slash. */
if (real_path && (! svn_path_is_empty(real_path)))
bc_url = svn_path_url_add_component(bc_url, real_path+1, pool);
/* make sure that the BC_URL is xml attribute safe. */
bc_url = apr_xml_quote_string(pool, bc_url, 1);
}
if (copyfrom_path == NULL)
{
if (bc_url)
elt = apr_psprintf(pool, "<S:add-%s name=\"%s\" "
"bc-url=\"%s\">" DEBUG_CR,
DIR_OR_FILE(is_dir), qname, bc_url);
else
elt = apr_psprintf(pool, "<S:add-%s name=\"%s\">" DEBUG_CR,
DIR_OR_FILE(is_dir), qname);
}
else
{
const char *qcopy = apr_xml_quote_string(pool, copyfrom_path, 1);
if (bc_url)
elt = apr_psprintf(pool, "<S:add-%s name=\"%s\" "
"copyfrom-path=\"%s\" copyfrom-rev=\"%ld\" "
"bc-url=\"%s\">" DEBUG_CR,
DIR_OR_FILE(is_dir),
qname, qcopy, copyfrom_revision,
bc_url);
else
elt = apr_psprintf(pool, "<S:add-%s name=\"%s\" "
"copyfrom-path=\"%s\""
" copyfrom-rev=\"%ld\">" DEBUG_CR,
DIR_OR_FILE(is_dir),
qname, qcopy, copyfrom_revision);
}
/* Resist the temptation to pass 'elt' as the format string.
Because it contains URIs, it might have sequences that look
like format string insert placeholders. For example,
"this%20dir" is a valid printf() format string that means
"this[insert an integer of width 20 here]ir". */
SVN_ERR( send_xml(child->uc, "%s", elt) );
}
SVN_ERR( send_vsn_url(child, pool) );
if (uc->resource_walk)
SVN_ERR( send_xml(child->uc, "</S:resource>" DEBUG_CR) );
*child_baton = child;
return SVN_NO_ERROR;
}
static svn_error_t * open_helper(svn_boolean_t is_dir,
const char *path,
item_baton_t *parent,
svn_revnum_t base_revision,
apr_pool_t *pool,
void **child_baton)
{
item_baton_t *child = make_child_baton(parent, path, pool);
const char *qname = apr_xml_quote_string(pool, child->name, 1);
SVN_ERR( send_xml(child->uc, "<S:open-%s name=\"%s\""
" rev=\"%ld\">" DEBUG_CR,
DIR_OR_FILE(is_dir), qname, base_revision));
SVN_ERR( send_vsn_url(child, pool) );
*child_baton = child;
return SVN_NO_ERROR;
}
static svn_error_t * close_helper(svn_boolean_t is_dir, item_baton_t *baton)
{
int i;
if (baton->uc->resource_walk)
return SVN_NO_ERROR;
/* ### ack! binary names won't float here! */
if (baton->removed_props && (! baton->added))
{
const char *qname;
for (i = 0; i < baton->removed_props->nelts; i++)
{
/* We already XML-escaped the property name in change_xxx_prop. */
qname = ((const char **)(baton->removed_props->elts))[i];
SVN_ERR( send_xml(baton->uc, "<S:remove-prop name=\"%s\"/>"
DEBUG_CR, qname) );
}
}
if ((! baton->uc->send_all) && baton->changed_props && (! baton->added))
{
/* Tell the client to fetch all the props */
SVN_ERR( send_xml(baton->uc, "<S:fetch-props/>" DEBUG_CR) );
}
SVN_ERR( send_xml(baton->uc, "<S:prop>") );
/* Both modern and non-modern clients need the checksum... */
if (baton->text_checksum)
{
SVN_ERR( send_xml(baton->uc, "<V:md5-checksum>%s</V:md5-checksum>",
baton->text_checksum) );
}
/* ...but only non-modern clients want the 3 CR-related properties
sent like here, because they can't handle receiving these special
props inline like any other prop.
### later on, compress via the 'scattered table' solution as
discussed with gstein. -bmcs */
if (! baton->uc->send_all)
{
/* ### grrr, these DAV: property names are already #defined in
ra_dav.h, and statically defined in liveprops.c. And now
they're hardcoded here. Isn't there some header file that both
sides of the network can share?? */
/* ### special knowledge: svn_repos_dir_delta will never send
*removals* of the commit-info "entry props". */
if (baton->committed_rev)
SVN_ERR( send_xml(baton->uc, "<D:version-name>%s</D:version-name>",
baton->committed_rev) );
if (baton->committed_date)
SVN_ERR( send_xml(baton->uc, "<D:creationdate>%s</D:creationdate>",
baton->committed_date) );
if (baton->last_author)
SVN_ERR( send_xml(baton->uc,
"<D:creator-displayname>%s</D:creator-displayname>",
baton->last_author) );
}
/* Close unconditionally, because we sent checksum unconditionally. */
SVN_ERR( send_xml(baton->uc, "</S:prop>\n") );
if (baton->added)
SVN_ERR( send_xml(baton->uc, "</S:add-%s>" DEBUG_CR,
DIR_OR_FILE(is_dir)) );
else
SVN_ERR( send_xml(baton->uc, "</S:open-%s>" DEBUG_CR,
DIR_OR_FILE(is_dir)) );
return SVN_NO_ERROR;
}
/* Send the opening tag of the update-report if it hasn't been sent
already.
Note: because send_xml does not return an error, this function
never returns error either. However, its prototype anticipates a
day when send_xml() can return error. */
static svn_error_t * maybe_start_update_report(update_ctx_t *uc)
{
if ((! uc->resource_walk) && (! uc->started_update))
{
SVN_ERR( send_xml(uc,
DAV_XML_HEADER DEBUG_CR
"<S:update-report xmlns:S=\"" SVN_XML_NAMESPACE "\" "
"xmlns:V=\"" SVN_DAV_PROP_NS_DAV "\" "
"xmlns:D=\"DAV:\" %s>" DEBUG_CR,
uc->send_all ? "send-all=\"true\"" : "") );
uc->started_update = TRUE;
}
return SVN_NO_ERROR;
}
static svn_error_t * upd_set_target_revision(void *edit_baton,
svn_revnum_t target_revision,
apr_pool_t *pool)
{
update_ctx_t *uc = edit_baton;
SVN_ERR( maybe_start_update_report(uc) );
if (! uc->resource_walk)
SVN_ERR( send_xml(uc, "<S:target-revision rev=\"%ld"
"\"/>" DEBUG_CR, target_revision) );
return SVN_NO_ERROR;
}
static svn_error_t * upd_open_root(void *edit_baton,
svn_revnum_t base_revision,
apr_pool_t *pool,
void **root_baton)
{
update_ctx_t *uc = edit_baton;
item_baton_t *b = apr_pcalloc(pool, sizeof(*b));
/* note that we create a subpool; the root_baton is passed to the
close_directory callback, where we will destroy the pool. */
b->uc = uc;
b->pool = pool;
b->path = uc->anchor;
b->path2 = uc->dst_path;
b->path3 = "";
*root_baton = b;
SVN_ERR( maybe_start_update_report(uc) );
if (uc->resource_walk)
{
const char *qpath = apr_xml_quote_string(pool, b->path3, 1);
SVN_ERR( send_xml(uc, "<S:resource path=\"%s\">" DEBUG_CR, qpath) );
}
else
{
SVN_ERR( send_xml(uc, "<S:open-directory rev=\"%ld\">"
DEBUG_CR, base_revision) );
}
/* Only transmit the root directory's Version Resource URL if
there's no target. */
if (! *uc->target)
SVN_ERR( send_vsn_url(b, pool) );
if (uc->resource_walk)
SVN_ERR( send_xml(uc, "</S:resource>" DEBUG_CR) );
return SVN_NO_ERROR;
}
static svn_error_t * upd_delete_entry(const char *path,
svn_revnum_t revision,
void *parent_baton,
apr_pool_t *pool)
{
item_baton_t *parent = parent_baton;
const char *qname = apr_xml_quote_string(pool,
svn_path_basename(path, pool), 1);
return send_xml(parent->uc, "<S:delete-entry name=\"%s\"/>" DEBUG_CR, qname);
}
static svn_error_t * upd_add_directory(const char *path,
void *parent_baton,
const char *copyfrom_path,
svn_revnum_t copyfrom_revision,
apr_pool_t *pool,
void **child_baton)
{
return add_helper(TRUE /* is_dir */,
path, parent_baton, copyfrom_path, copyfrom_revision, pool,
child_baton);
}
static svn_error_t * upd_open_directory(const char *path,
void *parent_baton,
svn_revnum_t base_revision,
apr_pool_t *pool,
void **child_baton)
{
open_helper(TRUE /* is_dir */,
path, parent_baton, base_revision, pool, child_baton);
return SVN_NO_ERROR;
}
static svn_error_t * upd_change_xxx_prop(void *baton,
const char *name,
const svn_string_t *value,
apr_pool_t *pool)
{
item_baton_t *b = baton;
const char *qname;
/* Resource walks say nothing about props. */
if (b->uc->resource_walk)
return SVN_NO_ERROR;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -