dav_error * dav_svn__replay_report(const dav_resource *resource, const apr_xml_doc *doc, dav_svn__output *output) { dav_error *derr = NULL; svn_revnum_t low_water_mark = SVN_INVALID_REVNUM; svn_revnum_t rev; const svn_delta_editor_t *editor; svn_boolean_t send_deltas = TRUE; dav_svn__authz_read_baton arb; const char *base_dir; apr_bucket_brigade *bb; apr_xml_elem *child; svn_fs_root_t *root; svn_error_t *err; void *edit_baton; int ns; /* In Subversion 1.8, we allowed this REPORT to be issue against a revision resource. Doing so means the REV is part of the request URL, and BASE_DIR is embedded in the request body. The old-school (and incorrect, see issue #4287 -- https://issues.apache.org/jira/browse/SVN-4287) way was to REPORT on the public URL of the BASE_DIR and embed the REV in the report body. */ if (resource->baselined && (resource->type == DAV_RESOURCE_TYPE_VERSION)) { rev = resource->info->root.rev; base_dir = NULL; } else { rev = SVN_INVALID_REVNUM; base_dir = resource->info->repos_path; } arb.r = resource->info->r; arb.repos = resource->info->repos; ns = dav_svn__find_ns(doc->namespaces, SVN_XML_NAMESPACE); if (ns == -1) return dav_svn__new_error_svn(resource->pool, HTTP_BAD_REQUEST, 0, 0, "The request does not contain the 'svn:' " "namespace, so it is not going to have an " "svn:revision element. That element is " "required"); for (child = doc->root->first_child; child != NULL; child = child->next) { if (child->ns == ns) { const char *cdata; if (strcmp(child->name, "revision") == 0) { if (SVN_IS_VALID_REVNUM(rev)) { /* Uh... we already have a revision to use, either because this tag is non-unique or because the request was submitted against a revision-bearing resource URL. Either way, something's not right. */ return malformed_element_error("revision", resource->pool); } cdata = dav_xml_get_cdata(child, resource->pool, 1); rev = SVN_STR_TO_REV(cdata); } else if (strcmp(child->name, "low-water-mark") == 0) { cdata = dav_xml_get_cdata(child, resource->pool, 1); if (! cdata) return malformed_element_error("low-water-mark", resource->pool); low_water_mark = SVN_STR_TO_REV(cdata); } else if (strcmp(child->name, "send-deltas") == 0) { apr_int64_t parsed_val; cdata = dav_xml_get_cdata(child, resource->pool, 1); if (! cdata) return malformed_element_error("send-deltas", resource->pool); err = svn_cstring_strtoi64(&parsed_val, cdata, 0, 1, 10); if (err) { svn_error_clear(err); return malformed_element_error("send-deltas", resource->pool); } send_deltas = parsed_val != 0; } else if (strcmp(child->name, "include-path") == 0) { cdata = dav_xml_get_cdata(child, resource->pool, 1); if ((derr = dav_svn__test_canonical(cdata, resource->pool))) return derr; /* Force BASE_DIR to be a relative path, not an fspath. */ base_dir = svn_relpath_canonicalize(cdata, resource->pool); } } } if (! SVN_IS_VALID_REVNUM(rev)) return dav_svn__new_error_svn (resource->pool, HTTP_BAD_REQUEST, 0, 0, "Request was missing the revision argument"); if (! SVN_IS_VALID_REVNUM(low_water_mark)) return dav_svn__new_error_svn (resource->pool, HTTP_BAD_REQUEST, 0, 0, "Request was missing the low-water-mark argument"); if (! base_dir) base_dir = ""; bb = apr_brigade_create(resource->pool, dav_svn__output_get_bucket_alloc(output)); if ((err = svn_fs_revision_root(&root, resource->info->repos->fs, rev, resource->pool))) { derr = dav_svn__convert_err(err, HTTP_INTERNAL_SERVER_ERROR, "Couldn't retrieve revision root", resource->pool); goto cleanup; } make_editor(&editor, &edit_baton, bb, output, dav_svn__get_compression_level(resource->info->r), resource->info->svndiff_version, resource->pool); if ((err = svn_repos_replay2(root, base_dir, low_water_mark, send_deltas, editor, edit_baton, dav_svn__authz_read_func(&arb), &arb, resource->pool))) { derr = dav_svn__convert_err(err, HTTP_INTERNAL_SERVER_ERROR, "Problem replaying revision", resource->pool); goto cleanup; } if ((err = end_report(edit_baton))) { derr = dav_svn__convert_err(err, HTTP_INTERNAL_SERVER_ERROR, "Problem closing editor drive", resource->pool); goto cleanup; } cleanup: dav_svn__operational_log(resource->info, svn_log__replay(base_dir, rev, resource->info->r->pool)); /* Flush the brigade. */ return dav_svn__final_flush_or_error(resource->info->r, bb, output, derr, resource->pool); }
dav_error * dav_svn__replay_report(const dav_resource *resource, const apr_xml_doc *doc, ap_filter_t *output) { svn_revnum_t low_water_mark = SVN_INVALID_REVNUM; svn_revnum_t rev = SVN_INVALID_REVNUM; const svn_delta_editor_t *editor; svn_boolean_t send_deltas = TRUE; dav_svn__authz_read_baton arb; const char *base_dir = resource->info->repos_path; apr_bucket_brigade *bb; apr_xml_elem *child; svn_fs_root_t *root; svn_error_t *err; void *edit_baton; int ns; /* The request won't have a repos_path if it's for the root. */ if (! base_dir) base_dir = ""; arb.r = resource->info->r; arb.repos = resource->info->repos; 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:revision element. That element is " "required.", SVN_DAV_ERROR_NAMESPACE, SVN_DAV_ERROR_TAG); for (child = doc->root->first_child; child != NULL; child = child->next) { if (child->ns == ns) { const char *cdata; if (strcmp(child->name, "revision") == 0) { cdata = dav_xml_get_cdata(child, resource->pool, 1); if (! cdata) return malformed_element_error("revision", resource->pool); rev = SVN_STR_TO_REV(cdata); } else if (strcmp(child->name, "low-water-mark") == 0) { cdata = dav_xml_get_cdata(child, resource->pool, 1); if (! cdata) return malformed_element_error("low-water-mark", resource->pool); low_water_mark = SVN_STR_TO_REV(cdata); } else if (strcmp(child->name, "send-deltas") == 0) { cdata = dav_xml_get_cdata(child, resource->pool, 1); if (! cdata) return malformed_element_error("send-deltas", resource->pool); send_deltas = atoi(cdata); } } } if (! SVN_IS_VALID_REVNUM(rev)) return dav_svn__new_error_tag (resource->pool, HTTP_BAD_REQUEST, 0, "Request was missing the revision argument.", SVN_DAV_ERROR_NAMESPACE, SVN_DAV_ERROR_TAG); if (! SVN_IS_VALID_REVNUM(low_water_mark)) return dav_svn__new_error_tag (resource->pool, HTTP_BAD_REQUEST, 0, "Request was missing the low-water-mark argument.", SVN_DAV_ERROR_NAMESPACE, SVN_DAV_ERROR_TAG); bb = apr_brigade_create(resource->pool, output->c->bucket_alloc); if ((err = svn_fs_revision_root(&root, resource->info->repos->fs, rev, resource->pool))) return dav_svn__convert_err(err, HTTP_INTERNAL_SERVER_ERROR, "Couldn't retrieve revision root", resource->pool); make_editor(&editor, &edit_baton, bb, output, resource->pool); if ((err = svn_repos_replay2(root, base_dir, low_water_mark, send_deltas, editor, edit_baton, dav_svn__authz_read_func(&arb), &arb, resource->pool))) return dav_svn__convert_err(err, HTTP_INTERNAL_SERVER_ERROR, "Problem replaying revision", resource->pool); if ((err = end_report(edit_baton))) return dav_svn__convert_err(err, HTTP_INTERNAL_SERVER_ERROR, "Problem closing editor drive", resource->pool); { const char *action, *log_base_dir; if (base_dir && base_dir[0] != '\0') log_base_dir = svn_path_uri_encode(base_dir, resource->info->r->pool); else log_base_dir = "/"; action = apr_psprintf(resource->info->r->pool, "replay %s r%ld", log_base_dir, rev); dav_svn__operational_log(resource->info, action); } ap_fflush(output, bb); return NULL; }