Modified: subversion/branches/remove-log-addressing/subversion/include/svn_repos.h URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/include/svn_repos.h?rev=1658362&r1=1658361&r2=1658362&view=diff ============================================================================== --- subversion/branches/remove-log-addressing/subversion/include/svn_repos.h (original) +++ subversion/branches/remove-log-addressing/subversion/include/svn_repos.h Mon Feb 9 11:23:39 2015 @@ -287,7 +287,14 @@ typedef enum svn_repos_notify_warning_t * * @since New in 1.9. */ - svn_repos_notify_warning_mergeinfo_collision + svn_repos_notify_warning_mergeinfo_collision, + + /** + * Detected invalid mergeinfo. + * + * @since New in 1.9. + */ + svn_repos_notify_warning_invalid_mergeinfo } svn_repos_notify_warning_t; /** @@ -1491,10 +1498,9 @@ svn_repos_replay(svn_fs_root_t *root, * filesystem of @a repos, beginning at location 'rev:@a base_path', * where "rev" is the argument given to open_root(). * - * @a repos is a previously opened repository. @a repos_url is the + * @a repos is a previously opened repository. @a repos_url_decoded is the * decoded URL to the base of the repository, and is used to check - * copyfrom paths. copyfrom paths passed to the editor must be full, - * URI-encoded, URLs. @a txn is a filesystem transaction object to use + * copyfrom paths. @a txn is a filesystem transaction object to use * during the commit, or @c NULL to indicate that this function should * create (and fully manage) a new transaction. * @@ -1530,15 +1536,19 @@ svn_repos_replay(svn_fs_root_t *root, * * @since New in 1.5. * - * @note Yes, @a repos_url is a <em>decoded</em> URL. We realize + * @note Yes, @a repos_url_decoded is a <em>decoded</em> URL. We realize * that's sorta wonky. Sorry about that. + * + * @note Like most commit editors, the returned editor requires that the + * @c copyfrom_path parameter passed to its @c add_file and @c add_directory + * methods is a full, URI-encoded URL, not a relative path. */ svn_error_t * svn_repos_get_commit_editor5(const svn_delta_editor_t **editor, void **edit_baton, svn_repos_t *repos, svn_fs_txn_t *txn, - const char *repos_url, + const char *repos_url_decoded, const char *base_path, apr_hash_t *revprop_table, svn_commit_callback2_t commit_callback, @@ -3086,7 +3096,7 @@ svn_repos_load_fs5(svn_repos_t *repos, /** Similar to svn_repos_load_fs5(), but with @a ignore_dates * always passed as FALSE. * - * @since New in 1.9. + * @since New in 1.8. * @deprecated Provided for backward compatibility with the 1.8 API. */ SVN_DEPRECATED @@ -3333,20 +3343,65 @@ svn_repos_parse_dumpstream3(svn_stream_t * @a end_rev). They refer to dump stream revision numbers rather than * committed revision numbers. * - * If @a use_history is set, then the parser will require relative - * 'copyfrom' history to exist in the repository when it encounters - * nodes that are added-with-history. + * If @a use_history is true, then when the parser encounters a node that + * is added-with-history, it will require 'copy-from' history to exist in + * the repository at the relative (adjusted) copy-from revision and path. + * It will perform a copy from that source location, and will fail if no + * suitable source exists there. If @a use_history is false, then it will + * instead convert every copy to a plain add. + * + * ### The 'use_history=FALSE' case is unused and untested in Subversion. + * It seems to me it would not work with a deltas dumpfile (a driver + * that calls the @c apply_textdelta method), as it would not have + * access to the delta base text. + * + * If @a use_pre_commit_hook is set, call the repository's pre-commit + * hook before committing each loaded revision. + * + * If @a use_post_commit_hook is set, call the repository's + * post-commit hook after committing each loaded revision. * * If @a validate_props is set, then validate Subversion revision and * node properties (those in the svn: namespace) against established * rules for those things. * + * If @a ignore_dates is set, ignore any revision datestamps found in + * @a dumpstream, allowing the revisions created by the load process + * to be stamped as if they were newly created via the normal commit + * process. + * * If @a parent_dir is not NULL, then the parser will reparent all the * loaded nodes, from root to @a parent_dir. The directory @a parent_dir * must be an existing directory in the repository. * + * @since New in 1.9. + */ +svn_error_t * +svn_repos_get_fs_build_parser5(const svn_repos_parse_fns3_t **callbacks, + void **parse_baton, + svn_repos_t *repos, + svn_revnum_t start_rev, + svn_revnum_t end_rev, + svn_boolean_t use_history, + svn_boolean_t validate_props, + enum svn_repos_load_uuid uuid_action, + const char *parent_dir, + svn_boolean_t use_pre_commit_hook, + svn_boolean_t use_post_commit_hook, + svn_boolean_t ignore_dates, + svn_repos_notify_func_t notify_func, + void *notify_baton, + apr_pool_t *pool); + +/** + * Similar to svn_repos_get_fs_build_parser5(), but with the + * @c use_pre_commit_hook, @c use_post_commit_hook and @c ignore_dates + * arguments all false. + * * @since New in 1.8. + * @deprecated Provided for backward compatibility with the 1.8 API. */ +SVN_DEPRECATED svn_error_t * svn_repos_get_fs_build_parser4(const svn_repos_parse_fns3_t **parser, void **parse_baton,
Modified: subversion/branches/remove-log-addressing/subversion/include/svn_string.h URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/include/svn_string.h?rev=1658362&r1=1658361&r2=1658362&view=diff ============================================================================== --- subversion/branches/remove-log-addressing/subversion/include/svn_string.h (original) +++ subversion/branches/remove-log-addressing/subversion/include/svn_string.h Mon Feb 9 11:23:39 2015 @@ -170,7 +170,11 @@ svn_string_createv(apr_pool_t *pool, con svn_boolean_t svn_string_isempty(const svn_string_t *str); -/** Return a duplicate of @a original_string. */ +/** Return a duplicate of @a original_string. + * + * @since Since 1.9, @a original_string can be NULL in which case NULL will + * be returned. + */ svn_string_t * svn_string_dup(const svn_string_t *original_string, apr_pool_t *pool); @@ -308,7 +312,7 @@ void svn_stringbuf_appendbyte(svn_stringbuf_t *targetstr, char byte); -/** Append an array of bytes onto @a targetstr. +/** Append the array of bytes @a bytes of length @a count onto @a targetstr. * * reallocs if necessary. @a targetstr is affected, nothing else is. * @@ -345,14 +349,15 @@ void svn_stringbuf_appendcstr(svn_stringbuf_t *targetstr, const char *cstr); -/** Read @a count bytes from @a bytes and insert them into @a str at - * position @a pos and following. The resulting string will be - * @c count+str->len bytes long. If @c pos is larger or equal to the - * number of bytes currently used in @a str, simply append @a bytes. +/** Insert into @a str at position @a pos an array of bytes @a bytes + * which is @a count bytes long. + * + * The resulting string will be @c count+str->len bytes long. If + * @a pos is larger than or equal to @c str->len, simply append @a bytes. * * Reallocs if necessary. @a str is affected, nothing else is. * - * @note The inserted string may be a sub-range if @a str. + * @note The inserted string may be a sub-range of @a str. * * @since New in 1.8. * @@ -364,9 +369,10 @@ svn_stringbuf_insert(svn_stringbuf_t *st const char *bytes, apr_size_t count); -/** Removes @a count bytes from @a str, starting at position @a pos. - * If that range exceeds the current string data, @a str gets truncated - * at @a pos. If the latter is larger or equal to @c str->pos, this will +/** Remove @a count bytes from @a str, starting at position @a pos. + * + * If that range exceeds the current string data, truncate @a str at + * @a pos. If @a pos is larger than or equal to @c str->len, this will * be a no-op. Otherwise, the resulting string will be @c str->len-count * bytes long. * @@ -378,8 +384,8 @@ svn_stringbuf_remove(svn_stringbuf_t *st apr_size_t count); /** Replace in @a str the substring which starts at @a pos and is @a - * old_count bytes long with a new substring @a bytes (which is @a - * new_count bytes long). + * old_count bytes long with a new substring @a bytes which is @a + * new_count bytes long. * * This is faster but functionally equivalent to the following sequence: * @code Modified: subversion/branches/remove-log-addressing/subversion/include/svn_version.h URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/include/svn_version.h?rev=1658362&r1=1658361&r2=1658362&view=diff ============================================================================== --- subversion/branches/remove-log-addressing/subversion/include/svn_version.h (original) +++ subversion/branches/remove-log-addressing/subversion/include/svn_version.h Mon Feb 9 11:23:39 2015 @@ -82,7 +82,7 @@ extern "C" { /** Version tag: a string describing the version. * - * This tag remains " (dev build)" in the repository so that we can + * This tag remains " (under development)" in the repository so that we can * always see from "svn --version" that the software has been built * from the repository rather than a "blessed" distribution. * @@ -175,10 +175,25 @@ struct svn_version_t * Generate the implementation of a version query function. * * @since New in 1.1. + * @since Since 1.9, embeds a string into the compiled object + * file that can be queried with the 'what' utility. */ -#define SVN_VERSION_BODY \ - SVN_VERSION_DEFINE(versioninfo); \ - return &versioninfo +#define SVN_VERSION_BODY \ + static struct versioninfo_t \ + { \ + const char *const str; \ + const svn_version_t num; \ + } const versioninfo = \ + { \ + "@(#)" SVN_VERSION, \ + { \ + SVN_VER_MAJOR, \ + SVN_VER_MINOR, \ + SVN_VER_PATCH, \ + SVN_VER_NUMTAG \ + } \ + }; \ + return &versioninfo.num /** * Check library version compatibility. Return #TRUE if the client's @@ -291,6 +306,11 @@ typedef struct svn_version_extended_t sv * retrieve (for example, the OS release name, list of shared * libraries, etc.). Use @a pool for all allocations. * + * @note This function may allocate significant auxiliary resources + * (memory and file descriptors) in @a pool. It is recommended to + * copy the returned data to suitable longer-lived memory and clear + * @a pool after calling this function. + * * @since New in 1.8. */ const svn_version_extended_t * Modified: subversion/branches/remove-log-addressing/subversion/include/svn_wc.h URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/include/svn_wc.h?rev=1658362&r1=1658361&r2=1658362&view=diff ============================================================================== --- subversion/branches/remove-log-addressing/subversion/include/svn_wc.h (original) +++ subversion/branches/remove-log-addressing/subversion/include/svn_wc.h Mon Feb 9 11:23:39 2015 @@ -907,13 +907,15 @@ svn_wc_external_item_dup(const svn_wc_ex * * Allocate the table, keys, and values in @a pool. * - * Use @a parent_directory only in constructing error strings. + * @a defining_directory is the path or URL of the directory on which + * the svn:externals property corresponding to @a desc is set. + * @a defining_directory is only used when constructing error strings. * * @since New in 1.5. */ svn_error_t * svn_wc_parse_externals_description3(apr_array_header_t **externals_p, - const char *parent_directory, + const char *defining_directory, const char *desc, svn_boolean_t canonicalize_url, apr_pool_t *pool); @@ -7537,6 +7539,10 @@ svn_wc_relocate(const char *path, * If @a clear_changelists is TRUE, then changelist information for the * paths is cleared. * + * If @a metadata_only is TRUE, the working copy files are untouched, but + * if there are conflict marker files attached to these files these + * markers are removed. + * * If @a cancel_func is non-NULL, call it with @a cancel_baton at * various points during the reversion process. If it returns an * error (typically #SVN_ERR_CANCELLED), return that error @@ -7562,6 +7568,7 @@ svn_wc_revert5(svn_wc_context_t *wc_ctx, svn_boolean_t use_commit_times, const apr_array_header_t *changelist_filter, svn_boolean_t clear_changelists, + svn_boolean_t metadata_only, svn_cancel_func_t cancel_func, void *cancel_baton, svn_wc_notify_func2_t notify_func, @@ -7569,7 +7576,7 @@ svn_wc_revert5(svn_wc_context_t *wc_ctx, apr_pool_t *scratch_pool); /** Similar to svn_wc_revert5() but with @a clear_changelists always set to - * FALSE. + * FALSE and @a metadata_only set to FALSE. * * @since New in 1.7. * @deprecated Provided for backward compatibility with the 1.8 API. Modified: subversion/branches/remove-log-addressing/subversion/libsvn_client/add.c URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_client/add.c?rev=1658362&r1=1658361&r2=1658362&view=diff ============================================================================== --- subversion/branches/remove-log-addressing/subversion/libsvn_client/add.c (original) +++ subversion/branches/remove-log-addressing/subversion/libsvn_client/add.c Mon Feb 9 11:23:39 2015 @@ -1270,11 +1270,7 @@ svn_client__make_local_parents(const cha else SVN_ERR(svn_io_dir_make(local_abspath, APR_OS_DEFAULT, scratch_pool)); - /* Should no longer use svn_depth_empty to indicate that only the directory - itself is added, since it not only constraints the operation depth, but - also defines the depth of the target directory now. Moreover, the new - directory will have no children at all.*/ - err = svn_client_add5(local_abspath, svn_depth_infinity, FALSE, FALSE, FALSE, + err = svn_client_add5(local_abspath, svn_depth_empty, FALSE, FALSE, FALSE, make_parents, ctx, scratch_pool); /* If we created a new directory, but couldn't add it to version Modified: subversion/branches/remove-log-addressing/subversion/libsvn_client/client.h URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_client/client.h?rev=1658362&r1=1658361&r2=1658362&view=diff ============================================================================== --- subversion/branches/remove-log-addressing/subversion/libsvn_client/client.h (original) +++ subversion/branches/remove-log-addressing/subversion/libsvn_client/client.h Mon Feb 9 11:23:39 2015 @@ -45,6 +45,35 @@ extern "C" { #endif /* __cplusplus */ + +/* Private client context. + * + * This is what is actually allocated by svn_client_create_context2(), + * which then returns the address of the public_ctx member. */ +typedef struct svn_client__private_ctx_t +{ + /* Reserved field, always zero, to detect misuse of the private + context as a public client context. */ + apr_uint64_t magic_null; + + /* Reserved field, always set to a known magic number, to identify + this struct as the private client context. */ + apr_uint64_t magic_id; + + /* Total number of bytes transferred over network across all RA sessions. */ + apr_off_t total_progress; + + /* The public context. */ + svn_client_ctx_t public_ctx; +} svn_client__private_ctx_t; + + +/* Given a public client context CTX, return the private context + within which it is allocated. */ +svn_client__private_ctx_t * +svn_client__get_private_ctx(svn_client_ctx_t *ctx); + + /* Set *REVNUM to the revision number identified by REVISION. If REVISION->kind is svn_opt_revision_number, just use Modified: subversion/branches/remove-log-addressing/subversion/libsvn_client/copy.c URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_client/copy.c?rev=1658362&r1=1658361&r2=1658362&view=diff ============================================================================== --- subversion/branches/remove-log-addressing/subversion/libsvn_client/copy.c (original) +++ subversion/branches/remove-log-addressing/subversion/libsvn_client/copy.c Mon Feb 9 11:23:39 2015 @@ -1058,8 +1058,13 @@ repos_to_repos_copy(const apr_array_head SVN_ERR(svn_ra_check_path(ra_session, dst_rel, SVN_INVALID_REVNUM, &dst_kind, pool)); if (dst_kind != svn_node_none) - return svn_error_createf(SVN_ERR_FS_ALREADY_EXISTS, NULL, - _("Path '%s' already exists"), dst_rel); + { + const char *path = svn_uri_skip_ancestor(repos_root, + pair->dst_abspath_or_url, + pool); + return svn_error_createf(SVN_ERR_FS_ALREADY_EXISTS, NULL, + _("Path '/%s' already exists"), path); + } /* More info for our INFO structure. */ info->src_path = src_rel; @@ -1088,6 +1093,7 @@ repos_to_repos_copy(const apr_array_head item = svn_client_commit_item3_create(pool); item->url = svn_path_url_add_component2(top_url, relpath, pool); + item->kind = svn_node_dir; item->state_flags = SVN_CLIENT_COMMIT_ITEM_ADD; APR_ARRAY_PUSH(commit_items, svn_client_commit_item3_t *) = item; } @@ -1101,6 +1107,7 @@ repos_to_repos_copy(const apr_array_head item = svn_client_commit_item3_create(pool); item->url = svn_path_url_add_component2(top_url, info->dst_path, pool); + item->kind = info->src_kind; item->state_flags = SVN_CLIENT_COMMIT_ITEM_ADD | SVN_CLIENT_COMMIT_ITEM_IS_COPY; item->copyfrom_url = info->src_url; @@ -1112,6 +1119,7 @@ repos_to_repos_copy(const apr_array_head item = svn_client_commit_item3_create(pool); item->url = svn_path_url_add_component2(top_url, info->src_path, pool); + item->kind = info->src_kind; item->state_flags = SVN_CLIENT_COMMIT_ITEM_DELETE; APR_ARRAY_PUSH(commit_items, svn_client_commit_item3_t *) = item; } @@ -1342,52 +1350,6 @@ wc_to_repos_copy(const apr_array_header_ } } - if (SVN_CLIENT__HAS_LOG_MSG_FUNC(ctx)) - { - /* Produce a list of new paths to add, and provide it to the - mechanism used to acquire a log message. */ - svn_client_commit_item3_t *item; - const char *tmp_file; - commit_items = apr_array_make(scratch_pool, copy_pairs->nelts, - sizeof(item)); - - /* Add any intermediate directories to the message */ - if (make_parents) - { - for (i = 0; i < new_dirs->nelts; i++) - { - const char *url = APR_ARRAY_IDX(new_dirs, i, const char *); - - item = svn_client_commit_item3_create(scratch_pool); - item->url = url; - item->state_flags = SVN_CLIENT_COMMIT_ITEM_ADD; - APR_ARRAY_PUSH(commit_items, svn_client_commit_item3_t *) = item; - } - } - - for (i = 0; i < copy_pairs->nelts; i++) - { - svn_client__copy_pair_t *pair = APR_ARRAY_IDX(copy_pairs, i, - svn_client__copy_pair_t *); - - item = svn_client_commit_item3_create(scratch_pool); - item->url = pair->dst_abspath_or_url; - item->state_flags = SVN_CLIENT_COMMIT_ITEM_ADD; - APR_ARRAY_PUSH(commit_items, svn_client_commit_item3_t *) = item; - } - - SVN_ERR(svn_client__get_log_msg(&message, &tmp_file, commit_items, - ctx, scratch_pool)); - if (! message) - { - svn_pool_destroy(iterpool); - svn_pool_destroy(session_pool); - return SVN_NO_ERROR; - } - } - else - message = ""; - cukb.session = ra_session; SVN_ERR(svn_ra_get_repos_root2(ra_session, &cukb.repos_root_url, session_pool)); cukb.should_reparent = FALSE; @@ -1418,6 +1380,7 @@ wc_to_repos_copy(const apr_array_header_ item = svn_client_commit_item3_create(scratch_pool); item->url = url; + item->kind = svn_node_dir; item->state_flags = SVN_CLIENT_COMMIT_ITEM_ADD; item->incoming_prop_changes = apr_array_make(scratch_pool, 1, sizeof(svn_prop_t *)); @@ -1445,8 +1408,6 @@ wc_to_repos_copy(const apr_array_header_ /* Set the mergeinfo for the destination to the combined merge info known to the WC and the repository. */ - item->outgoing_prop_changes = apr_array_make(scratch_pool, 1, - sizeof(svn_prop_t *)); /* Repository mergeinfo (or NULL if it's locally added)... */ if (src_origin) SVN_ERR(svn_client__get_repos_mergeinfo( @@ -1463,18 +1424,24 @@ wc_to_repos_copy(const apr_array_header_ iterpool)); else if (! mergeinfo) mergeinfo = wc_mergeinfo; + if (mergeinfo) { /* Push a mergeinfo prop representing MERGEINFO onto the * OUTGOING_PROP_CHANGES array. */ svn_prop_t *mergeinfo_prop - = apr_palloc(item->outgoing_prop_changes->pool, - sizeof(svn_prop_t)); + = apr_palloc(scratch_pool, sizeof(*mergeinfo_prop)); svn_string_t *prop_value; SVN_ERR(svn_mergeinfo_to_string(&prop_value, mergeinfo, - item->outgoing_prop_changes->pool)); + scratch_pool)); + + if (!item->outgoing_prop_changes) + { + item->outgoing_prop_changes = apr_array_make(scratch_pool, 1, + sizeof(svn_prop_t *)); + } mergeinfo_prop->name = SVN_PROP_MERGEINFO; mergeinfo_prop->value = prop_value; @@ -1483,6 +1450,22 @@ wc_to_repos_copy(const apr_array_header_ } } + if (SVN_CLIENT__HAS_LOG_MSG_FUNC(ctx)) + { + const char *tmp_file; + + SVN_ERR(svn_client__get_log_msg(&message, &tmp_file, commit_items, + ctx, scratch_pool)); + if (! message) + { + svn_pool_destroy(iterpool); + svn_pool_destroy(session_pool); + return SVN_NO_ERROR; + } + } + else + message = ""; + /* Sort and condense our COMMIT_ITEMS. */ SVN_ERR(svn_client__condense_commit_items(&top_dst_url, commit_items, scratch_pool)); @@ -1997,7 +1980,7 @@ try_copy(svn_boolean_t *timestamp_sleep, { svn_client_copy_source_t *source = APR_ARRAY_IDX(sources, i, svn_client_copy_source_t *); - svn_client__copy_pair_t *pair = apr_palloc(pool, sizeof(*pair)); + svn_client__copy_pair_t *pair = apr_pcalloc(pool, sizeof(*pair)); const char *src_basename; svn_boolean_t src_is_url = svn_path_is_url(source->path); @@ -2019,6 +2002,7 @@ try_copy(svn_boolean_t *timestamp_sleep, pair->src_op_revision = *source->revision; pair->src_peg_revision = *source->peg_revision; + pair->src_kind = svn_node_unknown; SVN_ERR(svn_opt_resolve_revisions(&pair->src_peg_revision, &pair->src_op_revision, @@ -2047,7 +2031,7 @@ try_copy(svn_boolean_t *timestamp_sleep, else { /* Only one source path. */ - svn_client__copy_pair_t *pair = apr_palloc(pool, sizeof(*pair)); + svn_client__copy_pair_t *pair = apr_pcalloc(pool, sizeof(*pair)); svn_client_copy_source_t *source = APR_ARRAY_IDX(sources, 0, svn_client_copy_source_t *); svn_boolean_t src_is_url = svn_path_is_url(source->path); @@ -2059,6 +2043,7 @@ try_copy(svn_boolean_t *timestamp_sleep, source->path, pool)); pair->src_op_revision = *source->revision; pair->src_peg_revision = *source->peg_revision; + pair->src_kind = svn_node_unknown; SVN_ERR(svn_opt_resolve_revisions(&pair->src_peg_revision, &pair->src_op_revision, Modified: subversion/branches/remove-log-addressing/subversion/libsvn_client/ctx.c URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_client/ctx.c?rev=1658362&r1=1658361&r2=1658362&view=diff ============================================================================== --- subversion/branches/remove-log-addressing/subversion/libsvn_client/ctx.c (original) +++ subversion/branches/remove-log-addressing/subversion/libsvn_client/ctx.c Mon Feb 9 11:23:39 2015 @@ -27,6 +27,7 @@ /*** Includes. ***/ +#include <stddef.h> #include <apr_pools.h> #include "svn_hash.h" #include "svn_client.h" @@ -34,6 +35,8 @@ #include "private/svn_wc_private.h" +#include "client.h" + /*** Code. ***/ @@ -76,6 +79,20 @@ call_conflict_func(svn_wc_conflict_resul return SVN_NO_ERROR; } +/* The magic number in client_ctx_t.magic_id. */ +#define CLIENT_CTX_MAGIC APR_UINT64_C(0xDEADBEEF600DF00D) + +svn_client__private_ctx_t * +svn_client__get_private_ctx(svn_client_ctx_t *ctx) +{ + svn_client__private_ctx_t *const private_ctx = + (void*)((char *)ctx - offsetof(svn_client__private_ctx_t, public_ctx)); + SVN_ERR_ASSERT_NO_RETURN(&private_ctx->public_ctx == ctx); + SVN_ERR_ASSERT_NO_RETURN(0 == private_ctx->magic_null); + SVN_ERR_ASSERT_NO_RETURN(CLIENT_CTX_MAGIC == private_ctx->magic_id); + return private_ctx; +} + svn_error_t * svn_client_create_context2(svn_client_ctx_t **ctx, apr_hash_t *cfg_hash, @@ -83,23 +100,29 @@ svn_client_create_context2(svn_client_ct { svn_config_t *cfg_config; - *ctx = apr_pcalloc(pool, sizeof(svn_client_ctx_t)); + svn_client__private_ctx_t *const private_ctx = + apr_pcalloc(pool, sizeof(*private_ctx)); + svn_client_ctx_t *const public_ctx = &private_ctx->public_ctx; + + private_ctx->magic_null = 0; + private_ctx->magic_id = CLIENT_CTX_MAGIC; - (*ctx)->notify_func2 = call_notify_func; - (*ctx)->notify_baton2 = *ctx; + public_ctx->notify_func2 = call_notify_func; + public_ctx->notify_baton2 = public_ctx; - (*ctx)->conflict_func2 = call_conflict_func; - (*ctx)->conflict_baton2 = *ctx; + public_ctx->conflict_func2 = call_conflict_func; + public_ctx->conflict_baton2 = public_ctx; - (*ctx)->config = cfg_hash; + public_ctx->config = cfg_hash; if (cfg_hash) cfg_config = svn_hash_gets(cfg_hash, SVN_CONFIG_CATEGORY_CONFIG); else cfg_config = NULL; - SVN_ERR(svn_wc_context_create(&(*ctx)->wc_ctx, cfg_config, pool, - pool)); + SVN_ERR(svn_wc_context_create(&public_ctx->wc_ctx, cfg_config, + pool, pool)); + *ctx = public_ctx; return SVN_NO_ERROR; } Modified: subversion/branches/remove-log-addressing/subversion/libsvn_client/deprecated.c URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_client/deprecated.c?rev=1658362&r1=1658361&r2=1658362&view=diff ============================================================================== --- subversion/branches/remove-log-addressing/subversion/libsvn_client/deprecated.c (original) +++ subversion/branches/remove-log-addressing/subversion/libsvn_client/deprecated.c Mon Feb 9 11:23:39 2015 @@ -2821,6 +2821,7 @@ svn_client_revert2(const apr_array_heade depth, changelists, FALSE /* clear_changelists */, + FALSE /* metadata_only */, ctx, pool)); } @@ -2862,7 +2863,7 @@ svn_client_uuid_from_url(const char **uu /* destroy the RA session */ svn_pool_destroy(subpool); - return svn_error_trace(err);; + return svn_error_trace(err); } svn_error_t * Modified: subversion/branches/remove-log-addressing/subversion/libsvn_client/diff.c URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_client/diff.c?rev=1658362&r1=1658361&r2=1658362&view=diff ============================================================================== --- subversion/branches/remove-log-addressing/subversion/libsvn_client/diff.c (original) +++ subversion/branches/remove-log-addressing/subversion/libsvn_client/diff.c Mon Feb 9 11:23:39 2015 @@ -52,6 +52,7 @@ #include "private/svn_diff_private.h" #include "private/svn_subr_private.h" #include "private/svn_io_private.h" +#include "private/svn_ra_private.h" #include "svn_private_config.h" @@ -154,9 +155,6 @@ adjust_paths_for_diff_labels(const char new_path = "."; else return MAKE_ERR_BAD_RELATIVE_PATH(new_path, relative_to_dir); - - child_path = svn_dirent_is_child(relative_to_dir, new_path1, - result_pool); } { @@ -1808,8 +1806,8 @@ diff_repos_repos(const char **root_relpa /* Now, we open an extra RA session to the correct anchor location for URL1. This is used during the editor calls to fetch file contents. */ - SVN_ERR(svn_ra_dup_session(&extra_ra_session, ra_session, anchor1, - scratch_pool, scratch_pool)); + SVN_ERR(svn_ra__dup_session(&extra_ra_session, ra_session, anchor1, + scratch_pool, scratch_pool)); if (ddi) { Modified: subversion/branches/remove-log-addressing/subversion/libsvn_client/externals.c URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_client/externals.c?rev=1658362&r1=1658361&r2=1658362&view=diff ============================================================================== --- subversion/branches/remove-log-addressing/subversion/libsvn_client/externals.c (original) +++ subversion/branches/remove-log-addressing/subversion/libsvn_client/externals.c Mon Feb 9 11:23:39 2015 @@ -146,6 +146,7 @@ relegate_dir_external(svn_wc_context_t * static svn_error_t * switch_dir_external(const char *local_abspath, const char *url, + const char *url_from_externals_definition, const svn_opt_revision_t *peg_revision, const svn_opt_revision_t *revision, const char *defining_abspath, @@ -197,7 +198,16 @@ switch_dir_external(const char *local_ab SVN_ERR(svn_wc__get_wcroot(&defining_wcroot_abspath, ctx->wc_ctx, defining_abspath, pool, pool)); if (strcmp(wcroot_abspath, defining_wcroot_abspath) == 0) - return svn_error_create(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL, NULL); + return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL, + _("The external '%s' defined in %s at '%s' " + "cannot be checked out because '%s' is " + "already a versioned path."), + url_from_externals_definition, + SVN_PROP_EXTERNALS, + svn_dirent_local_style(defining_abspath, + pool), + svn_dirent_local_style(local_abspath, + pool)); } /* If path is a directory, try to update/switch to the correct URL @@ -379,14 +389,15 @@ switch_dir_external(const char *local_ab return SVN_NO_ERROR; } -/* Try to update a file external at LOCAL_ABSPATH to URL at REVISION using a - access baton that has a write lock. Use SCRATCH_POOL for temporary +/* Try to update a file external at LOCAL_ABSPATH to SWITCH_LOC. This function + assumes caller has a write lock in CTX. Use SCRATCH_POOL for temporary allocations, and use the client context CTX. */ static svn_error_t * switch_file_external(const char *local_abspath, - const char *url, - const svn_opt_revision_t *peg_revision, - const svn_opt_revision_t *revision, + const svn_client__pathrev_t *switch_loc, + const char *record_url, + const svn_opt_revision_t *record_peg_revision, + const svn_opt_revision_t *record_revision, const char *def_dir_abspath, svn_ra_session_t *ra_session, svn_client_ctx_t *ctx, @@ -463,7 +474,8 @@ switch_file_external(const char *local_a SVN_ERR_CLIENT_FILE_EXTERNAL_OVERWRITE_VERSIONED, 0, _("The file external from '%s' cannot overwrite the existing " "versioned item at '%s'"), - url, svn_dirent_local_style(local_abspath, scratch_pool)); + switch_loc->url, + svn_dirent_local_style(local_abspath, scratch_pool)); } } else @@ -485,25 +497,17 @@ switch_file_external(const char *local_a void *report_baton; const svn_delta_editor_t *switch_editor; void *switch_baton; - svn_client__pathrev_t *switch_loc; svn_revnum_t revnum; apr_array_header_t *inherited_props; - const char *dir_abspath; - const char *target; + const char *target = svn_dirent_basename(local_abspath, scratch_pool); - svn_dirent_split(&dir_abspath, &target, local_abspath, scratch_pool); - - /* Open an RA session to 'source' URL */ - SVN_ERR(svn_client__ra_session_from_path2(&ra_session, &switch_loc, - url, dir_abspath, - peg_revision, revision, - ctx, scratch_pool)); /* Get the external file's iprops. */ SVN_ERR(svn_ra_get_inherited_props(ra_session, &inherited_props, "", switch_loc->rev, scratch_pool, scratch_pool)); - SVN_ERR(svn_ra_reparent(ra_session, svn_uri_dirname(url, scratch_pool), + SVN_ERR(svn_ra_reparent(ra_session, + svn_uri_dirname(switch_loc->url, scratch_pool), scratch_pool)); SVN_ERR(svn_wc__get_file_external_editor(&switch_editor, &switch_baton, @@ -517,7 +521,9 @@ switch_file_external(const char *local_a use_commit_times, diff3_cmd, preserved_exts, def_dir_abspath, - url, peg_revision, revision, + record_url, + record_peg_revision, + record_revision, ctx->cancel_func, ctx->cancel_baton, ctx->notify_func2, @@ -528,7 +534,7 @@ switch_file_external(const char *local_a invalid revnum, that means RA will use the latest revision. */ SVN_ERR(svn_ra_do_switch3(ra_session, &reporter, &report_baton, switch_loc->rev, - target, svn_depth_unknown, url, + target, svn_depth_unknown, switch_loc->url, FALSE /* send_copyfrom */, TRUE /* ignore_ancestry */, switch_editor, switch_baton, @@ -741,6 +747,8 @@ handle_external_item_change(svn_client_c &(new_item->peg_revision), &(new_item->revision), ctx, scratch_pool)); + + SVN_ERR(svn_ra_reparent(ra_session, new_loc->url, scratch_pool)); } } @@ -794,6 +802,7 @@ handle_external_item_change(svn_client_c { case svn_node_dir: SVN_ERR(switch_dir_external(local_abspath, new_loc->url, + new_item->url, &(new_item->peg_revision), &(new_item->revision), parent_dir_abspath, @@ -855,6 +864,7 @@ handle_external_item_change(svn_client_c } SVN_ERR(switch_file_external(local_abspath, + new_loc, new_url, &new_item->peg_revision, &new_item->revision, @@ -1187,6 +1197,17 @@ svn_client__export_externals(apr_hash_t sub_iterpool), sub_iterpool)); + /* First notify that we're about to handle an external. */ + if (ctx->notify_func2) + { + ctx->notify_func2( + ctx->notify_baton2, + svn_wc_create_notify(item_abspath, + svn_wc_notify_update_external, + sub_iterpool), + sub_iterpool); + } + SVN_ERR(wrap_external_error( ctx, item_abspath, svn_client_export5(NULL, new_url, item_abspath, Modified: subversion/branches/remove-log-addressing/subversion/libsvn_client/import.c URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_client/import.c?rev=1658362&r1=1658361&r2=1658362&view=diff ============================================================================== --- subversion/branches/remove-log-addressing/subversion/libsvn_client/import.c (original) +++ subversion/branches/remove-log-addressing/subversion/libsvn_client/import.c Mon Feb 9 11:23:39 2015 @@ -832,6 +832,8 @@ svn_client_import5(const char *path, SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, scratch_pool)); + SVN_ERR(svn_io_check_path(local_abspath, &kind, scratch_pool)); + /* Create a new commit item and add it to the array. */ if (SVN_CLIENT__HAS_LOG_MSG_FUNC(ctx)) { @@ -845,6 +847,8 @@ svn_client_import5(const char *path, item = svn_client_commit_item3_create(scratch_pool); item->path = local_abspath; + item->url = url; + item->kind = kind; item->state_flags = SVN_CLIENT_COMMIT_ITEM_ADD; APR_ARRAY_PUSH(commit_items, svn_client_commit_item3_t *) = item; @@ -860,8 +864,6 @@ svn_client_import5(const char *path, } } - SVN_ERR(svn_io_check_path(local_abspath, &kind, scratch_pool)); - SVN_ERR(svn_client_open_ra_session2(&ra_session, url, NULL, ctx, scratch_pool, iterpool)); Modified: subversion/branches/remove-log-addressing/subversion/libsvn_client/info.c URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_client/info.c?rev=1658362&r1=1658361&r2=1658362&view=diff ============================================================================== --- subversion/branches/remove-log-addressing/subversion/libsvn_client/info.c (original) +++ subversion/branches/remove-log-addressing/subversion/libsvn_client/info.c Mon Feb 9 11:23:39 2015 @@ -388,8 +388,7 @@ svn_client_info4(const char *abspath_or_ SVN_ERR(svn_client__ra_session_from_path2(&ra_session, &pathrev, abspath_or_url, NULL, peg_revision, revision, ctx, pool)); - - svn_uri_split(NULL, &base_name, pathrev->url, pool); + base_name = svn_uri_basename(pathrev->url, pool); /* Get the dirent for the URL itself. */ SVN_ERR(svn_ra_stat(ra_session, "", pathrev->rev, &the_ent, pool)); Modified: subversion/branches/remove-log-addressing/subversion/libsvn_client/locking_commands.c URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_client/locking_commands.c?rev=1658362&r1=1658361&r2=1658362&view=diff ============================================================================== --- subversion/branches/remove-log-addressing/subversion/libsvn_client/locking_commands.c (original) +++ subversion/branches/remove-log-addressing/subversion/libsvn_client/locking_commands.c Mon Feb 9 11:23:39 2015 @@ -402,10 +402,9 @@ organize_lock_targets(apr_array_header_t _("Unable to lock/unlock across multiple " "repositories")); - /* Now we need to create a couple of different hash mappings. */ + /* Now we need to create our mapping. */ rel_fs_paths = apr_hash_make(result_pool); - target_urls = apr_array_make(scratch_pool, targets->nelts, - sizeof(const char *)); + for (hi = apr_hash_first(scratch_pool, wc_info); hi; hi = apr_hash_next(hi)) Modified: subversion/branches/remove-log-addressing/subversion/libsvn_client/log.c URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_client/log.c?rev=1658362&r1=1658361&r2=1658362&view=diff ============================================================================== --- subversion/branches/remove-log-addressing/subversion/libsvn_client/log.c (original) +++ subversion/branches/remove-log-addressing/subversion/libsvn_client/log.c Mon Feb 9 11:23:39 2015 @@ -852,10 +852,12 @@ svn_client_log5(const apr_array_header_t svn_ra_session_t *ra_session; const char *old_session_url; const char *ra_target; + const char *path_or_url; svn_opt_revision_t youngest_opt_rev; svn_revnum_t youngest_rev; svn_revnum_t oldest_rev; svn_opt_revision_t peg_rev; + svn_client__pathrev_t *ra_session_loc; svn_client__pathrev_t *actual_loc; apr_array_header_t *log_segments; apr_array_header_t *revision_ranges; @@ -875,7 +877,7 @@ svn_client_log5(const apr_array_header_t SVN_ERR(resolve_log_targets(&relative_targets, &ra_target, &peg_rev, targets, ctx, pool, pool)); - SVN_ERR(svn_client__ra_session_from_path2(&ra_session, NULL, + SVN_ERR(svn_client__ra_session_from_path2(&ra_session, &ra_session_loc, ra_target, NULL, &peg_rev, &peg_rev, ctx, pool)); @@ -889,11 +891,22 @@ svn_client_log5(const apr_array_header_t opt_rev_ranges, &peg_rev, ctx, pool, pool)); + /* For some peg revisions we must resolve revision and url via a local path + so use the original RA_TARGET. For others, use the potentially corrected + (redirected) ra session URL. */ + if (peg_rev.kind == svn_opt_revision_previous || + peg_rev.kind == svn_opt_revision_base || + peg_rev.kind == svn_opt_revision_committed || + peg_rev.kind == svn_opt_revision_working) + path_or_url = ra_target; + else + path_or_url = ra_session_loc->url; + /* Make ACTUAL_LOC and RA_SESSION point to the youngest operative rev. */ youngest_opt_rev.kind = svn_opt_revision_number; youngest_opt_rev.value.number = youngest_rev; SVN_ERR(svn_client__resolve_rev_and_url(&actual_loc, ra_session, - ra_target, &peg_rev, + path_or_url, &peg_rev, &youngest_opt_rev, ctx, pool)); SVN_ERR(svn_client__ensure_ra_session_url(&old_session_url, ra_session, actual_loc->url, pool)); Modified: subversion/branches/remove-log-addressing/subversion/libsvn_client/mergeinfo.c URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_client/mergeinfo.c?rev=1658362&r1=1658361&r2=1658362&view=diff ============================================================================== --- subversion/branches/remove-log-addressing/subversion/libsvn_client/mergeinfo.c (original) +++ subversion/branches/remove-log-addressing/subversion/libsvn_client/mergeinfo.c Mon Feb 9 11:23:39 2015 @@ -2130,7 +2130,7 @@ svn_client__mergeinfo_log(svn_boolean_t svn_rangelist__initialize(youngest_range->end - 1, youngest_range->end, youngest_range->inheritable, - scratch_pool);; + scratch_pool); for (hi = apr_hash_first(scratch_pool, source_history); hi; Modified: subversion/branches/remove-log-addressing/subversion/libsvn_client/mtcc.c URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_client/mtcc.c?rev=1658362&r1=1658361&r2=1658362&view=diff ============================================================================== --- subversion/branches/remove-log-addressing/subversion/libsvn_client/mtcc.c (original) +++ subversion/branches/remove-log-addressing/subversion/libsvn_client/mtcc.c Mon Feb 9 11:23:39 2015 @@ -337,7 +337,6 @@ svn_client__mtcc_create(svn_client__mtcc *mtcc = apr_pcalloc(mtcc_pool, sizeof(**mtcc)); (*mtcc)->pool = mtcc_pool; - (*mtcc)->base_revision = base_revision; (*mtcc)->root_op = mtcc_op_create(NULL, FALSE, TRUE, mtcc_pool); @@ -350,9 +349,12 @@ svn_client__mtcc_create(svn_client__mtcc SVN_ERR(svn_ra_get_latest_revnum((*mtcc)->ra_session, &(*mtcc)->head_revision, scratch_pool)); - if (! SVN_IS_VALID_REVNUM(base_revision)) - base_revision = (*mtcc)->head_revision; - else if (base_revision > (*mtcc)->head_revision) + if (SVN_IS_VALID_REVNUM(base_revision)) + (*mtcc)->base_revision = base_revision; + else + (*mtcc)->base_revision = (*mtcc)->head_revision; + + if ((*mtcc)->base_revision > (*mtcc)->head_revision) return svn_error_createf(SVN_ERR_FS_NO_SUCH_REVISION, NULL, _("No such revision %ld (HEAD is %ld)"), base_revision, (*mtcc)->head_revision); @@ -461,8 +463,8 @@ mtcc_verify_create(svn_client__mtcc_t *m return SVN_NO_ERROR; /* Node is explicitly deleted. We can replace */ } - /* mod_dav_svn allows overwriting existing directories. Let's hide that - for users of this api */ + /* mod_dav_svn used to allow overwriting existing directories. Let's hide + that for users of this api */ SVN_ERR(svn_client__mtcc_check_path(&kind, new_relpath, FALSE, mtcc, scratch_pool)); @@ -708,8 +710,7 @@ mtcc_prop_getter(const svn_string_t **mi if (! strcmp(mod->name, SVN_PROP_MIME_TYPE)) { - *mime_type = mod->value ? svn_string_dup(mod->value, pool) - : NULL; + *mime_type = svn_string_dup(mod->value, pool); mime_type = NULL; } } Modified: subversion/branches/remove-log-addressing/subversion/libsvn_client/patch.c URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_client/patch.c?rev=1658362&r1=1658361&r2=1658362&view=diff ============================================================================== --- subversion/branches/remove-log-addressing/subversion/libsvn_client/patch.c (original) +++ subversion/branches/remove-log-addressing/subversion/libsvn_client/patch.c Mon Feb 9 11:23:39 2015 @@ -48,6 +48,7 @@ #include "private/svn_dep_compat.h" #include "private/svn_string_private.h" #include "private/svn_subr_private.h" +#include "private/svn_sorts_private.h" typedef struct hunk_info_t { /* The hunk. */ @@ -1578,7 +1579,8 @@ match_existing_target(svn_boolean_t *mat /* Determine the line at which a HUNK applies to CONTENT of the TARGET * file, and return an appropriate hunk_info object in *HI, allocated from * RESULT_POOL. Use fuzz factor FUZZ. Set HI->FUZZ to FUZZ. If no correct - * line can be determined, set HI->REJECTED to TRUE. + * line can be determined, set HI->REJECTED to TRUE. PREVIOUS_OFFSET + * is the offset at which the previous matching hunk was applied, or zero. * IGNORE_WHITESPACE tells whether whitespace should be considered when * matching. IS_PROP_HUNK indicates whether the hunk patches file content * or a property. @@ -1590,6 +1592,7 @@ static svn_error_t * get_hunk_info(hunk_info_t **hi, patch_target_t *target, target_content_t *content, svn_diff_hunk_t *hunk, svn_linenum_t fuzz, + apr_int64_t previous_offset, svn_boolean_t ignore_whitespace, svn_boolean_t is_prop_hunk, svn_cancel_func_t cancel_func, void *cancel_baton, @@ -1599,7 +1602,7 @@ get_hunk_info(hunk_info_t **hi, patch_ta svn_linenum_t original_start; svn_boolean_t already_applied; - original_start = svn_diff_hunk_get_original_start(hunk); + original_start = svn_diff_hunk_get_original_start(hunk) + previous_offset; already_applied = FALSE; /* An original offset of zero means that this hunk wants to create @@ -1707,7 +1710,9 @@ get_hunk_info(hunk_info_t **hi, patch_ta modified_start = svn_diff_hunk_get_modified_start(hunk); if (modified_start == 0) { - /* Patch wants to delete the file. */ + /* Patch wants to delete the file. + + ### locally_deleted is always false here? */ already_applied = target->locally_deleted; } else @@ -1728,27 +1733,85 @@ get_hunk_info(hunk_info_t **hi, patch_ta if (! already_applied) { - /* Scan the whole file again from the start. */ - SVN_ERR(seek_to_line(content, 1, scratch_pool)); + int i; + svn_linenum_t search_start = 1, search_end = 0; + svn_linenum_t matched_line2; + + /* Search for closest match before or after original + start. We have no backward search so search forwards + from the previous match (or start of file) to the + original start looking for the last match. Then + search forwards from the original start looking for a + better match. Finally search forwards from the start + of file to the previous hunk if that could result in + a better match. */ + + for (i = content->hunks->nelts; i > 0; --i) + { + const hunk_info_t *prev + = APR_ARRAY_IDX(content->hunks, i - 1, const hunk_info_t *); + if (!prev->rejected) + { + svn_linenum_t length; + + length = svn_diff_hunk_get_original_length(prev->hunk); + search_start = prev->matched_line + length; + break; + } + } - /* Scan forward towards the hunk's line and look for a line - * where the hunk matches. */ + /* Search from the previous match, or start of file, + towards the original location. */ + SVN_ERR(seek_to_line(content, search_start, scratch_pool)); SVN_ERR(scan_for_match(&matched_line, content, hunk, FALSE, original_start, fuzz, ignore_whitespace, FALSE, cancel_func, cancel_baton, scratch_pool)); - /* In tie-break situations, we arbitrarily prefer early matches - * to save us from scanning the rest of the file. */ - if (matched_line == 0) + /* If a match we only need to search forwards for a + better match, otherwise to the end of the file. */ + if (matched_line) + search_end = original_start + (original_start - matched_line); + + /* Search from original location, towards the end. */ + SVN_ERR(seek_to_line(content, original_start + 1, scratch_pool)); + SVN_ERR(scan_for_match(&matched_line2, content, hunk, + TRUE, search_end, fuzz, ignore_whitespace, + FALSE, cancel_func, cancel_baton, + scratch_pool)); + + /* Chose the forward match if it is closer than the + backward match or if there is no backward match. */ + if (matched_line2 + && (!matched_line + || (matched_line2 - original_start + < original_start - matched_line))) + matched_line = matched_line2; + + /* Search from before previous hunk if there could be a + better match. */ + if (search_start > 1 + && (!matched_line + || (matched_line > original_start + && (matched_line - original_start + > original_start - search_start)))) { - /* Scan forward towards the end of the file and look - * for a line where the hunk matches. */ - SVN_ERR(scan_for_match(&matched_line, content, hunk, - TRUE, 0, fuzz, ignore_whitespace, - FALSE, cancel_func, cancel_baton, + svn_linenum_t search_start2 = 1; + + if (matched_line + && matched_line - original_start < original_start) + search_start2 + = original_start - (matched_line - original_start) + 1; + + SVN_ERR(seek_to_line(content, search_start2, scratch_pool)); + SVN_ERR(scan_for_match(&matched_line2, content, hunk, FALSE, + search_start - 1, fuzz, + ignore_whitespace, FALSE, + cancel_func, cancel_baton, scratch_pool)); + if (matched_line2) + matched_line = matched_line2; } } } @@ -2139,6 +2202,48 @@ send_patch_notification(const patch_targ return SVN_NO_ERROR; } +/* Implements the callback for svn_sort__array. Puts hunks that match + before hunks that do not match, puts hunks that match in order + based on postion matched, puts hunks that do not match in order + based on original position. */ +static int +sort_matched_hunks(const void *a, const void *b) +{ + const hunk_info_t *item1 = *((const hunk_info_t * const *)a); + const hunk_info_t *item2 = *((const hunk_info_t * const *)b); + svn_boolean_t matched1 = !item1->rejected && !item1->already_applied; + svn_boolean_t matched2 = !item2->rejected && !item2->already_applied; + svn_linenum_t original1, original2; + + if (matched1 && matched2) + { + /* Both match so use order matched in file. */ + if (item1->matched_line > item2->matched_line) + return 1; + else if (item1->matched_line == item2->matched_line) + return 0; + else + return -1; + } + else if (matched2) + /* Only second matches, put it before first. */ + return 1; + else if (matched1) + /* Only first matches, put it before second. */ + return -1; + + /* Neither matches, sort by original_start. */ + original1 = svn_diff_hunk_get_original_start(item1->hunk); + original2 = svn_diff_hunk_get_original_start(item2->hunk); + if (original1 > original2) + return 1; + else if (original1 == original2) + return 0; + else + return -1; +} + + /* Apply a PATCH to a working copy at ABS_WC_PATH and put the result * into temporary files, to be installed in the working copy later. * Return information about the patch target in *PATCH_TARGET, allocated @@ -2167,6 +2272,7 @@ apply_one_patch(patch_target_t **patch_t int i; static const svn_linenum_t MAX_FUZZ = 2; apr_hash_index_t *hash_index; + apr_int64_t previous_offset = 0; SVN_ERR(init_patch_target(&target, patch, abs_wc_path, wc_ctx, strip_count, remove_tempfiles, result_pool, scratch_pool)); @@ -2209,6 +2315,7 @@ apply_one_patch(patch_target_t **patch_t do { SVN_ERR(get_hunk_info(&hi, target, target->content, hunk, fuzz, + previous_offset, ignore_whitespace, FALSE /* is_prop_hunk */, cancel_func, cancel_baton, @@ -2217,9 +2324,17 @@ apply_one_patch(patch_target_t **patch_t } while (hi->rejected && fuzz <= MAX_FUZZ && ! hi->already_applied); + if (hi->matched_line) + previous_offset + = hi->matched_line - svn_diff_hunk_get_original_start(hunk); + APR_ARRAY_PUSH(target->content->hunks, hunk_info_t *) = hi; } + /* Hunks are applied in the order determined by the matched line and + this may be different from the order of the original lines. */ + svn_sort__array(target->content->hunks, sort_matched_hunks); + /* Apply or reject hunks. */ for (i = 0; i < target->content->hunks->nelts; i++) { @@ -2291,7 +2406,7 @@ apply_one_patch(patch_target_t **patch_t do { SVN_ERR(get_hunk_info(&hi, target, prop_target->content, - hunk, fuzz, + hunk, fuzz, 0, ignore_whitespace, TRUE /* is_prop_hunk */, cancel_func, cancel_baton, Modified: subversion/branches/remove-log-addressing/subversion/libsvn_client/prop_commands.c URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_client/prop_commands.c?rev=1658362&r1=1658361&r2=1658362&view=diff ============================================================================== --- subversion/branches/remove-log-addressing/subversion/libsvn_client/prop_commands.c (original) +++ subversion/branches/remove-log-addressing/subversion/libsvn_client/prop_commands.c Mon Feb 9 11:23:39 2015 @@ -206,6 +206,7 @@ propset_on_url(const char *propname, item = svn_client_commit_item3_create(pool); item->url = target; + item->kind = node_kind; item->state_flags = SVN_CLIENT_COMMIT_ITEM_PROP_MODS; APR_ARRAY_PUSH(commit_items, svn_client_commit_item3_t *) = item; SVN_ERR(svn_client__get_log_msg(&message, &tmp_file, commit_items, @@ -528,9 +529,10 @@ svn_client_revprop_set2(const char *prop /* Helper for the remote case of svn_client_propget. * - * If PROPS is not null, then get the value of property PROPNAME in REVNUM, - using RA_LIB and SESSION. Store the value ('svn_string_t *') in PROPS, - under the path key "TARGET_PREFIX/TARGET_RELATIVE" ('const char *'). + * If PROPS is not null, then get the value of property PROPNAME in + * REVNUM, using RA_SESSION. Store the value ('svn_string_t *') in + * PROPS, under the path key "TARGET_PREFIX/TARGET_RELATIVE" + * ('const char *'). * * If INHERITED_PROPS is not null, then set *INHERITED_PROPS to a * depth-first ordered array of svn_prop_inherited_item_t * structures Modified: subversion/branches/remove-log-addressing/subversion/libsvn_client/ra.c URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_client/ra.c?rev=1658362&r1=1658361&r2=1658362&view=diff ============================================================================== --- subversion/branches/remove-log-addressing/subversion/libsvn_client/ra.c (original) +++ subversion/branches/remove-log-addressing/subversion/libsvn_client/ra.c Mon Feb 9 11:23:39 2015 @@ -299,17 +299,20 @@ progress_func(apr_off_t progress, apr_pool_t *pool) { callback_baton_t *b = baton; - svn_client_ctx_t *ctx = b->ctx; + svn_client_ctx_t *public_ctx = b->ctx; + svn_client__private_ctx_t *private_ctx = + svn_client__get_private_ctx(public_ctx); - ctx->progress += (progress - b->last_progress); + private_ctx->total_progress += (progress - b->last_progress); b->last_progress = progress; - if (ctx->progress_func) + if (public_ctx->progress_func) { /* All RA implementations currently provide -1 for total. So it doesn't make sense to develop some complex logic to combine total across all RA sessions. */ - ctx->progress_func(ctx->progress, -1, ctx->progress_baton, pool); + public_ctx->progress_func(private_ctx->total_progress, -1, + public_ctx->progress_baton, pool); } } Modified: subversion/branches/remove-log-addressing/subversion/libsvn_client/repos_diff.c URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_client/repos_diff.c?rev=1658362&r1=1658361&r2=1658362&view=diff ============================================================================== --- subversion/branches/remove-log-addressing/subversion/libsvn_client/repos_diff.c (original) +++ subversion/branches/remove-log-addressing/subversion/libsvn_client/repos_diff.c Mon Feb 9 11:23:39 2015 @@ -389,6 +389,10 @@ remove_non_prop_changes(apr_hash_t *pris { int i; + /* For added nodes, there is nothing to filter. */ + if (apr_hash_count(pristine_props) == 0) + return; + for (i = 0; i < changes->nelts; i++) { svn_prop_t *change = &APR_ARRAY_IDX(changes, i, svn_prop_t); @@ -1162,7 +1166,7 @@ change_file_prop(void *file_baton, propchange = apr_array_push(fb->propchanges); propchange->name = apr_pstrdup(fb->pool, name); - propchange->value = value ? svn_string_dup(value, fb->pool) : NULL; + propchange->value = svn_string_dup(value, fb->pool); return SVN_NO_ERROR; } @@ -1192,7 +1196,7 @@ change_dir_prop(void *dir_baton, propchange = apr_array_push(db->propchanges); propchange->name = apr_pstrdup(db->pool, name); - propchange->value = value ? svn_string_dup(value, db->pool) : NULL; + propchange->value = svn_string_dup(value, db->pool); return SVN_NO_ERROR; } Modified: subversion/branches/remove-log-addressing/subversion/libsvn_client/revert.c URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_client/revert.c?rev=1658362&r1=1658361&r2=1658362&view=diff ============================================================================== --- subversion/branches/remove-log-addressing/subversion/libsvn_client/revert.c (original) +++ subversion/branches/remove-log-addressing/subversion/libsvn_client/revert.c Mon Feb 9 11:23:39 2015 @@ -50,6 +50,7 @@ struct revert_with_write_lock_baton { svn_boolean_t use_commit_times; const apr_array_header_t *changelists; svn_boolean_t clear_changelists; + svn_boolean_t metadata_only; svn_client_ctx_t *ctx; }; @@ -85,6 +86,7 @@ revert(void *baton, apr_pool_t *result_p b->use_commit_times, b->changelists, b->clear_changelists, + b->metadata_only, b->ctx->cancel_func, b->ctx->cancel_baton, b->ctx->notify_func2, b->ctx->notify_baton2, scratch_pool); @@ -98,11 +100,18 @@ revert(void *baton, apr_pool_t *result_p || err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND) { if (b->ctx->notify_func2) - b->ctx->notify_func2( - b->ctx->notify_baton2, - svn_wc_create_notify(b->local_abspath, svn_wc_notify_skip, - scratch_pool), - scratch_pool); + { + svn_wc_notify_t *notify; + + notify = svn_wc_create_notify(b->local_abspath, + svn_wc_notify_skip, + scratch_pool); + + notify->err = err; + + b->ctx->notify_func2(b->ctx->notify_baton2, + notify, scratch_pool); + } svn_error_clear(err); } else @@ -118,10 +127,11 @@ svn_client_revert3(const apr_array_heade svn_depth_t depth, const apr_array_header_t *changelists, svn_boolean_t clear_changelists, + svn_boolean_t metadata_only, svn_client_ctx_t *ctx, apr_pool_t *pool) { - apr_pool_t *subpool; + apr_pool_t *iterpool; svn_error_t *err = SVN_NO_ERROR; int i; svn_config_t *cfg; @@ -148,7 +158,7 @@ svn_client_revert3(const apr_array_heade SVN_CONFIG_OPTION_USE_COMMIT_TIMES, FALSE)); - subpool = svn_pool_create(pool); + iterpool = svn_pool_create(pool); for (i = 0; i < paths->nelts; i++) { @@ -156,14 +166,14 @@ svn_client_revert3(const apr_array_heade const char *local_abspath, *lock_target; svn_boolean_t wc_root; - svn_pool_clear(subpool); + svn_pool_clear(iterpool); /* See if we've been asked to cancel this operation. */ if ((ctx->cancel_func) && ((err = ctx->cancel_func(ctx->cancel_baton)))) goto errorful; - err = svn_dirent_get_absolute(&local_abspath, path, pool); + err = svn_dirent_get_absolute(&local_abspath, path, iterpool); if (err) goto errorful; @@ -172,15 +182,17 @@ svn_client_revert3(const apr_array_heade baton.use_commit_times = use_commit_times; baton.changelists = changelists; baton.clear_changelists = clear_changelists; + baton.metadata_only = metadata_only; baton.ctx = ctx; - err = svn_wc__is_wcroot(&wc_root, ctx->wc_ctx, local_abspath, pool); + err = svn_wc__is_wcroot(&wc_root, ctx->wc_ctx, local_abspath, iterpool); if (err) goto errorful; lock_target = wc_root ? local_abspath : svn_dirent_dirname(local_abspath, pool); err = svn_wc__call_with_write_lock(revert, &baton, ctx->wc_ctx, - lock_target, FALSE, pool, pool); + lock_target, FALSE, + iterpool, iterpool); if (err) goto errorful; } @@ -196,10 +208,10 @@ svn_client_revert3(const apr_array_heade if (paths->nelts == 1) sleep_path = APR_ARRAY_IDX(paths, 0, const char *); - svn_io_sleep_for_timestamps(sleep_path, subpool); + svn_io_sleep_for_timestamps(sleep_path, iterpool); } - svn_pool_destroy(subpool); + svn_pool_destroy(iterpool); return svn_error_trace(err); } Modified: subversion/branches/remove-log-addressing/subversion/libsvn_client/util.c URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_client/util.c?rev=1658362&r1=1658361&r2=1658362&view=diff ============================================================================== --- subversion/branches/remove-log-addressing/subversion/libsvn_client/util.c (original) +++ subversion/branches/remove-log-addressing/subversion/libsvn_client/util.c Mon Feb 9 11:23:39 2015 @@ -142,6 +142,7 @@ svn_client_commit_item3_create(apr_pool_ item->revision = SVN_INVALID_REVNUM; item->copyfrom_rev = SVN_INVALID_REVNUM; + item->kind = svn_node_unknown; return item; } Modified: subversion/branches/remove-log-addressing/subversion/libsvn_delta/path_driver.c URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_delta/path_driver.c?rev=1658362&r1=1658361&r2=1658362&view=diff ============================================================================== --- subversion/branches/remove-log-addressing/subversion/libsvn_delta/path_driver.c (original) +++ subversion/branches/remove-log-addressing/subversion/libsvn_delta/path_driver.c Mon Feb 9 11:23:39 2015 @@ -187,7 +187,7 @@ svn_delta_path_driver2(const svn_delta_e driving the editor. */ for (; i < paths->nelts; i++) { - const char *pdir, *bname; + const char *pdir; const char *common = ""; size_t common_len; @@ -224,9 +224,10 @@ svn_delta_path_driver2(const svn_delta_e /*** Step C - Open any directories between the common ancestor and the parent of the current path. ***/ if (*path == '/') - svn_fspath__split(&pdir, &bname, path, iterpool); + pdir = svn_fspath__dirname(path, iterpool); else - svn_relpath_split(&pdir, &bname, path, iterpool); + pdir = svn_relpath_dirname(path, iterpool); + if (strlen(pdir) > common_len) { const char *piece = pdir + common_len + 1; Modified: subversion/branches/remove-log-addressing/subversion/libsvn_diff/diff_file.c URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_diff/diff_file.c?rev=1658362&r1=1658361&r2=1658362&view=diff ============================================================================== --- subversion/branches/remove-log-addressing/subversion/libsvn_diff/diff_file.c (original) +++ subversion/branches/remove-log-addressing/subversion/libsvn_diff/diff_file.c Mon Feb 9 11:23:39 2015 @@ -544,7 +544,6 @@ find_identical_suffix(apr_off_t *suffix_ int suffix_lines_to_keep = SUFFIX_LINES_TO_KEEP; svn_boolean_t is_match; apr_off_t lines = 0; - svn_boolean_t had_cr; svn_boolean_t had_nl; apr_size_t i; @@ -685,7 +684,6 @@ find_identical_suffix(apr_off_t *suffix_ /* We skipped some bytes, so there are no closing EOLs */ had_nl = FALSE; - had_cr = FALSE; } /* The > min_curp[i] check leaves at least one final byte for checking @@ -712,7 +710,7 @@ find_identical_suffix(apr_off_t *suffix_ one file reaches its end. */ do { - had_cr = FALSE; + svn_boolean_t had_cr = FALSE; while (!is_one_at_eof(file_for_suffix, file_len) && *file_for_suffix[0].curp != '\n' && *file_for_suffix[0].curp != '\r') Modified: subversion/branches/remove-log-addressing/subversion/libsvn_fs/fs-loader.h URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_fs/fs-loader.h?rev=1658362&r1=1658361&r2=1658362&view=diff ============================================================================== --- subversion/branches/remove-log-addressing/subversion/libsvn_fs/fs-loader.h (original) +++ subversion/branches/remove-log-addressing/subversion/libsvn_fs/fs-loader.h Mon Feb 9 11:23:39 2015 @@ -548,7 +548,8 @@ struct svn_fs_access_t const char *username; /* A collection of lock-tokens supplied by the fs caller. - Hash maps (const char *) UUID --> (void *) 1 + Hash maps (const char *) UUID --> path where path can be the + magic value (void *) 1 if no path was specified. fs functions should really only be interested whether a UUID exists as a hash key at all; the value is irrelevant. */ apr_hash_t *lock_tokens; Modified: subversion/branches/remove-log-addressing/subversion/libsvn_fs_base/dag.c URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_fs_base/dag.c?rev=1658362&r1=1658361&r2=1658362&view=diff ============================================================================== --- subversion/branches/remove-log-addressing/subversion/libsvn_fs_base/dag.c (original) +++ subversion/branches/remove-log-addressing/subversion/libsvn_fs_base/dag.c Mon Feb 9 11:23:39 2015 @@ -1028,12 +1028,14 @@ svn_fs_base__dag_delete_if_mutable(svn_f void *val; svn_fs_dirent_t *dirent; + svn_pool_clear(subpool); apr_hash_this(hi, NULL, NULL, &val); dirent = val; SVN_ERR(svn_fs_base__dag_delete_if_mutable(fs, dirent->id, txn_id, trail, subpool)); } + svn_pool_destroy(subpool); } } Modified: subversion/branches/remove-log-addressing/subversion/libsvn_fs_base/fs.c URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_fs_base/fs.c?rev=1658362&r1=1658361&r2=1658362&view=diff ============================================================================== --- subversion/branches/remove-log-addressing/subversion/libsvn_fs_base/fs.c (original) +++ subversion/branches/remove-log-addressing/subversion/libsvn_fs_base/fs.c Mon Feb 9 11:23:39 2015 @@ -1516,6 +1516,7 @@ svn_fs_base__init(const svn_version_t *l { { "svn_subr", svn_subr_version }, { "svn_delta", svn_delta_version }, + { "svn_fs_util", svn_fs_util__version }, { NULL, NULL } }; Modified: subversion/branches/remove-log-addressing/subversion/libsvn_fs_base/tree.c URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_fs_base/tree.c?rev=1658362&r1=1658361&r2=1658362&view=diff ============================================================================== --- subversion/branches/remove-log-addressing/subversion/libsvn_fs_base/tree.c (original) +++ subversion/branches/remove-log-addressing/subversion/libsvn_fs_base/tree.c Mon Feb 9 11:23:39 2015 @@ -1237,7 +1237,7 @@ base_node_prop(svn_string_t **value_p, args.propname = propname; SVN_ERR(svn_fs_base__retry_txn(root->fs, txn_body_node_prop, &args, FALSE, scratch_pool)); - *value_p = value ? svn_string_dup(value, pool) : NULL; + *value_p = svn_string_dup(value, pool); svn_pool_destroy(scratch_pool); return SVN_NO_ERROR; } Modified: subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/cached_data.c URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/cached_data.c?rev=1658362&r1=1658361&r2=1658362&view=diff ============================================================================== --- subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/cached_data.c (original) +++ subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/cached_data.c Mon Feb 9 11:23:39 2015 @@ -2325,7 +2325,7 @@ get_dir_contents(apr_array_header_t **en changes we've made in this transaction. */ SVN_ERR(svn_stream_open_readonly(&contents, filename, scratch_pool, scratch_pool)); - SVN_ERR(read_dir_entries(*entries, contents, TRUE, noderev->id, + SVN_ERR(read_dir_entries(*entries, contents, TRUE, noderev->id, result_pool, scratch_pool)); SVN_ERR(svn_stream_close(contents)); } @@ -2389,7 +2389,7 @@ locate_dir_cache(svn_fs_t *fs, A NULL key causes a cache miss. */ *key = NULL; } - + return ffd->dir_cache; } } Modified: subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/caching.c URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/caching.c?rev=1658362&r1=1658361&r2=1658362&view=diff ============================================================================== --- subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/caching.c (original) +++ subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/caching.c Mon Feb 9 11:23:39 2015 @@ -620,12 +620,44 @@ struct txn_cleanup_baton_t /* the position where to reset it */ svn_cache__t **to_reset; + + /* pool that TXN_CACHE was allocated in */ + apr_pool_t *txn_pool; + + /* pool that the FS containing the TO_RESET pointer was allocator */ + apr_pool_t *fs_pool; }; +/* Forward declaration. */ +static apr_status_t +remove_txn_cache_fs(void *baton_void); + /* APR pool cleanup handler that will reset the cache pointer given in - BATON_VOID. */ + BATON_VOID when the TXN_POOL gets cleaned up. */ static apr_status_t -remove_txn_cache(void *baton_void) +remove_txn_cache_txn(void *baton_void) +{ + struct txn_cleanup_baton_t *baton = baton_void; + + /* be careful not to hurt performance by resetting newer txn's caches. */ + if (*baton->to_reset == baton->txn_cache) + { + /* This is equivalent to calling svn_fs_fs__reset_txn_caches(). */ + *baton->to_reset = NULL; + } + + /* It's cleaned up now. Prevent double cleanup. */ + apr_pool_cleanup_kill(baton->fs_pool, + baton, + remove_txn_cache_fs); + + return APR_SUCCESS; +} + +/* APR pool cleanup handler that will reset the cache pointer given in + BATON_VOID when the FS_POOL gets cleaned up. */ +static apr_status_t +remove_txn_cache_fs(void *baton_void) { struct txn_cleanup_baton_t *baton = baton_void; @@ -633,19 +665,25 @@ remove_txn_cache(void *baton_void) if (*baton->to_reset == baton->txn_cache) { /* This is equivalent to calling svn_fs_fs__reset_txn_caches(). */ - *baton->to_reset = NULL; + *baton->to_reset = NULL; } + /* It's cleaned up now. Prevent double cleanup. */ + apr_pool_cleanup_kill(baton->txn_pool, + baton, + remove_txn_cache_txn); + return APR_SUCCESS; } /* This function sets / registers the required callbacks for a given - * transaction-specific *CACHE object, if CACHE is not NULL and a no-op - * otherwise. In particular, it will ensure that *CACHE gets reset to NULL - * upon POOL destruction latest. + * transaction-specific *CACHE object in FS, if CACHE is not NULL and + * a no-op otherwise. In particular, it will ensure that *CACHE gets + * reset to NULL upon POOL or FS->POOL destruction latest. */ static void -init_txn_callbacks(svn_cache__t **cache, +init_txn_callbacks(svn_fs_t *fs, + svn_cache__t **cache, apr_pool_t *pool) { if (*cache != NULL) @@ -655,10 +693,20 @@ init_txn_callbacks(svn_cache__t **cache, baton = apr_palloc(pool, sizeof(*baton)); baton->txn_cache = *cache; baton->to_reset = cache; + baton->txn_pool = pool; + baton->fs_pool = fs->pool; + /* If any of these pools gets cleaned, we must reset the cache. + * We don't know which one will get cleaned up first, so register + * cleanup actions for both and during the cleanup action, unregister + * the respective other action. */ apr_pool_cleanup_register(pool, baton, - remove_txn_cache, + remove_txn_cache_txn, + apr_pool_cleanup_null); + apr_pool_cleanup_register(fs->pool, + baton, + remove_txn_cache_fs, apr_pool_cleanup_null); } } @@ -708,7 +756,7 @@ svn_fs_fs__initialize_txn_caches(svn_fs_ pool, pool)); /* reset the transaction-specific cache if the pool gets cleaned up. */ - init_txn_callbacks(&(ffd->txn_dir_cache), pool); + init_txn_callbacks(fs, &(ffd->txn_dir_cache), pool); return SVN_NO_ERROR; } Modified: subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/dag.c URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/dag.c?rev=1658362&r1=1658361&r2=1658362&view=diff ============================================================================== --- subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/dag.c (original) +++ subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/dag.c Mon Feb 9 11:23:39 2015 @@ -866,14 +866,20 @@ svn_fs_fs__dag_delete_if_mutable(svn_fs_ { apr_array_header_t *entries; int i; + apr_pool_t *iterpool = svn_pool_create(pool); /* Loop over directory entries */ SVN_ERR(svn_fs_fs__dag_dir_entries(&entries, node, pool)); if (entries) for (i = 0; i < entries->nelts; ++i) - SVN_ERR(svn_fs_fs__dag_delete_if_mutable(fs, - APR_ARRAY_IDX(entries, i, svn_fs_dirent_t *)->id, - pool)); + { + svn_pool_clear(iterpool); + SVN_ERR(svn_fs_fs__dag_delete_if_mutable(fs, + APR_ARRAY_IDX(entries, i, svn_fs_dirent_t *)->id, + iterpool)); + } + + svn_pool_destroy(iterpool); } /* ... then delete the node itself, after deleting any mutable Modified: subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/fs.c URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/fs.c?rev=1658362&r1=1658361&r2=1658362&view=diff ============================================================================== --- subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/fs.c (original) +++ subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/fs.c Mon Feb 9 11:23:39 2015 @@ -595,6 +595,7 @@ svn_fs_fs__init(const svn_version_t *loa { { "svn_subr", svn_subr_version }, { "svn_delta", svn_delta_version }, + { "svn_fs_util", svn_fs_util__version }, { NULL, NULL } }; Modified: subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/fs_fs.c URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/fs_fs.c?rev=1658362&r1=1658361&r2=1658362&view=diff ============================================================================== --- subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/fs_fs.c (original) +++ subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/fs_fs.c Mon Feb 9 11:23:39 2015 @@ -26,6 +26,7 @@ #include "svn_private_config.h" +#include "svn_checksum.h" #include "svn_hash.h" #include "svn_props.h" #include "svn_time.h" @@ -1211,10 +1212,45 @@ svn_fs_fs__file_length(svn_filesize_t *l node_revision_t *noderev, apr_pool_t *pool) { - if (noderev->data_rep) - *length = noderev->data_rep->expanded_size; + representation_t *data_rep = noderev->data_rep; + if (!data_rep) + { + /* Treat "no representation" as "empty file". */ + *length = 0; + } + else if (data_rep->expanded_size) + { + /* Standard case: a non-empty file. */ + *length = data_rep->expanded_size; + } else - *length = 0; + { + /* Work around a FSFS format quirk (see issue #4554). + + A plain representation may specify its EXPANDED LENGTH as "0" + in which case, the SIZE value is what we want. + + Because EXPANDED_LENGTH will also be 0 for empty files, while + SIZE is non-null, we need to check wether the content is + actually empty. We simply compare with the MD5 checksum of + empty content (sha-1 is not always available). + */ + svn_checksum_t *empty_md5 + = svn_checksum_empty_checksum(svn_checksum_md5, pool); + + if (memcmp(empty_md5->digest, data_rep->md5_digest, + sizeof(data_rep->md5_digest))) + { + /* Contents is not empty, i.e. EXPANDED_LENGTH cannot be the + actual file length. */ + *length = data_rep->size; + } + else + { + /* Contents is empty. */ + *length = 0; + } + } return SVN_NO_ERROR; }
