static svn_error_t * svn_ra_local__get_mergeinfo(svn_ra_session_t *session, svn_mergeinfo_catalog_t *catalog, const apr_array_header_t *paths, svn_revnum_t revision, svn_mergeinfo_inheritance_t inherit, svn_boolean_t include_descendants, apr_pool_t *pool) { svn_ra_local__session_baton_t *sess = session->priv; svn_mergeinfo_catalog_t tmp_catalog; int i; apr_array_header_t *abs_paths = apr_array_make(pool, 0, sizeof(const char *)); for (i = 0; i < paths->nelts; i++) { const char *relative_path = APR_ARRAY_IDX(paths, i, const char *); APR_ARRAY_PUSH(abs_paths, const char *) = svn_path_join(sess->fs_path->data, relative_path, pool); } SVN_ERR(svn_repos_fs_get_mergeinfo(&tmp_catalog, sess->repos, abs_paths, revision, inherit, include_descendants, NULL, NULL, pool)); if (apr_hash_count(tmp_catalog) > 0) SVN_ERR(svn_mergeinfo__remove_prefix_from_catalog(catalog, tmp_catalog, sess->fs_path->data, pool)); else *catalog = NULL; return SVN_NO_ERROR; }
dav_error * dav_svn__get_mergeinfo_report(const dav_resource *resource, const apr_xml_doc *doc, ap_filter_t *output) { svn_error_t *serr; dav_error *derr = NULL; apr_xml_elem *child; svn_mergeinfo_catalog_t catalog; svn_boolean_t include_descendants = FALSE; dav_svn__authz_read_baton arb; const dav_svn_repos *repos = resource->info->repos; int ns; apr_bucket_brigade *bb; apr_hash_index_t *hi; /* These get determined from the request document. */ svn_revnum_t rev = SVN_INVALID_REVNUM; /* By default look for explicit mergeinfo only. */ svn_mergeinfo_inheritance_t inherit = svn_mergeinfo_explicit; apr_array_header_t *paths = apr_array_make(resource->pool, 0, sizeof(const char *)); /* Sanity check. */ if (!resource->info->repos_path) return dav_svn__new_error(resource->pool, HTTP_BAD_REQUEST, 0, "The request does not specify a repository path"); 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 " "certain required elements.", SVN_DAV_ERROR_NAMESPACE, SVN_DAV_ERROR_TAG); } for (child = doc->root->first_child; child != NULL; child = child->next) { /* if this element isn't one of ours, then skip it */ if (child->ns != ns) continue; if (strcmp(child->name, SVN_DAV__REVISION) == 0) rev = SVN_STR_TO_REV(dav_xml_get_cdata(child, resource->pool, 1)); else if (strcmp(child->name, SVN_DAV__INHERIT) == 0) { inherit = svn_inheritance_from_word( dav_xml_get_cdata(child, resource->pool, 1)); } else if (strcmp(child->name, SVN_DAV__PATH) == 0) { const char *target; const char *rel_path = dav_xml_get_cdata(child, resource->pool, 0); if ((derr = dav_svn__test_canonical(rel_path, resource->pool))) return derr; /* Force REL_PATH to be a relative path, not an fspath. */ rel_path = svn_relpath_canonicalize(rel_path, resource->pool); /* Append the REL_PATH to the base FS path to get an absolute repository path. */ target = svn_fspath__join(resource->info->repos_path, rel_path, resource->pool); (*((const char **)(apr_array_push(paths)))) = target; } else if (strcmp(child->name, SVN_DAV__INCLUDE_DESCENDANTS) == 0) { const char *word = dav_xml_get_cdata(child, resource->pool, 1); if (strcmp(word, "yes") == 0) include_descendants = TRUE; /* Else the client isn't supposed to send anyway, so just leave it false. */ } /* else unknown element; skip it */ } /* Build authz read baton */ arb.r = resource->info->r; arb.repos = resource->info->repos; /* Build mergeinfo brigade */ bb = apr_brigade_create(resource->pool, output->c->bucket_alloc); serr = svn_repos_fs_get_mergeinfo(&catalog, repos->repos, paths, rev, inherit, include_descendants, dav_svn__authz_read_func(&arb), &arb, resource->pool); if (serr) { derr = dav_svn__convert_err(serr, HTTP_BAD_REQUEST, serr->message, resource->pool); goto cleanup; } serr = svn_mergeinfo__remove_prefix_from_catalog(&catalog, catalog, resource->info->repos_path, resource->pool); if (serr) { derr = dav_svn__convert_err(serr, HTTP_BAD_REQUEST, serr->message, resource->pool); goto cleanup; } /* Ideally, dav_svn__brigade_printf() would set a flag in bb (or rather, in r->sent_bodyct, see dav_method_report()), and ap_fflush() would not set that flag unless it actually sent something. But we are condemned to live in another universe, so we must keep track ourselves of whether we've sent anything or not. See the long comment after the 'cleanup' label for more details. */ serr = dav_svn__brigade_puts(bb, output, DAV_XML_HEADER DEBUG_CR "<S:" SVN_DAV__MERGEINFO_REPORT " " "xmlns:S=\"" SVN_XML_NAMESPACE "\" " "xmlns:D=\"DAV:\">" DEBUG_CR); if (serr) { derr = dav_svn__convert_err(serr, HTTP_BAD_REQUEST, serr->message, resource->pool); goto cleanup; } for (hi = apr_hash_first(resource->pool, catalog); hi; hi = apr_hash_next(hi)) { const void *key; void *value; const char *path; svn_mergeinfo_t mergeinfo; svn_string_t *mergeinfo_string; apr_hash_this(hi, &key, NULL, &value); path = key; mergeinfo = value; serr = svn_mergeinfo_to_string(&mergeinfo_string, mergeinfo, resource->pool); if (serr) { derr = dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "Error ending REPORT response.", resource->pool); goto cleanup; } serr = dav_svn__brigade_printf (bb, output, "<S:" SVN_DAV__MERGEINFO_ITEM ">" DEBUG_CR "<S:" SVN_DAV__MERGEINFO_PATH ">%s</S:" SVN_DAV__MERGEINFO_PATH ">" DEBUG_CR "<S:" SVN_DAV__MERGEINFO_INFO ">%s</S:" SVN_DAV__MERGEINFO_INFO ">" DEBUG_CR "</S:" SVN_DAV__MERGEINFO_ITEM ">", apr_xml_quote_string(resource->pool, path, 0), apr_xml_quote_string(resource->pool, mergeinfo_string->data, 0)); if (serr) { derr = dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "Error ending REPORT response.", resource->pool); goto cleanup; } } if ((serr = dav_svn__brigade_puts(bb, output, "</S:" SVN_DAV__MERGEINFO_REPORT ">" DEBUG_CR))) { derr = dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "Error ending REPORT response.", resource->pool); goto cleanup; } cleanup: /* We've detected a 'high level' svn action to log. */ dav_svn__operational_log(resource->info, svn_log__get_mergeinfo(paths, inherit, include_descendants, resource->pool)); return dav_svn__final_flush_or_error(resource->info->r, bb, output, derr, resource->pool); }