summaryrefslogtreecommitdiff
path: root/subversion/libsvn_wc/questions.c
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/libsvn_wc/questions.c')
-rw-r--r--subversion/libsvn_wc/questions.c195
1 files changed, 160 insertions, 35 deletions
diff --git a/subversion/libsvn_wc/questions.c b/subversion/libsvn_wc/questions.c
index c2a42b6..0858363 100644
--- a/subversion/libsvn_wc/questions.c
+++ b/subversion/libsvn_wc/questions.c
@@ -117,6 +117,7 @@ compare_and_verify(svn_boolean_t *modified_p,
apr_hash_t *keywords;
svn_boolean_t special = FALSE;
svn_boolean_t need_translation;
+ svn_stream_t *v_stream; /* versioned_file */
SVN_ERR_ASSERT(svn_dirent_is_absolute(versioned_file_abspath));
@@ -150,22 +151,24 @@ compare_and_verify(svn_boolean_t *modified_p,
/* ### Other checks possible? */
- if (need_translation)
+ /* Reading files is necessary. */
+ if (special && need_translation)
{
- /* Reading files is necessary. */
- svn_stream_t *v_stream; /* versioned_file */
-
- if (special)
- {
- SVN_ERR(svn_subst_read_specialfile(&v_stream, versioned_file_abspath,
- scratch_pool, scratch_pool));
- }
- else
+ SVN_ERR(svn_subst_read_specialfile(&v_stream, versioned_file_abspath,
+ scratch_pool, scratch_pool));
+ }
+ else
+ {
+ /* We don't use APR-level buffering because the comparison function
+ * will do its own buffering. */
+ apr_file_t *file;
+ SVN_ERR(svn_io_file_open(&file, versioned_file_abspath, APR_READ,
+ APR_OS_DEFAULT, scratch_pool));
+ v_stream = svn_stream_from_aprfile2(file, FALSE, scratch_pool);
+
+ if (need_translation)
{
- SVN_ERR(svn_stream_open_readonly(&v_stream, versioned_file_abspath,
- scratch_pool, scratch_pool));
-
- if (!exact_comparison && need_translation)
+ if (!exact_comparison)
{
if (eol_style == svn_subst_eol_style_native)
eol_str = SVN_SUBST_NATIVE_EOL_STR;
@@ -183,7 +186,7 @@ compare_and_verify(svn_boolean_t *modified_p,
FALSE /* expand */,
scratch_pool);
}
- else if (need_translation)
+ else
{
/* Wrap base stream to translate into working copy form, and
* arrange to throw an error if its EOL style is inconsistent. */
@@ -193,21 +196,10 @@ compare_and_verify(svn_boolean_t *modified_p,
scratch_pool);
}
}
-
- SVN_ERR(svn_stream_contents_same2(&same, pristine_stream, v_stream,
- scratch_pool));
}
- else
- {
- /* Translation would be a no-op, so compare the original file. */
- svn_stream_t *v_stream; /* versioned_file */
- SVN_ERR(svn_stream_open_readonly(&v_stream, versioned_file_abspath,
- scratch_pool, scratch_pool));
-
- SVN_ERR(svn_stream_contents_same2(&same, pristine_stream, v_stream,
- scratch_pool));
- }
+ SVN_ERR(svn_stream_contents_same2(&same, pristine_stream, v_stream,
+ scratch_pool));
*modified_p = (! same);
@@ -377,7 +369,8 @@ internal_conflicted_p(svn_boolean_t *text_conflicted_p,
svn_boolean_t resolved_text = FALSE;
svn_boolean_t resolved_props = FALSE;
- SVN_ERR(svn_wc__db_read_conflict(&conflicts, db, local_abspath,
+ SVN_ERR(svn_wc__db_read_conflict(&conflicts, NULL, NULL,
+ db, local_abspath,
scratch_pool, scratch_pool));
if (!conflicts)
@@ -604,18 +597,150 @@ svn_wc__has_switched_subtrees(svn_boolean_t *is_switched,
}
+/* A baton for use with modcheck_found_entry(). */
+typedef struct modcheck_baton_t {
+ svn_boolean_t ignore_unversioned;
+ svn_boolean_t found_mod; /* whether a modification has been found */
+ svn_boolean_t found_not_delete; /* Found a not-delete modification */
+} modcheck_baton_t;
+
+/* An implementation of svn_wc_status_func4_t. */
+static svn_error_t *
+modcheck_callback(void *baton,
+ const char *local_abspath,
+ const svn_wc_status3_t *status,
+ apr_pool_t *scratch_pool)
+{
+ modcheck_baton_t *mb = baton;
+
+ switch (status->node_status)
+ {
+ case svn_wc_status_normal:
+ case svn_wc_status_ignored:
+ case svn_wc_status_none:
+ case svn_wc_status_external:
+ break;
+
+ case svn_wc_status_incomplete:
+ if ((status->text_status != svn_wc_status_normal
+ && status->text_status != svn_wc_status_none)
+ || (status->prop_status != svn_wc_status_normal
+ && status->prop_status != svn_wc_status_none))
+ {
+ mb->found_mod = TRUE;
+ mb->found_not_delete = TRUE;
+ /* Incomplete, but local modifications */
+ return svn_error_create(SVN_ERR_CEASE_INVOCATION, NULL, NULL);
+ }
+ break;
+
+ case svn_wc_status_deleted:
+ mb->found_mod = TRUE;
+ if (!mb->ignore_unversioned
+ && status->actual_kind != svn_node_none
+ && status->actual_kind != svn_node_unknown)
+ {
+ /* The delete is obstructed by something unversioned */
+ mb->found_not_delete = TRUE;
+ return svn_error_create(SVN_ERR_CEASE_INVOCATION, NULL, NULL);
+ }
+ break;
+
+ case svn_wc_status_unversioned:
+ if (mb->ignore_unversioned)
+ break;
+ /* else fall through */
+ case svn_wc_status_missing:
+ case svn_wc_status_obstructed:
+ mb->found_mod = TRUE;
+ mb->found_not_delete = TRUE;
+ /* Exit from the status walker: We know what we want to know */
+ return svn_error_create(SVN_ERR_CEASE_INVOCATION, NULL, NULL);
+
+ default:
+ case svn_wc_status_added:
+ case svn_wc_status_replaced:
+ case svn_wc_status_modified:
+ mb->found_mod = TRUE;
+ mb->found_not_delete = TRUE;
+ /* Exit from the status walker: We know what we want to know */
+ return svn_error_create(SVN_ERR_CEASE_INVOCATION, NULL, NULL);
+ }
+
+ return SVN_NO_ERROR;
+}
+
+
+/* Set *MODIFIED to true iff there are any local modifications within the
+ * tree rooted at LOCAL_ABSPATH, using DB. If *MODIFIED
+ * is set to true and all the local modifications were deletes then set
+ * *ALL_EDITS_ARE_DELETES to true, set it to false otherwise. LOCAL_ABSPATH
+ * may be a file or a directory. */
+svn_error_t *
+svn_wc__node_has_local_mods(svn_boolean_t *modified,
+ svn_boolean_t *all_edits_are_deletes,
+ svn_wc__db_t *db,
+ const char *local_abspath,
+ svn_boolean_t ignore_unversioned,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ apr_pool_t *scratch_pool)
+{
+ modcheck_baton_t modcheck_baton = { FALSE, FALSE, FALSE };
+ svn_error_t *err;
+
+ if (!all_edits_are_deletes)
+ {
+ SVN_ERR(svn_wc__db_has_db_mods(modified, db, local_abspath,
+ scratch_pool));
+
+ if (*modified)
+ return SVN_NO_ERROR;
+ }
+
+ modcheck_baton.ignore_unversioned = ignore_unversioned;
+
+ /* Walk the WC tree for status with depth infinity, looking for any local
+ * modifications. If it's a "sparse" directory, that's OK: there can be
+ * no local mods in the pieces that aren't present in the WC. */
+
+ err = svn_wc__internal_walk_status(db, local_abspath,
+ svn_depth_infinity,
+ FALSE, FALSE, FALSE, NULL,
+ modcheck_callback, &modcheck_baton,
+ cancel_func, cancel_baton,
+ scratch_pool);
+
+ if (err && err->apr_err == SVN_ERR_CEASE_INVOCATION)
+ svn_error_clear(err);
+ else
+ SVN_ERR(err);
+
+ *modified = modcheck_baton.found_mod;
+ if (all_edits_are_deletes)
+ *all_edits_are_deletes = (modcheck_baton.found_mod
+ && !modcheck_baton.found_not_delete);
+
+ return SVN_NO_ERROR;
+}
+
svn_error_t *
svn_wc__has_local_mods(svn_boolean_t *is_modified,
svn_wc_context_t *wc_ctx,
const char *local_abspath,
+ svn_boolean_t ignore_unversioned,
svn_cancel_func_t cancel_func,
void *cancel_baton,
apr_pool_t *scratch_pool)
{
- return svn_error_trace(svn_wc__db_has_local_mods(is_modified,
- wc_ctx->db,
- local_abspath,
- cancel_func,
- cancel_baton,
- scratch_pool));
+ svn_boolean_t modified;
+
+ SVN_ERR(svn_wc__node_has_local_mods(&modified, NULL,
+ wc_ctx->db, local_abspath,
+ ignore_unversioned,
+ cancel_func, cancel_baton,
+ scratch_pool));
+
+ *is_modified = modified;
+ return SVN_NO_ERROR;
}