📄 update.c
字号:
const char *qval; if (svn_xml_is_xml_safe(value->data, value->len)) { svn_stringbuf_t *tmp = NULL; svn_xml_escape_cdata_string(&tmp, value, pool); qval = tmp->data; SVN_ERR(dav_svn__send_xml(b->uc->bb, b->uc->output, "<S:set-prop name=\"%s\">", qname)); } else { qval = svn_base64_encode_string(value, pool)->data; SVN_ERR(dav_svn__send_xml(b->uc->bb, b->uc->output, "<S:set-prop name=\"%s\" " "encoding=\"base64\">" DEBUG_CR, qname)); } SVN_ERR(dav_svn__send_xml(b->uc->bb, b->uc->output, "%s", qval)); SVN_ERR(dav_svn__send_xml(b->uc->bb, b->uc->output, "</S:set-prop>" DEBUG_CR)); } else /* value is null, so this is a prop removal */ { SVN_ERR(dav_svn__send_xml(b->uc->bb, b->uc->output, "<S:remove-prop name=\"%s\"/>" DEBUG_CR, qname)); } } else /* don't do inline response, just cache prop names for close_helper */ { /* For now, store certain entry props, because we'll need to send them later as standard DAV ("D:") props. ### this should go away and we should just tunnel those props on through for the client to deal with. */#define NSLEN (sizeof(SVN_PROP_ENTRY_PREFIX) - 1) if (! strncmp(name, SVN_PROP_ENTRY_PREFIX, NSLEN)) { if (! strcmp(name, SVN_PROP_ENTRY_COMMITTED_REV)) { b->committed_rev = value ? apr_pstrdup(b->pool, value->data) : NULL; } else if (! strcmp(name, SVN_PROP_ENTRY_COMMITTED_DATE)) { b->committed_date = value ? apr_pstrdup(b->pool, value->data) : NULL; } else if (! strcmp(name, SVN_PROP_ENTRY_LAST_AUTHOR)) { b->last_author = value ? apr_pstrdup(b->pool, value->data) : NULL; } return SVN_NO_ERROR; }#undef NSLEN if (value) { if (! b->changed_props) b->changed_props = apr_array_make(b->pool, 1, sizeof(name)); (*((const char **)(apr_array_push(b->changed_props)))) = qname; } else { if (! b->removed_props) b->removed_props = apr_array_make(b->pool, 1, sizeof(name)); (*((const char **)(apr_array_push(b->removed_props)))) = qname; } } return SVN_NO_ERROR;}static svn_error_t * upd_close_directory(void *dir_baton, apr_pool_t *pool){ return close_helper(TRUE /* is_dir */, dir_baton);}static svn_error_t * upd_add_file(const char *path, void *parent_baton, const char *copyfrom_path, svn_revnum_t copyfrom_revision, apr_pool_t *pool, void **file_baton){ return add_helper(FALSE /* is_dir */, path, parent_baton, copyfrom_path, copyfrom_revision, pool, file_baton);}static svn_error_t * upd_open_file(const char *path, void *parent_baton, svn_revnum_t base_revision, apr_pool_t *pool, void **file_baton){ return open_helper(FALSE /* is_dir */, path, parent_baton, base_revision, pool, file_baton);}/* We have our own window handler and baton as a simple wrapper around the real handler (which converts vdelta windows to base64-encoded svndiff data). The wrapper is responsible for sending the opening and closing XML tags around the svndiff data. */struct window_handler_baton{ svn_boolean_t seen_first_window; /* False until first window seen. */ update_ctx_t *uc; /* The _real_ window handler and baton. */ svn_txdelta_window_handler_t handler; void *handler_baton;};/* This implements 'svn_txdelta_window_handler_t'. */static svn_error_t * window_handler(svn_txdelta_window_t *window, void *baton){ struct window_handler_baton *wb = baton; if (! wb->seen_first_window) { wb->seen_first_window = TRUE; SVN_ERR(dav_svn__send_xml(wb->uc->bb, wb->uc->output, "<S:txdelta>")); } SVN_ERR(wb->handler(window, wb->handler_baton)); if (window == NULL) SVN_ERR(dav_svn__send_xml(wb->uc->bb, wb->uc->output, "</S:txdelta>")); return SVN_NO_ERROR;}/* This implements 'svn_txdelta_window_handler_t'. During a resource walk, the driver sends an empty window as a boolean indicating that a change happened to this file, but we don't want to send anything over the wire as a result. */static svn_error_t * dummy_window_handler(svn_txdelta_window_t *window, void *baton){ return SVN_NO_ERROR;}static svn_error_t * upd_apply_textdelta(void *file_baton, const char *base_checksum, apr_pool_t *pool, svn_txdelta_window_handler_t *handler, void **handler_baton){ item_baton_t *file = file_baton; struct window_handler_baton *wb; svn_stream_t *base64_stream; /* Store the base checksum and the fact the file's text changed. */ file->base_checksum = apr_pstrdup(file->pool, base_checksum); file->text_changed = TRUE; /* If this is a resource walk, or if we're not in "send-all" mode, we don't actually want to transmit text-deltas. */ if (file->uc->resource_walk || (! file->uc->send_all)) { *handler = dummy_window_handler; *handler_baton = NULL; return SVN_NO_ERROR; } wb = apr_palloc(file->pool, sizeof(*wb)); wb->seen_first_window = FALSE; wb->uc = file->uc; base64_stream = dav_svn_make_base64_output_stream(wb->uc->bb, wb->uc->output, file->pool); svn_txdelta_to_svndiff2(&(wb->handler), &(wb->handler_baton), base64_stream, file->uc->svndiff_version, file->pool); *handler = window_handler; *handler_baton = wb; return SVN_NO_ERROR;}static svn_error_t * upd_close_file(void *file_baton, const char *text_checksum, apr_pool_t *pool){ item_baton_t *file = file_baton; file->text_checksum = text_checksum ? apr_pstrdup(file->pool, text_checksum) : NULL; /* If we are not in "send all" mode, and this file is not a new addition or didn't otherwise have changed text, tell the client to fetch it. */ if ((! file->uc->send_all) && (! file->added) && file->text_changed) { const char *elt; elt = apr_psprintf(pool, "<S:fetch-file%s%s%s/>" DEBUG_CR, file->base_checksum ? " base-checksum=\"" : "", file->base_checksum ? file->base_checksum : "", file->base_checksum ? "\"" : ""); SVN_ERR(dav_svn__send_xml(file->uc->bb, file->uc->output, "%s", elt)); } return close_helper(FALSE /* is_dir */, file);}static svn_error_t * upd_close_edit(void *edit_baton, apr_pool_t *pool){ update_ctx_t *uc = edit_baton; /* Our driver will unconditionally close the update report... So if the report hasn't even been started yet, start it now. */ return maybe_start_update_report(uc);}/* Return a specific error associated with the contents of TAGNAME being malformed. Use pool for allocations. */static dav_error *malformed_element_error(const char *tagname, apr_pool_t *pool){ const char *errstr = apr_pstrcat(pool, "The request's '", tagname, "' element is malformed; there " "is a problem with the client.", NULL); return dav_svn__new_error_tag(pool, HTTP_BAD_REQUEST, 0, errstr, SVN_DAV_ERROR_NAMESPACE, SVN_DAV_ERROR_TAG);}dav_error * dav_svn__update_report(const dav_resource *resource, const apr_xml_doc *doc, ap_filter_t *output){ svn_delta_editor_t *editor; apr_xml_elem *child; void *rbaton = NULL; update_ctx_t uc = { 0 }; svn_revnum_t revnum = SVN_INVALID_REVNUM; int ns; int entry_counter = 0; svn_boolean_t entry_is_empty = FALSE; svn_error_t *serr; dav_error *derr = NULL; apr_status_t apr_err; const char *src_path = NULL; const char *dst_path = NULL; const dav_svn_repos *repos = resource->info->repos; const char *target = ""; svn_boolean_t text_deltas = TRUE; svn_boolean_t recurse = TRUE; svn_boolean_t resource_walk = FALSE; svn_boolean_t ignore_ancestry = FALSE; dav_svn_authz_read_baton arb; apr_pool_t *subpool = svn_pool_create(resource->pool); /* Construct the authz read check baton. */ arb.r = resource->info->r; arb.repos = repos; if (resource->info->restype != DAV_SVN_RESTYPE_VCC) { return dav_svn__new_error_tag(resource->pool, HTTP_CONFLICT, 0, "This report can only be run against " "a VCC.", SVN_DAV_ERROR_NAMESPACE, SVN_DAV_ERROR_TAG); } ns = dav_svn_find_ns(doc->namespaces, SVN_XML_NAMESPACE); if (ns == -1) { return dav_svn__new_error_tag(resource->pool, HTTP_BAD_REQUEST, 0, "The request does not contain the 'svn:' " "namespace, so it is not going to have an " "svn:target-revision element. That element " "is required.", SVN_DAV_ERROR_NAMESPACE, SVN_DAV_ERROR_TAG); } /* Look to see if client wants a report with props and textdeltas inline, rather than placeholder tags that tell the client to do further fetches. Modern clients prefer inline. */ { apr_xml_attr *this_attr; for (this_attr = doc->root->attr; this_attr; this_attr = this_attr->next) { if ((strcmp(this_attr->name, "send-all") == 0) && (strcmp(this_attr->value, "true") == 0)) { uc.send_all = TRUE; break; } } } for (child = doc->root->first_child; child != NULL; child = child->next) { /* Note that child->name might not match any of the cases below. Thus, the check for non-empty cdata in each of these cases cannot be moved to the top of the loop, because then it would wrongly catch other elements that do allow empty cdata. */ const char *cdata; if (child->ns == ns && strcmp(child->name, "target-revision") == 0) { cdata = dav_xml_get_cdata(child, resource->pool, 1); if (! *cdata) return malformed_element_error(child->name, resource->pool); revnum = SVN_STR_TO_REV(cdata); } if (child->ns == ns && strcmp(child->name, "src-path") == 0) { dav_svn_uri_info this_info; cdata = dav_xml_get_cdata(child, resource->pool, 0); if (! *cdata) return malformed_element_error(child->name, resource->pool); if ((derr = dav_svn__test_canonical(cdata, resource->pool))) return derr; if ((serr = dav_svn_simple_parse_uri(&this_info, resource, cdata, resource->pool))) return dav_svn_convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "Could not parse 'src-path' URL.", resource->pool); src_path = this_info.repos_path; } if (child->ns == ns && strcmp(child->name, "dst-path") == 0) { dav_svn_uri_info this_info; cdata = dav_xml_get_cdata(child, resource->pool, 0); if (! *cdata) return malformed_element_error(child->name, resource->pool); if ((derr = dav_svn__test_canonical(cdata, resource->pool))) return derr; if ((serr = dav_svn_simple_parse_uri(&this_info, resource, cdata, resource->pool))) return dav_svn_convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "Could not parse 'dst-path' URL.", resource->pool); dst_path = this_info.repos_path; } if (child->ns == ns && strcmp(child->name, "update-target") == 0) { cdata = dav_xml_get_cdata(child, resource->pool, 0); if ((derr = dav_svn__test_canonical(cdata, resource->pool))) return derr; target = cdata; } if (child->ns == ns && strcmp(child->name, "recursive") == 0) { cdata = dav_xml_get_cdata(child, resource->pool, 1); if (! *cdata) return malformed_element_error(child->name, resource->pool); if (strcmp(cdata, "no") == 0) recurse = FALSE; } if (child->ns == ns && strcmp(child->name, "ignore-ancestry") == 0) { cdata = dav_xml_get_cdata(child, resource->pool, 1); if (! *cdata) return malformed_element_error(child->name, resource->pool); if (strcmp(cdata, "no") != 0) ignore_ancestry = TRUE; } if (child->ns == ns && strcmp(child->name, "resource-walk") == 0) { cdata = dav_xml_get_cdata(child, resource->pool, 1); if (! *cdata) return malformed_element_error(child->name, resource->pool); if (strcmp(cdata, "no") != 0) resource_walk = TRUE; } if (child->ns == ns && strcmp(child->name, "text-deltas") == 0) { cdata = dav_xml_get_cdata(child, resource->pool, 1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -