📄 update.c
字号:
{
if (! child->first_cdata.first)
return dav_new_error_tag(resource->pool, HTTP_BAD_REQUEST, 0,
"The request's 'update-target' element contains empty cdata; "
"there is a problem with the client.",
SVN_DAV_ERROR_NAMESPACE,
SVN_DAV_ERROR_TAG);
/* ### assume no white space, no child elems, etc */
if ((derr = dav_svn__test_canonical
(child->first_cdata.first->text, resource->pool)))
return derr;
target = child->first_cdata.first->text;
}
if (child->ns == ns && strcmp(child->name, "recursive") == 0)
{
if (! child->first_cdata.first)
return dav_new_error_tag(resource->pool, HTTP_BAD_REQUEST, 0,
"The request's 'recursive' element contains empty cdata; "
"there is a problem with the client.",
SVN_DAV_ERROR_NAMESPACE,
SVN_DAV_ERROR_TAG);
/* ### assume no white space, no child elems, etc */
if (strcmp(child->first_cdata.first->text, "no") == 0)
recurse = FALSE;
}
if (child->ns == ns && strcmp(child->name, "ignore-ancestry") == 0)
{
if (! child->first_cdata.first)
return dav_new_error_tag(resource->pool, HTTP_BAD_REQUEST, 0,
"The request's 'ignore-ancestry' element contains empty cdata; "
"there is a problem with the client.",
SVN_DAV_ERROR_NAMESPACE,
SVN_DAV_ERROR_TAG);
/* ### assume no white space, no child elems, etc */
ignore_ancestry = TRUE;
if (strcmp(child->first_cdata.first->text, "no") == 0)
ignore_ancestry = FALSE;
}
if (child->ns == ns && strcmp(child->name, "resource-walk") == 0)
{
if (! child->first_cdata.first)
return dav_new_error_tag(resource->pool, HTTP_BAD_REQUEST, 0,
"The request's 'resource-walk' element contains empty cdata; "
"there is a problem with the client.",
SVN_DAV_ERROR_NAMESPACE,
SVN_DAV_ERROR_TAG);
/* ### assume no white space, no child elems, etc */
if (strcmp(child->first_cdata.first->text, "no") != 0)
resource_walk = TRUE;
}
}
if (revnum == SVN_INVALID_REVNUM)
{
serr = svn_fs_youngest_rev(&revnum, repos->fs, resource->pool);
if (serr != NULL)
{
return dav_svn_convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
"Could not determine the youngest "
"revision for the update process.",
resource->pool);
}
}
editor = svn_delta_default_editor(resource->pool);
editor->set_target_revision = upd_set_target_revision;
editor->open_root = upd_open_root;
editor->delete_entry = upd_delete_entry;
editor->add_directory = upd_add_directory;
editor->open_directory = upd_open_directory;
editor->change_dir_prop = upd_change_xxx_prop;
editor->close_directory = upd_close_directory;
editor->absent_directory = upd_absent_directory;
editor->add_file = upd_add_file;
editor->open_file = upd_open_file;
editor->apply_textdelta = upd_apply_textdelta;
editor->change_file_prop = upd_change_xxx_prop;
editor->close_file = upd_close_file;
editor->absent_file = upd_absent_file;
editor->close_edit = upd_close_edit;
/* If the client never sent a <src-path> element, it's old and
sending a style of report that we no longer allow. */
if (! src_path)
{
return dav_new_error_tag
(resource->pool, HTTP_BAD_REQUEST, 0,
"The request did not contain the '<src-path>' element.\n"
"This may indicate that your client is too old.",
SVN_DAV_ERROR_NAMESPACE,
SVN_DAV_ERROR_TAG);
}
uc.resource = resource;
uc.output = output;
uc.anchor = src_path;
uc.target = target;
uc.bb = apr_brigade_create(resource->pool, output->c->bucket_alloc);
uc.pathmap = NULL;
if (dst_path) /* we're doing a 'switch' */
{
if (*target)
{
/* if the src is split into anchor/target, so must the
telescoping dst_path be. */
uc.dst_path = svn_path_dirname(dst_path, resource->pool);
/* Also, the svn_repos_dir_delta() is going to preserve our
target's name, so we need a pathmap entry for that. */
if (! uc.pathmap)
uc.pathmap = apr_hash_make(resource->pool);
add_to_path_map(uc.pathmap,
svn_path_join(src_path, target, resource->pool),
dst_path);
}
else
{
uc.dst_path = dst_path;
}
}
else /* we're doing an update, so src and dst are the same. */
uc.dst_path = uc.anchor;
/* Get the root of the revision we want to update to. This will be used
to generated stable id values. */
if ((serr = svn_fs_revision_root(&uc.rev_root, repos->fs,
revnum, resource->pool)))
{
return dav_svn_convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
"The revision root could not be created.",
resource->pool);
}
/* When we call svn_repos_finish_report, it will ultimately run
dir_delta() between REPOS_PATH/TARGET and TARGET_PATH. In the
case of an update or status, these paths should be identical. In
the case of a switch, they should be different. */
if ((serr = svn_repos_begin_report(&rbaton, revnum, repos->username,
repos->repos,
src_path, target,
dst_path,
uc.send_all,
recurse,
ignore_ancestry,
editor, &uc,
dav_svn_authz_read,
&arb,
resource->pool)))
{
return dav_svn_convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
"The state report gatherer could not be "
"created.",
resource->pool);
}
/* scan the XML doc for state information */
for (child = doc->root->first_child; child != NULL; child = child->next)
if (child->ns == ns)
{
/* Clear our subpool. */
svn_pool_clear(subpool);
if (strcmp(child->name, "entry") == 0)
{
const char *path;
svn_revnum_t rev = SVN_INVALID_REVNUM;
const char *linkpath = NULL;
svn_boolean_t start_empty = FALSE;
apr_xml_attr *this_attr = child->attr;
while (this_attr)
{
if (! strcmp(this_attr->name, "rev"))
rev = SVN_STR_TO_REV(this_attr->value);
else if (! strcmp(this_attr->name, "linkpath"))
linkpath = this_attr->value;
else if (! strcmp(this_attr->name, "start-empty"))
start_empty = TRUE;
this_attr = this_attr->next;
}
/* we require the `rev' attribute for this to make sense */
if (! SVN_IS_VALID_REVNUM (rev))
{
serr = svn_error_create (SVN_ERR_XML_ATTRIB_NOT_FOUND,
NULL, "Missing XML attribute: rev");
derr = dav_svn_convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
"A failure occurred while "
"recording one of the items of "
"working copy state.",
resource->pool);
goto cleanup;
}
/* get cdata, stripping whitespace */
path = dav_xml_get_cdata(child, subpool, 1);
if (! linkpath)
serr = svn_repos_set_path(rbaton, path, rev,
start_empty, subpool);
else
serr = svn_repos_link_path(rbaton, path, linkpath, rev,
start_empty, subpool);
if (serr != NULL)
{
derr = dav_svn_convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
"A failure occurred while "
"recording one of the items of "
"working copy state.",
resource->pool);
goto cleanup;
}
/* now, add this path to our path map, but only if we are
doing a regular update (not a `switch') */
if (linkpath && (! dst_path))
{
const char *this_path;
if (! uc.pathmap)
uc.pathmap = apr_hash_make(resource->pool);
this_path = svn_path_join_many(apr_hash_pool_get(uc.pathmap),
src_path, target, path, NULL);
add_to_path_map(uc.pathmap, this_path, linkpath);
}
}
else if (strcmp(child->name, "missing") == 0)
{
/* get cdata, stripping whitespace */
const char *path = dav_xml_get_cdata(child, subpool, 1);
serr = svn_repos_delete_path(rbaton, path, subpool);
if (serr != NULL)
{
derr = dav_svn_convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
"A failure occurred while "
"recording one of the (missing) "
"items of working copy state.",
resource->pool);
goto cleanup;
}
}
}
/* this will complete the report, and then drive our editor to generate
the response to the client. */
serr = svn_repos_finish_report(rbaton, resource->pool);
if (serr)
{
derr = dav_svn_convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
"A failure occurred while "
"driving the update report editor",
resource->pool);
goto cleanup;
}
/* We're finished with the report baton. Note that so we don't try
to abort this report later. */
rbaton = NULL;
/* ### Temporarily disable resource_walks for single-file switch
operations. It isn't strictly necessary. */
if (dst_path && resource_walk)
{
/* Sanity check: if we switched a file, we can't do a resource
walk. dir_delta would choke if we pass a filepath as the
'target'. Also, there's no need to do the walk, since the
new vsn-rsc-url was already in the earlier part of the report. */
svn_node_kind_t dst_kind;
if ((serr = svn_fs_check_path(&dst_kind, uc.rev_root, dst_path,
resource->pool)))
{
derr = dav_svn_convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
"Failed checking destination path kind.",
resource->pool);
goto cleanup;
}
if (dst_kind != svn_node_dir)
resource_walk = FALSE;
}
/* The potential "resource walk" part of the update-report. */
if (dst_path && resource_walk) /* this was a 'switch' operation */
{
/* send a second embedded <S:resource-walk> tree that contains
the new vsn-rsc-urls for the switched dir. this walk
contains essentially nothing but <add> tags. */
svn_fs_root_t *zero_root;
serr = svn_fs_revision_root(&zero_root, repos->fs, 0,
resource->pool);
if (serr)
{
derr = dav_svn_convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
"Failed to find the revision root",
resource->pool);
goto cleanup;
}
serr = send_xml(&uc, "<S:resource-walk>" DEBUG_CR);
if (serr)
{
derr = dav_svn_convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
"Unable to begin resource walk",
resource->pool);
goto cleanup;
}
uc.resource_walk = TRUE;
/* Compare subtree DST_PATH within a pristine revision to
revision 0. This should result in nothing but 'add' calls
to the editor. */
serr = svn_repos_dir_delta(zero_root, "", target,
uc.rev_root, dst_path,
/* re-use the editor */
editor, &uc, dav_svn_authz_read,
&arb, FALSE /* text-deltas */, recurse,
TRUE /* entryprops */,
FALSE /* ignore-ancestry */, resource->pool);
if (serr)
{
derr = dav_svn_convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
"Resource walk failed.", resource->pool);
goto cleanup;
}
serr = send_xml(&uc, "</S:resource-walk>" DEBUG_CR);
if (serr)
{
derr = dav_svn_convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
"Unable to complete resource walk.",
resource->pool);
goto cleanup;
}
}
/* Close the report body, unless some error prevented it from being
started in the first place. */
if (uc.started_update)
{
serr = send_xml(&uc, "</S:update-report>" DEBUG_CR);
if (serr)
{
derr = dav_svn_convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
"Unable to complete update report.",
resource->pool);
goto cleanup;
}
}
cleanup:
/* Flush the contents of the brigade (returning an error only if we
don't already have one). */
if ((! derr) && ((apr_err = ap_fflush(output, uc.bb))))
derr = dav_svn_convert_err(svn_error_create(apr_err, 0, NULL),
HTTP_INTERNAL_SERVER_ERROR,
"Error flushing brigade.",
resource->pool);
/* if an error was produced EITHER by the dir_delta drive or the
resource-walker... */
if (derr)
{
if (rbaton)
svn_error_clear(svn_repos_abort_report(rbaton, resource->pool));
return derr;
}
/* Destroy our subpool. */
svn_pool_destroy(subpool);
return NULL;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -