Return-Path: X-Original-To: apmail-subversion-commits-archive@minotaur.apache.org Delivered-To: apmail-subversion-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 97FB91748D for ; Mon, 16 Mar 2015 10:10:24 +0000 (UTC) Received: (qmail 94781 invoked by uid 500); 16 Mar 2015 10:10:24 -0000 Delivered-To: apmail-subversion-commits-archive@subversion.apache.org Received: (qmail 94750 invoked by uid 500); 16 Mar 2015 10:10:24 -0000 Mailing-List: contact commits-help@subversion.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@subversion.apache.org Delivered-To: mailing list commits@subversion.apache.org Received: (qmail 94626 invoked by uid 99); 16 Mar 2015 10:10:24 -0000 Received: from eris.apache.org (HELO hades.apache.org) (140.211.11.105) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 16 Mar 2015 10:10:24 +0000 Received: from hades.apache.org (localhost [127.0.0.1]) by hades.apache.org (ASF Mail Server at hades.apache.org) with ESMTP id 1677FAC073F for ; Mon, 16 Mar 2015 10:10:24 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1666947 [3/4] - in /subversion/branches/move-tracking-2: ./ subversion/ subversion/bindings/javahl/native/ subversion/bindings/javahl/tests/org/apache/subversion/javahl/ subversion/include/ subversion/include/private/ subversion/libsvn_cli... Date: Mon, 16 Mar 2015 10:10:22 -0000 To: commits@subversion.apache.org From: julianfoad@apache.org X-Mailer: svnmailer-1.0.9 Message-Id: <20150316101024.1677FAC073F@hades.apache.org> Modified: subversion/branches/move-tracking-2/subversion/libsvn_ra_serf/replay.c URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_ra_serf/replay.c?rev=1666947&r1=1666946&r2=1666947&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/libsvn_ra_serf/replay.c (original) +++ subversion/branches/move-tracking-2/subversion/libsvn_ra_serf/replay.c Mon Mar 16 10:10:20 2015 @@ -427,10 +427,11 @@ replay_closed(svn_ra_serf__xml_estate_t { struct replay_node_t *node = ctx->current_node; - if (! node || ! node->file || ! node->stream) + if (! node || ! node->file) return svn_error_create(SVN_ERR_XML_MALFORMED, NULL, NULL); - SVN_ERR(svn_stream_close(node->stream)); + if (node->stream) + SVN_ERR(svn_stream_close(node->stream)); node->stream = NULL; } @@ -565,10 +566,10 @@ svn_ra_serf__replay(svn_ra_session_t *ra SVN_ERR(svn_ra_serf__context_run_one(handler, scratch_pool)); - return svn_error_trace( - svn_ra_serf__error_on_status(handler->sline, - handler->path, - handler->location)); + if (handler->sline.code != 200) + SVN_ERR(svn_ra_serf__unexpected_status(handler)); + + return SVN_NO_ERROR; } /* The maximum number of outstanding requests at any time. When this @@ -646,9 +647,10 @@ svn_ra_serf__replay_range(svn_ra_session int active_reports = 0; const char *include_path; svn_boolean_t done; + apr_pool_t *subpool = svn_pool_create(scratch_pool); SVN_ERR(svn_ra_serf__report_resource(&report_target, session, - scratch_pool)); + subpool)); /* Prior to 1.8, mod_dav_svn expect to get replay REPORT requests aimed at the session URL. But that's incorrect -- these reports @@ -671,7 +673,7 @@ svn_ra_serf__replay_range(svn_ra_session { SVN_ERR(svn_ra_serf__get_relative_path(&include_path, session->session_url.path, - session, scratch_pool)); + session, subpool)); } else { @@ -689,7 +691,7 @@ svn_ra_serf__replay_range(svn_ra_session { struct revision_report_t *rev_ctx; svn_ra_serf__handler_t *handler; - apr_pool_t *rev_pool = svn_pool_create(scratch_pool); + apr_pool_t *rev_pool = svn_pool_create(subpool); svn_ra_serf__xml_context_t *xmlctx; const char *replay_target; @@ -769,13 +771,23 @@ svn_ra_serf__replay_range(svn_ra_session /* Run the serf loop. */ done = FALSE; - SVN_ERR(svn_ra_serf__context_run_wait(&done, session, scratch_pool)); + { + svn_error_t *err = svn_ra_serf__context_run_wait(&done, session, + subpool); + + if (err) + { + svn_pool_destroy(subpool); /* Unregister all requests! */ + return svn_error_trace(err); + } + } /* The done handler of reports decrements active_reports when a report is done. This same handler reports (fatal) report errors, so we can just loop here. */ } + svn_pool_destroy(subpool); return SVN_NO_ERROR; } #undef MAX_OUTSTANDING_REQUESTS Modified: subversion/branches/move-tracking-2/subversion/libsvn_ra_serf/serf.c URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_ra_serf/serf.c?rev=1666947&r1=1666946&r2=1666947&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/libsvn_ra_serf/serf.c (original) +++ subversion/branches/move-tracking-2/subversion/libsvn_ra_serf/serf.c Mon Mar 16 10:10:20 2015 @@ -600,7 +600,7 @@ svn_ra_serf__open(svn_ra_session_t *sess #endif err = svn_ra_serf__exchange_capabilities(serf_sess, corrected_url, - result_pool, scratch_pool); + result_pool, scratch_pool); /* serf should produce a usable error code instead of APR_EGENERAL */ if (err && err->apr_err == APR_EGENERAL) Modified: subversion/branches/move-tracking-2/subversion/libsvn_ra_serf/stat.c URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_ra_serf/stat.c?rev=1666947&r1=1666946&r2=1666947&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/libsvn_ra_serf/stat.c (original) +++ subversion/branches/move-tracking-2/subversion/libsvn_ra_serf/stat.c Mon Mar 16 10:10:20 2015 @@ -472,6 +472,7 @@ svn_ra_serf__get_dir(svn_ra_session_t *r svn_ra_serf__handler_t *props_handler = NULL; const char *path; struct get_dir_baton_t gdb; + svn_error_t *err = SVN_NO_ERROR; gdb.result_pool = result_pool; gdb.is_directory = FALSE; @@ -542,10 +543,17 @@ svn_ra_serf__get_dir(svn_ra_session_t *r if (dirent_handler) { - SVN_ERR(svn_ra_serf__context_run_wait(&dirent_handler->done, + err = svn_error_trace( + svn_ra_serf__context_run_wait(&dirent_handler->done, session, scratch_pool)); + if (err) + { + svn_pool_clear(scratch_pool); /* Unregisters outstanding requests */ + return err; + } + if (gdb.supports_deadprop_count == svn_tristate_false && session->supports_deadprop_count == svn_tristate_unknown && dirent_fields & SVN_DIRENT_HAS_PROPS) @@ -571,23 +579,27 @@ svn_ra_serf__get_dir(svn_ra_session_t *r if (props_handler) { - SVN_ERR(svn_ra_serf__context_run_wait(&props_handler->done, + err = svn_error_trace( + svn_ra_serf__context_run_wait(&props_handler->done, session, scratch_pool)); } /* And dirent again for the case when we had to send the request again */ - if (dirent_handler) + if (! err && dirent_handler) { - SVN_ERR(svn_ra_serf__context_run_wait(&dirent_handler->done, + err = svn_error_trace( + svn_ra_serf__context_run_wait(&dirent_handler->done, session, scratch_pool)); } - if (gdb.supports_deadprop_count != svn_tristate_unknown) + if (!err && gdb.supports_deadprop_count != svn_tristate_unknown) session->supports_deadprop_count = gdb.supports_deadprop_count; - svn_pool_destroy(scratch_pool); + svn_pool_destroy(scratch_pool); /* Unregisters outstanding requests */ + + SVN_ERR(err); if (!gdb.is_directory) return svn_error_create(SVN_ERR_FS_NOT_DIRECTORY, NULL, Modified: subversion/branches/move-tracking-2/subversion/libsvn_ra_serf/util.c URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_ra_serf/util.c?rev=1666947&r1=1666946&r2=1666947&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/libsvn_ra_serf/util.c (original) +++ subversion/branches/move-tracking-2/subversion/libsvn_ra_serf/util.c Mon Mar 16 10:10:20 2015 @@ -947,6 +947,22 @@ svn_ra_serf__context_run_wait(svn_boolea return SVN_NO_ERROR; } +/* Ensure that a handler is no longer scheduled on the connection. + + Eventually serf will have a reliable way to cancel existing requests, + but currently it doesn't even have a way to relyable identify a request + after rescheduling, for auth reasons. + + So the only thing we can do today is reset the connection, which + will cancel all outstanding requests and prepare the connection + for re-use. +*/ +static void +svn_ra_serf__unschedule_handler(svn_ra_serf__handler_t *handler) +{ + serf_connection_reset(handler->conn->conn); + handler->scheduled = FALSE; +} svn_error_t * svn_ra_serf__context_run_one(svn_ra_serf__handler_t *handler, @@ -960,6 +976,15 @@ svn_ra_serf__context_run_one(svn_ra_serf /* Wait until the response logic marks its DONE status. */ err = svn_ra_serf__context_run_wait(&handler->done, handler->session, scratch_pool); + + if (handler->scheduled) + { + /* We reset the connection (breaking pipelining, etc.), as + if we didn't the next data would still be handled by this handler, + which is done as far as our caller is concerned. */ + svn_ra_serf__unschedule_handler(handler); + } + return svn_error_trace(err); } @@ -1453,7 +1478,13 @@ handle_response_cb(serf_request_t *reque { handler->discard_body = TRUE; /* Discard further data */ handler->done = TRUE; /* Mark as done */ - handler->scheduled = FALSE; + /* handler->scheduled is still TRUE, as we still expect data. + If we would return an error outer-status the connection + would have to be restarted. With scheduled still TRUE + destroying the handler's pool will still reset the + connection, avoiding the posibility of returning + an error for this handler when a new request is + scheduled. */ outer_status = APR_EAGAIN; /* Exit context loop */ } @@ -1762,8 +1793,9 @@ svn_ra_serf__error_on_status(serf_status return svn_error_createf(SVN_ERR_FS_NOT_FOUND, NULL, _("'%s' path not found"), path); case 405: - return svn_error_createf(SVN_ERR_FS_OUT_OF_DATE, NULL, - _("'%s' is out of date"), path); + return svn_error_createf(SVN_ERR_RA_DAV_METHOD_NOT_ALLOWED, NULL, + _("HTTP method is not allowed on '%s'"), + path); case 409: return svn_error_createf(SVN_ERR_FS_CONFLICT, NULL, _("'%s' conflicts"), path); @@ -1802,9 +1834,10 @@ svn_error_t * svn_ra_serf__unexpected_status(svn_ra_serf__handler_t *handler) { /* Is it a standard error status? */ - SVN_ERR(svn_ra_serf__error_on_status(handler->sline, - handler->path, - handler->location)); + if (handler->sline.code != 405) + SVN_ERR(svn_ra_serf__error_on_status(handler->sline, + handler->path, + handler->location)); switch (handler->sline.code) { @@ -1817,6 +1850,11 @@ svn_ra_serf__unexpected_status(svn_ra_se _("Path '%s' already exists"), handler->path); + case 405: + return svn_error_createf(SVN_ERR_RA_DAV_METHOD_NOT_ALLOWED, NULL, + _("The HTTP method '%s' is not allowed" + " on '%s'"), + handler->method, handler->path); default: return svn_error_createf(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL, _("Unexpected HTTP status %d '%s' on '%s' " @@ -1874,14 +1912,14 @@ response_done(serf_request_t *request, handlers registered in no freed memory. This fallback kills the connection for this case, which will make serf - unregister any*/ + unregister any outstanding requests on it. */ static apr_status_t handler_cleanup(void *baton) { svn_ra_serf__handler_t *handler = baton; - if (handler->scheduled && handler->conn && handler->conn->conn) + if (handler->scheduled) { - serf_connection_reset(handler->conn->conn); + svn_ra_serf__unschedule_handler(handler); } return APR_SUCCESS; Modified: subversion/branches/move-tracking-2/subversion/libsvn_ra_svn/client.c URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_ra_svn/client.c?rev=1666947&r1=1666946&r2=1666947&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/libsvn_ra_svn/client.c (original) +++ subversion/branches/move-tracking-2/subversion/libsvn_ra_svn/client.c Mon Mar 16 10:10:20 2015 @@ -1778,7 +1778,7 @@ perform_ra_svn_log(svn_error_t **outer_e - Except if the server sends more than a >= 1 limit top level items - Or when the callback reported a SVN_ERR_CEASE_INVOCATION in an earlier invocation. */ - if (! (limit && (nest_level == 0) && (++nreceived > limit)) + if (! ((limit > 0) && (nest_level == 0) && (++nreceived > limit)) && ! *outer_error) { svn_error_t *err; @@ -1806,7 +1806,7 @@ perform_ra_svn_log(svn_error_t **outer_e SVN_PROP_REVISION_LOG, message); err = receiver(receiver_baton, log_entry, iterpool); - if (err && err->apr_err == SVN_ERR_CEASE_INVOCATION) + if (svn_error_find_cause(err, SVN_ERR_CEASE_INVOCATION)) { *outer_error = svn_error_trace( svn_error_compose_create(*outer_error, err)); @@ -1994,14 +1994,15 @@ static svn_error_t *ra_svn_get_locations } static svn_error_t * -ra_svn_get_location_segments(svn_ra_session_t *session, - const char *path, - svn_revnum_t peg_revision, - svn_revnum_t start_rev, - svn_revnum_t end_rev, - svn_location_segment_receiver_t receiver, - void *receiver_baton, - apr_pool_t *pool) +perform_get_location_segments(svn_error_t **outer_error, + svn_ra_session_t *session, + const char *path, + svn_revnum_t peg_revision, + svn_revnum_t start_rev, + svn_revnum_t end_rev, + svn_location_segment_receiver_t receiver, + void *receiver_baton, + apr_pool_t *pool) { svn_ra_svn__session_baton_t *sess_baton = session->priv; svn_ra_svn_conn_t *conn = sess_baton->conn; @@ -2048,7 +2049,17 @@ ra_svn_get_location_segments(svn_ra_sess segment->path = ret_path; segment->range_start = range_start; segment->range_end = range_end; - SVN_ERR(receiver(segment, receiver_baton, iterpool)); + + if (!*outer_error) + { + svn_error_t *err = svn_error_trace(receiver(segment, receiver_baton, + iterpool)); + + if (svn_error_find_cause(err, SVN_ERR_CEASE_INVOCATION)) + *outer_error = err; + else + SVN_ERR(err); + } } } svn_pool_destroy(iterpool); @@ -2060,6 +2071,26 @@ ra_svn_get_location_segments(svn_ra_sess return SVN_NO_ERROR; } +static svn_error_t * +ra_svn_get_location_segments(svn_ra_session_t *session, + const char *path, + svn_revnum_t peg_revision, + svn_revnum_t start_rev, + svn_revnum_t end_rev, + svn_location_segment_receiver_t receiver, + void *receiver_baton, + apr_pool_t *pool) +{ + svn_error_t *outer_err = SVN_NO_ERROR; + svn_error_t *err; + + err = svn_error_trace( + perform_get_location_segments(&outer_err, session, path, + peg_revision, start_rev, end_rev, + receiver, receiver_baton, pool)); + return svn_error_compose_create(outer_err, err); +} + static svn_error_t *ra_svn_get_file_revs(svn_ra_session_t *session, const char *path, svn_revnum_t start, svn_revnum_t end, @@ -2720,10 +2751,16 @@ ra_svn_replay_range(svn_ra_session_t *se SVN_ERR(svn_ra_svn__read_tuple(sess->conn, iterpool, "wl", &word, &list)); + if (strcmp(word, "revprops") != 0) - return svn_error_createf(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL, - _("Expected 'revprops', found '%s'"), - word); + { + if (strcmp(word, "failure") == 0) + SVN_ERR(svn_ra_svn__handle_failure_status(list, iterpool)); + + return svn_error_createf(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL, + _("Expected 'revprops', found '%s'"), + word); + } SVN_ERR(svn_ra_svn__parse_proplist(list, iterpool, &rev_props)); Modified: subversion/branches/move-tracking-2/subversion/libsvn_ra_svn/editorp.c URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_ra_svn/editorp.c?rev=1666947&r1=1666946&r2=1666947&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/libsvn_ra_svn/editorp.c (original) +++ subversion/branches/move-tracking-2/subversion/libsvn_ra_svn/editorp.c Mon Mar 16 10:10:20 2015 @@ -843,6 +843,14 @@ static svn_error_t *ra_svn_handle_close_ { SVN_CMD_ERR(ds->editor->close_edit(ds->edit_baton, pool)); ds->done = TRUE; +#ifdef SVN_DEBUG + /* Before enabling this in non-maintainer mode: + * Note that this code is used on both client *and* server */ + if (apr_hash_count(ds->tokens) != 0) + return svn_error_create( + SVN_ERR_FS_INCORRECT_EDITOR_COMPLETION, NULL, + _("Closing editor with directories or files open")); +#endif if (ds->aborted) *ds->aborted = FALSE; return svn_ra_svn__write_cmd_response(conn, pool, ""); Modified: subversion/branches/move-tracking-2/subversion/libsvn_repos/replay.c URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_repos/replay.c?rev=1666947&r1=1666946&r2=1666947&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/libsvn_repos/replay.c (original) +++ subversion/branches/move-tracking-2/subversion/libsvn_repos/replay.c Mon Mar 16 10:10:20 2015 @@ -555,10 +555,6 @@ path_driver_cb_func(void **dir_baton, return svn_error_create(SVN_ERR_FS_ALREADY_EXISTS, NULL, _("Root directory already exists.")); - /* A NULL parent_baton will cause a segfault. It should never be - NULL for non-root paths. */ - SVN_ERR_ASSERT(parent_baton); - /* Was this node copied? */ SVN_ERR(fill_copyfrom(©from_root, ©from_path, ©from_rev, &src_readable, root, change, @@ -971,6 +967,11 @@ svn_repos_replay2(svn_fs_root_t *root, const char *repos_root = ""; void *unlock_baton; + /* If we were not given a low water mark, assume that everything is there, + all the way back to revision 0. */ + if (! SVN_IS_VALID_REVNUM(low_water_mark)) + low_water_mark = 0; + /* Special-case r0, which we know is an empty revision; if we don't special-case it we might end up trying to compare it to "r-1". */ if (svn_fs_is_revision_root(root) @@ -1493,7 +1494,7 @@ svn_repos__replay_ev2(svn_fs_root_t *roo svn_error_t *err = SVN_NO_ERROR; int i; - SVN_ERR_ASSERT(!svn_dirent_is_absolute(base_repos_relpath)); + SVN_ERR_ASSERT(svn_relpath_is_canonical(base_repos_relpath)); /* Special-case r0, which we know is an empty revision; if we don't special-case it we might end up trying to compare it to "r-1". */ Modified: subversion/branches/move-tracking-2/subversion/libsvn_repos/rev_hunt.c URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_repos/rev_hunt.c?rev=1666947&r1=1666946&r2=1666947&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/libsvn_repos/rev_hunt.c (original) +++ subversion/branches/move-tracking-2/subversion/libsvn_repos/rev_hunt.c Mon Mar 16 10:10:20 2015 @@ -837,27 +837,32 @@ svn_repos_node_location_segments(svn_rep { svn_fs_t *fs = svn_repos_fs(repos); svn_stringbuf_t *current_path; - svn_revnum_t youngest_rev = SVN_INVALID_REVNUM, current_rev; + svn_revnum_t youngest_rev, current_rev; apr_pool_t *subpool; + SVN_ERR(svn_fs_youngest_rev(&youngest_rev, fs, pool)); + /* No PEG_REVISION? We'll use HEAD. */ if (! SVN_IS_VALID_REVNUM(peg_revision)) - { - SVN_ERR(svn_fs_youngest_rev(&youngest_rev, fs, pool)); - peg_revision = youngest_rev; - } + peg_revision = youngest_rev; + + if (peg_revision > youngest_rev) + return svn_error_createf(SVN_ERR_FS_NO_SUCH_REVISION, NULL, + _("No such revision %ld"), peg_revision); - /* No START_REV? We'll use HEAD (which we may have already fetched). */ + /* No START_REV? We'll use peg rev. */ if (! SVN_IS_VALID_REVNUM(start_rev)) - { - if (SVN_IS_VALID_REVNUM(youngest_rev)) - start_rev = youngest_rev; - else - SVN_ERR(svn_fs_youngest_rev(&start_rev, fs, pool)); - } + start_rev = peg_revision; + else if (start_rev > peg_revision) + return svn_error_createf(SVN_ERR_FS_NO_SUCH_REVISION, NULL, + _("No such revision %ld"), start_rev); /* No END_REV? We'll use 0. */ - end_rev = SVN_IS_VALID_REVNUM(end_rev) ? end_rev : 0; + if (! SVN_IS_VALID_REVNUM(end_rev)) + end_rev = 0; + else if (end_rev > start_rev) + return svn_error_createf(SVN_ERR_FS_NO_SUCH_REVISION, NULL, + _("No such revision %ld"), end_rev); /* Are the revision properly ordered? They better be -- the API demands it. */ Modified: subversion/branches/move-tracking-2/subversion/libsvn_subr/atomic.c URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_subr/atomic.c?rev=1666947&r1=1666946&r2=1666947&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/libsvn_subr/atomic.c (original) +++ subversion/branches/move-tracking-2/subversion/libsvn_subr/atomic.c Mon Mar 16 10:10:20 2015 @@ -20,6 +20,7 @@ * ==================================================================== */ +#include #include #include "private/svn_atomic.h" @@ -29,11 +30,20 @@ #define SVN_ATOMIC_INIT_FAILED 2 #define SVN_ATOMIC_INITIALIZED 3 -svn_error_t* -svn_atomic__init_once(volatile svn_atomic_t *global_status, - svn_error_t *(*init_func)(void*,apr_pool_t*), - void *baton, - apr_pool_t* pool) + +/* + * This is the actual atomic initialization driver. The caller must + * provide either ERR_INIT_FUNC and ERR_P, or STR_INIT_FUNC and + * ERRSTR_P, but never both. + */ +static void +init_once(svn_atomic__err_init_func_t err_init_func, + svn_error_t **err_p, + svn_atomic__str_init_func_t str_init_func, + const char **errstr_p, + volatile svn_atomic_t *global_status, + void *baton, + apr_pool_t* pool) { /* !! Don't use localizable strings in this function, because these !! might cause deadlocks. This function can be used to initialize @@ -42,44 +52,94 @@ svn_atomic__init_once(volatile svn_atomi /* We have to call init_func exactly once. Because APR doesn't have statically-initialized mutexes, we implement a poor man's spinlock using svn_atomic_cas. */ + + svn_error_t *err = SVN_NO_ERROR; + const char *errstr = NULL; svn_atomic_t status = svn_atomic_cas(global_status, SVN_ATOMIC_START_INIT, SVN_ATOMIC_UNINITIALIZED); - if (status == SVN_ATOMIC_UNINITIALIZED) +#ifdef SVN_DEBUG + /* Check that the parameters are valid. */ + assert(!err_init_func != !str_init_func); + assert(!err_init_func == !err_p); + assert(!str_init_func == !errstr_p); +#endif /* SVN_DEBUG */ + + for (;;) { - svn_error_t *err = init_func(baton, pool); - if (err) + switch (status) { -#if APR_HAS_THREADS - /* Tell other threads that the initialization failed. */ - svn_atomic_cas(global_status, - SVN_ATOMIC_INIT_FAILED, - SVN_ATOMIC_START_INIT); -#endif - return svn_error_create(SVN_ERR_ATOMIC_INIT_FAILURE, err, - "Couldn't perform atomic initialization"); + case SVN_ATOMIC_UNINITIALIZED: + if (err_init_func) + err = err_init_func(baton, pool); + else + errstr = str_init_func(baton); + if (err || errstr) + { + status = svn_atomic_cas(global_status, + SVN_ATOMIC_INIT_FAILED, + SVN_ATOMIC_START_INIT); + } + else + { + status = svn_atomic_cas(global_status, + SVN_ATOMIC_INITIALIZED, + SVN_ATOMIC_START_INIT); + } + + /* Take another spin through the switch to report either + failure or success. */ + continue; + + case SVN_ATOMIC_START_INIT: + /* Wait for the init function to complete. */ + apr_sleep(APR_USEC_PER_SEC / 1000); + status = svn_atomic_cas(global_status, + SVN_ATOMIC_UNINITIALIZED, + SVN_ATOMIC_UNINITIALIZED); + continue; + + case SVN_ATOMIC_INIT_FAILED: + if (err_init_func) + *err_p = svn_error_create(SVN_ERR_ATOMIC_INIT_FAILURE, err, + "Couldn't perform atomic initialization"); + else + *errstr_p = errstr; + return; + + case SVN_ATOMIC_INITIALIZED: + if (err_init_func) + *err_p = SVN_NO_ERROR; + else + *errstr_p = NULL; + return; + + default: + /* Something went seriously wrong with the atomic operations. */ + abort(); } - svn_atomic_cas(global_status, - SVN_ATOMIC_INITIALIZED, - SVN_ATOMIC_START_INIT); - } -#if APR_HAS_THREADS - /* Wait for whichever thread is performing initialization to finish. */ - /* XXX FIXME: Should we have a maximum wait here, like we have in - the Windows file IO spinner? */ - else while (status != SVN_ATOMIC_INITIALIZED) - { - if (status == SVN_ATOMIC_INIT_FAILED) - return svn_error_create(SVN_ERR_ATOMIC_INIT_FAILURE, NULL, - "Couldn't perform atomic initialization"); - - apr_sleep(APR_USEC_PER_SEC / 1000); - status = svn_atomic_cas(global_status, - SVN_ATOMIC_UNINITIALIZED, - SVN_ATOMIC_UNINITIALIZED); } -#endif /* APR_HAS_THREADS */ +} + - return SVN_NO_ERROR; +svn_error_t * +svn_atomic__init_once(volatile svn_atomic_t *global_status, + svn_atomic__err_init_func_t err_init_func, + void *baton, + apr_pool_t* pool) +{ + svn_error_t *err; + init_once(err_init_func, &err, NULL, NULL, global_status, baton, pool); + return err; +} + +const char * +svn_atomic__init_once_no_error(volatile svn_atomic_t *global_status, + svn_atomic__str_init_func_t str_init_func, + void *baton) +{ + const char *errstr; + init_once(NULL, NULL, str_init_func, &errstr, global_status, baton, NULL); + return errstr; } Modified: subversion/branches/move-tracking-2/subversion/libsvn_subr/auth.c URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_subr/auth.c?rev=1666947&r1=1666946&r2=1666947&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/libsvn_subr/auth.c (original) +++ subversion/branches/move-tracking-2/subversion/libsvn_subr/auth.c Mon Mar 16 10:10:20 2015 @@ -207,8 +207,7 @@ svn_auth_get_parameter(svn_auth_baton_t value = svn_hash_gets(auth_baton->slave_parameters, name); if (value) - return (value == &auth_NULL) ? NULL - : value; + return (value == &auth_NULL ? NULL : value); return svn_hash_gets(auth_baton->parameters, name); } @@ -354,7 +353,7 @@ svn_auth_next_credentials(void **credent { SVN_ERR(provider->vtable->first_credentials( &creds, &(state->provider_iter_baton), - provider->provider_baton, auth_baton->parameters, + provider->provider_baton, state->parameters, state->realmstring, auth_baton->pool)); state->got_first = TRUE; } @@ -392,19 +391,17 @@ svn_auth_save_credentials(svn_auth_iters svn_auth_provider_object_t *provider; svn_boolean_t save_succeeded = FALSE; const char *no_auth_cache; - svn_auth_baton_t *auth_baton; void *creds; if (! state || state->table->providers->nelts <= state->provider_idx) return SVN_NO_ERROR; - auth_baton = state->auth_baton; creds = svn_hash_gets(state->auth_baton->creds_cache, state->cache_key); if (! creds) return SVN_NO_ERROR; /* Do not save the creds if SVN_AUTH_PARAM_NO_AUTH_CACHE is set */ - no_auth_cache = svn_hash_gets(auth_baton->parameters, + no_auth_cache = svn_hash_gets(state->parameters, SVN_AUTH_PARAM_NO_AUTH_CACHE); if (no_auth_cache) return SVN_NO_ERROR; @@ -417,7 +414,7 @@ svn_auth_save_credentials(svn_auth_iters SVN_ERR(provider->vtable->save_credentials(&save_succeeded, creds, provider->provider_baton, - auth_baton->parameters, + state->parameters, state->realmstring, pool)); if (save_succeeded) @@ -433,7 +430,7 @@ svn_auth_save_credentials(svn_auth_iters if (provider->vtable->save_credentials) SVN_ERR(provider->vtable->save_credentials(&save_succeeded, creds, provider->provider_baton, - auth_baton->parameters, + state->parameters, state->realmstring, pool)); @@ -768,12 +765,10 @@ svn_auth__make_session_auth(svn_auth_bat * "store-auth-creds = yes" -- they'll get the expected behaviour. */ - if (svn_auth_get_parameter(ab, - SVN_AUTH_PARAM_DONT_STORE_PASSWORDS) != NULL) + if (svn_auth_get_parameter(ab, SVN_AUTH_PARAM_DONT_STORE_PASSWORDS) != NULL) store_passwords = FALSE; - if (svn_auth_get_parameter(ab, - SVN_AUTH_PARAM_NO_AUTH_CACHE) != NULL) + if (svn_auth_get_parameter(ab, SVN_AUTH_PARAM_NO_AUTH_CACHE) != NULL) store_auth_creds = FALSE; /* All the svn_auth_set_parameter() calls below this not only affect the @@ -858,8 +853,7 @@ svn_auth__make_session_auth(svn_auth_bat /* Save auth caching parameters in the auth parameter hash. */ if (! store_passwords) - svn_auth_set_parameter(ab, - SVN_AUTH_PARAM_DONT_STORE_PASSWORDS, ""); + svn_auth_set_parameter(ab, SVN_AUTH_PARAM_DONT_STORE_PASSWORDS, ""); svn_auth_set_parameter(ab, SVN_AUTH_PARAM_STORE_PLAINTEXT_PASSWORDS, @@ -875,8 +869,7 @@ svn_auth__make_session_auth(svn_auth_bat store_pp_plaintext); if (! store_auth_creds) - svn_auth_set_parameter(ab, - SVN_AUTH_PARAM_NO_AUTH_CACHE, ""); + svn_auth_set_parameter(ab, SVN_AUTH_PARAM_NO_AUTH_CACHE, ""); if (server_group) svn_auth_set_parameter(ab, Modified: subversion/branches/move-tracking-2/subversion/libsvn_subr/error.c URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_subr/error.c?rev=1666947&r1=1666946&r2=1666947&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/libsvn_subr/error.c (original) +++ subversion/branches/move-tracking-2/subversion/libsvn_subr/error.c Mon Mar 16 10:10:20 2015 @@ -59,11 +59,12 @@ static apr_threadkey_t *error_line_key = /* No-op destructor for apr_threadkey_private_create(). */ static void null_threadkey_dtor(void *stuff) {} -/* Handler for svn_atomic__init_once used by svn_error__locate to - initialize the thread-local error location storage. - This function will never return an error. */ -static svn_error_t * -locate_init_once(void *ignored_baton, apr_pool_t *ignored_pool) +/* Implements svn_atomic__str_init_func_t. + Callback used by svn_error__locate to initialize the thread-local + error location storage. This function will never return an + error string. */ +static const char * +locate_init_once(void *ignored_baton) { /* Strictly speaking, this is a memory leak, since we're creating an unmanaged, top-level pool and never destroying it. We do this @@ -86,7 +87,7 @@ locate_init_once(void *ignored_baton, ap if (status != APR_SUCCESS) error_file_key = error_line_key = NULL; - return SVN_NO_ERROR; + return NULL; } # endif /* APR_HAS_THREADS */ @@ -124,9 +125,7 @@ svn_error__locate(const char *file, long #ifdef SVN_DEBUG # if APR_HAS_THREADS static volatile svn_atomic_t init_status = 0; - svn_error_clear(svn_atomic__init_once(&init_status, - locate_init_once, - NULL, NULL)); + svn_atomic__init_once_no_error(&init_status, locate_init_once, NULL); if (error_file_key && error_line_key) { Modified: subversion/branches/move-tracking-2/subversion/libsvn_subr/utf8proc/utf8proc.h URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_subr/utf8proc/utf8proc.h?rev=1666947&r1=1666946&r2=1666947&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/libsvn_subr/utf8proc/utf8proc.h (original) +++ subversion/branches/move-tracking-2/subversion/libsvn_subr/utf8proc/utf8proc.h Mon Mar 16 10:10:20 2015 @@ -74,17 +74,17 @@ # if _MSC_VER >= 1600 # include # else - typedef signed char int8_t; - typedef unsigned char uint8_t; - typedef short int16_t; - typedef unsigned short uint16_t; - typedef int int32_t; +typedef signed char int8_t; +typedef unsigned char uint8_t; +typedef short int16_t; +typedef unsigned short uint16_t; +typedef int int32_t; # endif # if _MSC_VER >= 1800 # include # else - typedef unsigned char bool; - enum {false, true}; +typedef unsigned char bool; +enum {false, true}; # endif # ifdef _WIN64 # define ssize_t __int64 Modified: subversion/branches/move-tracking-2/subversion/libsvn_wc/update_editor.c URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_wc/update_editor.c?rev=1666947&r1=1666946&r2=1666947&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/libsvn_wc/update_editor.c (original) +++ subversion/branches/move-tracking-2/subversion/libsvn_wc/update_editor.c Mon Mar 16 10:10:20 2015 @@ -1935,7 +1935,8 @@ add_directory(const char *path, SVN_ERR_ASSERT(conflicted); versioned_locally_and_present = FALSE; /* Tree conflict ACTUAL-only node */ } - else if (status == svn_wc__db_status_normal) + else if (status == svn_wc__db_status_normal + || status == svn_wc__db_status_incomplete) { svn_boolean_t root; @@ -2752,7 +2753,8 @@ close_directory(void *dir_baton, db->old_revision, db->new_repos_relpath, svn_node_dir, svn_node_dir, - db->parent_baton->deletion_conflicts + (db->parent_baton + && db->parent_baton->deletion_conflicts) ? svn_hash_gets( db->parent_baton->deletion_conflicts, db->name) @@ -3118,7 +3120,8 @@ add_file(const char *path, SVN_ERR_ASSERT(conflicted); versioned_locally_and_present = FALSE; /* Tree conflict ACTUAL-only node */ } - else if (status == svn_wc__db_status_normal) + else if (status == svn_wc__db_status_normal + || status == svn_wc__db_status_incomplete) { svn_boolean_t root; Modified: subversion/branches/move-tracking-2/subversion/mod_dav_svn/reports/inherited-props.c URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/mod_dav_svn/reports/inherited-props.c?rev=1666947&r1=1666946&r2=1666947&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/mod_dav_svn/reports/inherited-props.c (original) +++ subversion/branches/move-tracking-2/subversion/mod_dav_svn/reports/inherited-props.c Mon Mar 16 10:10:20 2015 @@ -61,6 +61,7 @@ dav_svn__get_inherited_props_report(cons int i; svn_revnum_t rev = SVN_INVALID_REVNUM; apr_pool_t *iterpool; + svn_node_kind_t kind; /* Sanity check. */ if (!resource->info->repos_path) @@ -114,6 +115,20 @@ dav_svn__get_inherited_props_report(cons "couldn't retrieve revision root", resource->pool); + serr = svn_fs_check_path(&kind, root, path, resource->pool); + if (!serr && kind == svn_node_none) + { + serr = svn_error_createf(SVN_ERR_FS_NOT_FOUND, NULL, + "'%s' path not found", path); + } + + if (serr) + { + derr = dav_svn__convert_err(serr, HTTP_BAD_REQUEST, NULL, + resource->pool); + goto cleanup; + } + serr = svn_repos_fs_get_inherited_props(&inherited_props, root, path, NULL, dav_svn__authz_read_func(&arb), &arb, resource->pool, iterpool); Modified: subversion/branches/move-tracking-2/subversion/mod_dav_svn/util.c URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/mod_dav_svn/util.c?rev=1666947&r1=1666946&r2=1666947&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/mod_dav_svn/util.c (original) +++ subversion/branches/move-tracking-2/subversion/mod_dav_svn/util.c Mon Mar 16 10:10:20 2015 @@ -135,6 +135,7 @@ dav_svn__convert_err(svn_error_t *serr, switch (purged_serr->apr_err) { case SVN_ERR_FS_NOT_FOUND: + case SVN_ERR_FS_NO_SUCH_REVISION: status = HTTP_NOT_FOUND; break; case SVN_ERR_UNSUPPORTED_FEATURE: Modified: subversion/branches/move-tracking-2/subversion/svnserve/serve.c URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/svnserve/serve.c?rev=1666947&r1=1666946&r2=1666947&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/svnserve/serve.c (original) +++ subversion/branches/move-tracking-2/subversion/svnserve/serve.c Mon Mar 16 10:10:20 2015 @@ -3296,6 +3296,7 @@ get_inherited_props(svn_ra_svn_conn_t *c int i; apr_pool_t *iterpool = svn_pool_create(pool); authz_baton_t ab; + svn_node_kind_t node_kind; ab.server = b; ab.conn = conn; @@ -3311,15 +3312,18 @@ get_inherited_props(svn_ra_svn_conn_t *c SVN_ERR(must_have_access(conn, iterpool, b, svn_authz_read, full_path, FALSE)); - if (!SVN_IS_VALID_REVNUM(rev)) - SVN_CMD_ERR(svn_fs_youngest_rev(&rev, b->repository->fs, pool)); - SVN_ERR(log_command(b, conn, pool, "%s", svn_log__get_inherited_props(full_path, rev, iterpool))); /* Fetch the properties and a stream for the contents. */ SVN_CMD_ERR(svn_fs_revision_root(&root, b->repository->fs, rev, iterpool)); + SVN_CMD_ERR(svn_fs_check_path(&node_kind, root, full_path, pool)); + if (node_kind == svn_node_none) + { + SVN_CMD_ERR(svn_error_createf(SVN_ERR_FS_NOT_FOUND, NULL, + _("'%s' path not found"), full_path)); + } SVN_CMD_ERR(get_props(NULL, &inherited_props, &ab, root, full_path, pool)); /* Send successful command response with revision and props. */ Modified: subversion/branches/move-tracking-2/subversion/tests/cmdline/atomic-ra-revprop-change.c URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/tests/cmdline/atomic-ra-revprop-change.c?rev=1666947&r1=1666946&r2=1666947&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/tests/cmdline/atomic-ra-revprop-change.c (original) +++ subversion/branches/move-tracking-2/subversion/tests/cmdline/atomic-ra-revprop-change.c Mon Mar 16 10:10:20 2015 @@ -58,13 +58,14 @@ construct_auth_baton(svn_auth_baton_t ** const char *config_dir, apr_pool_t *pool) { - SVN_ERR(svn_cmdline_create_auth_baton(auth_baton_p, - TRUE /* non_interactive */, - "jrandom", "rayjandom", - config_dir, - TRUE /* no_auth_cache */, - FALSE /* trust_server_cert */, - NULL, NULL, NULL, pool)); + SVN_ERR(svn_cmdline_create_auth_baton2(auth_baton_p, + TRUE /* non_interactive */, + "jrandom", "rayjandom", + config_dir, + TRUE /* no_auth_cache */, + FALSE /* trust_server_cert */, + FALSE, FALSE, FALSE, FALSE, + NULL, NULL, NULL, pool)); return SVN_NO_ERROR; } Modified: subversion/branches/move-tracking-2/subversion/tests/cmdline/authz_tests.py URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/tests/cmdline/authz_tests.py?rev=1666947&r1=1666946&r2=1666947&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/tests/cmdline/authz_tests.py (original) +++ subversion/branches/move-tracking-2/subversion/tests/cmdline/authz_tests.py Mon Mar 16 10:10:20 2015 @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# authz_tests.py: testing authentication. +# authz_tests.py: testing authorization. # # Subversion is a tool for revision control. # See http://subversion.apache.org for more information. Modified: subversion/branches/move-tracking-2/subversion/tests/cmdline/basic_tests.py URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/tests/cmdline/basic_tests.py?rev=1666947&r1=1666946&r2=1666947&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/tests/cmdline/basic_tests.py (original) +++ subversion/branches/move-tracking-2/subversion/tests/cmdline/basic_tests.py Mon Mar 16 10:10:20 2015 @@ -3073,6 +3073,47 @@ def mkdir_parents_target_exists_on_disk( svntest.actions.run_and_verify_status(wc_dir, expected_status) +@Skip(svntest.main.is_ra_type_file) +def plaintext_password_storage_disabled(sbox): + "test store-plaintext-passwords = no" + + sbox.build() + + wc_dir = sbox.wc_dir + sbox.simple_append("iota", "New content for iota.") + + config_dir_path = sbox.get_tempname(prefix="config-dir") + os.mkdir(config_dir_path) + + # disable all encryped password stores + config_file = file(os.path.join(config_dir_path, "config"), "w") + config_file.write("[auth]\npassword-stores =\n") + config_file.close() + + # disable plaintext password storage + servers_file = file(os.path.join(config_dir_path, "servers"), "w") + servers_file.write("[global]\nstore-plaintext-passwords=no\n") + servers_file.close() + + svntest.main.run_command(svntest.main.svn_binary, False, False, + "commit", "--config-dir", config_dir_path, + "-m", "committing with plaintext password storage disabled", + "--username", svntest.main.wc_author, + "--password", svntest.main.wc_passwd, + "--non-interactive", wc_dir) + + # Verify that the password was not stored in plaintext + for root, dirs, files, in os.walk(os.path.join(config_dir_path, "auth")): + for file_name in files: + path = os.path.join(root, file_name) + f = file(path, "r") + for line in f.readlines(): + if svntest.main.wc_passwd in line: + f.close() + raise svntest.Failure("password was found in '%s'" % path) + f.close() + + ######################################################################## # Run the tests @@ -3142,6 +3183,7 @@ test_list = [ None, delete_conflicts_one_of_many, peg_rev_on_non_existent_wc_path, mkdir_parents_target_exists_on_disk, + plaintext_password_storage_disabled, ] if __name__ == '__main__': Modified: subversion/branches/move-tracking-2/subversion/tests/cmdline/davautocheck.sh URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/tests/cmdline/davautocheck.sh?rev=1666947&r1=1666946&r2=1666947&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/tests/cmdline/davautocheck.sh (original) +++ subversion/branches/move-tracking-2/subversion/tests/cmdline/davautocheck.sh Mon Mar 16 10:10:20 2015 @@ -596,12 +596,7 @@ if [ $# -eq 1 ] && [ "x$1" = 'x--gdb' ]; exit fi - -if type time > /dev/null; then - TIME_CMD=time -else - TIME_CMD="" -fi +if type time > /dev/null ; then TIME_CMD() { time "$@"; } ; else TIME_CMD() { "$@"; } ; fi MAKE=${MAKE:-make} @@ -620,13 +615,13 @@ else fi if [ $# = 0 ]; then - $TIME_CMD "$MAKE" check "BASE_URL=$BASE_URL" $SSL_MAKE_VAR + TIME_CMD "$MAKE" check "BASE_URL=$BASE_URL" $SSL_MAKE_VAR r=$? else (cd "$ABS_BUILDDIR/subversion/tests/cmdline/" TEST="$1" shift - $TIME_CMD "$ABS_SRCDIR/subversion/tests/cmdline/${TEST}_tests.py" "--url=$BASE_URL" $SSL_TEST_ARG "$@") + TIME_CMD "$ABS_SRCDIR/subversion/tests/cmdline/${TEST}_tests.py" "--url=$BASE_URL" $SSL_TEST_ARG "$@") r=$? fi Modified: subversion/branches/move-tracking-2/subversion/tests/cmdline/externals_tests.py URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/tests/cmdline/externals_tests.py?rev=1666947&r1=1666946&r2=1666947&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/tests/cmdline/externals_tests.py (original) +++ subversion/branches/move-tracking-2/subversion/tests/cmdline/externals_tests.py Mon Mar 16 10:10:20 2015 @@ -3849,8 +3849,8 @@ def copy_pin_externals_wc_mixed_revision '--pin-externals') @Issue(4558) -def copy_pin_externals_whitepace_dir(sbox): - "copy --pin-externals with whitepace dir" +def copy_pin_externals_whitespace_dir(sbox): + "copy --pin-externals with whitespace dir" sbox.build(empty=True) repo_url = sbox.repo_url @@ -4226,7 +4226,7 @@ test_list = [ None, copy_pin_externals_wc_local_mods, copy_pin_externals_wc_switched_subtrees, copy_pin_externals_wc_mixed_revisions, - copy_pin_externals_whitepace_dir, + copy_pin_externals_whitespace_dir, nested_notification, file_external_to_normal_file, ] Modified: subversion/branches/move-tracking-2/subversion/tests/cmdline/merge_tree_conflict_tests.py URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/tests/cmdline/merge_tree_conflict_tests.py?rev=1666947&r1=1666946&r2=1666947&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/tests/cmdline/merge_tree_conflict_tests.py (original) +++ subversion/branches/move-tracking-2/subversion/tests/cmdline/merge_tree_conflict_tests.py Mon Mar 16 10:10:20 2015 @@ -2087,6 +2087,116 @@ def merge_conflict_details(sbox): svntest.actions.run_and_verify_info(expected_info, sbox.ospath('B'), '--depth', 'infinity') +def merge_obstruction_recording(sbox): + "merge obstruction recording" + + sbox.build(empty=True) + wc_dir = sbox.wc_dir + + sbox.simple_mkdir('trunk') + sbox.simple_mkdir('branches') + sbox.simple_commit() #r1 + + svntest.actions.run_and_verify_svn(None, [], + 'copy', sbox.repo_url + '/trunk', + sbox.repo_url + '/branches/branch', + '-mCopy') # r2 + + sbox.simple_mkdir('trunk/dir') + sbox.simple_add_text('The file on trunk\n', 'trunk/dir/file.txt') + sbox.simple_commit() #r3 + + sbox.simple_update() + + sbox.simple_mkdir('branches/branch/dir') + sbox.simple_add_text('The file on branch\n', 'branches/branch/dir/file.txt') + sbox.simple_commit() #r4 + + sbox.simple_update() + + svntest.actions.run_and_verify_svn(None, [], + 'switch', '^/branches/branch', wc_dir, + '--ignore-ancestry') + + expected_output = wc.State(wc_dir, { + 'dir' : Item(status=' ', treeconflict='C'), + 'dir/file.txt' : Item(status=' ', treeconflict='A'), + }) + expected_mergeinfo_output = wc.State(wc_dir, { + '' : Item(status=' U'), + 'dir' : Item(status=' U'), # Because dir already exists + }) + expected_elision_output = wc.State(wc_dir, { + }) + expected_disk = wc.State('', { + 'dir/file.txt' : Item(contents="The file on branch\n"), + 'dir' : Item(props={'svn:mergeinfo':''}), + '.' : Item(props={'svn:mergeinfo':'/trunk:2-4'}), + }) + expected_status = wc.State(wc_dir, { + '' : Item(status=' M', wc_rev='4'), + 'dir' : Item(status=' M', treeconflict='C', wc_rev='4'), + 'dir/file.txt' : Item(status=' ', wc_rev='4'), + }) + expected_skip = wc.State('', { + }) + svntest.actions.run_and_verify_merge(wc_dir, '1', '4', sbox.repo_url + '/trunk', + None, + expected_output, + expected_mergeinfo_output, + expected_elision_output, + expected_disk, + expected_status, + expected_skip, + check_props=True) + expected_info = [ + { + "Path" : re.escape(sbox.ospath('dir')), + "Tree conflict": re.escape( + 'local dir obstruction, incoming dir add upon merge' + + ' Source left: (none) ^/trunk/dir@1' + + ' Source right: (dir) ^/trunk/dir@4') + }, + ] + + svntest.actions.run_and_verify_info(expected_info, sbox.ospath('dir')) + + # How should the user handle this conflict? + # ### Would be nice if we could just accept mine (leave as is, fix mergeinfo) + # ### or accept theirs (delete what is here and insert copy + svntest.actions.run_and_verify_svn(None, [], + 'resolve', '--accept=working', + sbox.ospath('dir')) + + # Redo the skipped merge as record only merge + expected_output = [ + '--- Recording mergeinfo for merge of r4 into \'%s\':\n' % \ + sbox.ospath('dir'), + ' G %s\n' % sbox.ospath('dir'), + ] + # ### Why are r1-r3 not recorded? + # ### Guess: Because dir's history only exists since r4. + svntest.actions.run_and_verify_svn(expected_output, [], + 'merge', '--record-only', + sbox.repo_url + '/trunk/dir', + sbox.ospath('dir'), + '-c', '1-4') + + expected_disk = wc.State('', { + 'dir' : Item(props={'svn:mergeinfo':'/trunk/dir:4'}), + 'dir/file.txt' : Item(contents="The file on branch\n"), + '.' : Item(props={'svn:mergeinfo':'/trunk:2-4'}), + }) + svntest.actions.verify_disk(wc_dir, expected_disk, check_props=True) + + # Because r1-r3 are not recorded, the mergeinfo is not elided :( + + # Even something like a two url merge wouldn't work, because dir + # didn't exist below trunk in r1 either. + + # A resolver action could be smarter though... + + ######################################################################## # Run the tests @@ -2118,6 +2228,7 @@ test_list = [ None, merge_replace_causes_tree_conflict2, merge_replace_on_del_fails, merge_conflict_details, + merge_obstruction_recording, ] if __name__ == '__main__': Modified: subversion/branches/move-tracking-2/subversion/tests/cmdline/move_tests.py URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/tests/cmdline/move_tests.py?rev=1666947&r1=1666946&r2=1666947&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/tests/cmdline/move_tests.py (original) +++ subversion/branches/move-tracking-2/subversion/tests/cmdline/move_tests.py Mon Mar 16 10:10:20 2015 @@ -1694,6 +1694,75 @@ def move_conflict_details(sbox): svntest.actions.run_and_verify_info(expected_info, sbox.ospath('B'), '--depth', 'infinity') +def move_conflict_markers(sbox): + "move conflict markers" + + sbox.build() + wc_dir = sbox.wc_dir + sbox.simple_propset('key','val', 'iota', 'A/B/E', 'A/B/E/beta') + sbox.simple_commit() + sbox.simple_update('', 1) + sbox.simple_propset('key','false', 'iota', 'A/B/E', 'A/B/E/beta') + + expected_output = svntest.wc.State(wc_dir, { + 'A/B/E' : Item(status=' C'), + 'A/B/E/beta' : Item(status=' C'), + 'iota' : Item(status=' C'), + }) + expected_status = svntest.actions.get_virginal_state(wc_dir, 2) + expected_status.tweak('iota', 'A/B/E', 'A/B/E/beta', status=' C') + expected_disk = svntest.main.greek_state.copy() + expected_disk.add({ + 'A/B/E/dir_conflicts.prej' : Item(contents= + "Trying to add new property 'key'\n" + "but the property already exists.\n" + "<<<<<<< (local property value)\n" + "false||||||| (incoming 'changed from' value)\n" + "=======\n" + "val>>>>>>> (incoming 'changed to' value)\n"), + 'A/B/E/beta.prej' : Item(contents= + "Trying to add new property 'key'\n" + "but the property already exists.\n" + "<<<<<<< (local property value)\n" + "false||||||| (incoming 'changed from' value)\n" + "=======\n" + "val>>>>>>> (incoming 'changed to' value)\n"), + 'iota.prej' : Item(contents= + "Trying to add new property 'key'\n" + "but the property already exists.\n" + "<<<<<<< (local property value)\n" + "false||||||| (incoming 'changed from' value)\n" + "=======\n" + "val>>>>>>> (incoming 'changed to' value)\n"), + }) + svntest.actions.run_and_verify_update(wc_dir, + expected_output, + expected_disk, + expected_status) + + sbox.simple_move('iota', 'A/iotb') + sbox.simple_move('A/B/E', 'E') + + expected_status.tweak('iota', status='D ', moved_to='A/iotb') + expected_status.tweak('A/B/E', status='D ', moved_to='E') + expected_status.tweak('A/B/E/alpha', 'A/B/E/beta', status='D ') + expected_status.add({ + 'A/iotb' : Item(status='A ', copied='+', moved_from='iota', wc_rev='-'), + 'E' : Item(status='A ', copied='+', moved_from='A/B/E', wc_rev='-'), + 'E/beta' : Item(status=' M', copied='+', wc_rev='-'), + 'E/alpha' : Item(status=' ', copied='+', wc_rev='-'), + }) + expected_disk.remove('iota', 'iota.prej', + 'A/B/E', 'A/B/E/alpha', 'A/B/E/beta', + 'A/B/E/dir_conflicts.prej', + 'A/B/E/beta.prej') + expected_disk.add({ + 'A/iotb' : Item(contents="This is the file 'iota'.\n"), + 'E/beta' : Item(contents="This is the file 'beta'.\n"), + 'E/alpha' : Item(contents="This is the file 'alpha'.\n"), + }) + svntest.actions.run_and_verify_status(wc_dir, expected_status) + svntest.actions.verify_disk(wc_dir, expected_disk) ####################################################################### # Run the tests @@ -1714,6 +1783,7 @@ test_list = [ None, move_to_from_external, revert_del_root_of_move, move_conflict_details, + move_conflict_markers, ] if __name__ == '__main__': Modified: subversion/branches/move-tracking-2/subversion/tests/cmdline/patch_tests.py URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/tests/cmdline/patch_tests.py?rev=1666947&r1=1666946&r2=1666947&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/tests/cmdline/patch_tests.py (original) +++ subversion/branches/move-tracking-2/subversion/tests/cmdline/patch_tests.py Mon Mar 16 10:10:20 2015 @@ -5437,6 +5437,189 @@ def patch_closest(sbox): expected_output, expected_disk, expected_status, expected_skip) +@SkipUnless(svntest.main.is_posix_os) +def patch_symlink_traversal(sbox): + """symlink traversal behaviour""" + + sbox.build(read_only=True) + wc_dir = sbox.wc_dir + alpha_contents = "This is the file 'alpha'.\n" + + # A/B/E/unversioned -> alpha + # A/B/E/versioned -> alpha + # A/B/unversioned -> E (so A/B/unversioned/alpha is A/B/E/alpha) + # A/B/versioned -> E (so A/B/versioned/alpha is A/B/E/alpha) + os.symlink('alpha', sbox.ospath('A/B/E/unversioned')) + os.symlink('alpha', sbox.ospath('A/B/E/versioned')) + os.symlink('E', sbox.ospath('A/B/unversioned')) + os.symlink('E', sbox.ospath('A/B/versioned')) + sbox.simple_add('A/B/E/versioned', 'A/B/versioned') + + prepatch_status = svntest.actions.get_virginal_state(wc_dir, 1) + prepatch_status.add({'A/B/E/versioned' : Item(status='A ', wc_rev='-')}) + prepatch_status.add({'A/B/versioned' : Item(status='A ', wc_rev='-')}) + svntest.actions.run_and_verify_status(wc_dir, prepatch_status) + + # Patch through unversioned symlink to file + unidiff_patch = ( + "Index: A/B/E/unversioned\n" + "===================================================================\n" + "--- A/B/E/unversioned\t(revision 2)\n" + "+++ A/B/E/unversioned\t(working copy)\n" + "@@ -1 +1,2 @@\n" + " This is the file 'alpha'.\n" + "+xx\n" + ) + patch_file_path = make_patch_path(sbox) + svntest.main.file_write(patch_file_path, unidiff_patch) + + expected_output = [ + 'Skipped missing target: \'%s\'\n' % sbox.ospath('A/B/E/unversioned'), + ] + svntest.main.summary_of_conflicts(skipped_paths=1) + expected_disk = svntest.main.greek_state.copy() + expected_disk.add({'A/B/E/unversioned' : Item(contents=alpha_contents)}) + expected_disk.add({'A/B/E/versioned' : Item(contents=alpha_contents)}) + expected_disk.add({'A/B/unversioned' : Item()}) + expected_disk.add({'A/B/versioned' : Item()}) + expected_status = svntest.actions.get_virginal_state(wc_dir, 1) + expected_status.add({'A/B/E/versioned' : Item(status='A ', wc_rev='-')}) + expected_status.add({'A/B/versioned' : Item(status='A ', wc_rev='-')}) + expected_skip = wc.State('', { + sbox.ospath('A/B/E/unversioned') : Item(verb='Skipped missing target'), + }) + svntest.actions.run_and_verify_patch(wc_dir, os.path.abspath(patch_file_path), + expected_output, expected_disk, + expected_status, expected_skip) + svntest.actions.run_and_verify_status(wc_dir, prepatch_status) + + # Patch through versioned symlink to file + unidiff_patch = ( + "Index: A/B/E/versioned\n" + "===================================================================\n" + "--- A/B/E/versioned\t(revision 2)\n" + "+++ A/B/E/versioned\t(working copy)\n" + "@@ -1 +1,2 @@\n" + " This is the file 'alpha'.\n" + "+xx\n" + ) + patch_file_path = make_patch_path(sbox) + svntest.main.file_write(patch_file_path, unidiff_patch) + reject_contents = ( + "--- A/B/E/versioned\n" + "+++ A/B/E/versioned\n" + "@@ -1,1 +1,2 @@\n" + " This is the file 'alpha'.\n" + "+xx\n" + ) + + expected_output = [ + 'C %s\n' % sbox.ospath('A/B/E/versioned'), + '> rejected hunk @@ -1,1 +1,2 @@\n', + ] + svntest.main.summary_of_conflicts(text_conflicts=1) + expected_disk.add({'A/B/E/versioned.svnpatch.rej' + : Item(contents=reject_contents)}) + expected_skip = wc.State('', { }) + svntest.actions.run_and_verify_patch(wc_dir, os.path.abspath(patch_file_path), + expected_output, expected_disk, + expected_status, expected_skip) + os.remove(sbox.ospath('A/B/E/versioned.svnpatch.rej')) + expected_disk.remove('A/B/E/versioned.svnpatch.rej') + svntest.actions.run_and_verify_status(wc_dir, prepatch_status) + + # Patch through unversioned symlink to parent of file + unidiff_patch = ( + "Index: A/B/unversioned/alpha\n" + "===================================================================\n" + "--- A/B/unversioned/alpha\t(revision 2)\n" + "+++ A/B/unversioned/alpha\t(working copy)\n" + "@@ -1 +1,2 @@\n" + " This is the file 'alpha'.\n" + "+xx\n" + ) + patch_file_path = make_patch_path(sbox) + svntest.main.file_write(patch_file_path, unidiff_patch) + + expected_output = [ + 'Skipped missing target: \'%s\'\n' % sbox.ospath('A/B/unversioned/alpha'), + ] + svntest.main.summary_of_conflicts(skipped_paths=1) + expected_skip = wc.State('', { + sbox.ospath('A/B/unversioned/alpha') : Item(verb='Skipped missing target'), + }) + svntest.actions.run_and_verify_patch(wc_dir, os.path.abspath(patch_file_path), + expected_output, expected_disk, + expected_status, expected_skip) + svntest.actions.run_and_verify_status(wc_dir, prepatch_status) + + # Patch through versioned symlink to parent of file + unidiff_patch = ( + "Index: A/B/versioned/alpha\n" + "===================================================================\n" + "--- A/B/versioned/alpha\t(revision 2)\n" + "+++ A/B/versioned/alpha\t(working copy)\n" + "@@ -1 +1,2 @@\n" + " This is the file 'alpha'.\n" + "+xx\n" + ) + patch_file_path = make_patch_path(sbox) + svntest.main.file_write(patch_file_path, unidiff_patch) + + expected_output = [ + 'Skipped missing target: \'%s\'\n' % sbox.ospath('A/B/versioned/alpha'), + ] + svntest.main.summary_of_conflicts(skipped_paths=1) + expected_skip = wc.State('', { + sbox.ospath('A/B/versioned/alpha') : Item(verb='Skipped missing target'), + }) + svntest.actions.run_and_verify_patch(wc_dir, os.path.abspath(patch_file_path), + expected_output, expected_disk, + expected_status, expected_skip) + svntest.actions.run_and_verify_status(wc_dir, prepatch_status) + +@SkipUnless(svntest.main.is_posix_os) +def patch_obstructing_symlink_traversal(sbox): + """obstructing symlink traversal behaviour""" + + sbox.build() + wc_dir = sbox.wc_dir + alpha_contents = "This is the file 'alpha'.\n" + sbox.simple_append('A/B/F/alpha', alpha_contents) + sbox.simple_add('A/B/F/alpha') + sbox.simple_commit() + sbox.simple_update() + + # Unversioned symlink A/B/E -> F obstructing versioned A/B/E so + # versioned A/B/E/alpha is A/B/F/alpha + svntest.main.safe_rmtree(sbox.ospath('A/B/E')) + os.symlink('F', sbox.ospath('A/B/E')) + + unidiff_patch = ( + "Index: A/B/E/alpha\n" + "===================================================================\n" + "--- A/B/E/alpha\t(revision 2)\n" + "+++ A/B/E/alpha\t(working copy)\n" + "@@ -1 +1,2 @@\n" + " This is the file 'alpha'.\n" + "+xx\n" + ) + patch_file_path = make_patch_path(sbox) + svntest.main.file_write(patch_file_path, unidiff_patch) + + ### Patch applies through the unversioned symlink + expected_output = [ + 'U %s\n' % sbox.ospath('A/B/E/alpha'), + ] + expected_disk = svntest.main.greek_state.copy() + expected_disk.remove('A/B/E/alpha', 'A/B/E/beta') + expected_disk.add({'A/B/F/alpha' : Item(contents=alpha_contents+"xx\n")}) + expected_status = svntest.actions.get_virginal_state(wc_dir, 2) + expected_status.add({'A/B/F/alpha' : Item(status=' ', wc_rev=2)}) + expected_status.tweak('A/B/E', status='~ ') + expected_status.tweak('A/B/E/alpha', 'A/B/F/alpha', status='M ') + expected_status.tweak('A/B/E/beta', status='! ') + expected_skip = wc.State('', { }) + svntest.actions.run_and_verify_patch(wc_dir, os.path.abspath(patch_file_path), + expected_output, expected_disk, + expected_status, expected_skip) + ######################################################################## #Run the tests @@ -5496,6 +5679,8 @@ test_list = [ None, patch_hunk_overlap, patch_delete_modified, patch_closest, + patch_symlink_traversal, + patch_obstructing_symlink_traversal, ] if __name__ == '__main__': Modified: subversion/branches/move-tracking-2/subversion/tests/cmdline/prop_tests.py URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/tests/cmdline/prop_tests.py?rev=1666947&r1=1666946&r2=1666947&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/tests/cmdline/prop_tests.py (original) +++ subversion/branches/move-tracking-2/subversion/tests/cmdline/prop_tests.py Mon Mar 16 10:10:20 2015 @@ -2783,6 +2783,31 @@ def wc_propop_on_url(sbox): 'pg', 'my:Q', '-r', 'PREV', sbox.repo_url) +def prop_conflict_root(sbox): + """property conflict on wc root""" + + sbox.build() + wc_dir = sbox.wc_dir + + sbox.simple_propset('propname', 'propval1', '') + sbox.simple_commit() + sbox.simple_propset('propname', 'propval2', '') + sbox.simple_commit() + sbox.simple_update(revision=2) + sbox.simple_propset('propname', 'propvalconflict', '') + + expected_output = svntest.wc.State(wc_dir, { + '' : Item(status=' C'), + }) + expected_disk = svntest.main.greek_state.copy() + expected_status = svntest.actions.get_virginal_state(wc_dir, 3) + expected_status.tweak('', status=' C') + extra_files = ['dir_conflicts.prej'] + svntest.actions.run_and_verify_update(wc_dir, + expected_output, + expected_disk, + expected_status, + extra_files=extra_files) ######################################################################## # Run the tests @@ -2834,6 +2859,7 @@ test_list = [ None, dir_prop_conflict_details, iprops_list_abspath, wc_propop_on_url, + prop_conflict_root, ] if __name__ == '__main__': Modified: subversion/branches/move-tracking-2/subversion/tests/cmdline/svnserveautocheck.sh URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/tests/cmdline/svnserveautocheck.sh?rev=1666947&r1=1666946&r2=1666947&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/tests/cmdline/svnserveautocheck.sh (original) +++ subversion/branches/move-tracking-2/subversion/tests/cmdline/svnserveautocheck.sh Mon Mar 16 10:10:20 2015 @@ -92,11 +92,7 @@ random_port() { fi } -if type time > /dev/null; then - TIME_CMD=time -else - TIME_CMD="" -fi +if type time > /dev/null ; then TIME_CMD() { time "$@"; } ; else TIME_CMD() { "$@"; } ; fi MAKE=${MAKE:-make} @@ -121,13 +117,13 @@ fi BASE_URL=svn://127.0.0.1:$SVNSERVE_PORT if [ $# = 0 ]; then - $TIME_CMD "$MAKE" check "BASE_URL=$BASE_URL" + TIME_CMD "$MAKE" check "BASE_URL=$BASE_URL" r=$? else cd "$ABS_BUILDDIR/subversion/tests/cmdline/" TEST="$1" shift - $TIME_CMD "./${TEST}_tests.py" "--url=$BASE_URL" $* + TIME_CMD "./${TEST}_tests.py" "--url=$BASE_URL" $* r=$? cd - > /dev/null fi Modified: subversion/branches/move-tracking-2/subversion/tests/cmdline/svntest/main.py URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/tests/cmdline/svntest/main.py?rev=1666947&r1=1666946&r2=1666947&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/tests/cmdline/svntest/main.py (original) +++ subversion/branches/move-tracking-2/subversion/tests/cmdline/svntest/main.py Mon Mar 16 10:10:20 2015 @@ -1534,9 +1534,16 @@ def is_plaintext_password_storage_disabl # https://issues.apache.org/bugzilla/show_bug.cgi?id=56480 +# https://issues.apache.org/bugzilla/show_bug.cgi?id=55397 __mod_dav_url_quoting_broken_versions = frozenset([ + '2.2.27', '2.2.26', + '2.2.25', '2.4.9', + '2.4.8', + '2.4.7', + '2.4.6', + '2.4.5', ]) def is_mod_dav_url_quoting_broken(): if is_ra_type_dav(): Modified: subversion/branches/move-tracking-2/subversion/tests/cmdline/upgrade_tests.py URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/tests/cmdline/upgrade_tests.py?rev=1666947&r1=1666946&r2=1666947&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/tests/cmdline/upgrade_tests.py (original) +++ subversion/branches/move-tracking-2/subversion/tests/cmdline/upgrade_tests.py Mon Mar 16 10:10:20 2015 @@ -1448,9 +1448,14 @@ def auto_analyze(sbox): '52ec7e4b-e5f0-451d-829f-f05d5571b4ab') # Don't use svn to do relocate as that will add the table. - val = svntest.wc.sqlite_exec(sbox.wc_dir, - "update repository " - "set root ='" + sbox.repo_url + "'"); + svntest.wc.sqlite_exec(sbox.wc_dir, + "update repository " + "set root ='" + sbox.repo_url + "'") + val = svntest.wc.sqlite_stmt(sbox.wc_dir, + "select 1 from sqlite_master " + "where name = 'sqlite_stat1'") + if val != []: + raise svntest.Failure("initial state failed") # Make working copy read-only (but not wc_dir itself as # svntest.main.chmod_tree will not reset it.) Modified: subversion/branches/move-tracking-2/subversion/tests/cmdline/upgrade_tests_data/wc-without-stat1.tar.bz2 URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/tests/cmdline/upgrade_tests_data/wc-without-stat1.tar.bz2?rev=1666947&r1=1666946&r2=1666947&view=diff ============================================================================== Binary files - no diff available. Modified: subversion/branches/move-tracking-2/subversion/tests/libsvn_fs/fs-test.c URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/tests/libsvn_fs/fs-test.c?rev=1666947&r1=1666946&r2=1666947&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/tests/libsvn_fs/fs-test.c (original) +++ subversion/branches/move-tracking-2/subversion/tests/libsvn_fs/fs-test.c Mon Mar 16 10:10:20 2015 @@ -4339,6 +4339,195 @@ check_related(const svn_test_opts_t *opt static svn_error_t * +check_txn_related(const svn_test_opts_t *opts, + apr_pool_t *pool) +{ + apr_pool_t *subpool = svn_pool_create(pool); + svn_fs_t *fs; + svn_fs_txn_t *txn[3]; + svn_fs_root_t *root[3]; + svn_revnum_t youngest_rev = 0; + + /* Create a filesystem and repository. */ + SVN_ERR(svn_test__create_fs(&fs, "test-repo-check-related", + opts, pool)); + + /*** Step I: Build up some state in our repository through a series + of commits */ + + /* This is the node graph we are testing. It contains one revision (r1) + and two transactions, T1 and T2 - yet uncommitted. + + A is a file that exists in r1 (A-0) and gets modified in both txns. + C is a copy of A1 made in both txns. + B is a new node created in both txns + D is a file that exists in r1 (D-0) and never gets modified. + + +--A-0--+ D-0 + | | + +-----+ +-----+ + | | | | + B-1 C-T A-1 A-2 C-1 B-2 + */ + /* Revision 1 */ + SVN_ERR(svn_fs_begin_txn(&txn[0], fs, youngest_rev, subpool)); + SVN_ERR(svn_fs_txn_root(&root[0], txn[0], subpool)); + SVN_ERR(svn_fs_make_file(root[0], "A", subpool)); + SVN_ERR(svn_test__set_file_contents(root[0], "A", "1", subpool)); + SVN_ERR(svn_fs_make_file(root[0], "D", subpool)); + SVN_ERR(svn_fs_commit_txn(NULL, &youngest_rev, txn[0], subpool)); + SVN_TEST_ASSERT(SVN_IS_VALID_REVNUM(youngest_rev)); + svn_pool_clear(subpool); + SVN_ERR(svn_fs_revision_root(&root[0], fs, youngest_rev, pool)); + + /* Transaction 1 */ + SVN_ERR(svn_fs_begin_txn(&txn[1], fs, youngest_rev, pool)); + SVN_ERR(svn_fs_txn_root(&root[1], txn[1], pool)); + SVN_ERR(svn_test__set_file_contents(root[1], "A", "2", pool)); + SVN_ERR(svn_fs_copy(root[0], "A", root[1], "C", pool)); + SVN_ERR(svn_fs_make_file(root[1], "B", pool)); + + /* Transaction 2 */ + SVN_ERR(svn_fs_begin_txn(&txn[2], fs, youngest_rev, pool)); + SVN_ERR(svn_fs_txn_root(&root[2], txn[2], pool)); + SVN_ERR(svn_test__set_file_contents(root[2], "A", "2", pool)); + SVN_ERR(svn_fs_copy(root[0], "A", root[2], "C", pool)); + SVN_ERR(svn_fs_make_file(root[2], "B", pool)); + + /*** Step II: Exhaustively verify relationship between all nodes in + existence. */ + { + int i, j; + + struct path_rev_t + { + const char *path; + int root; + }; + + /* Our 16 existing files/revisions. */ + struct path_rev_t path_revs[8] = { + { "A", 0 }, { "A", 1 }, { "A", 2 }, + { "B", 1 }, { "B", 2 }, + { "C", 1 }, { "C", 2 }, + { "D", 0 } + }; + + int related_matrix[8][8] = { + /* A-0 ... D-0 across the top here*/ + { 1, 1, 1, 0, 0, 1, 1, 0 }, /* A-0 */ + { 1, 1, 1, 0, 0, 1, 1, 0 }, /* A-1 */ + { 1, 1, 1, 0, 0, 1, 1, 0 }, /* A-2 */ + { 0, 0, 0, 1, 0, 0, 0, 0 }, /* C-1 */ + { 0, 0, 0, 0, 1, 0, 0, 0 }, /* C-2 */ + { 1, 1, 1, 0, 0, 1, 1, 0 }, /* B-1 */ + { 1, 1, 1, 0, 0, 1, 1, 0 }, /* B-2 */ + { 0, 0, 0, 0, 0, 0, 0, 1 } /* D-0 */ + }; + + /* Here's the fun part. Running the tests. */ + for (i = 0; i < 8; i++) + { + for (j = 0; j < 8; j++) + { + struct path_rev_t pr1 = path_revs[i]; + struct path_rev_t pr2 = path_revs[j]; + const svn_fs_id_t *id1, *id2; + int related = 0; + svn_fs_node_relation_t relation; + + svn_pool_clear(subpool); + + /* Get the ID for the first path/revision combination. */ + SVN_ERR(svn_fs_node_id(&id1, root[pr1.root], pr1.path, subpool)); + + /* Get the ID for the second path/revision combination. */ + SVN_ERR(svn_fs_node_id(&id2, root[pr2.root], pr2.path, subpool)); + + /* Now, run the relationship check! */ + related = svn_fs_check_related(id1, id2) ? 1 : 0; + if (related == related_matrix[i][j]) + { + /* xlnt! */ + } + else if ((! related) && related_matrix[i][j]) + { + return svn_error_createf + (SVN_ERR_TEST_FAILED, NULL, + "expected '%s-%d' to be related to '%s-%d'; it was not", + pr1.path, pr1.root, pr2.path, pr2.root); + } + else if (related && (! related_matrix[i][j])) + { + return svn_error_createf + (SVN_ERR_TEST_FAILED, NULL, + "expected '%s-%d' to not be related to '%s-%d'; it was", + pr1.path, pr1.root, pr2.path, pr2.root); + } + + /* Asking directly, i.e. without involving the noderev IDs as + * an intermediate, should yield the same results. */ + SVN_ERR(svn_fs_node_relation(&relation, root[pr1.root], pr1.path, + root[pr2.root], pr2.path, subpool)); + if (i == j) + { + /* Identical note. */ + if (!related || relation != svn_fs_node_same) + { + return svn_error_createf + (SVN_ERR_TEST_FAILED, NULL, + "expected '%s-%d' to be the same as '%s-%d';" + " it was not", + pr1.path, pr1.root, pr2.path, pr2.root); + } + } + else if (related && relation != svn_fs_node_common_ancestor) + { + return svn_error_createf + (SVN_ERR_TEST_FAILED, NULL, + "expected '%s-%d' to have a common ancestor with '%s-%d';" + " it had not", + pr1.path, pr1.root, pr2.path, pr2.root); + } + else if (!related && relation != svn_fs_node_unrelated) + { + return svn_error_createf + (SVN_ERR_TEST_FAILED, NULL, + "expected '%s-%d' to not be related to '%s-%d'; it was", + pr1.path, pr1.root, pr2.path, pr2.root); + } + } /* for ... */ + } /* for ... */ + + /* Verify that the noderevs stay the same after their last change. + There is only D that is not changed. */ + for (i = 1; i <= 2; ++i) + { + svn_fs_node_relation_t relation; + svn_pool_clear(subpool); + + /* Query their noderev relationship to the latest change. */ + SVN_ERR(svn_fs_node_relation(&relation, root[i], "D", + root[0], "D", subpool)); + + /* They shall use the same noderevs */ + if (relation != svn_fs_node_same) + { + return svn_error_createf + (SVN_ERR_TEST_FAILED, NULL, + "expected 'D-%d' to be the same as 'D-0'; it was not", i); + } + } /* for ... */ + } + + /* Destroy the subpool. */ + svn_pool_destroy(subpool); + + return SVN_NO_ERROR; +} + + +static svn_error_t * branch_test(const svn_test_opts_t *opts, apr_pool_t *pool) { @@ -6915,6 +7104,8 @@ static struct svn_test_descriptor_t test "test property and text rep-sharing collision"), SVN_TEST_OPTS_PASS(test_internal_txn_props, "test setting and getting internal txn props"), + SVN_TEST_OPTS_PASS(check_txn_related, + "test svn_fs_check_related for transactions"), SVN_TEST_NULL };