Modified: subversion/branches/ra-git/subversion/mod_dav_svn/reports/log.c URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/mod_dav_svn/reports/log.c?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/mod_dav_svn/reports/log.c (original) +++ subversion/branches/ra-git/subversion/mod_dav_svn/reports/log.c Tue Oct 11 09:11:50 2016 @@ -50,12 +50,17 @@ struct log_receiver_baton apr_bucket_brigade *bb; /* where to deliver the output */ - ap_filter_t *output; + dav_svn__output *output; /* Whether we've written the <S:log-report> header. Allows for lazy writes to support mod_dav-based error handling. */ svn_boolean_t needs_header; + /* Whether we've written the <S:log-item> header for the current revision. + Allows for lazy XML node creation while receiving the data through + callbacks. */ + svn_boolean_t needs_log_item; + /* How deep we are in the log message tree. We only need to surpress the SVN_INVALID_REVNUM message if the stack_depth is 0. */ int stack_depth; @@ -88,6 +93,22 @@ maybe_send_header(struct log_receiver_ba "xmlns:D=\"DAV:\">" DEBUG_CR)); lrb->needs_header = FALSE; } + + return SVN_NO_ERROR; +} + +/* If LRB->needs_log_item is true, send the "<S:log-item>" start + element and set LRB->needs_log_item to zero. Else do nothing. */ +static svn_error_t * +maybe_start_log_item(struct log_receiver_baton *lrb) +{ + if (lrb->needs_log_item) + { + SVN_ERR(dav_svn__brigade_printf(lrb->bb, lrb->output, + "<S:log-item>" DEBUG_CR)); + lrb->needs_log_item = FALSE; + } + return SVN_NO_ERROR; } @@ -99,17 +120,22 @@ maybe_send_header(struct log_receiver_ba static svn_error_t * start_path_with_copy_from(const char **element, struct log_receiver_baton *lrb, - svn_log_changed_path2_t *log_item, + svn_repos_path_change_t *log_item, apr_pool_t *pool) { - switch (log_item->action) + switch (log_item->change_kind) { - case 'A': *element = "S:added-path"; - break; - case 'R': *element = "S:replaced-path"; - break; - default: /* Caller, you did wrong! */ - SVN_ERR_MALFUNCTION(); + case svn_fs_path_change_add: + *element = "S:added-path"; + break; + + case svn_fs_path_change_replace: + *element = "S:replaced-path"; + break; + + default: + /* Caller, you did wrong! */ + SVN_ERR_MALFUNCTION(); } if (log_item->copyfrom_path @@ -129,15 +155,76 @@ start_path_with_copy_from(const char **e } -/* This implements `svn_log_entry_receiver_t'. +/* This implements `svn_repos_path_change_receiver_t'. BATON is a `struct log_receiver_baton *'. */ static svn_error_t * -log_receiver(void *baton, - svn_log_entry_t *log_entry, - apr_pool_t *pool) +log_change_receiver(void *baton, + svn_repos_path_change_t *change, + apr_pool_t *scratch_pool) +{ + struct log_receiver_baton *lrb = baton; + const char *close_element = NULL; + + /* We must open the XML nodes for the report and log-item before + sending the first changed path. + + Note that we can't get here for empty revisions that log() injects + to indicate the end of a recursive merged rev sequence. + */ + SVN_ERR(maybe_send_header(lrb)); + SVN_ERR(maybe_start_log_item(lrb)); + + /* ### todo: is there a D: namespace equivalent for + `changed-path'? Should use it if so. */ + switch (change->change_kind) + { + case svn_fs_path_change_add: + case svn_fs_path_change_replace: + SVN_ERR(start_path_with_copy_from(&close_element, lrb, + change, scratch_pool)); + break; + + case svn_fs_path_change_delete: + SVN_ERR(dav_svn__brigade_puts(lrb->bb, lrb->output, + "<S:deleted-path")); + close_element = "S:deleted-path"; + break; + + case svn_fs_path_change_modify: + SVN_ERR(dav_svn__brigade_puts(lrb->bb, lrb->output, + "<S:modified-path")); + close_element = "S:modified-path"; + break; + + default: + break; + } + + /* If we need to close the element, then send the attributes + that apply to all changed items and then close the element. */ + if (close_element) + SVN_ERR(dav_svn__brigade_printf + (lrb->bb, lrb->output, + " node-kind=\"%s\"" + " text-mods=\"%s\"" + " prop-mods=\"%s\">%s</%s>" DEBUG_CR, + svn_node_kind_to_word(change->node_kind), + change->text_mod ? "true" : "false", + change->prop_mod ? "true" : "false", + apr_xml_quote_string(scratch_pool, change->path.data, 0), + close_element)); + + return SVN_NO_ERROR; +} + +/* This implements `svn_repos_log_entry_receiver_t'. + BATON is a `struct log_receiver_baton *'. */ +static svn_error_t * +log_revision_receiver(void *baton, + svn_repos_log_entry_t *log_entry, + apr_pool_t *scratch_pool) { struct log_receiver_baton *lrb = baton; - apr_pool_t *iterpool = svn_pool_create(pool); SVN_ERR(maybe_send_header(lrb)); @@ -151,15 +238,24 @@ log_receiver(void *baton, lrb->stack_depth--; } + /* If we have not received any path changes, the log-item XML node + still needs to be opened. Also, reset the controlling flag to + prepare it for the next revision - if there should be one. */ + SVN_ERR(maybe_start_log_item(lrb)); + lrb->needs_log_item = TRUE; + + /* Path changes have been processed already. + Now send the remaining per-revision info. */ SVN_ERR(dav_svn__brigade_printf(lrb->bb, lrb->output, - "<S:log-item>" DEBUG_CR "<D:version-name>%ld" + "<D:version-name>%ld" "</D:version-name>" DEBUG_CR, log_entry->revision)); if (log_entry->revprops) { + apr_pool_t *iterpool = svn_pool_create(scratch_pool); apr_hash_index_t *hi; - for (hi = apr_hash_first(pool, log_entry->revprops); + for (hi = apr_hash_first(scratch_pool, log_entry->revprops); hi != NULL; hi = apr_hash_next(hi)) { @@ -200,7 +296,7 @@ log_receiver(void *baton, SVN_ERR(dav_svn__brigade_printf (lrb->bb, lrb->output, "<D:comment%s>%s</D:comment>" DEBUG_CR, encoding_str, - apr_xml_quote_string(pool, + apr_xml_quote_string(scratch_pool, svn_xml_fuzzy_escape(value->data, iterpool), 0))); else @@ -210,6 +306,8 @@ log_receiver(void *baton, apr_xml_quote_string(iterpool, name, 0), encoding_str, apr_xml_quote_string(iterpool, value->data, 0))); } + + svn_pool_destroy(iterpool); } if (log_entry->has_children) @@ -222,67 +320,6 @@ log_receiver(void *baton, SVN_ERR(dav_svn__brigade_puts(lrb->bb, lrb->output, "<S:subtractive-merge/>")); - if (log_entry->changed_paths2) - { - apr_hash_index_t *hi; - char *path; - - for (hi = apr_hash_first(pool, log_entry->changed_paths2); - hi != NULL; - hi = apr_hash_next(hi)) - { - void *val; - svn_log_changed_path2_t *log_item; - const char *close_element = NULL; - - svn_pool_clear(iterpool); - apr_hash_this(hi, (void *) &path, NULL, &val); - log_item = val; - - /* ### todo: is there a D: namespace equivalent for - `changed-path'? Should use it if so. */ - switch (log_item->action) - { - case 'A': - case 'R': - SVN_ERR(start_path_with_copy_from(&close_element, lrb, - log_item, iterpool)); - break; - - case 'D': - SVN_ERR(dav_svn__brigade_puts(lrb->bb, lrb->output, - "<S:deleted-path")); - close_element = "S:deleted-path"; - break; - - case 'M': - SVN_ERR(dav_svn__brigade_puts(lrb->bb, lrb->output, - "<S:modified-path")); - close_element = "S:modified-path"; - break; - - default: - break; - } - - /* If we need to close the element, then send the attributes - that apply to all changed items and then close the element. */ - if (close_element) - SVN_ERR(dav_svn__brigade_printf - (lrb->bb, lrb->output, - " node-kind=\"%s\"" - " text-mods=\"%s\"" - " prop-mods=\"%s\">%s</%s>" DEBUG_CR, - svn_node_kind_to_word(log_item->node_kind), - svn_tristate__to_word(log_item->text_modified), - svn_tristate__to_word(log_item->props_modified), - apr_xml_quote_string(iterpool, path, 0), - close_element)); - } - } - - svn_pool_destroy(iterpool); - SVN_ERR(dav_svn__brigade_puts(lrb->bb, lrb->output, "</S:log-item>" DEBUG_CR)); @@ -297,25 +334,17 @@ log_receiver(void *baton, lrb->result_count++; if (lrb->result_count == lrb->next_forced_flush) { - apr_status_t apr_err; - - /* This flush is similar to that in dav_svn__final_flush_or_error(). + apr_bucket *bkt; - Compared to using ap_filter_flush(), which we use in other place + /* Compared to using ap_filter_flush(), which we use in other place this adds a flush frame before flushing the brigade, to make output filters perform a flush as well */ /* No brigade empty check. We want output filters to flush anyway */ - apr_err = ap_fflush(lrb->output, lrb->bb); - if (apr_err) - return svn_error_create(apr_err, NULL, NULL); - - /* Check for an aborted connection, just like our brigade write - helper functions, since the brigade functions don't appear to - be return useful errors when the connection is dropped. */ - if (lrb->output->c->aborted) - return svn_error_create(SVN_ERR_APMOD_CONNECTION_ABORTED, - NULL, NULL); + bkt = apr_bucket_flush_create( + dav_svn__output_get_bucket_alloc(lrb->output)); + APR_BRIGADE_INSERT_TAIL(lrb->bb, bkt); + SVN_ERR(dav_svn__output_pass_brigade(lrb->output, lrb->bb)); if (lrb->result_count < 256) lrb->next_forced_flush = lrb->next_forced_flush * 4; @@ -328,7 +357,7 @@ log_receiver(void *baton, dav_error * dav_svn__log_report(const dav_resource *resource, const apr_xml_doc *doc, - ap_filter_t *output) + dav_svn__output *output) { svn_error_t *serr; dav_error *derr = NULL; @@ -460,9 +489,10 @@ dav_svn__log_report(const dav_resource * /* Build log receiver baton */ lrb.bb = apr_brigade_create(resource->pool, /* not the subpool! */ - output->c->bucket_alloc); + dav_svn__output_get_bucket_alloc(output)); lrb.output = output; lrb.needs_header = TRUE; + lrb.needs_log_item = TRUE; lrb.stack_depth = 0; /* lrb.requested_custom_revprops set above */ @@ -475,18 +505,20 @@ dav_svn__log_report(const dav_resource * flag in our log_receiver_baton structure). */ /* Send zero or more log items. */ - serr = svn_repos_get_logs4(repos->repos, + serr = svn_repos_get_logs5(repos->repos, paths, start, end, limit, - discover_changed_paths, strict_node_history, include_merged_revisions, revprops, dav_svn__authz_read_func(&arb), &arb, - log_receiver, + discover_changed_paths ? log_change_receiver + : NULL, + &lrb, + log_revision_receiver, &lrb, resource->pool); if (serr)
Modified: subversion/branches/ra-git/subversion/mod_dav_svn/reports/mergeinfo.c URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/mod_dav_svn/reports/mergeinfo.c?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/mod_dav_svn/reports/mergeinfo.c (original) +++ subversion/branches/ra-git/subversion/mod_dav_svn/reports/mergeinfo.c Tue Oct 11 09:11:50 2016 @@ -46,7 +46,7 @@ dav_error * dav_svn__get_mergeinfo_report(const dav_resource *resource, const apr_xml_doc *doc, - ap_filter_t *output) + dav_svn__output *output) { svn_error_t *serr; dav_error *derr = NULL; @@ -124,7 +124,8 @@ dav_svn__get_mergeinfo_report(const dav_ arb.repos = resource->info->repos; /* Build mergeinfo brigade */ - bb = apr_brigade_create(resource->pool, output->c->bucket_alloc); + bb = apr_brigade_create(resource->pool, + dav_svn__output_get_bucket_alloc(output)); serr = svn_repos_fs_get_mergeinfo(&catalog, repos->repos, paths, rev, inherit, include_descendants, Modified: subversion/branches/ra-git/subversion/mod_dav_svn/reports/replay.c URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/mod_dav_svn/reports/replay.c?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/mod_dav_svn/reports/replay.c (original) +++ subversion/branches/ra-git/subversion/mod_dav_svn/reports/replay.c Tue Oct 11 09:11:50 2016 @@ -44,7 +44,7 @@ typedef struct edit_baton_t { apr_bucket_brigade *bb; - ap_filter_t *output; + dav_svn__output *output; svn_boolean_t started; svn_boolean_t sending_textdelta; int compression_level; @@ -367,7 +367,7 @@ static void make_editor(const svn_delta_editor_t **editor, void **edit_baton, apr_bucket_brigade *bb, - ap_filter_t *output, + dav_svn__output *output, int compression_level, apr_pool_t *pool) { @@ -413,7 +413,7 @@ malformed_element_error(const char *tagn dav_error * dav_svn__replay_report(const dav_resource *resource, const apr_xml_doc *doc, - ap_filter_t *output) + dav_svn__output *output) { dav_error *derr = NULL; svn_revnum_t low_water_mark = SVN_INVALID_REVNUM; @@ -530,7 +530,8 @@ dav_svn__replay_report(const dav_resourc if (! base_dir) base_dir = ""; - bb = apr_brigade_create(resource->pool, output->c->bucket_alloc); + 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))) Modified: subversion/branches/ra-git/subversion/mod_dav_svn/reports/update.c URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/mod_dav_svn/reports/update.c?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/mod_dav_svn/reports/update.c (original) +++ subversion/branches/ra-git/subversion/mod_dav_svn/reports/update.c Tue Oct 11 09:11:50 2016 @@ -68,7 +68,7 @@ typedef struct update_ctx_t { apr_bucket_brigade *bb; /* where to deliver the output */ - ap_filter_t *output; + dav_svn__output *output; /* where do these editor paths *really* point to? */ apr_hash_t *pathmap; @@ -954,7 +954,7 @@ validate_input_revision(svn_revnum_t rev dav_error * dav_svn__update_report(const dav_resource *resource, const apr_xml_doc *doc, - ap_filter_t *output) + dav_svn__output *output) { svn_delta_editor_t *editor; apr_xml_elem *child; @@ -970,7 +970,7 @@ dav_svn__update_report(const dav_resourc dav_error *derr = NULL; const char *src_path = NULL; const char *dst_path = NULL; - const dav_svn_repos *repos = resource->info->repos; + dav_svn_repos *repos = resource->info->repos; const char *target = ""; svn_boolean_t text_deltas = TRUE; svn_depth_t requested_depth = svn_depth_unknown; @@ -1028,7 +1028,7 @@ dav_svn__update_report(const dav_resourc /* Ask the repository about its youngest revision (which we'll need for some input validation later). */ - if ((serr = svn_fs_youngest_rev(&youngest, repos->fs, resource->pool))) + if ((serr = dav_svn__get_youngest_rev(&youngest, repos, resource->pool))) return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "Could not determine the youngest " "revision for the update process.", @@ -1202,7 +1202,8 @@ dav_svn__update_report(const dav_resourc uc.output = output; uc.anchor = src_path; uc.target = target; - uc.bb = apr_brigade_create(resource->pool, output->c->bucket_alloc); + uc.bb = apr_brigade_create(resource->pool, + dav_svn__output_get_bucket_alloc(output)); uc.pathmap = NULL; uc.enable_v2_response = ((resource->info->restype == DAV_SVN_RESTYPE_ME) && (resource->info->repos->v2_protocol)); Modified: subversion/branches/ra-git/subversion/mod_dav_svn/repos.c URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/mod_dav_svn/repos.c?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/mod_dav_svn/repos.c (original) +++ subversion/branches/ra-git/subversion/mod_dav_svn/repos.c Tue Oct 11 09:11:50 2016 @@ -810,7 +810,7 @@ prep_regular(dav_resource_combined *comb ### other cases besides a BC? */ if (comb->priv.root.rev == SVN_INVALID_REVNUM) { - serr = svn_fs_youngest_rev(&comb->priv.root.rev, repos->fs, pool); + serr = dav_svn__get_youngest_rev(&comb->priv.root.rev, repos, pool); if (serr != NULL) { return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, @@ -879,9 +879,9 @@ prep_version(dav_resource_combined *comb /* if we don't have a revision, then assume the youngest */ if (!SVN_IS_VALID_REVNUM(comb->priv.root.rev)) { - serr = svn_fs_youngest_rev(&comb->priv.root.rev, - comb->priv.repos->fs, - pool); + serr = dav_svn__get_youngest_rev(&comb->priv.root.rev, + comb->priv.repos, + pool); if (serr != NULL) { /* ### might not be a baseline */ @@ -1583,6 +1583,7 @@ get_parentpath_resource(request_rec *r, repos->special_uri = dav_svn__get_special_uri(r); repos->username = r->user; repos->client_capabilities = apr_hash_make(repos->pool); + repos->youngest_rev = SVN_INVALID_REVNUM; /* Make sure this type of resource always has a trailing slash; if not, redirect to a URI that does. */ @@ -2020,7 +2021,7 @@ parse_querystring(request_rec *r, const else { /* No peg-rev? Default to HEAD, just like the cmdline client. */ - serr = svn_fs_youngest_rev(&peg_rev, comb->priv.repos->fs, pool); + serr = dav_svn__get_youngest_rev(&peg_rev, comb->priv.repos, pool); if (serr != NULL) return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "Couldn't fetch youngest rev.", pool); @@ -2259,6 +2260,7 @@ get_resource(request_rec *r, /* create the repository structure and stash it away */ repos = apr_pcalloc(r->pool, sizeof(*repos)); repos->pool = r->pool; + repos->youngest_rev = SVN_INVALID_REVNUM; comb->priv.repos = repos; @@ -2367,6 +2369,8 @@ get_resource(request_rec *r, dav_svn__get_fulltext_cache_flag(r) ? "1" :"0"); svn_hash_sets(fs_config, SVN_FS_CONFIG_FSFS_CACHE_REVPROPS, dav_svn__get_revprop_cache_flag(r) ? "2" :"0"); + svn_hash_sets(fs_config, SVN_FS_CONFIG_FSFS_CACHE_NODEPROPS, + dav_svn__get_nodeprop_cache_flag(r) ? "1" :"0"); svn_hash_sets(fs_config, SVN_FS_CONFIG_FSFS_BLOCK_READ, dav_svn__get_block_read_flag(r) ? "1" :"0"); @@ -3034,50 +3038,6 @@ seek_stream(dav_stream *stream, apr_off_ && resource->baselined)) -/* Return the last modification time of RESOURCE, or -1 if the DAV - resource type is not handled, or if an error occurs. Temporary - allocations are made from RESOURCE->POOL. */ -static apr_time_t -get_last_modified(const dav_resource *resource) -{ - apr_time_t last_modified; - svn_error_t *serr; - svn_revnum_t created_rev; - svn_string_t *date_time; - - if (RESOURCE_LACKS_ETAG_POTENTIAL(resource)) - return -1; - - if ((serr = svn_fs_node_created_rev(&created_rev, resource->info->root.root, - resource->info->repos_path, - resource->pool))) - { - svn_error_clear(serr); - return -1; - } - - if ((serr = svn_fs_revision_prop2(&date_time, resource->info->repos->fs, - created_rev, "svn:date", TRUE, - resource->pool, resource->pool))) - { - svn_error_clear(serr); - return -1; - } - - if (date_time == NULL || date_time->data == NULL) - return -1; - - if ((serr = svn_time_from_cstring(&last_modified, date_time->data, - resource->pool))) - { - svn_error_clear(serr); - return -1; - } - - return last_modified; -} - - const char * dav_svn__getetag(const dav_resource *resource, apr_pool_t *pool) { @@ -3147,7 +3107,6 @@ set_headers(request_rec *r, const dav_re svn_error_t *serr; svn_filesize_t length; const char *mimetype = NULL; - apr_time_t last_modified; /* As version resources don't change, encourage caching. */ if (is_cacheable(r, resource)) @@ -3159,15 +3118,6 @@ set_headers(request_rec *r, const dav_re if (!resource->exists) return NULL; - last_modified = get_last_modified(resource); - if (last_modified != -1) - { - /* Note the modification time for the requested resource, and - include the Last-Modified header in the response. */ - ap_update_mtime(r, last_modified); - ap_set_last_modified(r); - } - /* generate our etag and place it into the output */ apr_table_setn(r->headers_out, "ETag", dav_svn__getetag(resource, resource->pool)); @@ -3286,8 +3236,8 @@ set_headers(request_rec *r, const dav_re typedef struct diff_ctx_t { - ap_filter_t *output; - apr_pool_t *pool; + dav_svn__output *output; + apr_bucket_brigade *bb; } diff_ctx_t; @@ -3295,18 +3245,9 @@ static svn_error_t * __attribute__((war write_to_filter(void *baton, const char *buffer, apr_size_t *len) { diff_ctx_t *dc = baton; - apr_bucket_brigade *bb; - apr_bucket *bkt; - apr_status_t status; /* take the current data and shove it into the filter */ - bb = apr_brigade_create(dc->pool, dc->output->c->bucket_alloc); - bkt = apr_bucket_transient_create(buffer, *len, dc->output->c->bucket_alloc); - APR_BRIGADE_INSERT_TAIL(bb, bkt); - if ((status = ap_pass_brigade(dc->output, bb)) != APR_SUCCESS) { - return svn_error_create(status, NULL, - "Could not write data to filter"); - } + SVN_ERR(dav_svn__brigade_write(dc->bb, dc->output, buffer, *len)); return SVN_NO_ERROR; } @@ -3316,28 +3257,270 @@ static svn_error_t * __attribute__((war close_filter(void *baton) { diff_ctx_t *dc = baton; - apr_bucket_brigade *bb; apr_bucket *bkt; - apr_status_t status; /* done with the file. write an EOS bucket now. */ - bb = apr_brigade_create(dc->pool, dc->output->c->bucket_alloc); - bkt = apr_bucket_eos_create(dc->output->c->bucket_alloc); - APR_BRIGADE_INSERT_TAIL(bb, bkt); - if ((status = ap_pass_brigade(dc->output, bb)) != APR_SUCCESS) - return svn_error_create(status, NULL, "Could not write EOS to filter"); + bkt = apr_bucket_eos_create(dav_svn__output_get_bucket_alloc(dc->output)); + APR_BRIGADE_INSERT_TAIL(dc->bb, bkt); + SVN_ERR(dav_svn__output_pass_brigade(dc->output, dc->bb)); + + return SVN_NO_ERROR; +} + + +static svn_error_t * +emit_collection_head(const dav_resource *resource, + apr_bucket_brigade *bb, + dav_svn__output *output, + svn_boolean_t gen_html, + apr_pool_t *pool) +{ + /* XML schema for the directory index if xslt_uri is set: + + <?xml version="1.0"?> + <?xml-stylesheet type="text/xsl" href="[info->repos->xslt_uri]"?> */ + static const char xml_index_dtd[] = + "<!DOCTYPE svn [\n" + " <!ELEMENT svn (index)>\n" + " <!ATTLIST svn version CDATA #REQUIRED\n" + " href CDATA #REQUIRED>\n" + " <!ELEMENT index (updir?, (file | dir)*)>\n" + " <!ATTLIST index name CDATA #IMPLIED\n" + " path CDATA #IMPLIED\n" + " rev CDATA #IMPLIED\n" + " base CDATA #IMPLIED>\n" + " <!ELEMENT updir EMPTY>\n" + " <!ATTLIST updir href CDATA #REQUIRED>\n" + " <!ELEMENT file EMPTY>\n" + " <!ATTLIST file name CDATA #REQUIRED\n" + " href CDATA #REQUIRED>\n" + " <!ELEMENT dir EMPTY>\n" + " <!ATTLIST dir name CDATA #REQUIRED\n" + " href CDATA #REQUIRED>\n" + "]>\n"; + + if (gen_html) + { + const char *title; + if (resource->info->repos_path == NULL) + title = "unknown location"; + else + title = resource->info->repos_path; + + if (resource->info->restype != DAV_SVN_RESTYPE_PARENTPATH_COLLECTION) + { + if (SVN_IS_VALID_REVNUM(resource->info->root.rev)) + title = apr_psprintf(pool, + "Revision %ld: %s", + resource->info->root.rev, title); + if (resource->info->repos->repo_basename) + title = apr_psprintf(pool, "%s - %s", + resource->info->repos->repo_basename, + title); + if (resource->info->repos->repo_name) + title = apr_psprintf(pool, "%s: %s", + resource->info->repos->repo_name, + title); + } + + SVN_ERR(dav_svn__brigade_printf(bb, output, + "<html><head><title>%s</title></head>\n" + "<body>\n <h2>%s</h2>\n <ul>\n", + title, title)); + } + else + { + const char *name = resource->info->repos->repo_name; + const char *href = resource->info->repos_path; + const char *base = resource->info->repos->repo_basename; + + SVN_ERR(dav_svn__brigade_puts(bb, output, "<?xml version=\"1.0\"?>\n")); + SVN_ERR(dav_svn__brigade_printf(bb, output, + "<?xml-stylesheet type=\"text/xsl\" " + "href=\"%s\"?>\n", + resource->info->repos->xslt_uri)); + SVN_ERR(dav_svn__brigade_puts(bb, output, xml_index_dtd)); + SVN_ERR(dav_svn__brigade_puts(bb, output, + "<svn version=\"" SVN_VERSION "\"\n" + " href=\"http://subversion.apache.org/\">\n")); + SVN_ERR(dav_svn__brigade_puts(bb, output, " <index")); + + if (name) + SVN_ERR(dav_svn__brigade_printf(bb, output, + " name=\"%s\"", + apr_xml_quote_string(resource->pool, + name, 1))); + if (SVN_IS_VALID_REVNUM(resource->info->root.rev)) + SVN_ERR(dav_svn__brigade_printf(bb, output, " rev=\"%ld\"", + resource->info->root.rev)); + if (href) + SVN_ERR(dav_svn__brigade_printf(bb, output, " path=\"%s\"", + apr_xml_quote_string(resource->pool, + href, 1))); + if (base) + SVN_ERR(dav_svn__brigade_printf(bb, output, " base=\"%s\"", base)); + + SVN_ERR(dav_svn__brigade_puts(bb, output, ">\n")); + } + + if ((resource->info->restype != DAV_SVN_RESTYPE_PARENTPATH_COLLECTION) + && resource->info->repos_path + && ((resource->info->repos_path[1] != '\0') + || dav_svn__get_list_parentpath_flag(resource->info->r))) + { + const char *href; + if (resource->info->pegged) + { + href = apr_psprintf(pool, "../?p=%ld", resource->info->root.rev); + } + else + { + href = "../"; + } + + if (gen_html) + { + SVN_ERR(dav_svn__brigade_printf(bb, output, + " <li><a href=\"%s\">..</a></li>\n", + href)); + } + else + { + SVN_ERR(dav_svn__brigade_printf(bb, output, + " <updir href=\"%s\"/>\n", + href)); + } + } + + return SVN_NO_ERROR; +} + + +static svn_error_t * +emit_collection_entry(const dav_resource *resource, + apr_bucket_brigade *bb, + dav_svn__output *output, + const svn_fs_dirent_t *entry, + svn_boolean_t gen_html, + apr_pool_t *pool) +{ + const char *name = entry->name; + const char *href = name; + svn_boolean_t is_dir = (entry->kind == svn_node_dir); + + /* append a trailing slash onto the name for directories. we NEED + this for the href portion so that the relative reference will + descend properly. for the visible portion, it is just nice. */ + /* ### The xml output doesn't like to see a trailing slash on + ### the visible portion, so avoid that. */ + if (is_dir) + href = apr_pstrcat(pool, href, "/", SVN_VA_NULL); + + if (gen_html) + name = href; + + /* We quote special characters in both XML and HTML. */ + name = apr_xml_quote_string(pool, name, !gen_html); + + /* According to httpd-2.0.54/include/httpd.h, ap_os_escape_path() + behaves differently on different platforms. It claims to + "convert an OS path to a URL in an OS dependant way". + Nevertheless, there appears to be only one implementation + of the function in httpd, and the code seems completely + platform independent, so we'll assume it's appropriate for + mod_dav_svn to use it to quote outbound paths. */ + href = ap_os_escape_path(pool, href, 0); + href = apr_xml_quote_string(pool, href, 1); + + if (gen_html) + { + /* If our directory was access using the public peg-rev + CGI query interface, we'll let its dirents carry that + peg-rev, too. */ + if (resource->info->pegged) + { + SVN_ERR(dav_svn__brigade_printf(bb, output, + " <li><a href=\"%s?p=%ld\">%s</a></li>\n", + href, resource->info->root.rev, name)); + } + else + { + SVN_ERR(dav_svn__brigade_printf(bb, output, + " <li><a href=\"%s\">%s</a></li>\n", + href, name)); + } + } + else + { + const char *const tag = (is_dir ? "dir" : "file"); + + /* This is where we could search for props */ + + /* If our directory was access using the public peg-rev + CGI query interface, we'll let its dirents carry that + peg-rev, too. */ + if (resource->info->pegged) + { + SVN_ERR(dav_svn__brigade_printf(bb, output, + " <%s name=\"%s\" href=\"%s?p=%ld\" />\n", + tag, name, href, resource->info->root.rev)); + } + else + { + SVN_ERR(dav_svn__brigade_printf(bb, output, + " <%s name=\"%s\" href=\"%s\" />\n", + tag, name, href)); + } + } + + return SVN_NO_ERROR; +} + + +static svn_error_t * +emit_collection_tail(const dav_resource *resource, + apr_bucket_brigade *bb, + dav_svn__output *output, + svn_boolean_t gen_html, + apr_pool_t *pool) +{ + if (gen_html) + { + if (strcmp(ap_psignature("FOO", resource->info->r), "") != 0) + { + /* Apache's signature generation code didn't eat our prefix. + ServerSignature must be enabled. Print our version info. + + WARNING: This is a kludge!! ap_psignature() doesn't promise + to return the empty string when ServerSignature is off. We + know it does by code inspection, but this behavior is subject + to change. (Perhaps we should try to get the Apache folks to + make this promise, though. Seems harmless/useful enough...) + */ + SVN_ERR(dav_svn__brigade_puts(bb, output, + " </ul>\n <hr noshade><em>Powered by " + "<a href=\"http://subversion.apache.org/\">" + "Apache Subversion" + "</a> version " SVN_VERSION "." + "</em>\n</body></html>")); + } + else + SVN_ERR(dav_svn__brigade_puts(bb, output, " </ul>\n</body></html>")); + } + else + SVN_ERR(dav_svn__brigade_puts(bb, output, " </index>\n</svn>\n")); return SVN_NO_ERROR; } static dav_error * -deliver(const dav_resource *resource, ap_filter_t *output) +deliver(const dav_resource *resource, ap_filter_t *unused) { svn_error_t *serr; apr_bucket_brigade *bb; apr_bucket *bkt; - apr_status_t status; + dav_svn__output *output; /* Check resource type */ if (resource->baselined @@ -3350,39 +3533,17 @@ deliver(const dav_resource *resource, ap "Cannot GET this type of resource."); } + output = dav_svn__output_create(resource->info->r, resource->pool); + if (resource->collection) { const int gen_html = !resource->info->repos->xslt_uri; apr_hash_t *entries; - apr_pool_t *entry_pool; + apr_pool_t *iterpool; apr_array_header_t *sorted; svn_revnum_t dir_rev = SVN_INVALID_REVNUM; int i; - /* XML schema for the directory index if xslt_uri is set: - - <?xml version="1.0"?> - <?xml-stylesheet type="text/xsl" href="[info->repos->xslt_uri]"?> */ - static const char xml_index_dtd[] = - "<!DOCTYPE svn [\n" - " <!ELEMENT svn (index)>\n" - " <!ATTLIST svn version CDATA #REQUIRED\n" - " href CDATA #REQUIRED>\n" - " <!ELEMENT index (updir?, (file | dir)*)>\n" - " <!ATTLIST index name CDATA #IMPLIED\n" - " path CDATA #IMPLIED\n" - " rev CDATA #IMPLIED\n" - " base CDATA #IMPLIED>\n" - " <!ELEMENT updir EMPTY>\n" - " <!ATTLIST updir href CDATA #REQUIRED>\n" - " <!ELEMENT file EMPTY>\n" - " <!ATTLIST file name CDATA #REQUIRED\n" - " href CDATA #REQUIRED>\n" - " <!ELEMENT dir EMPTY>\n" - " <!ATTLIST dir name CDATA #REQUIRED\n" - " href CDATA #REQUIRED>\n" - "]>\n"; - /* <svn version="1.3.0 (dev-build)" href="http://subversion.apache.org"> <index name="[info->repos->repo_name]" @@ -3463,99 +3624,21 @@ deliver(const dav_resource *resource, ap resource->pool); } - bb = apr_brigade_create(resource->pool, output->c->bucket_alloc); - - if (gen_html) - { - const char *title; - if (resource->info->repos_path == NULL) - title = "unknown location"; - else - title = resource->info->repos_path; - - if (resource->info->restype != DAV_SVN_RESTYPE_PARENTPATH_COLLECTION) - { - if (SVN_IS_VALID_REVNUM(resource->info->root.rev)) - title = apr_psprintf(resource->pool, - "Revision %ld: %s", - resource->info->root.rev, title); - if (resource->info->repos->repo_basename) - title = apr_psprintf(resource->pool, "%s - %s", - resource->info->repos->repo_basename, - title); - if (resource->info->repos->repo_name) - title = apr_psprintf(resource->pool, "%s: %s", - resource->info->repos->repo_name, - title); - } - - ap_fprintf(output, bb, "<html><head><title>%s</title></head>\n" - "<body>\n <h2>%s</h2>\n <ul>\n", title, title); - } - else - { - const char *name = resource->info->repos->repo_name; - const char *href = resource->info->repos_path; - const char *base = resource->info->repos->repo_basename; - - ap_fputs(output, bb, "<?xml version=\"1.0\"?>\n"); - ap_fprintf(output, bb, - "<?xml-stylesheet type=\"text/xsl\" href=\"%s\"?>\n", - resource->info->repos->xslt_uri); - ap_fputs(output, bb, xml_index_dtd); - ap_fputs(output, bb, - "<svn version=\"" SVN_VERSION "\"\n" - " href=\"http://subversion.apache.org/\">\n"); - ap_fputs(output, bb, " <index"); - if (name) - ap_fprintf(output, bb, " name=\"%s\"", - apr_xml_quote_string(resource->pool, name, 1)); - if (SVN_IS_VALID_REVNUM(resource->info->root.rev)) - ap_fprintf(output, bb, " rev=\"%ld\"", - resource->info->root.rev); - if (href) - ap_fprintf(output, bb, " path=\"%s\"", - apr_xml_quote_string(resource->pool, - href, - 1)); - if (base) - ap_fprintf(output, bb, " base=\"%s\"", base); - - ap_fputs(output, bb, ">\n"); - } - - if ((resource->info->restype != DAV_SVN_RESTYPE_PARENTPATH_COLLECTION) - && resource->info->repos_path - && ((resource->info->repos_path[1] != '\0') - || dav_svn__get_list_parentpath_flag(resource->info->r))) - { - const char *href; - if (resource->info->pegged) - { - href = apr_psprintf(resource->pool, "../?p=%ld", - resource->info->root.rev); - } - else - { - href = "../"; - } + bb = apr_brigade_create(resource->pool, + dav_svn__output_get_bucket_alloc(output)); - if (gen_html) - { - ap_fprintf(output, bb, - " <li><a href=\"%s\">..</a></li>\n", href); - } - else - { - ap_fprintf(output, bb, " <updir href=\"%s\"/>\n", href); - } - } + serr = emit_collection_head(resource, bb, output, gen_html, + resource->pool); + if (serr != NULL) + return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, + "could not output collection", + resource->pool); /* get a sorted list of the entries */ sorted = svn_sort__hash(entries, svn_sort_compare_items_as_paths, resource->pool); - entry_pool = svn_pool_create(resource->pool); + iterpool = svn_pool_create(resource->pool); for (i = 0; i < sorted->nelts; ++i) { @@ -3563,11 +3646,9 @@ deliver(const dav_resource *resource, ap const svn_sort__item_t); const svn_fs_dirent_t *entry = item->value; const char *name = item->key; - const char *href = name; - svn_boolean_t is_dir = (entry->kind == svn_node_dir); const char *repos_relpath = NULL; - svn_pool_clear(entry_pool); + svn_pool_clear(iterpool); /* DIR_REV is set to a valid revision if we're looking at the entries of a versioned directory. Otherwise, we're @@ -3575,121 +3656,45 @@ deliver(const dav_resource *resource, ap if (SVN_IS_VALID_REVNUM(dir_rev)) { repos_relpath = svn_fspath__join(resource->info->repos_path, - name, entry_pool); + name, iterpool); if (! dav_svn__allow_read(resource->info->r, resource->info->repos, repos_relpath, dir_rev, - entry_pool)) + iterpool)) continue; } else { if (! dav_svn__allow_list_repos(resource->info->r, - entry->name, entry_pool)) + entry->name, iterpool)) continue; } - /* append a trailing slash onto the name for directories. we NEED - this for the href portion so that the relative reference will - descend properly. for the visible portion, it is just nice. */ - /* ### The xml output doesn't like to see a trailing slash on - ### the visible portion, so avoid that. */ - if (is_dir) - href = apr_pstrcat(entry_pool, href, "/", SVN_VA_NULL); - - if (gen_html) - name = href; - - /* We quote special characters in both XML and HTML. */ - name = apr_xml_quote_string(entry_pool, name, !gen_html); - - /* According to httpd-2.0.54/include/httpd.h, ap_os_escape_path() - behaves differently on different platforms. It claims to - "convert an OS path to a URL in an OS dependant way". - Nevertheless, there appears to be only one implementation - of the function in httpd, and the code seems completely - platform independent, so we'll assume it's appropriate for - mod_dav_svn to use it to quote outbound paths. */ - href = ap_os_escape_path(entry_pool, href, 0); - href = apr_xml_quote_string(entry_pool, href, 1); - - if (gen_html) - { - /* If our directory was access using the public peg-rev - CGI query interface, we'll let its dirents carry that - peg-rev, too. */ - if (resource->info->pegged) - { - ap_fprintf(output, bb, - " <li><a href=\"%s?p=%ld\">%s</a></li>\n", - href, resource->info->root.rev, name); - } - else - { - ap_fprintf(output, bb, - " <li><a href=\"%s\">%s</a></li>\n", - href, name); - } - } - else - { - const char *const tag = (is_dir ? "dir" : "file"); - - /* This is where we could search for props */ - - /* If our directory was access using the public peg-rev - CGI query interface, we'll let its dirents carry that - peg-rev, too. */ - if (resource->info->pegged) - { - ap_fprintf(output, bb, - " <%s name=\"%s\" href=\"%s?p=%ld\" />\n", - tag, name, href, resource->info->root.rev); - } - else - { - ap_fprintf(output, bb, - " <%s name=\"%s\" href=\"%s\" />\n", - tag, name, href); - } - } + serr = emit_collection_entry(resource, bb, output, entry, gen_html, + iterpool); + if (serr != NULL) + return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, + "could not output collection entry", + resource->pool); } - svn_pool_destroy(entry_pool); + svn_pool_destroy(iterpool); - if (gen_html) - { - if (strcmp(ap_psignature("FOO", resource->info->r), "") != 0) - { - /* Apache's signature generation code didn't eat our prefix. - ServerSignature must be enabled. Print our version info. - - WARNING: This is a kludge!! ap_psignature() doesn't promise - to return the empty string when ServerSignature is off. We - know it does by code inspection, but this behavior is subject - to change. (Perhaps we should try to get the Apache folks to - make this promise, though. Seems harmless/useful enough...) - */ - ap_fputs(output, bb, - " </ul>\n <hr noshade><em>Powered by " - "<a href=\"http://subversion.apache.org/\">" - "Apache Subversion" - "</a> version " SVN_VERSION "." - "</em>\n</body></html>"); - } - else - ap_fputs(output, bb, " </ul>\n</body></html>"); - } - else - ap_fputs(output, bb, " </index>\n</svn>\n"); + serr = emit_collection_tail(resource, bb, output, gen_html, + resource->pool); + if (serr != NULL) + return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, + "could not output collection", + resource->pool); - bkt = apr_bucket_eos_create(output->c->bucket_alloc); + bkt = apr_bucket_eos_create(dav_svn__output_get_bucket_alloc(output)); APR_BRIGADE_INSERT_TAIL(bb, bkt); - if ((status = ap_pass_brigade(output, bb)) != APR_SUCCESS) - return dav_svn__new_error(resource->pool, HTTP_INTERNAL_SERVER_ERROR, - 0, status, - "Could not write EOS to filter."); + serr = dav_svn__output_pass_brigade(output, bb); + if (serr != NULL) + return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, + "Could not write EOS to filter.", + resource->pool); return NULL; } @@ -3752,10 +3757,13 @@ deliver(const dav_resource *resource, ap "could not prepare to read a delta", resource->pool); + bb = apr_brigade_create(resource->pool, + dav_svn__output_get_bucket_alloc(output)); + /* create a stream that svndiff data will be written to, which will copy it to the network */ dc.output = output; - dc.pool = resource->pool; + dc.bb = bb; o_stream = svn_stream_create(&dc, resource->pool); svn_stream_set_write(o_stream, write_to_filter); svn_stream_set_close(o_stream, close_filter); @@ -3771,6 +3779,8 @@ deliver(const dav_resource *resource, ap to the network. */ serr = svn_txdelta_send_txstream(txd_stream, handler, h_baton, resource->pool); + apr_brigade_destroy(bb); + if (serr != NULL) return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "could not deliver the txdelta stream", @@ -3876,6 +3886,9 @@ deliver(const dav_resource *resource, ap ### which will read from the FS stream on demand */ block = apr_palloc(resource->pool, SVN__STREAM_CHUNK_SIZE); + bb = apr_brigade_create(resource->pool, + dav_svn__output_get_bucket_alloc(output)); + while (1) { apr_size_t bufsize = SVN__STREAM_CHUNK_SIZE; @@ -3883,6 +3896,7 @@ deliver(const dav_resource *resource, ap serr = svn_stream_read_full(stream, block, &bufsize); if (serr != NULL) { + apr_brigade_destroy(bb); return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "could not read the file contents", resource->pool); @@ -3890,30 +3904,35 @@ deliver(const dav_resource *resource, ap if (bufsize == 0) break; - /* build a brigade and write to the filter ... */ - bb = apr_brigade_create(resource->pool, output->c->bucket_alloc); - bkt = apr_bucket_transient_create(block, bufsize, - output->c->bucket_alloc); + /* write to the filter ... */ + bkt = apr_bucket_transient_create( + block, bufsize, dav_svn__output_get_bucket_alloc(output)); APR_BRIGADE_INSERT_TAIL(bb, bkt); - if ((status = ap_pass_brigade(output, bb)) != APR_SUCCESS) { - /* ### that HTTP code... */ - return dav_svn__new_error(resource->pool, - HTTP_INTERNAL_SERVER_ERROR, 0, status, - "Could not write data to filter."); - } + serr = dav_svn__output_pass_brigade(output, bb); + if (serr != NULL) + { + apr_brigade_destroy(bb); + /* ### that HTTP code... */ + return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, + "Could not write data to filter.", + resource->pool); + } } /* done with the file. write an EOS bucket now. */ - bb = apr_brigade_create(resource->pool, output->c->bucket_alloc); - bkt = apr_bucket_eos_create(output->c->bucket_alloc); + bkt = apr_bucket_eos_create(dav_svn__output_get_bucket_alloc(output)); APR_BRIGADE_INSERT_TAIL(bb, bkt); - if ((status = ap_pass_brigade(output, bb)) != APR_SUCCESS) { - /* ### that HTTP code... */ - return dav_svn__new_error(resource->pool, - HTTP_INTERNAL_SERVER_ERROR, 0, status, - "Could not write EOS to filter."); - } + serr = dav_svn__output_pass_brigade(output, bb); + if (serr != NULL) + { + apr_brigade_destroy(bb); + /* ### that HTTP code... */ + return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, + "Could not write EOS to filter.", + resource->pool); + } + apr_brigade_destroy(bb); return NULL; } } @@ -4633,7 +4652,7 @@ dav_svn__working_to_regular_resource(dav /* Change the URL into either a baseline-collection or a public one. */ if (priv->root.rev == SVN_INVALID_REVNUM) { - serr = svn_fs_youngest_rev(&priv->root.rev, repos->fs, resource->pool); + serr = dav_svn__get_youngest_rev(&priv->root.rev, repos, resource->pool); if (serr != NULL) return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "Could not determine youngest rev.", @@ -4692,7 +4711,7 @@ dav_svn__create_version_resource(dav_res static dav_error * handle_post_request(request_rec *r, dav_resource *resource, - ap_filter_t *output) + dav_svn__output *output) { svn_skel_t *request_skel, *post_skel; int status; @@ -4775,7 +4794,9 @@ int dav_svn__method_post(request_rec *r) content_type = apr_table_get(r->headers_in, "content-type"); if (content_type && (strcmp(content_type, SVN_SKEL_MIME_TYPE) == 0)) { - derr = handle_post_request(r, resource, r->output_filters); + dav_svn__output *output = dav_svn__output_create(resource->info->r, + resource->pool); + derr = handle_post_request(r, resource, output); } else { Modified: subversion/branches/ra-git/subversion/mod_dav_svn/util.c URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/mod_dav_svn/util.c?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/mod_dav_svn/util.c (original) +++ subversion/branches/ra-git/subversion/mod_dav_svn/util.c Tue Oct 11 09:11:50 2016 @@ -465,6 +465,48 @@ dav_svn__find_ns(const apr_array_header_ return -1; } + +/*** Output helpers ***/ + + +struct dav_svn__output +{ + request_rec *r; +}; + +dav_svn__output * +dav_svn__output_create(request_rec *r, + apr_pool_t *pool) +{ + dav_svn__output *output = apr_pcalloc(pool, sizeof(*output)); + output->r = r; + return output; +} + +apr_bucket_alloc_t * +dav_svn__output_get_bucket_alloc(dav_svn__output *output) +{ + return output->r->connection->bucket_alloc; +} + +svn_error_t * +dav_svn__output_pass_brigade(dav_svn__output *output, + apr_bucket_brigade *bb) +{ + apr_status_t status; + + status = ap_pass_brigade(output->r->output_filters, bb); + /* Empty the brigade here, as required by ap_pass_brigade(). */ + apr_brigade_cleanup(bb); + if (status) + return svn_error_create(status, NULL, "Could not write data to filter"); + + /* Check for an aborted connection, since the brigade functions don't + appear to return useful errors when the connection is dropped. */ + if (output->r->connection->aborted) + return svn_error_create(SVN_ERR_APMOD_CONNECTION_ABORTED, NULL, NULL); + return SVN_NO_ERROR; +} /*** Brigade I/O wrappers ***/ @@ -472,17 +514,18 @@ dav_svn__find_ns(const apr_array_header_ svn_error_t * dav_svn__brigade_write(apr_bucket_brigade *bb, - ap_filter_t *output, + dav_svn__output *output, const char *data, apr_size_t len) { apr_status_t apr_err; - apr_err = apr_brigade_write(bb, ap_filter_flush, output, data, len); + apr_err = apr_brigade_write(bb, ap_filter_flush, + output->r->output_filters, data, len); if (apr_err) return svn_error_create(apr_err, 0, NULL); /* Check for an aborted connection, since the brigade functions don't appear to be return useful errors when the connection is dropped. */ - if (output->c->aborted) + if (output->r->connection->aborted) return svn_error_create(SVN_ERR_APMOD_CONNECTION_ABORTED, 0, NULL); return SVN_NO_ERROR; } @@ -490,16 +533,17 @@ dav_svn__brigade_write(apr_bucket_brigad svn_error_t * dav_svn__brigade_puts(apr_bucket_brigade *bb, - ap_filter_t *output, + dav_svn__output *output, const char *str) { apr_status_t apr_err; - apr_err = apr_brigade_puts(bb, ap_filter_flush, output, str); + apr_err = apr_brigade_puts(bb, ap_filter_flush, + output->r->output_filters, str); if (apr_err) return svn_error_create(apr_err, 0, NULL); /* Check for an aborted connection, since the brigade functions don't appear to be return useful errors when the connection is dropped. */ - if (output->c->aborted) + if (output->r->connection->aborted) return svn_error_create(SVN_ERR_APMOD_CONNECTION_ABORTED, 0, NULL); return SVN_NO_ERROR; } @@ -507,7 +551,7 @@ dav_svn__brigade_puts(apr_bucket_brigade svn_error_t * dav_svn__brigade_printf(apr_bucket_brigade *bb, - ap_filter_t *output, + dav_svn__output *output, const char *fmt, ...) { @@ -515,18 +559,41 @@ dav_svn__brigade_printf(apr_bucket_briga va_list ap; va_start(ap, fmt); - apr_err = apr_brigade_vprintf(bb, ap_filter_flush, output, fmt, ap); + apr_err = apr_brigade_vprintf(bb, ap_filter_flush, + output->r->output_filters, fmt, ap); va_end(ap); if (apr_err) return svn_error_create(apr_err, 0, NULL); /* Check for an aborted connection, since the brigade functions don't appear to be return useful errors when the connection is dropped. */ - if (output->c->aborted) + if (output->r->connection->aborted) return svn_error_create(SVN_ERR_APMOD_CONNECTION_ABORTED, 0, NULL); return SVN_NO_ERROR; } +svn_error_t * +dav_svn__brigade_putstrs(apr_bucket_brigade *bb, + dav_svn__output *output, + ...) +{ + apr_status_t apr_err; + va_list ap; + + va_start(ap, output); + apr_err = apr_brigade_vputstrs(bb, ap_filter_flush, + output->r->output_filters, ap); + va_end(ap); + if (apr_err) + return svn_error_create(apr_err, NULL, NULL); + /* Check for an aborted connection, since the brigade functions don't + appear to return useful errors when the connection is dropped. */ + if (output->r->connection->aborted) + return svn_error_create(SVN_ERR_APMOD_CONNECTION_ABORTED, NULL, NULL); + return SVN_NO_ERROR; +} + + dav_error * @@ -588,7 +655,7 @@ dav_svn__sanitize_error(svn_error_t *ser struct brigade_write_baton { apr_bucket_brigade *bb; - ap_filter_t *output; + dav_svn__output *output; }; @@ -599,7 +666,8 @@ brigade_write_fn(void *baton, const char struct brigade_write_baton *wb = baton; apr_status_t apr_err; - apr_err = apr_brigade_write(wb->bb, ap_filter_flush, wb->output, data, *len); + apr_err = apr_brigade_write(wb->bb, ap_filter_flush, + wb->output->r->output_filters, data, *len); if (apr_err != APR_SUCCESS) return svn_error_wrap_apr(apr_err, "Error writing base64 data"); @@ -610,7 +678,7 @@ brigade_write_fn(void *baton, const char svn_stream_t * dav_svn__make_base64_output_stream(apr_bucket_brigade *bb, - ap_filter_t *output, + dav_svn__output *output, apr_pool_t *pool) { struct brigade_write_baton *wb = apr_palloc(pool, sizeof(*wb)); @@ -637,7 +705,7 @@ dav_svn__operational_log(struct dav_reso dav_error * dav_svn__final_flush_or_error(request_rec *r, apr_bucket_brigade *bb, - ap_filter_t *output, + dav_svn__output *output, dav_error *preferred_err, apr_pool_t *pool) { @@ -659,7 +727,7 @@ dav_svn__final_flush_or_error(request_re provided a more-important DERR, though. */ if (do_flush) { - apr_status_t apr_err = ap_fflush(output, bb); + apr_status_t apr_err = ap_fflush(output->r->output_filters, bb); if (apr_err && (! derr)) derr = dav_svn__new_error(pool, HTTP_INTERNAL_SERVER_ERROR, 0, apr_err, "Error flushing brigade."); @@ -870,3 +938,19 @@ dav_svn__parse_request_skel(svn_skel_t * *skel = svn_skel__parse(skel_str->data, skel_str->len, pool); return OK; } + +svn_error_t * +dav_svn__get_youngest_rev(svn_revnum_t *youngest_p, + dav_svn_repos *repos, + apr_pool_t *scratch_pool) +{ + if (repos->youngest_rev == SVN_INVALID_REVNUM) + { + svn_revnum_t revnum; + SVN_ERR(svn_fs_youngest_rev(&revnum, repos->fs, scratch_pool)); + repos->youngest_rev = revnum; + } + + *youngest_p = repos->youngest_rev; + return SVN_NO_ERROR; +} Modified: subversion/branches/ra-git/subversion/mod_dav_svn/version.c URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/mod_dav_svn/version.c?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/mod_dav_svn/version.c (original) +++ subversion/branches/ra-git/subversion/mod_dav_svn/version.c Tue Oct 11 09:11:50 2016 @@ -221,8 +221,8 @@ get_option(const dav_resource *resource, const char *uuid; /* Got youngest revision? */ - if ((serr = svn_fs_youngest_rev(&youngest, resource->info->repos->fs, - resource->pool))) + if ((serr = dav_svn__get_youngest_rev(&youngest, resource->info->repos, + resource->pool))) { return dav_svn__convert_err (serr, HTTP_INTERNAL_SERVER_ERROR, @@ -616,8 +616,8 @@ dav_svn__checkout(dav_resource *resource svn_revnum_t youngest; /* make sure the baseline being checked out is the latest */ - serr = svn_fs_youngest_rev(&youngest, resource->info->repos->fs, - resource->pool); + serr = dav_svn__get_youngest_rev(&youngest, resource->info->repos, + resource->pool); if (serr != NULL) { /* ### correct HTTP error? */ @@ -1096,12 +1096,16 @@ static dav_error * deliver_report(request_rec *r, const dav_resource *resource, const apr_xml_doc *doc, - ap_filter_t *output) + ap_filter_t *unused) { int ns = dav_svn__find_ns(doc->namespaces, SVN_XML_NAMESPACE); if (doc->root->ns == ns) { + dav_svn__output *output; + + output = dav_svn__output_create(resource->info->r, resource->pool); + /* ### note that these report names should have symbols... */ if (strcmp(doc->root->name, "update-report") == 0) @@ -1408,7 +1412,7 @@ merge(dav_resource *target, int no_auto_merge, int no_checkout, apr_xml_elem *prop_elem, - ap_filter_t *output) + ap_filter_t *unused) { apr_pool_t *pool; dav_error *err; @@ -1419,6 +1423,7 @@ merge(dav_resource *target, svn_revnum_t new_rev; apr_hash_t *locks; svn_boolean_t disable_merge_response = FALSE; + dav_svn__output *output; /* We'll use the target's pool for our operation. We happen to know that it matches the request pool, which (should) have the proper lifetime. */ @@ -1588,6 +1593,7 @@ merge(dav_resource *target, } /* process the response for the new revision. */ + output = dav_svn__output_create(target->info->r, pool); return dav_svn__merge_response(output, source->info->repos, new_rev, post_commit_err, prop_elem, disable_merge_response, pool); Modified: subversion/branches/ra-git/subversion/svn/cl-conflicts.c URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/svn/cl-conflicts.c?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/svn/cl-conflicts.c (original) +++ subversion/branches/ra-git/subversion/svn/cl-conflicts.c Tue Oct 11 09:11:50 2016 @@ -58,14 +58,6 @@ static const svn_token_map_t map_conflic { NULL, 0 } }; -static const svn_token_map_t map_conflict_kind_xml[] = -{ - { "text", svn_wc_conflict_kind_text }, - { "property", svn_wc_conflict_kind_property }, - { "tree", svn_wc_conflict_kind_tree }, - { NULL, 0 } -}; - /* Return a localised string representation of the local part of a conflict; NULL for non-localised odd cases. */ static const char * @@ -229,7 +221,7 @@ operation_str(svn_wc_operation_t operati svn_error_t * svn_cl__get_human_readable_prop_conflict_description( const char **desc, - const svn_client_conflict_t *conflict, + svn_client_conflict_t *conflict, apr_pool_t *pool) { const char *reason_str, *action_str; @@ -288,7 +280,7 @@ svn_cl__get_human_readable_prop_conflict svn_error_t * svn_cl__get_human_readable_tree_conflict_description( const char **desc, - const svn_client_conflict_t *conflict, + svn_client_conflict_t *conflict, apr_pool_t *pool) { const char *action, *reason, *operation; @@ -411,7 +403,7 @@ add_conflict_version_xml(svn_stringbuf_t static svn_error_t * append_tree_conflict_info_xml(svn_stringbuf_t *str, - const svn_client_conflict_t *conflict, + svn_client_conflict_t *conflict, apr_pool_t *pool) { apr_hash_t *att_hash = apr_hash_make(pool); @@ -479,115 +471,128 @@ append_tree_conflict_info_xml(svn_string svn_error_t * svn_cl__append_conflict_info_xml(svn_stringbuf_t *str, - const svn_client_conflict_t *conflict, + svn_client_conflict_t *conflict, apr_pool_t *scratch_pool) { apr_hash_t *att_hash; - const char *kind; - svn_wc_conflict_kind_t conflict_kind; + svn_boolean_t text_conflicted; + apr_array_header_t *props_conflicted; + svn_boolean_t tree_conflicted; svn_wc_operation_t conflict_operation; const char *repos_root_url; const char *repos_relpath; svn_revnum_t peg_rev; svn_node_kind_t node_kind; - conflict_kind = svn_client_conflict_get_kind(conflict); conflict_operation = svn_client_conflict_get_operation(conflict); - if (conflict_kind == svn_wc_conflict_kind_tree) + SVN_ERR(svn_client_conflict_get_conflicted(&text_conflicted, + &props_conflicted, + &tree_conflicted, + conflict, + scratch_pool, scratch_pool)); + if (tree_conflicted) { /* Uses other element type */ return svn_error_trace( append_tree_conflict_info_xml(str, conflict, scratch_pool)); } + SVN_ERR(svn_client_conflict_get_repos_info(&repos_root_url, NULL, + conflict, + scratch_pool, scratch_pool)); att_hash = apr_hash_make(scratch_pool); svn_hash_sets(att_hash, "operation", svn_cl__operation_str_xml(conflict_operation, scratch_pool)); - - kind = svn_token__to_word(map_conflict_kind_xml, conflict_kind); - svn_hash_sets(att_hash, "type", kind); - svn_hash_sets(att_hash, "operation", svn_cl__operation_str_xml(conflict_operation, scratch_pool)); - - /* "<conflict>" */ - svn_xml_make_open_tag_hash(&str, scratch_pool, - svn_xml_normal, "conflict", att_hash); - - SVN_ERR(svn_client_conflict_get_repos_info(&repos_root_url, NULL, conflict, - scratch_pool, scratch_pool)); - SVN_ERR(svn_client_conflict_get_incoming_old_repos_location(&repos_relpath, - &peg_rev, - &node_kind, - conflict, - scratch_pool, - scratch_pool)); - if (repos_root_url && repos_relpath) - SVN_ERR(add_conflict_version_xml(&str, "source-left", - repos_root_url, repos_relpath, peg_rev, - node_kind, scratch_pool)); - - SVN_ERR(svn_client_conflict_get_incoming_old_repos_location(&repos_relpath, - &peg_rev, - &node_kind, - conflict, - scratch_pool, - scratch_pool)); - if (repos_root_url && repos_relpath) - SVN_ERR(add_conflict_version_xml(&str, "source-right", - repos_root_url, repos_relpath, peg_rev, - node_kind, scratch_pool)); - - switch (conflict_kind) + if (text_conflicted) { const char *base_abspath; const char *my_abspath; const char *their_abspath; - case svn_wc_conflict_kind_text: - SVN_ERR(svn_client_conflict_text_get_contents(NULL, &my_abspath, - &base_abspath, - &their_abspath, - conflict, scratch_pool, - scratch_pool)); - /* "<prev-base-file> xx </prev-base-file>" */ - svn_cl__xml_tagged_cdata( - &str, scratch_pool, "prev-base-file", base_abspath); - - /* "<prev-wc-file> xx </prev-wc-file>" */ - svn_cl__xml_tagged_cdata( - &str, scratch_pool, "prev-wc-file", my_abspath); - - /* "<cur-base-file> xx </cur-base-file>" */ - svn_cl__xml_tagged_cdata( - &str, scratch_pool, "cur-base-file", their_abspath); + svn_hash_sets(att_hash, "type", "text"); - break; + /* "<conflict>" */ + svn_xml_make_open_tag_hash(&str, scratch_pool, + svn_xml_normal, "conflict", att_hash); - case svn_wc_conflict_kind_property: - { - const char *reject_abspath; - - /* "<prop-file> xx </prop-file>" */ - reject_abspath = - svn_client_conflict_prop_get_reject_abspath(conflict); - svn_cl__xml_tagged_cdata( - &str, scratch_pool, "prop-file", reject_abspath); - } - break; + SVN_ERR(svn_client_conflict_get_incoming_old_repos_location( + &repos_relpath, &peg_rev, &node_kind, conflict, + scratch_pool, scratch_pool)); + if (repos_root_url && repos_relpath) + SVN_ERR(add_conflict_version_xml(&str, "source-left", + repos_root_url, repos_relpath, peg_rev, + node_kind, scratch_pool)); - default: - case svn_wc_conflict_kind_tree: - SVN_ERR_MALFUNCTION(); /* Handled separately */ - break; - } + SVN_ERR(svn_client_conflict_get_incoming_old_repos_location( + &repos_relpath, &peg_rev, &node_kind, conflict, + scratch_pool, scratch_pool)); + if (repos_root_url && repos_relpath) + SVN_ERR(add_conflict_version_xml(&str, "source-right", + repos_root_url, repos_relpath, peg_rev, + node_kind, scratch_pool)); + + SVN_ERR(svn_client_conflict_text_get_contents(NULL, &my_abspath, + &base_abspath, + &their_abspath, + conflict, scratch_pool, + scratch_pool)); + /* "<prev-base-file> xx </prev-base-file>" */ + svn_cl__xml_tagged_cdata( + &str, scratch_pool, "prev-base-file", base_abspath); + + /* "<prev-wc-file> xx </prev-wc-file>" */ + svn_cl__xml_tagged_cdata( + &str, scratch_pool, "prev-wc-file", my_abspath); + + /* "<cur-base-file> xx </cur-base-file>" */ + svn_cl__xml_tagged_cdata( + &str, scratch_pool, "cur-base-file", their_abspath); + + /* "</conflict>" */ + svn_xml_make_close_tag(&str, scratch_pool, "conflict"); + } + + if (props_conflicted->nelts > 0) + { + const char *reject_abspath; + + svn_hash_sets(att_hash, "type", "property"); + + /* "<conflict>" */ + svn_xml_make_open_tag_hash(&str, scratch_pool, + svn_xml_normal, "conflict", att_hash); - /* "</conflict>" */ - svn_xml_make_close_tag(&str, scratch_pool, "conflict"); + SVN_ERR(svn_client_conflict_get_incoming_old_repos_location( + &repos_relpath, &peg_rev, &node_kind, conflict, + scratch_pool, scratch_pool)); + if (repos_root_url && repos_relpath) + SVN_ERR(add_conflict_version_xml(&str, "source-left", + repos_root_url, repos_relpath, peg_rev, + node_kind, scratch_pool)); + + SVN_ERR(svn_client_conflict_get_incoming_old_repos_location( + &repos_relpath, &peg_rev, &node_kind, conflict, + scratch_pool, scratch_pool)); + if (repos_root_url && repos_relpath) + SVN_ERR(add_conflict_version_xml(&str, "source-right", + repos_root_url, repos_relpath, peg_rev, + node_kind, scratch_pool)); + + /* "<prop-file> xx </prop-file>" */ + reject_abspath = + svn_client_conflict_prop_get_reject_abspath(conflict); + svn_cl__xml_tagged_cdata( + &str, scratch_pool, "prop-file", reject_abspath); + + /* "</conflict>" */ + svn_xml_make_close_tag(&str, scratch_pool, "conflict"); + } return SVN_NO_ERROR; } Modified: subversion/branches/ra-git/subversion/svn/cl-conflicts.h URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/svn/cl-conflicts.h?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/svn/cl-conflicts.h (original) +++ subversion/branches/ra-git/subversion/svn/cl-conflicts.h Tue Oct 11 09:11:50 2016 @@ -49,7 +49,7 @@ extern "C" { svn_error_t * svn_cl__get_human_readable_prop_conflict_description( const char **desc, - const svn_client_conflict_t *conflict, + svn_client_conflict_t *conflict, apr_pool_t *pool); /** @@ -61,7 +61,7 @@ svn_cl__get_human_readable_prop_conflict svn_error_t * svn_cl__get_human_readable_tree_conflict_description( const char **desc, - const svn_client_conflict_t *conflict, + svn_client_conflict_t *conflict, apr_pool_t *pool); /* Like svn_cl__get_human_readable_tree_conflict_description but @@ -81,7 +81,7 @@ svn_cl__get_human_readable_action_descri svn_error_t * svn_cl__append_conflict_info_xml( svn_stringbuf_t *str, - const svn_client_conflict_t *conflict, + svn_client_conflict_t *conflict, apr_pool_t *pool); #ifdef __cplusplus Modified: subversion/branches/ra-git/subversion/svn/cl-log.h URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/svn/cl-log.h?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/svn/cl-log.h (original) +++ subversion/branches/ra-git/subversion/svn/cl-log.h Tue Oct 11 09:11:50 2016 @@ -31,6 +31,8 @@ #include "svn_types.h" +#include "private/svn_string_private.h" + #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ @@ -70,6 +72,9 @@ typedef struct svn_cl__log_receiver_bato * the log message, or a changed path matches one of these patterns. */ apr_array_header_t *search_patterns; + /* Buffer for Unicode normalization and case folding. */ + svn_membuf_t buffer; + /* Pool for persistent allocations. */ apr_pool_t *pool; } svn_cl__log_receiver_baton; Modified: subversion/branches/ra-git/subversion/svn/cl.h URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/svn/cl.h?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/svn/cl.h (original) +++ subversion/branches/ra-git/subversion/svn/cl.h Tue Oct 11 09:11:50 2016 @@ -249,6 +249,7 @@ typedef struct svn_cl__opt_state_t svn_boolean_t show_passwords; /* show cached passwords */ svn_boolean_t pin_externals; /* pin externals to last-changed revisions */ const char *show_item; /* print only the given item */ + svn_boolean_t adds_as_modification; /* update 'add vs add' no tree conflict */ } svn_cl__opt_state_t; /* Conflict stats for operations such as update and merge. */ @@ -338,8 +339,7 @@ svn_cl__try(svn_error_t *err, /* Our cancellation callback. */ -svn_error_t * -svn_cl__check_cancel(void *baton); +extern svn_cancel_func_t svn_cl__check_cancel; @@ -362,6 +362,14 @@ svn_cl__conflict_stats_resolved(svn_cl__ const char *path_local, svn_wc_conflict_kind_t conflict_kind); +/* Set *CONFLICTED_PATHS to the conflicted paths contained in CONFLICT_STATS. + * If no conflicted path exists, set *CONFLICTED_PATHS to NULL. */ +svn_error_t * +svn_cl__conflict_stats_get_paths(apr_array_header_t **conflicted_paths, + svn_cl__conflict_stats_t *conflict_stats, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); + /* Print the conflict stats accumulated in CONFLICT_STATS. * * Return any error encountered during printing. @@ -371,39 +379,11 @@ svn_error_t * svn_cl__print_conflict_stats(svn_cl__conflict_stats_t *conflict_stats, apr_pool_t *scratch_pool); -/* Create and return an baton for use with svn_cl__conflict_func_interactive - * in *B, allocated from RESULT_POOL, and initialised with the values - * ACCEPT_WHICH, CONFIG, EDITOR_CMD, CANCEL_FUNC and CANCEL_BATON. */ -svn_error_t * -svn_cl__get_conflict_func_interactive_baton( - svn_cl__interactive_conflict_baton_t **b, - svn_cl__accept_t accept_which, - apr_hash_t *config, - const char *editor_cmd, - svn_cl__conflict_stats_t *conflict_stats, - svn_cancel_func_t cancel_func, - void *cancel_baton, - apr_pool_t *result_pool); - -/* A callback capable of doing interactive conflict resolution. - - The BATON must come from svn_cl__get_conflict_func_interactive_baton(). - Resolves based on the --accept option if one was given to that function, - otherwise prompts the user to choose one of the three fulltexts, edit - the merged file on the spot, or just skip the conflict (to be resolved - later), among other options. - - Implements svn_wc_conflict_resolver_func2_t. +/* + * Interactively resolve the conflict a @a CONFLICT. + * TODO: more docs */ svn_error_t * -svn_cl__conflict_func_interactive(svn_wc_conflict_result_t **result, - const svn_wc_conflict_description2_t *desc, - void *baton, - apr_pool_t *result_pool, - apr_pool_t *scratch_pool); - - -svn_error_t * svn_cl__resolve_conflict(svn_boolean_t *resolved, svn_cl__accept_t *accept_which, svn_boolean_t *quit, @@ -419,6 +399,18 @@ svn_cl__resolve_conflict(svn_boolean_t * svn_client_ctx_t *ctx, apr_pool_t *scratch_pool); +/* + * Interactively resolve conflicts for all TARGETS. + * TODO: more docs + */ +svn_error_t * +svn_cl__walk_conflicts(apr_array_header_t *targets, + svn_cl__conflict_stats_t *conflict_stats, + svn_boolean_t is_resolve_cmd, + svn_cl__opt_state_t *opt_state, + svn_client_ctx_t *ctx, + apr_pool_t *scratch_pool); + /*** Command-line output functions -- printing to the user. ***/