You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2010/12/02 21:55:18 UTC
svn commit: r1041580 [6/35] - in
/subversion/branches/gpg-agent-password-store: ./ build/ build/ac-macros/
build/generator/ build/generator/templates/ build/win32/
contrib/hook-scripts/ contrib/server-side/ notes/http-and-webdav/
notes/wc-ng/ subversio...
Modified: subversion/branches/gpg-agent-password-store/subversion/libsvn_client/patch.c
URL: http://svn.apache.org/viewvc/subversion/branches/gpg-agent-password-store/subversion/libsvn_client/patch.c?rev=1041580&r1=1041579&r2=1041580&view=diff
==============================================================================
--- subversion/branches/gpg-agent-password-store/subversion/libsvn_client/patch.c (original)
+++ subversion/branches/gpg-agent-password-store/subversion/libsvn_client/patch.c Thu Dec 2 20:55:08 2010
@@ -203,6 +203,9 @@ typedef struct patch_target_t {
/* True if the patch changed any of the properties of the target. */
svn_boolean_t has_prop_changes;
+ /* True if the patch contained a svn:special property. */
+ svn_boolean_t is_special;
+
/* All the information that is specific to the content of the target. */
target_content_info_t *content_info;
@@ -235,7 +238,7 @@ strip_path(const char **result, const ch
apr_array_header_t *stripped;
components = svn_path_decompose(path, scratch_pool);
- if (strip_count >= components->nelts)
+ if (strip_count > components->nelts)
return svn_error_createf(SVN_ERR_CLIENT_PATCH_BAD_STRIP_COUNT, NULL,
_("Cannot strip %u components from '%s'"),
strip_count,
@@ -346,9 +349,7 @@ resolve_target_path(patch_target_t *targ
target->canon_path_from_patchfile = svn_dirent_internal_style(
path_from_patchfile, result_pool);
- /* We allow properties to be set on the wc root dir.
- * ### Do we need to check for empty paths here, shouldn't the parser
- * ### guarentee that the paths returned are non-empty? */
+ /* We allow properties to be set on the wc root dir. */
if (! prop_changes_only && target->canon_path_from_patchfile[0] == '\0')
{
/* An empty patch target path? What gives? Skip this. */
@@ -498,7 +499,7 @@ init_prop_target(prop_patch_target_t **p
new_prop_target->content_info = content_info;
err = svn_wc_prop_get2(&value, wc_ctx, local_abspath, prop_name,
- result_pool, scratch_pool);
+ result_pool, scratch_pool);
if (err)
{
if (err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
@@ -528,12 +529,40 @@ init_prop_target(prop_patch_target_t **p
return SVN_NO_ERROR;
}
+/* Return a suitable filename for the target of PATCH.
+ * Examine the ``old'' and ``new'' file names, and choose the file name
+ * with the fewest path components, the shortest basename, and the shortest
+ * total file name length (in that order). In case of a tie, return the new
+ * filename. This heuristic is also used by Larry Wall's UNIX patch (except
+ * that it prompts for a filename in case of a tie). */
+static const char *
+choose_target_filename(const svn_patch_t *patch)
+{
+ apr_size_t old;
+ apr_size_t new;
+
+ old = svn_path_component_count(patch->old_filename);
+ new = svn_path_component_count(patch->new_filename);
+
+ if (old == new)
+ {
+ old = strlen(svn_dirent_basename(patch->old_filename, NULL));
+ new = strlen(svn_dirent_basename(patch->new_filename, NULL));
+
+ if (old == new)
+ {
+ old = strlen(patch->old_filename);
+ new = strlen(patch->new_filename);
+ }
+ }
+
+ return (old < new) ? patch->old_filename : patch->new_filename;
+}
+
/* Attempt to initialize a *PATCH_TARGET structure for a target file
* described by PATCH. Use working copy context WC_CTX.
* STRIP_COUNT specifies the number of leading path components
* which should be stripped from target paths in the patch.
- * OLD_PATCH_TARGET_NAMES indicates whether the old target's name parsed
- * from the patch file should be preferred over the new target's name.
* The patch target structure is allocated in RESULT_POOL, but if the target
* should be skipped, PATCH_TARGET->SKIPPED is set and the target should be
* treated as not fully initialized, e.g. the caller should not not do any
@@ -545,9 +574,7 @@ static svn_error_t *
init_patch_target(patch_target_t **patch_target,
const svn_patch_t *patch,
const char *base_dir,
- svn_wc_context_t *wc_ctx,
- int strip_count,
- svn_boolean_t old_patch_target_names,
+ svn_wc_context_t *wc_ctx, int strip_count,
svn_boolean_t remove_tempfiles,
apr_pool_t *result_pool, apr_pool_t *scratch_pool)
{
@@ -593,8 +620,7 @@ init_patch_target(patch_target_t **patch
target->prop_targets = apr_hash_make(result_pool);
target->pool = result_pool;
- SVN_ERR(resolve_target_path(target, old_patch_target_names ?
- patch->old_filename : patch->new_filename,
+ SVN_ERR(resolve_target_path(target, choose_target_filename(patch),
base_dir, strip_count, prop_changes_only,
wc_ctx, result_pool, scratch_pool));
if (! target->skipped)
@@ -913,9 +939,9 @@ match_hunk(svn_boolean_t *matched, targe
* Return the line at which HUNK was matched in *MATCHED_LINE.
* If the hunk did not match at all, set *MATCHED_LINE to zero.
* If the hunk matched multiple times, and MATCH_FIRST is TRUE,
- * return the line number at which the first match occured in *MATCHED_LINE.
+ * return the line number at which the first match occurred in *MATCHED_LINE.
* If the hunk matched multiple times, and MATCH_FIRST is FALSE,
- * return the line number at which the last match occured in *MATCHED_LINE.
+ * return the line number at which the last match occurred in *MATCHED_LINE.
* If IGNORE_WHITESPACE is set, ignore whitespace during the matching.
* If MATCH_MODIFIED is TRUE, match the modified hunk text,
* rather than the original hunk text.
@@ -1270,12 +1296,13 @@ copy_lines_to_target(target_content_info
return SVN_NO_ERROR;
}
-/* Write the diff text of the hunk described by HI to the
- * reject stream of CONTENT_INFO, and mark TARGET as having had rejects.
+/* Write the diff text of HUNK to the reject stream of CONTENT_INFO,
+ * and mark TARGET as having had rejects.
* Do temporary allocations in POOL. */
static svn_error_t *
reject_hunk(patch_target_t *target, target_content_info_t *content_info,
- hunk_info_t *hi, const char *prop_name, apr_pool_t *pool)
+ const svn_diff_hunk_t *hunk, const char *prop_name,
+ apr_pool_t *pool)
{
const char *hunk_header;
apr_size_t len;
@@ -1286,7 +1313,7 @@ reject_hunk(patch_target_t *target, targ
{
const char *prop_header;
- /* ### Print 'Added', 'Deleted' or 'Modified' instead of 'Propperty'.
+ /* ### Print 'Added', 'Deleted' or 'Modified' instead of 'Property'.
*/
prop_header = apr_psprintf(pool, "Property: %s\n", prop_name);
len = strlen(prop_header);
@@ -1296,18 +1323,18 @@ reject_hunk(patch_target_t *target, targ
/* ### What about just setting a variable to either "@@" or "##",
* ### and merging with the else clause below? */
hunk_header = apr_psprintf(pool, "## -%lu,%lu +%lu,%lu ##%s",
- svn_diff_hunk_get_original_start(hi->hunk),
- svn_diff_hunk_get_original_length(hi->hunk),
- svn_diff_hunk_get_modified_start(hi->hunk),
- svn_diff_hunk_get_modified_length(hi->hunk),
+ svn_diff_hunk_get_original_start(hunk),
+ svn_diff_hunk_get_original_length(hunk),
+ svn_diff_hunk_get_modified_start(hunk),
+ svn_diff_hunk_get_modified_length(hunk),
APR_EOL_STR);
}
else
hunk_header = apr_psprintf(pool, "@@ -%lu,%lu +%lu,%lu @@%s",
- svn_diff_hunk_get_original_start(hi->hunk),
- svn_diff_hunk_get_original_length(hi->hunk),
- svn_diff_hunk_get_modified_start(hi->hunk),
- svn_diff_hunk_get_modified_length(hi->hunk),
+ svn_diff_hunk_get_original_start(hunk),
+ svn_diff_hunk_get_original_length(hunk),
+ svn_diff_hunk_get_modified_start(hunk),
+ svn_diff_hunk_get_modified_length(hunk),
APR_EOL_STR);
len = strlen(hunk_header);
SVN_ERR(svn_stream_write(content_info->reject, hunk_header, &len));
@@ -1320,7 +1347,7 @@ reject_hunk(patch_target_t *target, targ
svn_pool_clear(iterpool);
- SVN_ERR(svn_diff_hunk_readline_diff_text(hi->hunk, &hunk_line, &eol_str,
+ SVN_ERR(svn_diff_hunk_readline_diff_text(hunk, &hunk_line, &eol_str,
&eof, iterpool, iterpool));
if (! eof)
{
@@ -1384,7 +1411,7 @@ apply_hunk(patch_target_t *target, targe
{
/* Seek failed, reject this hunk. */
hi->rejected = TRUE;
- SVN_ERR(reject_hunk(target, content_info, hi, prop_name, pool));
+ SVN_ERR(reject_hunk(target, content_info, hi->hunk, prop_name, pool));
return SVN_NO_ERROR;
}
}
@@ -1585,53 +1612,12 @@ send_patch_notification(const patch_targ
return SVN_NO_ERROR;
}
-/* Close the streams of the TARGET so that their content is flushed
- * to disk. This will also close underlying streams and files. Use POOL for
- * temporary allocations. */
-static svn_error_t *
-close_target_streams(const patch_target_t *target,
- apr_pool_t *pool)
-{
- apr_hash_index_t *hi;
- target_content_info_t *prop_content_info;
-
- /* First the streams belonging to properties .. */
- for (hi = apr_hash_first(pool, target->prop_targets);
- hi;
- hi = apr_hash_next(hi))
- {
- prop_patch_target_t *prop_target;
- prop_target = svn__apr_hash_index_val(hi);
- prop_content_info = prop_target->content_info;
-
- /* ### If the prop did not exist pre-patching we'll not have a
- * ### stream to read from. Find a better way to store info on
- * ### the existence of the target prop. */
- if (prop_content_info->stream)
- SVN_ERR(svn_stream_close(prop_content_info->stream));
-
- SVN_ERR(svn_stream_close(prop_content_info->patched));
- }
-
-
- /* .. And then streams associted with the file. The reject stream is
- * shared between all target_content_info structures. */
- if (target->kind_on_disk == svn_node_file)
- SVN_ERR(svn_stream_close(target->content_info->stream));
- SVN_ERR(svn_stream_close(target->content_info->patched));
- SVN_ERR(svn_stream_close(target->content_info->reject));
-
- return SVN_NO_ERROR;
-}
-
/* 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
* in RESULT_POOL. Use WC_CTX as the working copy context.
* STRIP_COUNT specifies the number of leading path components
* which should be stripped from target paths in the patch.
- * OLD_PATCH_TARGET_NAMES indicates whether the old filename parsed
- * from the patch file should be preferred over the new filename.
* REMOVE_TEMPFILES, PATCH_FUNC, and PATCH_BATON as in svn_client_patch().
* IGNORE_WHITESPACE tells whether whitespace should be considered when
* doing the matching.
@@ -1641,7 +1627,6 @@ static svn_error_t *
apply_one_patch(patch_target_t **patch_target, svn_patch_t *patch,
const char *abs_wc_path, svn_wc_context_t *wc_ctx,
int strip_count,
- svn_boolean_t old_patch_target_names,
svn_boolean_t ignore_whitespace,
svn_boolean_t remove_tempfiles,
svn_client_patch_func_t patch_func,
@@ -1655,9 +1640,9 @@ apply_one_patch(patch_target_t **patch_t
int i;
static const int MAX_FUZZ = 2;
apr_hash_index_t *hash_index;
+ target_content_info_t *prop_content_info;
- SVN_ERR(init_patch_target(&target, patch, abs_wc_path, wc_ctx,
- strip_count, old_patch_target_names,
+ SVN_ERR(init_patch_target(&target, patch, abs_wc_path, wc_ctx, strip_count,
remove_tempfiles, result_pool, scratch_pool));
if (target->skipped)
{
@@ -1720,7 +1705,7 @@ apply_one_patch(patch_target_t **patch_t
if (hi->already_applied)
continue;
else if (hi->rejected)
- SVN_ERR(reject_hunk(target, target->content_info, hi,
+ SVN_ERR(reject_hunk(target, target->content_info, hi->hunk,
NULL /* prop_name */,
iterpool));
else
@@ -1754,6 +1739,9 @@ apply_one_patch(patch_target_t **patch_t
prop_name = svn__apr_hash_index_key(hash_index);
prop_patch = svn__apr_hash_index_val(hash_index);
+ if (! strcmp(prop_name, SVN_PROP_SPECIAL))
+ target->is_special = TRUE;
+
/* We'll store matched hunks in prop_content_info. */
prop_target = apr_hash_get(target->prop_targets, prop_name,
APR_HASH_KEY_STRING);
@@ -1809,7 +1797,7 @@ apply_one_patch(patch_target_t **patch_t
if (hi->already_applied)
continue;
else if (hi->rejected)
- SVN_ERR(reject_hunk(target, prop_target->content_info, hi,
+ SVN_ERR(reject_hunk(target, prop_target->content_info, hi->hunk,
prop_target->name,
iterpool));
else
@@ -1836,7 +1824,31 @@ apply_one_patch(patch_target_t **patch_t
svn_pool_destroy(iterpool);
- SVN_ERR(close_target_streams(target, scratch_pool));
+ /* Now close some streams that we don't need any longer to get
+ * file buffers flushed to disk. First, close the props streams... */
+ for (hash_index = apr_hash_first(scratch_pool, target->prop_targets);
+ hash_index;
+ hash_index = apr_hash_next(hash_index))
+ {
+ prop_patch_target_t *prop_target;
+ prop_target = svn__apr_hash_index_val(hash_index);
+ prop_content_info = prop_target->content_info;
+
+ /* ### If the prop did not exist pre-patching we'll not have a
+ * ### stream to read from. Find a better way to store info on
+ * ### the existence of the target prop. */
+ if (prop_content_info->stream)
+ SVN_ERR(svn_stream_close(prop_content_info->stream));
+
+ SVN_ERR(svn_stream_close(prop_content_info->patched));
+ }
+
+ /* .. and then streams associated with the file.
+ * But we're not closing the reject stream -- it still needed and
+ * will be closed later in write_out_rejected_hunks(). */
+ if (target->kind_on_disk == svn_node_file)
+ SVN_ERR(svn_stream_close(target->content_info->stream));
+ SVN_ERR(svn_stream_close(target->content_info->patched));
if (! target->skipped)
{
@@ -2023,14 +2035,13 @@ create_missing_parents(patch_target_t *t
* to version control. Allow cancellation since we
* have not modified the working copy yet for this
* target. */
- SVN_ERR(svn_wc_add4(ctx->wc_ctx, local_abspath,
- svn_depth_infinity,
- NULL, SVN_INVALID_REVNUM,
- ctx->cancel_func,
- ctx->cancel_baton,
- ctx->notify_func2,
- ctx->notify_baton2,
- iterpool));
+
+ if (ctx->cancel_func)
+ SVN_ERR(ctx->cancel_func(ctx->cancel_baton));
+
+ SVN_ERR(svn_wc_add_from_disk(ctx->wc_ctx, local_abspath,
+ ctx->notify_func2, ctx->notify_baton2,
+ iterpool));
}
}
}
@@ -2100,20 +2111,42 @@ install_patched_target(patch_target_t *t
if (! dry_run && ! target->skipped)
{
- /* Copy the patched file on top of the target file. */
- SVN_ERR(svn_io_copy_file(target->patched_path,
- target->local_abspath, FALSE, pool));
+ if (target->is_special)
+ {
+ svn_stream_t *stream;
+ svn_stream_t *patched_stream;
+ apr_file_t *file;
+
+ SVN_ERR(svn_io_file_open(&file, target->patched_path,
+ APR_READ | APR_BINARY, APR_OS_DEFAULT,
+ pool));
+
+ patched_stream = svn_stream_from_aprfile2(file, FALSE /* disown */,
+ pool);
+ SVN_ERR(svn_subst_create_specialfile(&stream,
+ target->local_abspath,
+ pool, pool));
+ SVN_ERR(svn_stream_copy3(patched_stream, stream,
+ NULL, /* cancel_func */
+ NULL, /* cancel_baton */
+ pool));
+ }
+ else
+ {
+ /* Copy the patched file on top of the target file. */
+ SVN_ERR(svn_io_copy_file(target->patched_path,
+ target->local_abspath, FALSE, pool));
+ }
+
if (target->added || target->replaced)
{
/* The target file didn't exist previously,
* so add it to version control.
* Suppress notification, we'll do that later (and also
- * during dry-run). Also suppress cancellation because
+ * during dry-run). Don't allow cancellation because
* we'd rather notify about what we did before aborting. */
- SVN_ERR(svn_wc_add4(ctx->wc_ctx, target->local_abspath,
- svn_depth_infinity,
- NULL, SVN_INVALID_REVNUM,
- NULL, NULL, NULL, NULL, pool));
+ SVN_ERR(svn_wc_add_from_disk(ctx->wc_ctx, target->local_abspath,
+ NULL, NULL, pool));
}
/* Restore the target's executable bit if necessary. */
@@ -2135,6 +2168,8 @@ write_out_rejected_hunks(patch_target_t
svn_boolean_t dry_run,
apr_pool_t *pool)
{
+ SVN_ERR(svn_stream_close(target->content_info->reject));
+
if (! dry_run && (target->had_rejects || target->had_prop_rejects))
{
/* Write out rejected hunks, if any. */
@@ -2158,14 +2193,6 @@ install_patched_prop_targets(patch_targe
apr_hash_index_t *hi;
apr_pool_t *iterpool;
- if (dry_run)
- {
- if (! target->has_text_changes && target->kind_on_disk == svn_node_none)
- target->added = TRUE;
-
- return SVN_NO_ERROR;
- }
-
iterpool = svn_pool_create(scratch_pool);
for (hi = apr_hash_first(scratch_pool, target->prop_targets);
@@ -2177,19 +2204,22 @@ install_patched_prop_targets(patch_targe
svn_stream_t *patched_stream;
svn_stringbuf_t *line;
svn_stringbuf_t *prop_content;
+ const svn_string_t *prop_val;
const char *eol_str;
svn_boolean_t eof;
+ svn_error_t *err;
svn_pool_clear(iterpool);
/* For a deleted prop we only set the value to NULL. */
if (prop_target->operation == svn_diff_op_deleted)
{
- SVN_ERR(svn_wc_prop_set4(ctx->wc_ctx, target->local_abspath,
- prop_target->name, NULL,
- TRUE /* skip_checks */,
- NULL, NULL, /* suppress notification */
- iterpool));
+ if (! dry_run)
+ SVN_ERR(svn_wc_prop_set4(ctx->wc_ctx, target->local_abspath,
+ prop_target->name, NULL,
+ TRUE /* skip_checks */,
+ NULL, NULL, /* suppress notification */
+ iterpool));
continue;
}
@@ -2233,31 +2263,73 @@ install_patched_prop_targets(patch_targe
&& target->kind_on_disk == svn_node_none
&& ! target->added)
{
- SVN_ERR(svn_io_file_create(target->local_abspath, "", scratch_pool));
- SVN_ERR(svn_wc_add4(ctx->wc_ctx, target->local_abspath,
- svn_depth_infinity,
- NULL, SVN_INVALID_REVNUM,
- ctx->cancel_func,
- ctx->cancel_baton,
- NULL, NULL, /* suppress notification */
- iterpool));
+ if (! dry_run)
+ {
+ SVN_ERR(svn_io_file_create(target->local_abspath, "",
+ scratch_pool));
+ if (ctx->cancel_func)
+ SVN_ERR(ctx->cancel_func(ctx->cancel_baton));
+ SVN_ERR(svn_wc_add_from_disk(ctx->wc_ctx, target->local_abspath,
+ /* suppress notification */
+ NULL, NULL,
+ iterpool));
+ }
target->added = TRUE;
}
- /* ### How should we handle SVN_ERR_ILLEGAL_TARGET and
- * ### SVN_ERR_BAD_MIME_TYPE?
- *
- * ### stsp: I'd say reject the property hunk.
- * ### We should verify all modified prop hunk texts using
- * ### svn_wc_canonicalize_svn_prop() before starting the
- * ### patching process, to reject them as early as possible. */
- SVN_ERR(svn_wc_prop_set4(ctx->wc_ctx, target->local_abspath,
- prop_target->name,
- svn_string_create_from_buf(prop_content,
- iterpool),
- TRUE /* skip_checks */,
- NULL, NULL,
- iterpool));
+ /* Attempt to set the property, and reject all hunks if this fails. */
+ prop_val = svn_string_create_from_buf(prop_content, iterpool);
+ if (dry_run)
+ {
+ const svn_string_t *canon_propval;
+
+ err = svn_wc_canonicalize_svn_prop(&canon_propval,
+ prop_target->name,
+ prop_val, target->local_abspath,
+ target->db_kind,
+ TRUE, /* ### Skipping checks */
+ NULL, NULL,
+ iterpool);
+ }
+ else
+ {
+ err = (svn_wc_prop_set4(ctx->wc_ctx, target->local_abspath,
+ prop_target->name, prop_val,
+ TRUE, /* ### Skipping checks */
+ NULL, NULL,
+ iterpool));
+ }
+
+ if (err)
+ {
+ /* ### The errors which svn_wc_canonicalize_svn_prop() will
+ * ### return aren't documented. */
+ if (err->apr_err == SVN_ERR_ILLEGAL_TARGET ||
+ err->apr_err == SVN_ERR_NODE_UNEXPECTED_KIND ||
+ err->apr_err == SVN_ERR_IO_UNKNOWN_EOL ||
+ err->apr_err == SVN_ERR_BAD_MIME_TYPE ||
+ err->apr_err == SVN_ERR_CLIENT_INVALID_EXTERNALS_DESCRIPTION)
+ {
+ int i;
+
+ svn_error_clear(err);
+
+ for (i = 0; i < prop_target->content_info->hunks->nelts; i++)
+ {
+ hunk_info_t *hunk_info;
+
+ hunk_info = APR_ARRAY_IDX(prop_target->content_info->hunks,
+ i, hunk_info_t *);
+ hunk_info->rejected = TRUE;
+ SVN_ERR(reject_hunk(target, prop_target->content_info,
+ hunk_info->hunk, prop_target->name,
+ iterpool));
+ }
+ }
+ else
+ return svn_error_return(err);
+ }
+
}
svn_pool_destroy(iterpool);
@@ -2544,9 +2616,6 @@ typedef struct {
/* Number of leading components to strip from patch target paths. */
int strip_count;
- /* Whether to use the old path from the patch file instead of the new one. */
- svn_boolean_t old_patch_target_names;
-
/* Whether to apply the patch in reverse. */
svn_boolean_t reverse;
@@ -2612,7 +2681,6 @@ apply_patches(void *baton,
SVN_ERR(apply_one_patch(&target, patch, btn->abs_wc_path,
btn->ctx->wc_ctx, btn->strip_count,
- btn->old_patch_target_names,
btn->ignore_whitespace,
btn->remove_tempfiles,
btn->patch_func, btn->patch_baton,
@@ -2670,7 +2738,6 @@ svn_client_patch(const char *patch_abspa
const char *local_abspath,
svn_boolean_t dry_run,
int strip_count,
- svn_boolean_t old_patch_target_names,
svn_boolean_t reverse,
svn_boolean_t ignore_whitespace,
svn_boolean_t remove_tempfiles,
@@ -2686,12 +2753,15 @@ svn_client_patch(const char *patch_abspa
return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
_("strip count must be positive"));
+ if (svn_path_is_url(local_abspath))
+ return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
+ _("'%s' is not a local path"), local_abspath);
+
baton.patch_abspath = patch_abspath;
baton.abs_wc_path = local_abspath;
baton.dry_run = dry_run;
baton.ctx = ctx;
baton.strip_count = strip_count;
- baton.old_patch_target_names = old_patch_target_names;
baton.reverse = reverse;
baton.ignore_whitespace = ignore_whitespace;
baton.remove_tempfiles = remove_tempfiles;
Modified: subversion/branches/gpg-agent-password-store/subversion/libsvn_client/relocate.c
URL: http://svn.apache.org/viewvc/subversion/branches/gpg-agent-password-store/subversion/libsvn_client/relocate.c?rev=1041580&r1=1041579&r2=1041580&view=diff
==============================================================================
--- subversion/branches/gpg-agent-password-store/subversion/libsvn_client/relocate.c (original)
+++ subversion/branches/gpg-agent-password-store/subversion/libsvn_client/relocate.c Thu Dec 2 20:55:08 2010
@@ -125,15 +125,91 @@ validator_func(void *baton,
return SVN_NO_ERROR;
}
+
+/* Examing the array of svn_wc_external_item2_t's EXT_DESC (parsed
+ from the svn:externals property set on LOCAL_ABSPATH) and determine
+ if the external working copies described by such should be
+ relocated as a side-effect of the relocation of their parent
+ working copy (from OLD_PARENT_REPOS_ROOT_URL to
+ NEW_PARENT_REPOS_ROOT_URL). If so, attempt said relocation. */
+static svn_error_t *
+relocate_externals(const char *local_abspath,
+ apr_array_header_t *ext_desc,
+ const char *old_parent_repos_root_url,
+ const char *new_parent_repos_root_url,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *scratch_pool)
+{
+ const char *url;
+ apr_pool_t *iterpool;
+ int i;
+
+ SVN_ERR(svn_client_url_from_path2(&url, local_abspath, ctx,
+ scratch_pool, scratch_pool));
+
+ /* Parse an externals definition into an array of external items. */
+
+ iterpool = svn_pool_create(scratch_pool);
+
+ for (i = 0; i < ext_desc->nelts; i++)
+ {
+ svn_wc_external_item2_t *ext_item =
+ APR_ARRAY_IDX(ext_desc, i, svn_wc_external_item2_t *);
+ const char *target_repos_root_url;
+ const char *target_abspath;
+
+ svn_pool_clear(iterpool);
+
+ /* If this external isn't pulled in via a relative URL, ignore
+ it. There's no sense in relocating a working copy only to
+ have the next 'svn update' try to point it back to another
+ location. */
+ if (! ((strncmp("../", ext_item->url, 3) == 0) ||
+ (strncmp("^/", ext_item->url, 2) == 0)))
+ continue;
+
+ /* If the external working copy's not-yet-relocated repos root
+ URL matches the primary working copy's pre-relocated
+ repository root URL, try to relocate that external, too.
+ You might wonder why this check is needed, given that we're
+ already limiting ourselves to externals pulled via URLs
+ relative to their primary working copy. Well, it's because
+ you can use "../" to "crawl up" above one repository's URL
+ space and down into another one. */
+ SVN_ERR(svn_dirent_get_absolute(&target_abspath,
+ svn_dirent_join(local_abspath,
+ ext_item->target_dir,
+ iterpool),
+ iterpool));
+ SVN_ERR(svn_client_root_url_from_path(&target_repos_root_url,
+ target_abspath, ctx, iterpool));
+
+ if (strcmp(target_repos_root_url, old_parent_repos_root_url) == 0)
+ SVN_ERR(svn_client_relocate2(target_abspath,
+ old_parent_repos_root_url,
+ new_parent_repos_root_url,
+ TRUE, ctx, iterpool));
+ }
+
+ svn_pool_destroy(iterpool);
+
+ return SVN_NO_ERROR;
+}
+
svn_error_t *
svn_client_relocate2(const char *wcroot_dir,
- const char *from,
- const char *to,
+ const char *from_prefix,
+ const char *to_prefix,
+ svn_boolean_t ignore_externals,
svn_client_ctx_t *ctx,
apr_pool_t *pool)
{
struct validator_baton_t vb;
const char *local_abspath;
+ apr_hash_t *externals_hash = NULL;
+ apr_hash_index_t *hi;
+ apr_pool_t *iterpool = NULL;
+ const char *old_repos_root_url, *new_repos_root_url;
/* Populate our validator callback baton, and call the relocate code. */
vb.ctx = ctx;
@@ -141,9 +217,61 @@ svn_client_relocate2(const char *wcroot_
vb.url_uuids = apr_array_make(pool, 1, sizeof(struct url_uuid_t));
vb.pool = pool;
+ if (svn_path_is_url(wcroot_dir))
+ return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
+ _("'%s' is not a local path"),
+ wcroot_dir);
+
SVN_ERR(svn_dirent_get_absolute(&local_abspath, wcroot_dir, pool));
- SVN_ERR(svn_wc_relocate4(ctx->wc_ctx, local_abspath, from, to,
+
+ /* If we're ignoring externals, just relocate and get outta here. */
+ if (ignore_externals)
+ {
+ return svn_error_return(svn_wc_relocate4(ctx->wc_ctx, local_abspath,
+ from_prefix, to_prefix,
+ validator_func, &vb, pool));
+ }
+
+ /* Fetch our current root URL. */
+ SVN_ERR(svn_client_root_url_from_path(&old_repos_root_url, local_abspath,
+ ctx, pool));
+
+ /* Perform the relocation. */
+ SVN_ERR(svn_wc_relocate4(ctx->wc_ctx, local_abspath, from_prefix, to_prefix,
validator_func, &vb, pool));
+ /* Now fetch new current root URL. */
+ SVN_ERR(svn_client_root_url_from_path(&new_repos_root_url, local_abspath,
+ ctx, pool));
+
+
+ /* Relocate externals, too (if any). */
+ SVN_ERR(svn_client__crawl_for_externals(&externals_hash, local_abspath,
+ svn_depth_infinity, ctx, pool, pool));
+ if (! apr_hash_count(externals_hash))
+ return SVN_NO_ERROR;
+
+ iterpool = svn_pool_create(pool);
+
+ for (hi = apr_hash_first(pool, externals_hash);
+ hi != NULL;
+ hi = apr_hash_next(hi))
+ {
+ const char *this_abspath = svn__apr_hash_index_key(hi);
+ const svn_string_t *pval = svn__apr_hash_index_val(hi);
+ apr_array_header_t *ext_desc;
+
+ svn_pool_clear(iterpool);
+
+ SVN_ERR(svn_wc_parse_externals_description3(&ext_desc, this_abspath,
+ pval->data, FALSE,
+ iterpool));
+ if (ext_desc->nelts)
+ SVN_ERR(relocate_externals(this_abspath, ext_desc, old_repos_root_url,
+ new_repos_root_url, ctx, iterpool));
+ }
+
+ svn_pool_destroy(iterpool);
+
return SVN_NO_ERROR;
}
Modified: subversion/branches/gpg-agent-password-store/subversion/libsvn_client/resolved.c
URL: http://svn.apache.org/viewvc/subversion/branches/gpg-agent-password-store/subversion/libsvn_client/resolved.c?rev=1041580&r1=1041579&r2=1041580&view=diff
==============================================================================
--- subversion/branches/gpg-agent-password-store/subversion/libsvn_client/resolved.c (original)
+++ subversion/branches/gpg-agent-password-store/subversion/libsvn_client/resolved.c Thu Dec 2 20:55:08 2010
@@ -36,6 +36,7 @@
#include "client.h"
#include "private/svn_wc_private.h"
+#include "svn_private_config.h"
/*** Code. ***/
@@ -48,6 +49,10 @@ svn_client_resolve(const char *path,
{
const char *local_abspath;
+ if (svn_path_is_url(path))
+ return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
+ _("'%s' is not a local path"), path);
+
SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool));
SVN_ERR(svn_wc_resolved_conflict5(ctx->wc_ctx, local_abspath,
Modified: subversion/branches/gpg-agent-password-store/subversion/libsvn_client/revert.c
URL: http://svn.apache.org/viewvc/subversion/branches/gpg-agent-password-store/subversion/libsvn_client/revert.c?rev=1041580&r1=1041579&r2=1041580&view=diff
==============================================================================
--- subversion/branches/gpg-agent-password-store/subversion/libsvn_client/revert.c (original)
+++ subversion/branches/gpg-agent-password-store/subversion/libsvn_client/revert.c Thu Dec 2 20:55:08 2010
@@ -27,6 +27,7 @@
/*** Includes. ***/
+#include "svn_path.h"
#include "svn_wc.h"
#include "svn_client.h"
#include "svn_dirent_uri.h"
@@ -37,6 +38,7 @@
#include "client.h"
#include "private/svn_wc_private.h"
+#include "svn_private_config.h"
/*** Code. ***/
@@ -121,6 +123,17 @@ svn_client_revert2(const apr_array_heade
svn_boolean_t use_commit_times;
struct revert_with_write_lock_baton baton;
+ /* Don't even attempt to modify the working copy if any of the
+ * targets look like URLs. URLs are invalid input. */
+ for (i = 0; i < paths->nelts; i++)
+ {
+ const char *path = APR_ARRAY_IDX(paths, i, const char *);
+
+ if (svn_path_is_url(path))
+ return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
+ _("'%s' is not a local path"), path);
+ }
+
cfg = ctx->config ? apr_hash_get(ctx->config, SVN_CONFIG_CATEGORY_CONFIG,
APR_HASH_KEY_STRING) : NULL;
Modified: subversion/branches/gpg-agent-password-store/subversion/libsvn_client/status.c
URL: http://svn.apache.org/viewvc/subversion/branches/gpg-agent-password-store/subversion/libsvn_client/status.c?rev=1041580&r1=1041579&r2=1041580&view=diff
==============================================================================
--- subversion/branches/gpg-agent-password-store/subversion/libsvn_client/status.c (original)
+++ subversion/branches/gpg-agent-password-store/subversion/libsvn_client/status.c Thu Dec 2 20:55:08 2010
@@ -32,6 +32,7 @@
#include "svn_pools.h"
#include "client.h"
+#include "svn_path.h"
#include "svn_dirent_uri.h"
#include "svn_delta.h"
#include "svn_client.h"
@@ -266,7 +267,11 @@ svn_client_status5(svn_revnum_t *result_
apr_array_header_t *ignores;
svn_error_t *err;
apr_hash_t *changelist_hash = NULL;
- struct svn_cl__externals_store externals_store = { NULL };
+ struct svn_client__external_func_baton_t externals_store = { NULL };
+
+ if (svn_path_is_url(path))
+ return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
+ _("'%s' is not a local path"), path);
if (changelists && changelists->nelts)
SVN_ERR(svn_hash_from_cstring_keys(&changelist_hash, changelists, pool));
@@ -351,7 +356,7 @@ svn_client_status5(svn_revnum_t *result_
if (!ignore_externals)
{
- externals_store.pool = pool;
+ externals_store.result_pool = pool;
externals_store.externals_new = apr_hash_make(pool);
}
@@ -387,10 +392,10 @@ svn_client_status5(svn_revnum_t *result_
dir_abspath, target_basename,
depth, get_all,
no_ignore, ignores, tweak_status, &sb,
- ignore_externals ? NULL
- : svn_cl__store_externals,
- ignore_externals ? NULL
- : &externals_store,
+ ignore_externals
+ ? NULL
+ : svn_client__external_info_gatherer,
+ ignore_externals ? NULL : &externals_store,
ctx->cancel_func, ctx->cancel_baton,
pool, pool));
@@ -511,10 +516,10 @@ svn_client_status5(svn_revnum_t *result_
err = svn_wc_walk_status(ctx->wc_ctx, target_abspath,
depth, get_all, no_ignore, ignores,
tweak_status, &sb,
- ignore_externals ? NULL
- : svn_cl__store_externals,
- ignore_externals ? NULL
- : &externals_store,
+ ignore_externals
+ ? NULL
+ : svn_client__external_info_gatherer,
+ ignore_externals ? NULL : &externals_store,
ctx->cancel_func, ctx->cancel_baton,
pool);
Modified: subversion/branches/gpg-agent-password-store/subversion/libsvn_client/switch.c
URL: http://svn.apache.org/viewvc/subversion/branches/gpg-agent-password-store/subversion/libsvn_client/switch.c?rev=1041580&r1=1041579&r2=1041580&view=diff
==============================================================================
--- subversion/branches/gpg-agent-password-store/subversion/libsvn_client/switch.c (original)
+++ subversion/branches/gpg-agent-password-store/subversion/libsvn_client/switch.c Thu Dec 2 20:55:08 2010
@@ -329,6 +329,11 @@ svn_client_switch2(svn_revnum_t *result_
svn_client_ctx_t *ctx,
apr_pool_t *pool)
{
+ if (svn_path_is_url(path))
+ return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
+ _("'%s' is not a local path"),
+ path);
+
return svn_client__switch_internal(result_rev, path, switch_url,
peg_revision, revision, depth,
depth_is_sticky, NULL, ignore_externals,
Modified: subversion/branches/gpg-agent-password-store/subversion/libsvn_client/update.c
URL: http://svn.apache.org/viewvc/subversion/branches/gpg-agent-password-store/subversion/libsvn_client/update.c?rev=1041580&r1=1041579&r2=1041580&view=diff
==============================================================================
--- subversion/branches/gpg-agent-password-store/subversion/libsvn_client/update.c (original)
+++ subversion/branches/gpg-agent-password-store/subversion/libsvn_client/update.c Thu Dec 2 20:55:08 2010
@@ -44,7 +44,18 @@
/*** Code. ***/
-
+/* This is a helper for svn_client__update_internal(), which see for
+ an explanation of most of these parameters. Some stuff that's
+ unique is as follows:
+
+ ANCHOR_ABSPATH is the local absolute path of the update anchor.
+ This is typically either the same as LOCAL_ABSPATH, or the
+ immediate parent of LOCAL_ABSPATH.
+
+ If NOTIFY_SUMMARY is set (and there's a notification hander in
+ CTX), transmit the final update summary upon successful
+ completion of the update.
+*/
static svn_error_t *
update_internal(svn_revnum_t *result_rev,
const char *local_abspath,
@@ -56,6 +67,7 @@ update_internal(svn_revnum_t *result_rev
svn_boolean_t allow_unver_obstructions,
svn_boolean_t *timestamp_sleep,
svn_boolean_t innerupdate,
+ svn_boolean_t notify_summary,
svn_client_ctx_t *ctx,
apr_pool_t *pool)
{
@@ -144,6 +156,20 @@ update_internal(svn_revnum_t *result_rev
? svn_cstring_split(preserved_exts_str, "\n\r\t\v ", FALSE, pool)
: NULL;
+ /* Let everyone know we're starting a real update (unless we're
+ asked not to). */
+ if (ctx->notify_func2 && notify_summary)
+ {
+ svn_wc_notify_t *notify
+ = svn_wc_create_notify(local_abspath, svn_wc_notify_update_started,
+ pool);
+ notify->kind = svn_node_none;
+ notify->content_state = notify->prop_state
+ = svn_wc_notify_state_inapplicable;
+ notify->lock_state = svn_wc_notify_lock_state_inapplicable;
+ (*ctx->notify_func2)(ctx->notify_baton2, notify, pool);
+ }
+
/* Open an RA session for the URL */
SVN_ERR(svn_client__open_ra_session_internal(&ra_session, &corrected_url,
anchor_url,
@@ -235,8 +261,8 @@ update_internal(svn_revnum_t *result_rev
if (sleep_here)
svn_io_sleep_for_timestamps(local_abspath, pool);
- /* Let everyone know we're finished here. */
- if (ctx->notify_func2)
+ /* Let everyone know we're finished here (unless we're asked not to). */
+ if (ctx->notify_func2 && notify_summary)
{
svn_wc_notify_t *notify
= svn_wc_create_notify(local_abspath, svn_wc_notify_update_completed,
@@ -266,44 +292,99 @@ svn_client__update_internal(svn_revnum_t
svn_boolean_t allow_unver_obstructions,
svn_boolean_t *timestamp_sleep,
svn_boolean_t innerupdate,
+ svn_boolean_t make_parents,
svn_client_ctx_t *ctx,
apr_pool_t *pool)
{
- const char *anchor_abspath;
+ const char *anchor_abspath, *lockroot_abspath;
svn_error_t *err;
+ svn_opt_revision_t peg_revision = *((svn_opt_revision_t *)revision);
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
+ SVN_ERR_ASSERT(! (innerupdate && make_parents));
+
+ if (make_parents)
+ {
+ int i;
+ const char *parent_abspath = local_abspath;
+ apr_array_header_t *missing_parents =
+ apr_array_make(pool, 4, sizeof(const char *));
+
+ while (1)
+ {
+ /* Try to lock. If we can't lock because our target (or its
+ parent) isn't a working copy, we'll try to walk up the
+ tree to find a working copy, remembering this path's
+ parent as one we need to flesh out. */
+ err = svn_wc__acquire_write_lock(&lockroot_abspath, ctx->wc_ctx,
+ parent_abspath, !innerupdate,
+ pool, pool);
+ if (!err)
+ break;
+ if ((err->apr_err != SVN_ERR_WC_NOT_WORKING_COPY)
+ || svn_dirent_is_root(parent_abspath, strlen(parent_abspath)))
+ return err;
+ svn_error_clear(err);
+
+ /* Remember the parent of our update target as a missing
+ parent. */
+ parent_abspath = svn_dirent_dirname(parent_abspath, pool);
+ APR_ARRAY_PUSH(missing_parents, const char *) = parent_abspath;
+ }
+
+ /* Run 'svn up --depth=empty' (effectively) on the missing
+ parents, if any. */
+ anchor_abspath = lockroot_abspath;
+ for (i = missing_parents->nelts - 1; i >= 0; i--)
+ {
+ const char *missing_parent =
+ APR_ARRAY_IDX(missing_parents, i, const char *);
+ err = update_internal(result_rev, missing_parent, anchor_abspath,
+ &peg_revision, svn_depth_empty, FALSE,
+ ignore_externals, allow_unver_obstructions,
+ timestamp_sleep, innerupdate, FALSE,
+ ctx, pool);
+ if (err)
+ goto cleanup;
+ anchor_abspath = missing_parent;
- if (!innerupdate)
- SVN_ERR(svn_wc__acquire_write_lock(&anchor_abspath,
- ctx->wc_ctx, local_abspath, TRUE,
- pool, pool));
+ /* If we successfully updated a missing parent, let's re-use
+ the returned revision number for future updates for the
+ sake of consistency. */
+ peg_revision.kind = svn_opt_revision_number;
+ peg_revision.value.number = *result_rev;
+ }
+ }
else
- SVN_ERR(svn_wc__acquire_write_lock(&anchor_abspath,
- ctx->wc_ctx, local_abspath, FALSE,
- pool, pool));
+ {
+ SVN_ERR(svn_wc__acquire_write_lock(&lockroot_abspath, ctx->wc_ctx,
+ local_abspath, !innerupdate,
+ pool, pool));
+ anchor_abspath = lockroot_abspath;
+ }
err = update_internal(result_rev, local_abspath, anchor_abspath,
- revision, depth, depth_is_sticky,
- ignore_externals, allow_unver_obstructions,
- timestamp_sleep, innerupdate, ctx, pool);
-
+ &peg_revision, depth, depth_is_sticky,
+ ignore_externals, allow_unver_obstructions,
+ timestamp_sleep, innerupdate, TRUE, ctx, pool);
+ cleanup:
err = svn_error_compose_create(
err,
- svn_wc__release_write_lock(ctx->wc_ctx, anchor_abspath, pool));
+ svn_wc__release_write_lock(ctx->wc_ctx, lockroot_abspath, pool));
return svn_error_return(err);
}
svn_error_t *
-svn_client_update3(apr_array_header_t **result_revs,
+svn_client_update4(apr_array_header_t **result_revs,
const apr_array_header_t *paths,
const svn_opt_revision_t *revision,
svn_depth_t depth,
svn_boolean_t depth_is_sticky,
svn_boolean_t ignore_externals,
svn_boolean_t allow_unver_obstructions,
+ svn_boolean_t make_parents,
svn_client_ctx_t *ctx,
apr_pool_t *pool)
{
@@ -340,7 +421,8 @@ svn_client_update3(apr_array_header_t **
revision, depth, depth_is_sticky,
ignore_externals,
allow_unver_obstructions,
- &sleep, FALSE, ctx, subpool);
+ &sleep, FALSE, make_parents,
+ ctx, subpool);
if (err && err->apr_err != SVN_ERR_WC_NOT_WORKING_COPY)
{
Modified: subversion/branches/gpg-agent-password-store/subversion/libsvn_delta/path_driver.c
URL: http://svn.apache.org/viewvc/subversion/branches/gpg-agent-password-store/subversion/libsvn_delta/path_driver.c?rev=1041580&r1=1041579&r2=1041580&view=diff
==============================================================================
--- subversion/branches/gpg-agent-password-store/subversion/libsvn_delta/path_driver.c (original)
+++ subversion/branches/gpg-agent-password-store/subversion/libsvn_delta/path_driver.c Thu Dec 2 20:55:08 2010
@@ -194,7 +194,9 @@ svn_delta_path_driver(const svn_delta_ed
current one. For the first iteration, this is just the
empty string. ***/
if (i > 0)
- common = svn_relpath_get_longest_ancestor(last_path, path, iterpool);
+ common = (last_path[0] == '/')
+ ? svn_fspath__get_longest_ancestor(last_path, path, iterpool)
+ : svn_relpath_get_longest_ancestor(last_path, path, iterpool);
common_len = strlen(common);
/*** Step B - Close any directories between the last path and
@@ -215,7 +217,7 @@ svn_delta_path_driver(const svn_delta_ed
/*** Step C - Open any directories between the common ancestor
and the parent of the current path. ***/
if (*path == '/')
- svn_uri_split(&pdir, &bname, path, iterpool);
+ svn_fspath__split(&pdir, &bname, path, iterpool);
else
svn_relpath_split(&pdir, &bname, path, iterpool);
if (strlen(pdir) > common_len)
Modified: subversion/branches/gpg-agent-password-store/subversion/libsvn_diff/diff_file.c
URL: http://svn.apache.org/viewvc/subversion/branches/gpg-agent-password-store/subversion/libsvn_diff/diff_file.c?rev=1041580&r1=1041579&r2=1041580&view=diff
==============================================================================
--- subversion/branches/gpg-agent-password-store/subversion/libsvn_diff/diff_file.c (original)
+++ subversion/branches/gpg-agent-password-store/subversion/libsvn_diff/diff_file.c Thu Dec 2 20:55:08 2010
@@ -67,21 +67,26 @@ typedef struct svn_diff__file_token_t
typedef struct svn_diff__file_baton_t
{
const svn_diff_file_options_t *options;
- const char *path[4];
- apr_file_t *file[4];
- apr_off_t size[4];
+ struct file_info {
+ const char *path; /* path to this file, absolute or relative to CWD */
- int chunk[4];
- char *buffer[4];
- char *curp[4];
- char *endp[4];
+ /* All the following fields are active while this datasource is open */
+ apr_file_t *file; /* handle of this file */
+ apr_off_t size; /* total raw size in bytes of this file */
+
+ /* The current chunk: CHUNK_SIZE bytes except for the last chunk. */
+ int chunk; /* the current chunk number, zero-based */
+ char *buffer; /* a buffer containing the current chunk */
+ char *curp; /* current position in the current chunk */
+ char *endp; /* next memory address after the current chunk */
+
+ svn_diff__normalize_state_t normalize_state;
+ } files[4];
/* List of free tokens that may be reused. */
svn_diff__file_token_t *tokens;
- svn_diff__normalize_state_t normalize_state[4];
-
apr_pool_t *pool;
} svn_diff__file_baton_t;
@@ -198,26 +203,30 @@ map_or_read_file(apr_file_t **file,
}
-/* Implements svn_diff_fns_t::datasource_open */
+/* Let FILE stand for the file_info struct element of BATON->files that is
+ * indexed by DATASOURCE. BATON's type is (svn_diff__file_baton_t *).
+ *
+ * Open the file at FILE.path; initialize FILE.file, FILE.size, FILE.buffer,
+ * FILE.curp and FILE.endp; allocate a buffer and read the first chunk.
+ *
+ * Implements svn_diff_fns_t::datasource_open. */
static svn_error_t *
datasource_open(void *baton, svn_diff_datasource_e datasource)
{
svn_diff__file_baton_t *file_baton = baton;
- int idx;
+ struct file_info *file = &file_baton->files[datasource_to_index(datasource)];
apr_finfo_t finfo;
apr_off_t length;
char *curp;
char *endp;
- idx = datasource_to_index(datasource);
-
- SVN_ERR(svn_io_file_open(&file_baton->file[idx], file_baton->path[idx],
+ SVN_ERR(svn_io_file_open(&file->file, file->path,
APR_READ, APR_OS_DEFAULT, file_baton->pool));
SVN_ERR(svn_io_file_info_get(&finfo, APR_FINFO_SIZE,
- file_baton->file[idx], file_baton->pool));
+ file->file, file_baton->pool));
- file_baton->size[idx] = finfo.size;
+ file->size = finfo.size;
length = finfo.size > CHUNK_SIZE ? CHUNK_SIZE : finfo.size;
if (length == 0)
@@ -226,10 +235,10 @@ datasource_open(void *baton, svn_diff_da
endp = curp = apr_palloc(file_baton->pool, (apr_size_t) length);
endp += length;
- file_baton->buffer[idx] = file_baton->curp[idx] = curp;
- file_baton->endp[idx] = endp;
+ file->buffer = file->curp = curp;
+ file->endp = endp;
- return read_chunk(file_baton->file[idx], file_baton->path[idx],
+ return read_chunk(file->file, file->path,
curp, length, 0, file_baton->pool);
}
@@ -252,7 +261,7 @@ datasource_get_next_token(apr_uint32_t *
{
svn_diff__file_baton_t *file_baton = baton;
svn_diff__file_token_t *file_token;
- int idx;
+ struct file_info *file = &file_baton->files[datasource_to_index(datasource)];
char *endp;
char *curp;
char *eol;
@@ -264,15 +273,13 @@ datasource_get_next_token(apr_uint32_t *
*token = NULL;
- idx = datasource_to_index(datasource);
+ curp = file->curp;
+ endp = file->endp;
- curp = file_baton->curp[idx];
- endp = file_baton->endp[idx];
-
- last_chunk = offset_to_chunk(file_baton->size[idx]);
+ last_chunk = offset_to_chunk(file->size);
if (curp == endp
- && last_chunk == file_baton->chunk[idx])
+ && last_chunk == file->chunk)
{
return SVN_NO_ERROR;
}
@@ -289,8 +296,8 @@ datasource_get_next_token(apr_uint32_t *
}
file_token->datasource = datasource;
- file_token->offset = chunk_to_offset(file_baton->chunk[idx])
- + (curp - file_baton->buffer[idx]);
+ file_token->offset = chunk_to_offset(file->chunk)
+ + (curp - file->buffer);
file_token->raw_length = 0;
file_token->length = 0;
@@ -311,7 +318,7 @@ datasource_get_next_token(apr_uint32_t *
}
}
- if (file_baton->chunk[idx] == last_chunk)
+ if (file->chunk == last_chunk)
{
eol = endp;
break;
@@ -320,21 +327,21 @@ datasource_get_next_token(apr_uint32_t *
length = endp - curp;
file_token->raw_length += length;
svn_diff__normalize_buffer(&curp, &length,
- &file_baton->normalize_state[idx],
+ &file->normalize_state,
curp, file_baton->options);
file_token->length += length;
h = svn_diff__adler32(h, curp, length);
- curp = endp = file_baton->buffer[idx];
- file_baton->chunk[idx]++;
- length = file_baton->chunk[idx] == last_chunk ?
- offset_in_chunk(file_baton->size[idx]) : CHUNK_SIZE;
+ curp = endp = file->buffer;
+ file->chunk++;
+ length = file->chunk == last_chunk ?
+ offset_in_chunk(file->size) : CHUNK_SIZE;
endp += length;
- file_baton->endp[idx] = endp;
+ file->endp = endp;
- SVN_ERR(read_chunk(file_baton->file[idx], file_baton->path[idx],
+ SVN_ERR(read_chunk(file->file, file->path,
curp, length,
- chunk_to_offset(file_baton->chunk[idx]),
+ chunk_to_offset(file->chunk),
file_baton->pool));
/* If the last chunk ended in a CR, we're done. */
@@ -349,7 +356,7 @@ datasource_get_next_token(apr_uint32_t *
length = eol - curp;
file_token->raw_length += length;
- file_baton->curp[idx] = eol;
+ file->curp = eol;
/* If the file length is exactly a multiple of CHUNK_SIZE, we will end up
* with a spurious empty token. Avoid returning it.
@@ -360,7 +367,7 @@ datasource_get_next_token(apr_uint32_t *
{
char *c = curp;
svn_diff__normalize_buffer(&c, &length,
- &file_baton->normalize_state[idx],
+ &file->normalize_state,
curp, file_baton->options);
file_token->norm_offset = file_token->offset;
@@ -388,13 +395,12 @@ token_compare(void *baton, void *token1,
char buffer[2][COMPARE_CHUNK_SIZE];
char *bufp[2];
apr_off_t offset[2];
- int idx[2];
+ struct file_info *file[2];
apr_off_t length[2];
apr_off_t total_length;
/* How much is left to read of each token from the file. */
apr_off_t raw_length[2];
int i;
- int chunk[2];
svn_diff__normalize_state_t state[2];
file_token[0] = token1;
@@ -420,17 +426,18 @@ token_compare(void *baton, void *token1,
for (i = 0; i < 2; ++i)
{
- idx[i] = datasource_to_index(file_token[i]->datasource);
+ int idx = datasource_to_index(file_token[i]->datasource);
+
+ file[i] = &file_baton->files[idx];
offset[i] = file_token[i]->norm_offset;
- chunk[i] = file_baton->chunk[idx[i]];
state[i] = svn_diff__normalize_state_normal;
- if (offset_to_chunk(offset[i]) == chunk[i])
+ if (offset_to_chunk(offset[i]) == file[i]->chunk)
{
/* If the start of the token is in memory, the entire token is
* in memory.
*/
- bufp[i] = file_baton->buffer[idx[i]];
+ bufp[i] = file[i]->buffer;
bufp[i] += offset_in_chunk(offset[i]);
length[i] = total_length;
@@ -458,15 +465,15 @@ token_compare(void *baton, void *token1,
NULL,
_("The file '%s' changed unexpectedly"
" during diff"),
- file_baton->path[idx[i]]);
+ file[i]->path);
/* Read a chunk from disk into a buffer */
bufp[i] = buffer[i];
length[i] = raw_length[i] > COMPARE_CHUNK_SIZE ?
COMPARE_CHUNK_SIZE : raw_length[i];
- SVN_ERR(read_chunk(file_baton->file[idx[i]],
- file_baton->path[idx[i]],
+ SVN_ERR(read_chunk(file[i]->file,
+ file[i]->path,
bufp[i], length[i], offset[i],
file_baton->pool));
offset[i] += length[i];
@@ -555,12 +562,42 @@ svn_diff_file_options_create(apr_pool_t
return apr_pcalloc(pool, sizeof(svn_diff_file_options_t));
}
+/* A baton for use with opt_parsing_error_func(). */
+struct opt_parsing_error_baton_t
+{
+ svn_error_t *err;
+ apr_pool_t *pool;
+};
+
+/* Store an error message from apr_getopt_long(). Set BATON->err to a new
+ * error with a message generated from FMT and the remaining arguments.
+ * Implements apr_getopt_err_fn_t. */
+static void
+opt_parsing_error_func(void *baton,
+ const char *fmt, ...)
+{
+ struct opt_parsing_error_baton_t *b = baton;
+ const char *message;
+ va_list ap;
+
+ va_start(ap, fmt);
+ message = apr_pvsprintf(b->pool, fmt, ap);
+ va_end(ap);
+
+ /* Skip leading ": " (if present, which it always is in known cases). */
+ if (strncmp(message, ": ", 2) == 0)
+ message += 2;
+
+ b->err = svn_error_create(SVN_ERR_INVALID_DIFF_OPTION, NULL, message);
+}
+
svn_error_t *
svn_diff_file_options_parse(svn_diff_file_options_t *options,
const apr_array_header_t *args,
apr_pool_t *pool)
{
apr_getopt_t *os;
+ struct opt_parsing_error_baton_t opt_parsing_error_baton = { NULL, pool };
/* Make room for each option (starting at index 1) plus trailing NULL. */
const char **argv = apr_palloc(pool, sizeof(char*) * (args->nelts + 2));
@@ -569,8 +606,12 @@ svn_diff_file_options_parse(svn_diff_fil
argv[args->nelts + 1] = NULL;
apr_getopt_init(&os, pool, args->nelts + 1, argv);
- /* No printing of error messages, please! */
- os->errfn = NULL;
+
+ /* Capture any error message from apr_getopt_long(). This will typically
+ * say which option is wrong, which we would not otherwise know. */
+ os->errfn = opt_parsing_error_func;
+ os->errarg = &opt_parsing_error_baton;
+
while (1)
{
const char *opt_arg;
@@ -580,7 +621,13 @@ svn_diff_file_options_parse(svn_diff_fil
if (APR_STATUS_IS_EOF(err))
break;
if (err)
- return svn_error_wrap_apr(err, _("Error parsing diff options"));
+ /* Wrap apr_getopt_long()'s error message. Its doc string implies
+ * it always will produce one, but never mind if it doesn't. Avoid
+ * using the message associated with the return code ERR, because
+ * it refers to the "command line" which may be misleading here. */
+ return svn_error_create(SVN_ERR_INVALID_DIFF_OPTION,
+ opt_parsing_error_baton.err,
+ _("Error in options to internal diff"));
switch (opt_id)
{
@@ -623,8 +670,8 @@ svn_diff_file_diff_2(svn_diff_t **diff,
memset(&baton, 0, sizeof(baton));
baton.options = options;
- baton.path[0] = original;
- baton.path[1] = modified;
+ baton.files[0].path = original;
+ baton.files[1].path = modified;
baton.pool = svn_pool_create(pool);
SVN_ERR(svn_diff_diff(diff, &baton, &svn_diff__file_vtable, pool));
@@ -645,9 +692,9 @@ svn_diff_file_diff3_2(svn_diff_t **diff,
memset(&baton, 0, sizeof(baton));
baton.options = options;
- baton.path[0] = original;
- baton.path[1] = modified;
- baton.path[2] = latest;
+ baton.files[0].path = original;
+ baton.files[1].path = modified;
+ baton.files[2].path = latest;
baton.pool = svn_pool_create(pool);
SVN_ERR(svn_diff_diff3(diff, &baton, &svn_diff__file_vtable, pool));
@@ -669,10 +716,10 @@ svn_diff_file_diff4_2(svn_diff_t **diff,
memset(&baton, 0, sizeof(baton));
baton.options = options;
- baton.path[0] = original;
- baton.path[1] = modified;
- baton.path[2] = latest;
- baton.path[3] = ancestor;
+ baton.files[0].path = original;
+ baton.files[1].path = modified;
+ baton.files[2].path = latest;
+ baton.files[3].path = ancestor;
baton.pool = svn_pool_create(pool);
SVN_ERR(svn_diff_diff4(diff, &baton, &svn_diff__file_vtable, pool));
Modified: subversion/branches/gpg-agent-password-store/subversion/libsvn_diff/parse-diff.c
URL: http://svn.apache.org/viewvc/subversion/branches/gpg-agent-password-store/subversion/libsvn_diff/parse-diff.c?rev=1041580&r1=1041579&r2=1041580&view=diff
==============================================================================
--- subversion/branches/gpg-agent-password-store/subversion/libsvn_diff/parse-diff.c (original)
+++ subversion/branches/gpg-agent-password-store/subversion/libsvn_diff/parse-diff.c Thu Dec 2 20:55:08 2010
@@ -28,6 +28,7 @@
#include "svn_error.h"
#include "svn_io.h"
#include "svn_pools.h"
+#include "svn_props.h"
#include "svn_string.h"
#include "svn_utf.h"
#include "svn_dirent_uri.h"
@@ -189,6 +190,7 @@ parse_hunk_header(const char *header, sv
const char *atat, apr_pool_t *pool)
{
const char *p;
+ const char *start;
svn_stringbuf_t *range;
p = header + strlen(atat);
@@ -201,16 +203,18 @@ parse_hunk_header(const char *header, sv
return FALSE;
/* OK, this may be worth allocating some memory for... */
range = svn_stringbuf_create_ensure(31, pool);
- p++;
+ start = ++p;
while (*p && *p != ' ')
{
- svn_stringbuf_appendbyte(range, *p);
p++;
}
+
if (*p != ' ')
/* No no no... */
return FALSE;
+ svn_stringbuf_appendbytes(range, start, p - start);
+
/* Try to parse the first range. */
if (! parse_range(&hunk->original_start, &hunk->original_length, range->data))
return FALSE;
@@ -222,16 +226,17 @@ parse_hunk_header(const char *header, sv
/* Eeek! */
return FALSE;
/* OK, this may be worth copying... */
- p++;
+ start = ++p;
while (*p && *p != ' ')
{
- svn_stringbuf_appendbyte(range, *p);
p++;
}
if (*p != ' ')
/* No no no... */
return FALSE;
+ svn_stringbuf_appendbytes(range, start, p - start);
+
/* Check for trailing @@ */
p++;
if (! starts_with(p, atat))
@@ -477,19 +482,24 @@ svn_diff_hunk_readline_diff_text(const s
return SVN_NO_ERROR;
}
-/* Parse PROP_NAME from HEADER as the part after the INDICATOR line. */
+/* Parse *PROP_NAME from HEADER as the part after the INDICATOR line.
+ * Allocate *PROP_NAME in RESULT_POOL.
+ * Set *PROP_NAME to NULL if no valid property name was found. */
static svn_error_t *
parse_prop_name(const char **prop_name, const char *header,
const char *indicator, apr_pool_t *result_pool)
{
- /* ### This can fail if the filename cannot be represented in the current
- * ### locale's encoding. */
SVN_ERR(svn_utf_cstring_to_utf8(prop_name,
header + strlen(indicator),
result_pool));
-
- /* ### Are we guarenteed that there are no trailing or leading
- * ### whitespaces in the name? */
+ if (**prop_name == '\0')
+ *prop_name = NULL;
+ else if (! svn_prop_name_is_valid(*prop_name))
+ {
+ svn_stringbuf_t *buf = svn_stringbuf_create(*prop_name, result_pool);
+ svn_stringbuf_strip_whitespace(buf);
+ *prop_name = (svn_prop_name_is_valid(buf->data) ? buf->data : NULL);
+ }
return SVN_NO_ERROR;
}
@@ -674,20 +684,23 @@ parse_next_hunk(svn_diff_hunk_t **hunk,
else if (starts_with(line->data, "Added: "))
{
SVN_ERR(parse_prop_name(prop_name, line->data, "Added: ",
- result_pool));
- *prop_operation = svn_diff_op_added;
+ result_pool));
+ if (*prop_name)
+ *prop_operation = svn_diff_op_added;
}
else if (starts_with(line->data, "Deleted: "))
{
SVN_ERR(parse_prop_name(prop_name, line->data, "Deleted: ",
result_pool));
- *prop_operation = svn_diff_op_deleted;
+ if (*prop_name)
+ *prop_operation = svn_diff_op_deleted;
}
else if (starts_with(line->data, "Modified: "))
{
SVN_ERR(parse_prop_name(prop_name, line->data, "Modified: ",
result_pool));
- *prop_operation = svn_diff_op_modified;
+ if (*prop_name)
+ *prop_operation = svn_diff_op_modified;
}
else if (starts_with(line->data, minus)
|| starts_with(line->data, "diff --git "))
@@ -1027,7 +1040,7 @@ git_move_from(enum parse_state *new_stat
return SVN_NO_ERROR;
}
-/* Parse the 'rename to ' line fo a git extended unidiff. */
+/* Parse the 'rename to ' line of a git extended unidiff. */
static svn_error_t *
git_move_to(enum parse_state *new_state, const char *line, svn_patch_t *patch,
apr_pool_t *result_pool, apr_pool_t *scratch_pool)
@@ -1262,6 +1275,8 @@ svn_diff_parse_next_patch(svn_patch_t **
const char *prop_name;
svn_diff_operation_kind_t prop_operation;
+ last_prop_name = NULL;
+
/* Parse hunks. */
(*patch)->hunks = apr_array_make(result_pool, 10,
sizeof(svn_diff_hunk_t *));
Modified: subversion/branches/gpg-agent-password-store/subversion/libsvn_fs/fs-loader.c
URL: http://svn.apache.org/viewvc/subversion/branches/gpg-agent-password-store/subversion/libsvn_fs/fs-loader.c?rev=1041580&r1=1041579&r2=1041580&view=diff
==============================================================================
--- subversion/branches/gpg-agent-password-store/subversion/libsvn_fs/fs-loader.c (original)
+++ subversion/branches/gpg-agent-password-store/subversion/libsvn_fs/fs-loader.c Thu Dec 2 20:55:08 2010
@@ -991,6 +991,22 @@ svn_fs_closest_copy(svn_fs_root_t **root
}
svn_error_t *
+svn_fs_get_mergeinfo2(svn_mergeinfo_catalog_t *catalog,
+ svn_fs_root_t *root,
+ const apr_array_header_t *paths,
+ svn_mergeinfo_inheritance_t inherit,
+ svn_boolean_t validate_inherited_mergeinfo,
+ svn_boolean_t include_descendants,
+ apr_pool_t *pool)
+{
+ return svn_error_return(root->vtable->get_mergeinfo(catalog, root, paths,
+ inherit,
+ validate_inherited_mergeinfo,
+ include_descendants,
+ pool));
+}
+
+svn_error_t *
svn_fs_get_mergeinfo(svn_mergeinfo_catalog_t *catalog,
svn_fs_root_t *root,
const apr_array_header_t *paths,
@@ -998,10 +1014,24 @@ svn_fs_get_mergeinfo(svn_mergeinfo_catal
svn_boolean_t include_descendants,
apr_pool_t *pool)
{
- return svn_error_return(root->vtable->get_mergeinfo(catalog, root, paths,
- inherit,
- include_descendants,
- pool));
+ return svn_error_return(svn_fs_get_mergeinfo2(catalog, root, paths,
+ inherit,
+ FALSE,
+ include_descendants,
+ pool));
+}
+
+svn_error_t *
+svn_fs_validate_mergeinfo(svn_mergeinfo_t *validated_mergeinfo,
+ svn_fs_t *fs,
+ svn_mergeinfo_t mergeinfo,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ return svn_error_return(fs->vtable->validate_mergeinfo(validated_mergeinfo,
+ fs, mergeinfo,
+ result_pool,
+ scratch_pool));
}
svn_error_t *
Modified: subversion/branches/gpg-agent-password-store/subversion/libsvn_fs/fs-loader.h
URL: http://svn.apache.org/viewvc/subversion/branches/gpg-agent-password-store/subversion/libsvn_fs/fs-loader.h?rev=1041580&r1=1041579&r2=1041580&view=diff
==============================================================================
--- subversion/branches/gpg-agent-password-store/subversion/libsvn_fs/fs-loader.h (original)
+++ subversion/branches/gpg-agent-password-store/subversion/libsvn_fs/fs-loader.h Thu Dec 2 20:55:08 2010
@@ -197,6 +197,11 @@ typedef struct fs_vtable_t
svn_error_t *(*bdb_set_errcall)(svn_fs_t *fs,
void (*handler)(const char *errpfx,
char *msg));
+ svn_error_t *(*validate_mergeinfo)(svn_mergeinfo_t *validated_mergeinfo,
+ svn_fs_t *fs,
+ svn_mergeinfo_t mergeinfo,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
} fs_vtable_t;
@@ -331,6 +336,7 @@ typedef struct root_vtable_t
svn_fs_root_t *root,
const apr_array_header_t *paths,
svn_mergeinfo_inheritance_t inherit,
+ svn_boolean_t validate_inherited_mergeinfo,
svn_boolean_t include_descendants,
apr_pool_t *pool);
} root_vtable_t;
Modified: subversion/branches/gpg-agent-password-store/subversion/libsvn_fs_base/dag.c
URL: http://svn.apache.org/viewvc/subversion/branches/gpg-agent-password-store/subversion/libsvn_fs_base/dag.c?rev=1041580&r1=1041579&r2=1041580&view=diff
==============================================================================
--- subversion/branches/gpg-agent-password-store/subversion/libsvn_fs_base/dag.c (original)
+++ subversion/branches/gpg-agent-password-store/subversion/libsvn_fs_base/dag.c Thu Dec 2 20:55:08 2010
@@ -481,7 +481,7 @@ make_entry(dag_node_t **child_p,
/* Create the new node's NODE-REVISION */
memset(&new_noderev, 0, sizeof(new_noderev));
new_noderev.kind = is_dir ? svn_node_dir : svn_node_file;
- new_noderev.created_path = svn_uri_join(parent_path, name, pool);
+ new_noderev.created_path = svn_fspath__join(parent_path, name, pool);
SVN_ERR(svn_fs_base__create_node
(&new_node_id, svn_fs_base__dag_get_fs(parent), &new_noderev,
svn_fs_base__id_copy_id(svn_fs_base__dag_get_id(parent)),
@@ -763,7 +763,7 @@ svn_fs_base__dag_clone_child(dag_node_t
noderev->predecessor_id = cur_entry->id;
if (noderev->predecessor_count != -1)
noderev->predecessor_count++;
- noderev->created_path = svn_uri_join(parent_path, name, pool);
+ noderev->created_path = svn_fspath__join(parent_path, name, pool);
SVN_ERR(svn_fs_base__create_successor(&new_node_id, fs, cur_entry->id,
noderev, copy_id, txn_id,
trail, pool));
@@ -1422,7 +1422,7 @@ svn_fs_base__dag_copy(dag_node_t *to_nod
noderev->predecessor_id = svn_fs_base__id_copy(src_id, pool);
if (noderev->predecessor_count != -1)
noderev->predecessor_count++;
- noderev->created_path = svn_uri_join
+ noderev->created_path = svn_fspath__join
(svn_fs_base__dag_get_created_path(to_node), entry, pool);
SVN_ERR(svn_fs_base__create_successor(&id, fs, src_id, noderev,
copy_id, txn_id, trail, pool));
Modified: subversion/branches/gpg-agent-password-store/subversion/libsvn_fs_base/fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/gpg-agent-password-store/subversion/libsvn_fs_base/fs.c?rev=1041580&r1=1041579&r2=1041580&view=diff
==============================================================================
--- subversion/branches/gpg-agent-password-store/subversion/libsvn_fs_base/fs.c (original)
+++ subversion/branches/gpg-agent-password-store/subversion/libsvn_fs_base/fs.c Thu Dec 2 20:55:08 2010
@@ -497,6 +497,7 @@ static fs_vtable_t fs_vtable = {
svn_fs_base__get_lock,
svn_fs_base__get_locks,
base_bdb_set_errcall,
+ svn_fs_base__validate_mergeinfo,
};
/* Where the format number is stored. */