Modified: subversion/branches/compressed-pristines/subversion/mod_dav_svn/reports/file-revs.c URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/mod_dav_svn/reports/file-revs.c?rev=1413258&r1=1413257&r2=1413258&view=diff ============================================================================== --- subversion/branches/compressed-pristines/subversion/mod_dav_svn/reports/file-revs.c (original) +++ subversion/branches/compressed-pristines/subversion/mod_dav_svn/reports/file-revs.c Sat Nov 24 20:29:11 2012 @@ -52,6 +52,9 @@ struct file_rev_baton { /* SVNDIFF version to use when sending to client. */ int svndiff_version; + /* Compression level to use for SVNDIFF. */ + int compression_level; + /* Used by the delta iwndow handler. */ svn_txdelta_window_handler_t window_handler; void *window_baton; @@ -208,7 +211,7 @@ file_rev_handler(void *baton, pool); svn_txdelta_to_svndiff3(&frb->window_handler, &frb->window_baton, base64_stream, frb->svndiff_version, - dav_svn__get_compression_level(), pool); + frb->compression_level, pool); *window_handler = delta_window_handler; *window_baton = frb; /* Start the txdelta element wich will be terminated by the window @@ -306,6 +309,7 @@ dav_svn__file_revs_report(const dav_reso frb.output = output; frb.needs_header = TRUE; frb.svndiff_version = resource->info->svndiff_version; + frb.compression_level = dav_svn__get_compression_level(resource->info->r); /* file_rev_handler will send header first time it is called. */
Added: subversion/branches/compressed-pristines/subversion/mod_dav_svn/reports/inherited-props.c URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/mod_dav_svn/reports/inherited-props.c?rev=1413258&view=auto ============================================================================== --- subversion/branches/compressed-pristines/subversion/mod_dav_svn/reports/inherited-props.c (added) +++ subversion/branches/compressed-pristines/subversion/mod_dav_svn/reports/inherited-props.c Sat Nov 24 20:29:11 2012 @@ -0,0 +1,233 @@ +/* + * inherited-props.c: mod_dav_svn REPORT handler for querying inherited props. + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + */ + +#include <apr_pools.h> +#include <apr_strings.h> +#include <apr_xml.h> + +#include <http_request.h> +#include <http_log.h> +#include <mod_dav.h> + +#include "svn_pools.h" +#include "svn_repos.h" +#include "svn_xml.h" +#include "svn_path.h" +#include "svn_dav.h" +#include "svn_props.h" +#include "svn_base64.h" + +#include "private/svn_fspath.h" +#include "private/svn_dav_protocol.h" +#include "private/svn_log.h" +#include "private/svn_mergeinfo_private.h" + +#include "../dav_svn.h" + +dav_error * +dav_svn__get_inherited_props_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; + apr_array_header_t *inherited_props; + dav_svn__authz_read_baton arb; + int ns; + apr_bucket_brigade *bb; + const char *path = "/"; + svn_fs_root_t *root; + int i; + svn_revnum_t rev = SVN_INVALID_REVNUM; + apr_pool_t *iterpool; + + /* Sanity check. */ + 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); + } + + iterpool = svn_pool_create(resource->pool); + + 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, iterpool, 1)); + } + else if (strcmp(child->name, SVN_DAV__PATH) == 0) + { + path = dav_xml_get_cdata(child, resource->pool, 0); + if ((derr = dav_svn__test_canonical(path, iterpool))) + return derr; + path = svn_fspath__join(resource->info->repos_path, path, + resource->pool); + } + /* else unknown element; skip it */ + } + + /* Build authz read baton */ + arb.r = resource->info->r; + arb.repos = resource->info->repos; + + /* Build inherited property brigade */ + bb = apr_brigade_create(resource->pool, output->c->bucket_alloc); + + serr = svn_fs_revision_root(&root, resource->info->repos->fs, + rev, resource->pool); + if (serr != NULL) + return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, + "couldn't retrieve revision root", + resource->pool); + + serr = svn_repos_fs_get_inherited_props(&inherited_props, root, path, + dav_svn__authz_read_func(&arb), + &arb, resource->pool, iterpool); + if (serr) + { + derr = dav_svn__convert_err(serr, HTTP_BAD_REQUEST, serr->message, + resource->pool); + goto cleanup; + } + + serr = dav_svn__brigade_puts(bb, output, + DAV_XML_HEADER DEBUG_CR + "<S:" SVN_DAV__INHERITED_PROPS_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 (i = 0; i < inherited_props->nelts; i++) + { + svn_prop_inherited_item_t *elt = + APR_ARRAY_IDX(inherited_props, i, svn_prop_inherited_item_t *); + + svn_pool_clear(iterpool); + + serr = dav_svn__brigade_printf( + bb, output, + "<S:" SVN_DAV__IPROP_ITEM ">" + DEBUG_CR + "<S:" SVN_DAV__IPROP_PATH ">%s</S:" SVN_DAV__IPROP_PATH ">" + DEBUG_CR, + apr_xml_quote_string(resource->pool, elt->path_or_url, 0)); + + if (!serr) + { + apr_hash_index_t *hi; + + for (hi = apr_hash_first(resource->pool, elt->prop_hash); + hi; + hi = apr_hash_next(hi)) + { + const char *propname = svn__apr_hash_index_key(hi); + svn_string_t *propval = svn__apr_hash_index_val(hi); + const char *xml_safe; + + serr = dav_svn__brigade_printf( + bb, output, + "<S:" SVN_DAV__IPROP_PROPNAME ">%s</S:" + SVN_DAV__IPROP_PROPNAME ">" DEBUG_CR, + apr_xml_quote_string(iterpool, propname, 0)); + + if (!serr) + { + if (svn_xml_is_xml_safe(propval->data, propval->len)) + { + svn_stringbuf_t *tmp = NULL; + svn_xml_escape_cdata_string(&tmp, propval, + iterpool); + xml_safe = tmp->data; + serr = dav_svn__brigade_printf( + bb, output, + "<S:" SVN_DAV__IPROP_PROPVAL ">%s</S:" + SVN_DAV__IPROP_PROPVAL ">" DEBUG_CR, xml_safe); + } + else + { + xml_safe = svn_base64_encode_string2( + propval, TRUE, iterpool)->data; + serr = dav_svn__brigade_printf( + bb, output, + "<S:" SVN_DAV__IPROP_PROPVAL + " encoding=\"base64\"" ">%s</S:" + SVN_DAV__IPROP_PROPVAL ">" DEBUG_CR, xml_safe); + } + } + + if (serr) + break; + } + if (!serr) + serr = dav_svn__brigade_printf(bb, output, + "</S:" SVN_DAV__IPROP_ITEM ">" + DEBUG_CR); + } + + 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__INHERITED_PROPS_REPORT ">" + DEBUG_CR))) + { + derr = dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, + "Error ending REPORT response.", + resource->pool); + goto cleanup; + } + + cleanup: + + /* Log this 'high level' svn action. */ + dav_svn__operational_log(resource->info, + svn_log__get_inherited_props(path, rev, + resource->pool)); + svn_pool_destroy(iterpool); + return dav_svn__final_flush_or_error(resource->info->r, bb, output, + derr, resource->pool); +} Modified: subversion/branches/compressed-pristines/subversion/mod_dav_svn/reports/replay.c URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/mod_dav_svn/reports/replay.c?rev=1413258&r1=1413257&r2=1413258&view=diff ============================================================================== --- subversion/branches/compressed-pristines/subversion/mod_dav_svn/reports/replay.c (original) +++ subversion/branches/compressed-pristines/subversion/mod_dav_svn/reports/replay.c Sat Nov 24 20:29:11 2012 @@ -47,6 +47,7 @@ typedef struct edit_baton_t { ap_filter_t *output; svn_boolean_t started; svn_boolean_t sending_textdelta; + int compression_level; } edit_baton_t; @@ -326,7 +327,7 @@ apply_textdelta(void *file_baton, eb->output, pool), 0, - dav_svn__get_compression_level(), + eb->compression_level, pool); eb->sending_textdelta = TRUE; @@ -367,6 +368,7 @@ make_editor(const svn_delta_editor_t **e void **edit_baton, apr_bucket_brigade *bb, ap_filter_t *output, + int compression_level, apr_pool_t *pool) { edit_baton_t *eb = apr_pcalloc(pool, sizeof(*eb)); @@ -376,6 +378,7 @@ make_editor(const svn_delta_editor_t **e eb->output = output; eb->started = FALSE; eb->sending_textdelta = FALSE; + eb->compression_level = compression_level; e->set_target_revision = set_target_revision; e->open_root = open_root; @@ -506,7 +509,9 @@ dav_svn__replay_report(const dav_resourc goto cleanup; } - make_editor(&editor, &edit_baton, bb, output, resource->pool); + make_editor(&editor, &edit_baton, bb, output, + dav_svn__get_compression_level(resource->info->r), + resource->pool); if ((err = svn_repos_replay2(root, base_dir, low_water_mark, send_deltas, editor, edit_baton, Modified: subversion/branches/compressed-pristines/subversion/mod_dav_svn/reports/update.c URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/mod_dav_svn/reports/update.c?rev=1413258&r1=1413257&r2=1413258&view=diff ============================================================================== --- subversion/branches/compressed-pristines/subversion/mod_dav_svn/reports/update.c (original) +++ subversion/branches/compressed-pristines/subversion/mod_dav_svn/reports/update.c Sat Nov 24 20:29:11 2012 @@ -81,9 +81,16 @@ typedef struct update_ctx_t { /* True iff client requested all data inline in the report. */ svn_boolean_t send_all; + /* True iff client requested that properties be transmitted + inline. (This is implied when "send_all" is set.) */ + svn_boolean_t include_props; + /* SVNDIFF version to send to client. */ int svndiff_version; + /* Compression level of SVNDIFF deltas. */ + int compression_level; + /* Did the client submit this REPORT request via the HTTPv2 "me resource" and are we advertising support for as much? */ svn_boolean_t enable_v2_response; @@ -119,6 +126,10 @@ typedef struct item_baton_t { /* File/dir copied? */ svn_boolean_t copyfrom; + /* Does the client need to fetch additional properties for this + item? */ + svn_boolean_t fetch_props; + /* Array of const char * names of removed properties. (Used only for copied files/dirs in skelta mode.) */ apr_array_header_t *removed_props; @@ -432,7 +443,7 @@ open_helper(svn_boolean_t is_dir, static svn_error_t * -close_helper(svn_boolean_t is_dir, item_baton_t *baton) +close_helper(svn_boolean_t is_dir, item_baton_t *baton, apr_pool_t *pool) { if (baton->uc->resource_walk) return SVN_NO_ERROR; @@ -446,14 +457,21 @@ close_helper(svn_boolean_t is_dir, item_ for (i = 0; i < baton->removed_props->nelts; i++) { - /* We already XML-escaped the property name in change_xxx_prop. */ qname = APR_ARRAY_IDX(baton->removed_props, i, const char *); + qname = apr_xml_quote_string(pool, qname, 1); SVN_ERR(dav_svn__brigade_printf(baton->uc->bb, baton->uc->output, "<S:remove-prop name=\"%s\"/>" DEBUG_CR, qname)); } } + /* If our client need to fetch properties, let it know. */ + if (baton->fetch_props) + SVN_ERR(dav_svn__brigade_printf(baton->uc->bb, baton->uc->output, + "<S:fetch-props/>" DEBUG_CR)); + + + /* Let's tie it off, nurse. */ if (baton->added) SVN_ERR(dav_svn__brigade_printf(baton->uc->bb, baton->uc->output, "</S:add-%s>" DEBUG_CR, @@ -473,13 +491,13 @@ maybe_start_update_report(update_ctx_t * { if ((! uc->resource_walk) && (! uc->started_update)) { - SVN_ERR(dav_svn__brigade_printf(uc->bb, uc->output, - DAV_XML_HEADER DEBUG_CR - "<S:update-report xmlns:S=\"" - SVN_XML_NAMESPACE "\" " - "xmlns:V=\"" SVN_DAV_PROP_NS_DAV "\" " - "xmlns:D=\"DAV:\" %s>" DEBUG_CR, - uc->send_all ? "send-all=\"true\"" : "")); + SVN_ERR(dav_svn__brigade_printf( + uc->bb, uc->output, + DAV_XML_HEADER DEBUG_CR "<S:update-report xmlns:S=\"" + SVN_XML_NAMESPACE "\" xmlns:V=\"" SVN_DAV_PROP_NS_DAV "\" " + "xmlns:D=\"DAV:\" %s %s>" DEBUG_CR, + uc->send_all ? "send-all=\"true\"" : "", + uc->include_props ? "inline-props=\"true\"" : "")); uc->started_update = TRUE; } @@ -593,87 +611,117 @@ upd_open_directory(const char *path, static svn_error_t * +send_propchange(item_baton_t *b, + const char *name, + const svn_string_t *value, + apr_pool_t *pool) +{ + const char *qname; + + /* Ensure that the property name is XML-safe. + apr_xml_quote_string() doesn't realloc if there is nothing to + quote, so dup the name, but only if necessary. */ + qname = apr_xml_quote_string(b->pool, name, 1); + if (qname == name) + qname = apr_pstrdup(b->pool, name); + + if (value) + { + 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__brigade_printf(b->uc->bb, b->uc->output, + "<S:set-prop name=\"%s\">", + qname)); + } + else + { + qval = svn_base64_encode_string2(value, TRUE, pool)->data; + SVN_ERR(dav_svn__brigade_printf(b->uc->bb, b->uc->output, + "<S:set-prop name=\"%s\" " + "encoding=\"base64\">" DEBUG_CR, + qname)); + } + + SVN_ERR(dav_svn__brigade_puts(b->uc->bb, b->uc->output, qval)); + SVN_ERR(dav_svn__brigade_puts(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__brigade_printf(b->uc->bb, b->uc->output, + "<S:remove-prop name=\"%s\"/>" + DEBUG_CR, + qname)); + } + + return SVN_NO_ERROR; +} + +static svn_error_t * upd_change_xxx_prop(void *baton, const char *name, const svn_string_t *value, apr_pool_t *pool) { item_baton_t *b = baton; - const char *qname; /* Resource walks say nothing about props. */ if (b->uc->resource_walk) return SVN_NO_ERROR; - /* Else this not a resource walk, so either send props or cache them - to send later, depending on whether this is a modern report - response or not. */ - - qname = apr_xml_quote_string(b->pool, name, 1); - - /* apr_xml_quote_string doesn't realloc if there is nothing to - quote, so dup the name, but only if necessary. */ - if (qname == name) - qname = apr_pstrdup(b->pool, name); + /* If we get here, this not a resource walk, so either send props or + cache them to send later, depending on whether this is a modern + report response or not. */ /* Even if we are not in send-all mode we have the prop changes already, so send them to the client now instead of telling the client to fetch them later. */ - if (b->uc->send_all || !b->added) + if (b->uc->send_all) + { + SVN_ERR(send_propchange(b, name, value, pool)); + } + else { - if (value) + if (b->added) { - const char *qval; - - if (svn_xml_is_xml_safe(value->data, value->len)) + /* This is an addition in "skelta" (that is, "not send-all") + mode so there is no strict need for an inline response. + Clients will assume that added objects need all to have + all their properties explicitly fetched from the + server. */ + + /* That said, beginning in Subversion 1.8, clients might + request even in skelta mode that we transmit properties + on newly added files explicitly. */ + if ((! b->copyfrom) && value && b->uc->include_props) { - svn_stringbuf_t *tmp = NULL; - svn_xml_escape_cdata_string(&tmp, value, pool); - qval = tmp->data; - SVN_ERR(dav_svn__brigade_printf(b->uc->bb, b->uc->output, - "<S:set-prop name=\"%s\">", - qname)); + SVN_ERR(send_propchange(b, name, value, pool)); } - else + + /* Now, if the object is actually a copy and this is a + property removal, we'll still need to cache (and later + transmit) property removals, because fetching the + object's current property set alone isn't sufficient to + communicate the fact that additional properties were, in + fact, removed from the copied base object in order to + arrive at that set. */ + if (b->copyfrom && (! value)) { - qval = svn_base64_encode_string2(value, TRUE, pool)->data; - SVN_ERR(dav_svn__brigade_printf(b->uc->bb, b->uc->output, - "<S:set-prop name=\"%s\" " - "encoding=\"base64\">" DEBUG_CR, - qname)); + if (! b->removed_props) + b->removed_props = apr_array_make(b->pool, 1, sizeof(name)); + + APR_ARRAY_PUSH(b->removed_props, const char *) = name; } - - SVN_ERR(dav_svn__brigade_puts(b->uc->bb, b->uc->output, qval)); - SVN_ERR(dav_svn__brigade_puts(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__brigade_printf(b->uc->bb, b->uc->output, - "<S:remove-prop name=\"%s\"/>" - DEBUG_CR, - qname)); } - } - else if (!value) - { - /* This is an addition in "skelta" (that is, "not send-all") - mode so there is no strict need for an inline response. - Clients will assume that added objects need all to have all - their properties explicitly fetched from the server. */ - - /* Now, if the object is actually a copy, we'll still need to - cache (and later transmit) property removals, because - fetching the object's current property set alone isn't - sufficient to communicate the fact that additional properties - were, in fact, removed from the copied base object in order - to arrive at that set. */ - if (b->copyfrom) + else { - if (! b->removed_props) - b->removed_props = apr_array_make(b->pool, 1, sizeof(name)); - - APR_ARRAY_PUSH(b->removed_props, const char *) = qname; + /* "skelta" mode non-addition. Just send the change. */ + SVN_ERR(send_propchange(b, name, value, pool)); } } @@ -684,7 +732,7 @@ upd_change_xxx_prop(void *baton, static svn_error_t * upd_close_directory(void *dir_baton, apr_pool_t *pool) { - return close_helper(TRUE /* is_dir */, dir_baton); + return close_helper(TRUE /* is_dir */, dir_baton, pool); } @@ -795,7 +843,7 @@ upd_apply_textdelta(void *file_baton, svn_txdelta_to_svndiff3(&(wb->handler), &(wb->handler_baton), base64_stream, file->uc->svndiff_version, - dav_svn__get_compression_level(), file->pool); + file->uc->compression_level, file->pool); *handler = window_handler; *handler_baton = wb; @@ -845,7 +893,7 @@ upd_close_file(void *file_baton, const c text_checksum)); } - return close_helper(FALSE /* is_dir */, file); + return close_helper(FALSE /* is_dir */, file, pool); } @@ -874,6 +922,49 @@ malformed_element_error(const char *tagn } +/* Validate that REVISION is a valid revision number for repository in + which YOUNGEST is the latest revision. Use RESOURCE as a + convenient way to access the request record and a pool for error + messaging. (It's okay if REVISION is SVN_INVALID_REVNUM, as in + the related contexts that just means "the youngest revision".) + + REVTYPE is just a string describing the type/purpose of REVISION, + used in the generated error string. */ +static dav_error * +validate_input_revision(svn_revnum_t revision, + svn_revnum_t youngest, + const char *revtype, + const dav_resource *resource) +{ + if (! SVN_IS_VALID_REVNUM(revision)) + return SVN_NO_ERROR; + + if (revision > youngest) + { + svn_error_t *serr; + + if (dav_svn__get_master_uri(resource->info->r)) + { + serr = svn_error_createf(SVN_ERR_FS_NO_SUCH_REVISION, 0, + "No such %s '%ld' found in the repository. " + "Perhaps the repository is out of date with " + "respect to the master repository?", + revtype, revision); + } + else + { + serr = svn_error_createf(SVN_ERR_FS_NO_SUCH_REVISION, 0, + "No such %s '%ld' found in the repository.", + revtype, revision); + } + return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, + "Invalid revision found in update report " + "request.", resource->pool); + } + return SVN_NO_ERROR; +} + + dav_error * dav_svn__update_report(const dav_resource *resource, const apr_xml_doc *doc, @@ -883,8 +974,7 @@ dav_svn__update_report(const dav_resourc apr_xml_elem *child; void *rbaton = NULL; update_ctx_t uc = { 0 }; - svn_revnum_t revnum = SVN_INVALID_REVNUM; - svn_boolean_t revnum_is_head = FALSE; + svn_revnum_t youngest, revnum = SVN_INVALID_REVNUM; svn_revnum_t from_revnum = SVN_INVALID_REVNUM; int ns; /* entry_counter and entry_is_empty are for operational logging. */ @@ -944,11 +1034,20 @@ dav_svn__update_report(const dav_resourc && (strcmp(this_attr->value, "true") == 0)) { uc.send_all = TRUE; + uc.include_props = TRUE; break; } } } + /* 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))) + return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, + "Could not determine the youngest " + "revision for the update process.", + resource->pool); + for (child = doc->root->first_child; child != NULL; child = child->next) { /* Note that child->name might not match any of the cases below. @@ -1066,6 +1165,31 @@ dav_svn__update_report(const dav_resourc if (strcmp(cdata, "no") == 0) text_deltas = FALSE; } + if (child->ns == ns && strcmp(child->name, "include-props") == 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) + uc.include_props = TRUE; + } + } + + /* If a target revision wasn't requested, or the requested target + revision was invalid, just update to HEAD as of the moment we + queried the youngest revision. Otherwise, at least make sure the + request makes sense in light of that youngest revision + number. */ + if (! SVN_IS_VALID_REVNUM(revnum)) + { + revnum = youngest; + } + else + { + derr = validate_input_revision(revnum, youngest, "target revision", + resource); + if (derr) + return derr; } if (!saw_depth && !saw_recursive && (requested_depth == svn_depth_unknown)) @@ -1083,19 +1207,8 @@ dav_svn__update_report(const dav_resourc SVN_DAV_ERROR_TAG); } - /* If a revision for this operation was not dictated to us, this - means "update to whatever the current HEAD is now". */ - if (revnum == SVN_INVALID_REVNUM) - { - if ((serr = svn_fs_youngest_rev(&revnum, repos->fs, resource->pool))) - return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, - "Could not determine the youngest " - "revision for the update process.", - resource->pool); - revnum_is_head = TRUE; - } - uc.svndiff_version = resource->info->svndiff_version; + uc.compression_level = dav_svn__get_compression_level(resource->info->r); uc.resource = resource; uc.output = output; uc.anchor = src_path; @@ -1165,7 +1278,7 @@ dav_svn__update_report(const dav_resourc editor->close_file = upd_close_file; editor->absent_file = upd_absent_file; editor->close_edit = upd_close_edit; - if ((serr = svn_repos_begin_report2(&rbaton, revnum, + if ((serr = svn_repos_begin_report3(&rbaton, revnum, repos->repos, src_path, target, dst_path, @@ -1176,6 +1289,7 @@ dav_svn__update_report(const dav_resourc editor, &uc, dav_svn__authz_read_func(&arb), &arb, + 0, /* disable zero-copy for now */ resource->pool))) { return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, @@ -1211,27 +1325,10 @@ dav_svn__update_report(const dav_resourc { rev = SVN_STR_TO_REV(this_attr->value); saw_rev = TRUE; - if (revnum_is_head && rev > revnum) - { - if (dav_svn__get_master_uri(resource->info->r)) - return dav_svn__new_error_tag( - resource->pool, - HTTP_INTERNAL_SERVER_ERROR, 0, - "A reported revision is higher than the " - "current repository HEAD revision. " - "Perhaps the repository is out of date " - "with respect to the master repository?", - SVN_DAV_ERROR_NAMESPACE, - SVN_DAV_ERROR_TAG); - else - return dav_svn__new_error_tag( - resource->pool, - HTTP_INTERNAL_SERVER_ERROR, 0, - "A reported revision is higher than the " - "current repository HEAD revision.", - SVN_DAV_ERROR_NAMESPACE, - SVN_DAV_ERROR_TAG); - } + if ((derr = validate_input_revision(rev, youngest, + "reported revision", + resource))) + return derr; } else if (strcmp(this_attr->name, "depth") == 0) depth = svn_depth_from_word(this_attr->value); Modified: subversion/branches/compressed-pristines/subversion/mod_dav_svn/repos.c URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/mod_dav_svn/repos.c?rev=1413258&r1=1413257&r2=1413258&view=diff ============================================================================== --- subversion/branches/compressed-pristines/subversion/mod_dav_svn/repos.c (original) +++ subversion/branches/compressed-pristines/subversion/mod_dav_svn/repos.c Sat Nov 24 20:29:11 2012 @@ -1149,8 +1149,11 @@ create_private_resource(const dav_resour comb->res.collection = TRUE; /* ### always true? */ /* versioned = baselined = working = FALSE */ - comb->res.uri = apr_pstrcat(base->pool, base->info->repos->root_path, - path->data, (char *)NULL); + if (base->info->repos->root_path[1]) + comb->res.uri = apr_pstrcat(base->pool, base->info->repos->root_path, + path->data, (char *)NULL); + else + comb->res.uri = path->data; comb->res.info = &comb->priv; comb->res.hooks = &dav_svn__hooks_repository; comb->res.pool = base->pool; @@ -1499,7 +1502,7 @@ get_parentpath_resource(request_rec *r, repos->xslt_uri = dav_svn__get_xslt_uri(r); repos->autoversioning = dav_svn__get_autoversioning_flag(r); repos->bulk_updates = dav_svn__get_bulk_updates_flag(r); - repos->v2_protocol = dav_svn__get_v2_protocol_flag(r); + repos->v2_protocol = dav_svn__check_httpv2_support(r); repos->base_url = ap_construct_url(r->pool, "", r); repos->special_uri = dav_svn__get_special_uri(r); repos->username = r->user; @@ -1908,9 +1911,11 @@ parse_querystring(request_rec *r, const only use a temporary redirect. */ apr_table_setn(r->headers_out, "Location", ap_construct_url(r->pool, - apr_psprintf(r->pool, "%s%s?p=%ld", - comb->priv.repos->root_path, - newpath, working_rev), + apr_psprintf(r->pool, "%s%s?p=%ld", + (comb->priv.repos->root_path[1] + ? comb->priv.repos->root_path + : ""), + newpath, working_rev), r)); return dav_svn__new_error(r->pool, prevstr ? HTTP_MOVED_PERMANENTLY @@ -2077,7 +2082,7 @@ get_resource(request_rec *r, repos->bulk_updates = dav_svn__get_bulk_updates_flag(r); /* Are we advertising HTTP v2 protocol support? */ - repos->v2_protocol = dav_svn__get_v2_protocol_flag(r); + repos->v2_protocol = dav_svn__check_httpv2_support(r); /* Path to activities database */ repos->activities_db = dav_svn__get_activities_db(r); @@ -2217,8 +2222,13 @@ get_resource(request_rec *r, HTTP_INTERNAL_SERVER_ERROR, r); } - /* Configure the hooks environment, if not empty. */ - svn_repos_hooks_setenv(repos->repos, dav_svn__get_hooks_env(r)); + /* Configure hook script environment variables. */ + serr = svn_repos_hooks_setenv(repos->repos, dav_svn__get_hooks_env(r), + r->connection->pool, r->pool); + if (serr) + return dav_svn__sanitize_error(serr, + "Error settings hooks environment", + HTTP_INTERNAL_SERVER_ERROR, r); } /* cache the filesystem object */ @@ -3077,6 +3087,13 @@ set_headers(request_rec *r, const dav_re if ((serr == NULL) && (info.rev != SVN_INVALID_REVNUM)) { mimetype = SVN_SVNDIFF_MIME_TYPE; + + /* Note the base that this svndiff is based on, and tell any + intermediate caching proxies that this header is + significant. */ + apr_table_setn(r->headers_out, "Vary", SVN_DAV_DELTA_BASE_HEADER); + apr_table_setn(r->headers_out, SVN_DAV_DELTA_BASE_HEADER, + resource->info->delta_base); } svn_error_clear(serr); } @@ -3158,7 +3175,7 @@ typedef struct diff_ctx_t { } diff_ctx_t; -static svn_error_t * +static svn_error_t * __attribute__((warn_unused_result)) write_to_filter(void *baton, const char *buffer, apr_size_t *len) { diff_ctx_t *dc = baton; @@ -3179,7 +3196,7 @@ write_to_filter(void *baton, const char } -static svn_error_t * +static svn_error_t * __attribute__((warn_unused_result)) close_filter(void *baton) { diff_ctx_t *dc = baton; @@ -3629,7 +3646,7 @@ deliver(const dav_resource *resource, ap /* get a handler/baton for writing into the output stream */ svn_txdelta_to_svndiff3(&handler, &h_baton, o_stream, resource->info->svndiff_version, - dav_svn__get_compression_level(), + dav_svn__get_compression_level(resource->info->r), resource->pool); /* got everything set up. read in delta windows and shove them into @@ -4345,8 +4362,11 @@ dav_svn__create_working_resource(dav_res res->baselined = base->baselined; /* collection = FALSE. ### not necessarily correct */ - res->uri = apr_pstrcat(base->pool, base->info->repos->root_path, - path, (char *)NULL); + if (base->info->repos->root_path[1]) + res->uri = apr_pstrcat(base->pool, base->info->repos->root_path, + path, (char *)NULL); + else + res->uri = path; res->hooks = &dav_svn__hooks_repository; res->pool = base->pool; @@ -4444,7 +4464,7 @@ handle_post_request(request_rec *r, dav_resource *resource, ap_filter_t *output) { - svn_skel_t *request_skel; + svn_skel_t *request_skel, *post_skel; int status; apr_pool_t *pool = resource->pool; @@ -4461,16 +4481,23 @@ handle_post_request(request_rec *r, return dav_svn__new_error(pool, HTTP_BAD_REQUEST, 0, "Unable to identify skel POST request flavor."); - if (svn_skel__matches_atom(request_skel->children, "create-txn")) + post_skel = request_skel->children; + + /* NOTE: If you add POST handlers here, you'll want to advertise + that the server supports them, too. See version.c:get_option(). */ + + if (svn_skel__matches_atom(post_skel, "create-txn")) { return dav_svn__post_create_txn(resource, request_skel, output); } - else + else if (svn_skel__matches_atom(post_skel, "create-txn-with-props")) { - return dav_svn__new_error(pool, HTTP_BAD_REQUEST, 0, - "Unsupported skel POST request flavor."); + return dav_svn__post_create_txn_with_props(resource, + request_skel, output); } - /* NOTREACHED */ + + return dav_svn__new_error(pool, HTTP_BAD_REQUEST, 0, + "Unsupported skel POST request flavor."); } int dav_svn__method_post(request_rec *r) Modified: subversion/branches/compressed-pristines/subversion/mod_dav_svn/util.c URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/mod_dav_svn/util.c?rev=1413258&r1=1413257&r2=1413258&view=diff ============================================================================== --- subversion/branches/compressed-pristines/subversion/mod_dav_svn/util.c (original) +++ subversion/branches/compressed-pristines/subversion/mod_dav_svn/util.c Sat Nov 24 20:29:11 2012 @@ -45,6 +45,9 @@ dav_svn__new_error(apr_pool_t *pool, int error_id, const char *desc) { + if (error_id == 0) + error_id = SVN_ERR_RA_DAV_REQUEST_FAILED; + /* * Note: dav_new_error() in httpd 2.0/2.2 always treated * the errno field in dav_error as an apr_status_t when @@ -70,6 +73,9 @@ dav_svn__new_error_tag(apr_pool_t *pool, const char *namespace, const char *tagname) { + if (error_id == 0) + error_id = SVN_ERR_RA_DAV_REQUEST_FAILED; + #if AP_MODULE_MAGIC_AT_LEAST(20091119,0) return dav_new_error_tag(pool, status, error_id, 0, desc, namespace, tagname); Modified: subversion/branches/compressed-pristines/subversion/mod_dav_svn/version.c URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/mod_dav_svn/version.c?rev=1413258&r1=1413257&r2=1413258&view=diff ============================================================================== --- subversion/branches/compressed-pristines/subversion/mod_dav_svn/version.c (original) +++ subversion/branches/compressed-pristines/subversion/mod_dav_svn/version.c Sat Nov 24 20:29:11 2012 @@ -37,7 +37,9 @@ #include "svn_props.h" #include "svn_dav.h" #include "svn_base64.h" +#include "svn_version.h" #include "private/svn_repos_private.h" +#include "private/svn_subr_private.h" #include "private/svn_dav_protocol.h" #include "private/svn_log.h" #include "private/svn_fspath.h" @@ -146,6 +148,7 @@ get_vsn_options(apr_pool_t *p, apr_text_ apr_text_append(p, phdr, SVN_DAV_NS_DAV_SVN_LOG_REVPROPS); apr_text_append(p, phdr, SVN_DAV_NS_DAV_SVN_ATOMIC_REVPROPS); apr_text_append(p, phdr, SVN_DAV_NS_DAV_SVN_PARTIAL_REPLAY); + apr_text_append(p, phdr, SVN_DAV_NS_DAV_SVN_INHERITED_PROPS); /* Mergeinfo is a special case: here we merely say that the server * knows how to handle mergeinfo -- whether the repository does too * is a separate matter. @@ -192,6 +195,14 @@ get_option(const dav_resource *resource, } } + /* If we're allowed (by configuration) to do so, advertise support + for ephemeral transaction properties. */ + if (dav_svn__check_ephemeral_txnprops_support(r)) + { + apr_table_addn(r->headers_out, "DAV", + SVN_DAV_NS_DAV_SVN_EPHEMERAL_TXNPROPS); + } + if (resource->info->repos->fs) { svn_error_t *serr; @@ -234,6 +245,25 @@ get_option(const dav_resource *resource, DeltaV-free! If we're configured to advise this support, do so. */ if (resource->info->repos->v2_protocol) { + int i; + svn_version_t *master_version = dav_svn__get_master_version(r); + + /* The list of Subversion's custom POSTs and which versions of + Subversion support them. We need this latter information + when acting as a WebDAV slave -- we don't want to claim + support for a POST type if the master server which will + actually have to handle it won't recognize it. + + Keep this in sync with what's handled in handle_post_request(). + */ + struct posts_versions_t { + const char *post_name; + svn_version_t min_version; + } posts_versions[] = { + { "create-txn", { 1, 7, 0, "" } }, + { "create-txn-with-props", { 1, 8, 0, "" } }, + }; + apr_table_set(r->headers_out, SVN_DAV_ROOT_URI_HEADER, repos_root_uri); apr_table_set(r->headers_out, SVN_DAV_ME_RESOURCE_HEADER, apr_pstrcat(resource->pool, repos_root_uri, "/", @@ -256,6 +286,23 @@ get_option(const dav_resource *resource, apr_table_set(r->headers_out, SVN_DAV_VTXN_STUB_HEADER, apr_pstrcat(resource->pool, repos_root_uri, "/", dav_svn__get_vtxn_stub(r), (char *)NULL)); + + /* Report the supported POST types. */ + for (i = 0; i < sizeof(posts_versions)/sizeof(posts_versions[0]); ++i) + { + /* If we're proxying to a master server and its version + number is declared, we can selectively filter out POST + types that it doesn't support. */ + if (master_version + && (! svn_version__at_least(master_version, + posts_versions[i].min_version.major, + posts_versions[i].min_version.minor, + posts_versions[i].min_version.patch))) + continue; + + apr_table_addn(r->headers_out, SVN_DAV_SUPPORTED_POSTS_HEADER, + apr_pstrdup(resource->pool, posts_versions[i].post_name)); + } } return NULL; @@ -398,7 +445,7 @@ dav_svn__checkout(dav_resource *resource shared_activity = apr_pstrdup(resource->info->r->pool, uuid_buf); derr = dav_svn__create_txn(resource->info->repos, &shared_txn_name, - resource->info->r->pool); + NULL, resource->info->r->pool); if (derr) return derr; derr = dav_svn__store_activity(resource->info->repos, @@ -1093,6 +1140,10 @@ deliver_report(request_rec *r, { return dav_svn__get_deleted_rev_report(resource, doc, output); } + else if (strcmp(doc->root->name, SVN_DAV__INHERITED_PROPS_REPORT) == 0) + { + return dav_svn__get_inherited_props_report(resource, doc, output); + } /* NOTE: if you add a report, don't forget to add it to the * dav_svn__reports_list[] array. */ @@ -1138,7 +1189,8 @@ make_activity(dav_resource *resource) SVN_DAV_ERROR_NAMESPACE, SVN_DAV_ERROR_TAG); - err = dav_svn__create_txn(resource->info->repos, &txn_name, resource->pool); + err = dav_svn__create_txn(resource->info->repos, &txn_name, + NULL, resource->pool); if (err != NULL) return err; Modified: subversion/branches/compressed-pristines/subversion/po/es.po URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/po/es.po?rev=1413258&r1=1413257&r2=1413258&view=diff ============================================================================== --- subversion/branches/compressed-pristines/subversion/po/es.po [UTF-8] (original) +++ subversion/branches/compressed-pristines/subversion/po/es.po [UTF-8] Sat Nov 24 20:29:11 2012 @@ -13565,7 +13565,7 @@ msgstr "" #~ " 'HEAD' lo último del repositorio\n" #~ " 'BASE' rev base del ítem de la c. de trab.\n" #~ " 'COMMITTED' último commit en o antes de BASE\n" -#~ " 'PREV' revisión justo antes de COMMITED" +#~ " 'PREV' revisión justo antes de COMMITTED" #~ msgid "Can't open file '%s' for reading" #~ msgstr "No se pudo abrir el archivo '%s' para leer" Modified: subversion/branches/compressed-pristines/subversion/po/pl.po URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/po/pl.po?rev=1413258&r1=1413257&r2=1413258&view=diff ============================================================================== --- subversion/branches/compressed-pristines/subversion/po/pl.po [UTF-8] (original) +++ subversion/branches/compressed-pristines/subversion/po/pl.po [UTF-8] Sat Nov 24 20:29:11 2012 @@ -2225,7 +2225,7 @@ msgstr "Nieznany typ systemu plików: '% #: ../libsvn_fs/fs-loader.c:313 #, c-format msgid "Can't allocate FS mutex" -msgstr "Nie udało się utworzyć semefora FS" +msgstr "Nie udało się utworzyć semafora FS" #: ../libsvn_fs/fs-loader.c:348 #, c-format @@ -3675,7 +3675,7 @@ msgstr "Uzyskano nierozpoznane kodowanie #: ../libsvn_ra_neon/get_locks.c:425 ../libsvn_ra_neon/get_locks.c:429 #: ../libsvn_ra_serf/locks.c:566 msgid "Server does not support locking features" -msgstr "Serwer nie obsługuje blokowania zatwiedzeń" +msgstr "Serwer nie obsługuje blokowania zatwierdzeń" #: ../libsvn_ra_neon/lock.c:196 msgid "Invalid creation date header value in response." @@ -3703,7 +3703,7 @@ msgstr "'%s' nie jest zablokowane w repo #: ../libsvn_ra_neon/lock.c:553 msgid "Failed to fetch lock information" -msgstr "Nieudało się pobrać informacji o blokadzie" +msgstr "Nie udało się pobrać informacji o blokadzie" #: ../libsvn_ra_neon/log.c:169 ../libsvn_ra_serf/log.c:228 #, c-format @@ -4751,7 +4751,7 @@ msgstr "Błąd podczas zamykania pliku n #: ../libsvn_repos/hooks.c:379 #, c-format msgid "Failed to run '%s' hook; broken symlink" -msgstr "Niepowiodło się uruchomienie skryptu hook '%s'; uszkodzone dowiązanie symboliczne" +msgstr "Nie powiodło się uruchomienie skryptu hook '%s'; uszkodzone dowiązanie symboliczne" #: ../libsvn_repos/hooks.c:589 msgid "" @@ -4863,7 +4863,7 @@ msgstr "Brak uprawnień do otwarcia kata #: ../libsvn_repos/reporter.c:1234 #, c-format msgid "Target path '%s' does not exist" -msgstr "Docelowa śieżka '%s' nie istnieje" +msgstr "Docelowa ścieżka '%s' nie istnieje" #: ../libsvn_repos/reporter.c:1242 msgid "Cannot replace a directory from within" @@ -5215,7 +5215,7 @@ msgstr "W pliku '%s' w linii %d: asercja #: ../libsvn_subr/error.c:602 #, c-format msgid "In file '%s' line %d: internal malfunction" -msgstr "W pliku '%s' w linii %d: wewnątrzne niepoprawne funkcjonowanie" +msgstr "W pliku '%s' w linii %d: wewnętrzne niepoprawne funkcjonowanie" #: ../libsvn_subr/io.c:169 #, c-format @@ -5230,7 +5230,7 @@ msgstr "Nie można sprawdzić ścieżki #: ../libsvn_subr/io.c:457 ../libsvn_subr/io.c:3771 #, c-format msgid "Can't open '%s'" -msgstr "Nie mozna otworzyć '%s'" +msgstr "Nie można otworzyć '%s'" #: ../libsvn_subr/io.c:483 ../libsvn_subr/io.c:569 #, c-format @@ -6280,7 +6280,7 @@ msgstr "Format logów zbyt stary. Prosz� #: ../libsvn_wc/conflicts.c:299 msgid "Invalid 'conflict_result' argument" -msgstr "Błądny argument 'conflict_result'" +msgstr "Błędny argument 'conflict_result'" #: ../libsvn_wc/conflicts.c:409 #, c-format @@ -6731,7 +6731,7 @@ msgstr "Nieprawidłowy atrybut %s dla '% #: ../libsvn_wc/props.c:2643 #, c-format msgid "Invalid %s property on '%s': target '%s' is an absolute path or involves '..'" -msgstr "Błędny atrybut %s dla '%s': cel '%s' jest ścieżką bezwględną albo wykorzystuje '..'" +msgstr "Błędny atrybut %s dla '%s': cel '%s' jest ścieżką bezwzględną albo wykorzystuje '..'" #: ../libsvn_wc/questions.c:203 #, fuzzy, c-format @@ -8245,7 +8245,7 @@ msgstr "" "\n" "OSTRZEŻENIE: Dla kompatybilności z poprzednimi wersjami Subversion kopiowania\n" "wykonywane pomiędzy dwoma ścieżkami kopii roboczej (KR -> KR) nie kontaktują\n" -"się z reporytorium. W związku z tym nie mogą domyślnie propagować informacji\n" +"się z repozytorium. W związku z tym nie mogą domyślnie propagować informacji\n" "o łączeniach zmian ze źródła kopii do celu.\n" #: ../svn/main.c:505 @@ -8673,7 +8673,7 @@ msgstr "" " E Istniały (Existed)\n" " R Zastąpiony (Replaced)\n" "\n" -" Znaki w pierwszej kolumnia informują o samym obiekcie. Znaki w drugiej\n" +" Znaki w pierwszej kolumnie informują o samym obiekcie. Znaki w drugiej\n" " kolumnie informują o atrybutach obiektu. 'C' w trzeciej kolumnie wskazuje\n" " na konflikt drzewny, podczas gdy 'C' w pierwszej i drugiej kolumnie\n" " wskazuje odpowiednio na konflikt tekstowy w plikach i w atrybutach plików.\n" @@ -9663,7 +9663,7 @@ msgstr "Opis zmian jest ścieżką (chci #: ../svn/main.c:2065 msgid "The lock comment is a pathname (was -F intended?); use '--force-log' to override" -msgstr "Opis blokady jest ścieżką (chciano użyć -F?); użyj --force-log, bywymusić użycie takiego opisu" +msgstr "Opis blokady jest ścieżką (chciano użyć -F?); użyj --force-log, by wymusić użycie takiego opisu" #: ../svn/main.c:2079 msgid "--relocate and --depth are mutually exclusive" Modified: subversion/branches/compressed-pristines/subversion/po/pt_BR.po URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/po/pt_BR.po?rev=1413258&r1=1413257&r2=1413258&view=diff ============================================================================== --- subversion/branches/compressed-pristines/subversion/po/pt_BR.po [UTF-8] (original) +++ subversion/branches/compressed-pristines/subversion/po/pt_BR.po [UTF-8] Sat Nov 24 20:29:11 2012 @@ -12663,8 +12663,8 @@ msgstr "" #~ " '{' DATA '}' revisão no início da data\n" #~ " 'HEAD' último no repositório\n" #~ " 'BASE' revisão base do item da cópia de trabalho\n" -#~ " 'COMMITED' último commit em ou antes de BASE\n" -#~ " 'PREV' revisão exatamente antes de COMMITED" +#~ " 'COMMITTED' último commit em ou antes de BASE\n" +#~ " 'PREV' revisão exatamente antes de COMMITTED" #~ msgid "Can't get user name" #~ msgstr "Não foi possível obter o nome do usuário"
