You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by hw...@apache.org on 2010/08/10 22:56:05 UTC
svn commit: r984206 [20/35] - in /subversion/branches/ignore-mergeinfo: ./
build/ build/generator/ build/generator/templates/ build/hudson/
build/hudson/jobs/subversion-1.6.x-solaris/
build/hudson/jobs/subversion-1.6.x-ubuntu/ build/hudson/jobs/subvers...
Modified: subversion/branches/ignore-mergeinfo/subversion/libsvn_wc/props.c
URL: http://svn.apache.org/viewvc/subversion/branches/ignore-mergeinfo/subversion/libsvn_wc/props.c?rev=984206&r1=984205&r2=984206&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_wc/props.c (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_wc/props.c Tue Aug 10 20:55:56 2010
@@ -38,7 +38,6 @@
#include "svn_pools.h"
#include "svn_dirent_uri.h"
#include "svn_path.h"
-#include "svn_xml.h"
#include "svn_error.h"
#include "svn_props.h"
#include "svn_io.h"
@@ -50,6 +49,7 @@
#include "private/svn_wc_private.h"
#include "private/svn_mergeinfo_private.h"
+#include "private/svn_skel.h"
#include "wc.h"
#include "log.h"
@@ -57,43 +57,23 @@
#include "entries.h"
#include "props.h"
#include "translate.h"
-#include "lock.h"
+#include "lock.h" /* for svn_wc__write_check() */
#include "workqueue.h"
+#include "conflicts.h"
#include "svn_private_config.h"
/* #define TEST_DB_PROPS */
-/*** Reading/writing property hashes from disk ***/
-/* ### HKW/WC-NG: This is a summary of the my efforts to localize accesses to
- svn_wc__prop_path(), in preparation to moving to the wc_db API. The
- general idea here is to combine all calls to svn_wc__prop_path() into a
- single one, which will make conversion to the new db API easier. The catch
- is our currently loggy implementation, which uses the properties file path
- all over the place. Rather than attempt to refactor all of those right
- now, I'm going to punt and leave properties loggy-ness to the SQLite
- transaction mechanism.
-
- Also, several of these could be funnelled through the load_props()
- interface, but for the fact that it may complicate handling of propcaching.
- I'm happy to do that, but I'm wary of killing performance right before
- branching 1.6, so those will happen after we branch, and trunk is once
- again a free-for-all.
-
- The following functions currently call this API:
- load_props(): The current "gateway" function through we all access to
- properties should be funneled.
- svn_wc__working_props_committed(): Moves WORKING props to BASE props,
- sync'ing to disk and clearing appropriate caches.
- install_props_file(): Used with loggy.
- svn_wc__install_props(): Used with loggy.
- svn_wc__loggy_revert_props_create(): Used with loggy.
- svn_wc__loggy_revert_props_restore(): Used with loggy.
- */
+/* Forward declaration. */
+static const svn_string_t *
+message_from_skel(const svn_skel_t *skel,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
-/* The real functionality here is part of libsvn_subr, in hashdump.c.
- But these are convenience routines for use in libsvn_wc. */
+
+#if (SVN_WC__VERSION < SVN_WC__PROPS_IN_DB)
/* Get PATH's properies of PROPS_KIND, and put them into *HASH.
PATH should be of kind NODE_KIND. */
@@ -152,78 +132,145 @@ load_props(apr_hash_t **hash,
return svn_stream_close(stream);
}
+#endif /* (SVN_WC__VERSION < SVN_WC__PROPS_IN_DB) */
+
-/* */
static svn_error_t *
-loggy_write_properties(svn_stringbuf_t **log_accum,
- apr_hash_t *properties,
- const char *dest_abspath,
- const char *adm_abspath,
- apr_pool_t *scratch_pool)
+load_pristine_props(apr_hash_t **props,
+ svn_wc__db_t *db,
+ const char *local_abspath,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
- const char *prop_tmp_abspath;
- svn_stream_t *stream;
+#if (SVN_WC__VERSION >= SVN_WC__PROPS_IN_DB)
- /* Write the property hash into a temporary file. */
- SVN_ERR(svn_stream_open_unique(&stream, &prop_tmp_abspath,
- svn_dirent_dirname(dest_abspath,
- scratch_pool),
- svn_io_file_del_none,
- scratch_pool, scratch_pool));
- if (apr_hash_count(properties) != 0)
- SVN_ERR(svn_hash_write2(properties, stream, SVN_HASH_TERMINATOR,
- scratch_pool));
- SVN_ERR(svn_stream_close(stream));
+ SVN_ERR(svn_wc__db_read_pristine_props(props, db, local_abspath,
+ result_pool, scratch_pool));
+
+#ifdef TEST_DB_PROPS
+ {
+ SVN_ERR_MALFUNCTION(); /* ### not yet implemented */
+ }
+#endif
+
+#else /* (SVN_WC__VERSION >= SVN_WC__PROPS_IN_DB) */
+
+ /* NOTE: svn_wc__props_base really means "pristine" props, which may
+ come from BASE or WORKING. */
+ SVN_ERR(load_props(props, db, local_abspath, svn_wc__props_base,
+ result_pool));
+
+#ifdef TEST_DB_PROPS
+ {
+ apr_hash_t *db_base_props;
+
+ SVN_ERR(svn_wc__db_read_pristine_props(&db_base_props, db,
+ local_abspath,
+ scratch_pool, scratch_pool));
- /* Write a log entry to move tmp file to the destination. */
- SVN_ERR(svn_wc__loggy_move(log_accum, adm_abspath,
- prop_tmp_abspath, dest_abspath,
- scratch_pool, scratch_pool));
-
- /* And make the destination read-only. */
- SVN_ERR(svn_wc__loggy_set_readonly(log_accum, adm_abspath,
- dest_abspath,
- scratch_pool, scratch_pool));
+ if (*props != NULL && apr_hash_count(*props) > 0)
+ {
+ apr_array_header_t *diffs;
+
+ SVN_ERR_ASSERT(db_base_props != NULL);
+
+ SVN_ERR(svn_prop_diffs(&diffs, *props, db_base_props, scratch_pool));
+ SVN_ERR_ASSERT(diffs->nelts == 0);
+ }
+ else
+ {
+ /* If the propfile is missing, then we should see no/empty props
+ in the database. */
+ SVN_ERR_ASSERT(db_base_props == NULL
+ || apr_hash_count(db_base_props) == 0);
+ }
+ }
+#endif /* TEST_DB_PROPS */
+#endif /* (SVN_WC__VERSION >= SVN_WC__PROPS_IN_DB) */
return SVN_NO_ERROR;
}
-/*---------------------------------------------------------------------*/
-
-/*** Misc ***/
-
-/* Opens reject temporary stream for FULL_PATH in the appropriate tmp space. */
static svn_error_t *
-open_reject_tmp_stream(svn_stream_t **stream,
- const char **reject_tmp_path,
- svn_wc__db_t *db,
- const char *local_abspath,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
+load_actual_props(apr_hash_t **props,
+ svn_wc__db_t *db,
+ const char *local_abspath,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
- const char *tmp_base_abspath;
+#if (SVN_WC__VERSION >= SVN_WC__PROPS_IN_DB)
+
+ SVN_ERR(svn_wc__db_read_props(props, db, local_abspath,
+ result_pool, scratch_pool));
- SVN_ERR(svn_wc__db_temp_wcroot_tempdir(&tmp_base_abspath, db, local_abspath,
- scratch_pool, scratch_pool));
+#ifdef TEST_DB_PROPS
+ {
+ SVN_ERR_MALFUNCTION(); /* ### not yet implemented */
+ }
+#endif
- return svn_stream_open_unique(stream, reject_tmp_path, tmp_base_abspath,
- svn_io_file_del_none, result_pool,
- scratch_pool);
+#else /* (SVN_WC__VERSION >= SVN_WC__PROPS_IN_DB) */
+ /* NOTE: svn_wc__props_working really means ACTUAL. */
+ SVN_ERR(load_props(props, db, local_abspath, svn_wc__props_working,
+ result_pool));
+
+ /* It is possible that we'll get NULL back, meaning "no props file".
+ For this case, just use the pristine properties. This is very
+ different from an empty file, which means "all props deleted". */
+ if (*props == NULL)
+ {
+ SVN_ERR(load_pristine_props(props, db, local_abspath,
+ result_pool, scratch_pool));
+
+ /* If pristines are not defined for this node, then define this
+ node to have an empty set of properties. */
+ if (*props == NULL)
+ *props = apr_hash_make(result_pool);
+ }
+
+#ifdef TEST_DB_PROPS
+ {
+ apr_hash_t *db_props;
+ apr_array_header_t *diffs;
+
+ SVN_ERR_ASSERT(*props != NULL);
+
+ SVN_ERR(svn_wc__db_read_props(&db_props, db, local_abspath,
+ scratch_pool, scratch_pool));
+
+ if (db_props != NULL)
+ {
+ SVN_ERR(svn_prop_diffs(&diffs, *props, db_props, scratch_pool));
+ SVN_ERR_ASSERT(diffs->nelts == 0);
+ }
+ else
+ {
+ SVN_ERR_ASSERT(apr_hash_count(*props) == 0);
+ }
+ }
+#endif /* TEST_DB_PROPS */
+#endif /* (SVN_WC__VERSION >= SVN_WC__PROPS_IN_DB) */
+
+ return SVN_NO_ERROR;
}
-/* Write CONFLICT_DESCRIPTION to STREAM, plus a trailing EOL sequence. */
+/* Given a *SINGLE* property conflict in PROP_SKEL, generate a message
+ for it, and write it to STREAM, along with a trailing EOL sequence.
+
+ See message_from_skel() for details on PROP_SKEL. */
static svn_error_t *
append_prop_conflict(svn_stream_t *stream,
- const svn_string_t *conflict_description,
+ const svn_skel_t *prop_skel,
apr_pool_t *pool)
{
/* TODO: someday, perhaps prefix each conflict_description with a
timestamp or something? */
+ const svn_string_t *message = message_from_skel(prop_skel, pool, pool);
apr_size_t len;
const char *native_text =
- svn_utf_cstring_from_utf8_fuzzy(conflict_description->data, pool);
+ svn_utf_cstring_from_utf8_fuzzy(message->data, pool);
len = strlen(native_text);
SVN_ERR(svn_stream_write(stream, native_text, &len));
@@ -236,20 +283,18 @@ append_prop_conflict(svn_stream_t *strea
/* Get the reject file for LOCAL_ABSPATH in DB. Set *REJECT_FILE to the
name of that file, or to NULL if no such file exists. */
-static svn_error_t *
-get_existing_prop_reject_file(const char **reject_file,
- svn_wc__db_t *db,
- const char *adm_abspath,
- const char *local_abspath,
- apr_pool_t *pool)
+svn_error_t *
+svn_wc__get_prejfile_abspath(const char **prejfile_abspath,
+ svn_wc__db_t *db,
+ const char *local_abspath,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
const apr_array_header_t *conflicts;
int i;
- *reject_file = NULL;
-
SVN_ERR(svn_wc__db_read_conflicts(&conflicts, db, local_abspath,
- pool, pool));
+ scratch_pool, scratch_pool));
for (i = 0; i < conflicts->nelts; i++)
{
@@ -257,148 +302,103 @@ get_existing_prop_reject_file(const char
cd = APR_ARRAY_IDX(conflicts, i, const svn_wc_conflict_description2_t *);
if (cd->kind == svn_wc_conflict_kind_property)
- *reject_file = svn_dirent_join(adm_abspath, cd->their_file, pool);
+ {
+ if (strcmp(cd->their_file,
+ SVN_WC__THIS_DIR_PREJ SVN_WC__PROP_REJ_EXT) == 0)
+ *prejfile_abspath = svn_dirent_join(
+ local_abspath,
+ SVN_WC__THIS_DIR_PREJ SVN_WC__PROP_REJ_EXT,
+ result_pool);
+ else
+ *prejfile_abspath = svn_dirent_join(
+ svn_dirent_dirname(local_abspath,
+ scratch_pool),
+ cd->their_file,
+ result_pool);
+ return SVN_NO_ERROR;
+ }
}
+ *prejfile_abspath = NULL;
return SVN_NO_ERROR;
}
-/*---------------------------------------------------------------------*/
-
-
-/*** Loading regular properties. ***/
svn_error_t *
-svn_wc__load_props(apr_hash_t **base_props_p,
- apr_hash_t **props_p,
- svn_wc__db_t *db,
- const char *local_abspath,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
+svn_wc__get_revert_props(apr_hash_t **revert_props_p,
+ svn_wc__db_t *db,
+ const char *local_abspath,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
- apr_hash_t *base_props = NULL; /* Silence uninitialized warning. */
-
- SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
-
- /* We will need the base props if the user requested them, or we need
- them if no (working) prop mods have occurred. */
- if (base_props_p != NULL || props_p != NULL)
- {
- SVN_ERR(load_props(&base_props, db, local_abspath, svn_wc__props_base,
- result_pool));
-
- if (base_props_p)
- *base_props_p = base_props;
-
-#ifdef TEST_DB_PROPS
- {
- apr_hash_t *db_base_props;
-
- SVN_ERR(svn_wc__db_read_pristine_props(&db_base_props, db,
- local_abspath,
- scratch_pool, scratch_pool));
- SVN_ERR_ASSERT(db_base_props != NULL);
+ svn_boolean_t replaced;
- if (base_props != NULL)
- {
- apr_array_header_t *diffs;
-
- SVN_ERR(svn_prop_diffs(&diffs, base_props, db_base_props,
- scratch_pool));
- SVN_ERR_ASSERT(diffs->nelts == 0);
- }
- else
- {
- /* If the propfile is missing, then we should see empty props
- in the database. */
- SVN_ERR_ASSERT(apr_hash_count(db_base_props) == 0);
- }
- }
-#endif
- }
+ SVN_ERR_ASSERT(revert_props_p != NULL);
- if (props_p)
+ SVN_ERR(svn_wc__internal_is_replaced(&replaced, db, local_abspath,
+ scratch_pool));
+ if (replaced)
{
- SVN_ERR(load_props(props_p, db, local_abspath, svn_wc__props_working,
- result_pool));
-
- /* If the WORKING props are not present, then no modifications have
- occurred. Simply return a copy of the BASE props.
-
- Note that the WORKING props might be present, but simply empty,
- signifying that all BASE props have been deleted. */
- if (*props_p == NULL)
- *props_p = apr_hash_copy(result_pool, base_props);
-
-#ifdef TEST_DB_PROPS
- {
- apr_hash_t *db_props;
- apr_array_header_t *diffs;
-
- SVN_ERR_ASSERT(*props_p != NULL);
-
- SVN_ERR(svn_wc__db_read_props(&db_props, db, local_abspath,
- scratch_pool, scratch_pool));
- SVN_ERR_ASSERT(db_props != NULL);
-
- SVN_ERR(svn_prop_diffs(&diffs, *props_p, db_props, scratch_pool));
- SVN_ERR_ASSERT(diffs->nelts == 0);
- }
+#if (SVN_WC__VERSION >= SVN_WC__PROPS_IN_DB)
+ SVN_ERR(svn_wc__db_base_get_props(revert_props_p, db, local_abspath,
+ result_pool, scratch_pool));
+#else
+ SVN_ERR(load_props(revert_props_p, db, local_abspath,
+ svn_wc__props_revert, result_pool));
#endif
}
-
- return SVN_NO_ERROR;
-}
-
-svn_error_t *
-svn_wc__load_revert_props(apr_hash_t **revert_props_p,
- svn_wc__db_t *db,
- const char *local_abspath,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
- if (revert_props_p)
- {
- svn_boolean_t replaced;
-
- SVN_ERR(svn_wc__internal_is_replaced(&replaced, db, local_abspath,
- scratch_pool));
- if (replaced)
- SVN_ERR(load_props(revert_props_p, db, local_abspath,
- svn_wc__props_revert, result_pool));
- else
- *revert_props_p = apr_hash_make(result_pool);
- }
+ else
+ *revert_props_p = apr_hash_make(result_pool);
#ifdef TEST_DB_PROPS
{
- apr_hash_t *db_props;
+ apr_hash_t *other_props;
apr_array_header_t *diffs;
- SVN_ERR(svn_wc__db_base_get_props(&db_props, db, local_abspath,
+#if (SVN_WC__VERSION >= SVN_WC__PROPS_IN_DB)
+ SVN_ERR(svn_wc__db_base_get_props(&other_props, db, local_abspath,
scratch_pool, scratch_pool));
- SVN_ERR_ASSERT(db_props != NULL);
+#else
+ SVN_ERR(load_props(&other_props, db, local_abspath,
+ svn_wc__props_revert, scratch_pool));
+ if (other_props == NULL)
+ other_props = apr_hash_make(scratch_pool);
+#endif
+ SVN_ERR_ASSERT(other_props != NULL);
- SVN_ERR(svn_prop_diffs(&diffs, *revert_props_p, db_props,
+ SVN_ERR(svn_prop_diffs(&diffs, *revert_props_p, other_props,
scratch_pool));
SVN_ERR_ASSERT(diffs->nelts == 0);
}
-#endif
+#endif /* TEST_DB_PROPS */
return SVN_NO_ERROR;
}
-svn_error_t *
-svn_wc__install_props(svn_wc__db_t *db,
- const char *local_abspath,
- apr_hash_t *pristine_props,
- apr_hash_t *props,
- svn_boolean_t install_pristine_props,
- svn_boolean_t force_base_install,
- apr_pool_t *scratch_pool)
+/* See props.h */
+#ifdef SVN__SUPPORT_BASE_MERGE
+
+/* Add a working queue item to install PROPS and, if INSTALL_PRISTINE_PROPS is
+ TRUE, BASE_PROPS for the LOCAL_ABSPATH in DB, updating the node to reflect
+ the changes. PRISTINE_PROPS must be supplied even if INSTALL_PRISTINE_PROPS
+ is FALSE.
+
+ Use SCRATCH_POOL for temporary allocations. */
+static svn_error_t *
+queue_install_props(svn_wc__db_t *db,
+ const char *local_abspath,
+ svn_wc__db_kind_t kind,
+ apr_hash_t *pristine_props,
+ apr_hash_t *props,
+ svn_boolean_t install_pristine_props,
+ apr_pool_t *scratch_pool)
{
apr_array_header_t *prop_diffs;
+ const char *prop_abspath;
+ svn_skel_t *work_item;
+
+ SVN_ERR_ASSERT(pristine_props != NULL);
/* Check if the props are modified. */
SVN_ERR(svn_prop_diffs(&prop_diffs, props, pristine_props, scratch_pool));
@@ -407,66 +407,96 @@ svn_wc__install_props(svn_wc__db_t *db,
if (prop_diffs->nelts == 0)
props = NULL; /* Remove actual properties*/
+ if (install_pristine_props)
+ {
+ /* Write out a new set of pristine properties. */
+ SVN_ERR(svn_wc__prop_path(&prop_abspath, local_abspath, kind,
+ svn_wc__props_base, scratch_pool));
+ SVN_ERR(svn_wc__wq_build_write_old_props(&work_item,
+ prop_abspath,
+ pristine_props,
+ scratch_pool));
+ SVN_ERR(svn_wc__db_wq_add(db, local_abspath, work_item, scratch_pool));
+ }
+
+ /* For the old school: write the properties into the "working" (aka ACTUAL)
+ location. Note that PROPS may be NULL, indicating a removal of the
+ props file. */
+ SVN_ERR(svn_wc__prop_path(&prop_abspath, local_abspath, kind,
+ svn_wc__props_working, scratch_pool));
+ SVN_ERR(svn_wc__wq_build_write_old_props(&work_item,
+ prop_abspath,
+ props,
+ scratch_pool));
+ SVN_ERR(svn_wc__db_wq_add(db, local_abspath, work_item, scratch_pool));
+
+ /* ### this is disappearing. for now, it is a delayed call to put
+ ### properties into wc_db. */
if (!install_pristine_props)
pristine_props = NULL; /* Don't change the pristine properties */
-
SVN_ERR(svn_wc__wq_add_install_properties(db,
local_abspath,
pristine_props,
props,
- force_base_install,
scratch_pool));
return SVN_NO_ERROR;
}
+#endif /* SVN__SUPPORT_BASE_MERGE */
+
+
/* */
static svn_error_t *
immediate_install_props(svn_wc__db_t *db,
const char *local_abspath,
svn_wc__db_kind_t kind,
- apr_hash_t *base_props,
apr_hash_t *working_props,
apr_pool_t *scratch_pool)
{
+ apr_hash_t *base_props;
const char *propfile_abspath;
- apr_array_header_t *prop_diffs;
+ svn_skel_t *work_item;
+
+ /* ### no pristines should be okay. */
+ SVN_ERR_W(load_pristine_props(&base_props, db, local_abspath,
+ scratch_pool, scratch_pool),
+ _("Failed to load pristine properties"));
SVN_ERR(svn_wc__prop_path(&propfile_abspath, local_abspath, kind,
svn_wc__props_working, scratch_pool));
- /* Check if the props are modified. */
- SVN_ERR(svn_prop_diffs(&prop_diffs, working_props, base_props,
- scratch_pool));
-
- /* Save the working properties file if it differs from base. */
- if (prop_diffs->nelts > 0)
- {
- /* Write out the properties (synchronously). */
- svn_stream_t *stream;
-
- SVN_ERR(svn_io_remove_file2(propfile_abspath, TRUE, scratch_pool));
- SVN_ERR(svn_stream_open_writable(&stream, propfile_abspath, scratch_pool,
- scratch_pool));
- if (apr_hash_count(working_props) != 0)
- SVN_ERR(svn_hash_write2(working_props, stream, SVN_HASH_TERMINATOR,
- scratch_pool));
- SVN_ERR(svn_stream_close(stream));
-
- SVN_ERR(svn_io_set_file_read_only(propfile_abspath, FALSE,
- scratch_pool));
- }
- else
- {
- /* No property modifications, remove the file instead. */
- SVN_ERR(svn_io_remove_file2(propfile_abspath, TRUE, scratch_pool));
- }
+ /* Check if the props are modified. If no changes, then wipe out
+ the ACTUAL props. No pristines defined means that any ACTUAL
+ props are okay, so go ahead and set them. */
+ if (base_props != NULL)
+ {
+ apr_array_header_t *prop_diffs;
+
+ SVN_ERR(svn_prop_diffs(&prop_diffs, working_props, base_props,
+ scratch_pool));
+ if (prop_diffs->nelts == 0)
+ working_props = NULL;
+ }
+
+ /* Save (if there are differences from "base") or remove the
+ ACTUAL (aka "props_working") properties file. */
+ SVN_ERR(svn_wc__wq_build_write_old_props(&work_item,
+ propfile_abspath,
+ working_props,
+ scratch_pool));
SVN_ERR(svn_wc__db_op_set_props(db, local_abspath,
- (prop_diffs->nelts > 0) ? working_props
- : NULL,
+ working_props,
+ NULL /* conflict */,
+ work_item,
scratch_pool));
+ /* ### should really leave this to the caller. but for now... */
+ SVN_ERR(svn_wc__wq_run(db, local_abspath,
+ NULL, NULL, /* cancel_func/baton */
+ scratch_pool));
+
return SVN_NO_ERROR;
}
@@ -476,6 +506,9 @@ svn_wc__working_props_committed(svn_wc__
const char *local_abspath,
apr_pool_t *scratch_pool)
{
+#if (SVN_WC__VERSION >= SVN_WC__PROPS_IN_DB)
+ return SVN_NO_ERROR;
+#else
svn_wc__db_kind_t kind;
const char *working;
const char *base;
@@ -495,6 +528,7 @@ svn_wc__working_props_committed(svn_wc__
/* svn_io_file_rename() retains a read-only bit, so there's no
need to explicitly set it. */
return svn_error_return(svn_io_file_rename(working, base, scratch_pool));
+#endif
}
@@ -504,6 +538,9 @@ svn_wc__props_delete(svn_wc__db_t *db,
svn_wc__props_kind_t props_kind,
apr_pool_t *pool)
{
+#if (SVN_WC__VERSION >= SVN_WC__PROPS_IN_DB)
+ return SVN_NO_ERROR;
+#else
const char *props_file;
svn_wc__db_kind_t kind;
@@ -513,51 +550,7 @@ svn_wc__props_delete(svn_wc__db_t *db,
SVN_ERR(svn_wc__prop_path(&props_file, local_abspath, kind, props_kind,
pool));
return svn_error_return(svn_io_remove_file2(props_file, TRUE, pool));
-}
-
-svn_error_t *
-svn_wc__loggy_revert_props_create(svn_stringbuf_t **log_accum,
- svn_wc__db_t *db,
- const char *local_abspath,
- const char *adm_abspath,
- apr_pool_t *pool)
-{
- svn_wc__db_kind_t kind;
- const char *revert_prop_abspath;
- const char *base_prop_abspath;
- svn_node_kind_t on_disk;
-
- SVN_ERR(svn_wc__db_read_kind(&kind, db, local_abspath, FALSE, pool));
-
- /* TODO(#2843) The current caller ensures that PATH will not be an excluded
- item. But do we really need show_hidden = TRUE here? */
-
- SVN_ERR(svn_wc__prop_path(&revert_prop_abspath, local_abspath, kind,
- svn_wc__props_revert, pool));
- SVN_ERR(svn_wc__prop_path(&base_prop_abspath, local_abspath, kind,
- svn_wc__props_base, pool));
-
- /* If prop base exist, copy it to revert base. */
- SVN_ERR(svn_io_check_path(base_prop_abspath, &on_disk, pool));
- if (on_disk == svn_node_file)
- {
- SVN_ERR(svn_wc__loggy_move(log_accum, adm_abspath,
- base_prop_abspath, revert_prop_abspath,
- pool, pool));
- }
- else if (on_disk == svn_node_none)
- {
- /* If there wasn't any prop base we still need an empty revert
- propfile, otherwise a revert won't know that a change to the
- props needs to be made (it'll just see no file, and do nothing).
- So (loggily) write out an empty revert propfile. */
-
- SVN_ERR(loggy_write_properties(log_accum, apr_hash_make(pool),
- revert_prop_abspath,
- adm_abspath, pool));
- }
-
- return SVN_NO_ERROR;
+#endif
}
@@ -602,11 +595,14 @@ combine_mergeinfo_props(const svn_string
apr_pool_t *scratch_pool)
{
svn_mergeinfo_t mergeinfo1, mergeinfo2;
+ svn_string_t *mergeinfo_string;
+
SVN_ERR(svn_mergeinfo_parse(&mergeinfo1, prop_val1->data, scratch_pool));
SVN_ERR(svn_mergeinfo_parse(&mergeinfo2, prop_val2->data, scratch_pool));
SVN_ERR(svn_mergeinfo_merge(mergeinfo1, mergeinfo2, scratch_pool));
- return svn_mergeinfo_to_string((svn_string_t **)output, mergeinfo1,
- result_pool);
+ SVN_ERR(svn_mergeinfo_to_string(&mergeinfo_string, mergeinfo1, result_pool));
+ *output = mergeinfo_string;
+ return SVN_NO_ERROR;
}
/* Perform a 3-way merge operation on mergeinfo. FROM_PROP_VAL is
@@ -620,6 +616,7 @@ combine_forked_mergeinfo_props(const svn
apr_pool_t *pool)
{
svn_mergeinfo_t from_mergeinfo, l_deleted, l_added, r_deleted, r_added;
+ svn_string_t *mergeinfo_string;
/* ### OPTIMIZE: Use from_mergeinfo when diff'ing. */
SVN_ERR(diff_mergeinfo_props(&l_deleted, &l_added, from_prop_val,
@@ -636,48 +633,79 @@ combine_forked_mergeinfo_props(const svn
SVN_ERR(svn_mergeinfo_remove2(&from_mergeinfo, l_deleted,
from_mergeinfo, TRUE, pool, pool));
- return svn_mergeinfo_to_string((svn_string_t **)output, from_mergeinfo, pool);
+ SVN_ERR(svn_mergeinfo_to_string(&mergeinfo_string, from_mergeinfo, pool));
+ *output = mergeinfo_string;
+ return SVN_NO_ERROR;
}
svn_error_t *
-svn_wc_merge_props3(svn_wc_notify_state_t *state,
- svn_wc_context_t *wc_ctx,
- const char *local_abspath,
- const svn_wc_conflict_version_t *left_version,
- const svn_wc_conflict_version_t *right_version,
- apr_hash_t *baseprops,
- const apr_array_header_t *propchanges,
- svn_boolean_t base_merge,
- svn_boolean_t dry_run,
- svn_wc_conflict_resolver_func_t conflict_func,
- void *conflict_baton,
- svn_cancel_func_t cancel_func,
- void *cancel_baton,
- apr_pool_t *pool /* scratch_pool */)
+svn_wc__perform_props_merge(svn_wc_notify_state_t *state,
+ svn_wc__db_t *db,
+ const char *local_abspath,
+ const svn_wc_conflict_version_t *left_version,
+ const svn_wc_conflict_version_t *right_version,
+ apr_hash_t *baseprops,
+ const apr_array_header_t *propchanges,
+ svn_boolean_t base_merge,
+ svn_boolean_t dry_run,
+ svn_wc_conflict_resolver_func_t conflict_func,
+ void *conflict_baton,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ apr_pool_t *pool /* scratch_pool */)
{
svn_boolean_t hidden;
+ int i;
+ svn_wc__db_kind_t kind;
apr_hash_t *new_base_props;
apr_hash_t *new_actual_props;
+ apr_hash_t *base_props;
+ apr_hash_t *actual_props;
/* IMPORTANT: svn_wc_merge_prop_diffs relies on the fact that baseprops
may be NULL. */
/* Checks whether the node exists and returns the hidden flag */
- SVN_ERR(svn_wc__db_node_hidden(&hidden, wc_ctx->db, local_abspath, pool));
-
+ SVN_ERR(svn_wc__db_node_hidden(&hidden, db, local_abspath, pool));
if (hidden)
return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
_("The node '%s' was not found."),
svn_dirent_local_style(local_abspath, pool));
+ /* The PROPCHANGES may not have non-"normal" properties in it. If entry
+ or wc props were allowed, then the following code would install them
+ into the BASE and/or WORKING properties(!). */
+ for (i = propchanges->nelts; i--; )
+ {
+ const svn_prop_t *change = &APR_ARRAY_IDX(propchanges, i, svn_prop_t);
+
+ if (!svn_wc_is_normal_prop(change->name))
+ return svn_error_createf(SVN_ERR_BAD_PROP_KIND, NULL,
+ _("The property '%s' may not be merged "
+ "into '%s'."),
+ change->name,
+ svn_dirent_local_style(local_abspath, pool));
+ }
+
+ SVN_ERR(svn_wc__db_read_kind(&kind, db, local_abspath, FALSE, pool));
+
+ SVN_ERR(svn_wc__get_pristine_props(&base_props, db, local_abspath,
+ pool, pool));
+ if (base_props == NULL)
+ base_props = apr_hash_make(pool); /* some nodes have no pristines */
+ SVN_ERR(svn_wc__get_actual_props(&actual_props, db, local_abspath,
+ pool, pool));
+
/* Note that while this routine does the "real" work, it's only
prepping tempfiles and writing log commands. */
SVN_ERR(svn_wc__merge_props(state,
&new_base_props, &new_actual_props,
- wc_ctx->db, local_abspath,
+ db, local_abspath, kind,
left_version, right_version,
- baseprops, NULL, NULL,
+ baseprops /* server_baseprops */,
+ base_props,
+ actual_props,
propchanges, base_merge, dry_run,
conflict_func, conflict_baton,
cancel_func, cancel_baton,
@@ -685,26 +713,58 @@ svn_wc_merge_props3(svn_wc_notify_state_
if (!dry_run)
{
- svn_wc__db_kind_t kind;
const char *dir_abspath;
- SVN_ERR(svn_wc__db_read_kind(&kind, wc_ctx->db, local_abspath,
- FALSE, pool));
if (kind == svn_wc__db_kind_dir)
dir_abspath = local_abspath;
else
dir_abspath = svn_dirent_dirname(local_abspath, pool);
/* Verify that we're holding this directory's write lock. */
- SVN_ERR(svn_wc__write_check(wc_ctx->db, dir_abspath, pool));
+ SVN_ERR(svn_wc__write_check(db, dir_abspath, pool));
+
+ /* After a (not-dry-run) merge, we ALWAYS have props to save. */
+ SVN_ERR_ASSERT(new_base_props != NULL && new_actual_props != NULL);
- SVN_ERR(svn_wc__install_props(wc_ctx->db, local_abspath,
- new_base_props, new_actual_props,
- base_merge, FALSE, pool));
+/* See props.h */
+#ifdef SVN__SUPPORT_BASE_MERGE
+ SVN_ERR(queue_install_props(db, local_abspath, kind,
+ new_base_props, new_actual_props,
+ base_merge, pool));
+#else
+ if (base_merge)
+ return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
+ U_("base_merge=TRUE is no longer supported"));
- /* ### add_loggy takes a DIR, but wq_run is a simple WRI_ABSPATH */
+ {
+ apr_array_header_t *prop_diffs;
+ const char *props_abspath;
+ svn_skel_t *work_item;
+
+ SVN_ERR(svn_prop_diffs(&prop_diffs, new_actual_props, new_base_props,
+ pool));
+
+ /* Save the actual properties file if it differs from base. */
+ if (prop_diffs->nelts == 0)
+ new_actual_props = NULL; /* Remove actual properties*/
+
+ /* For the old school: write the properties into the "working"
+ (aka ACTUAL) location. Note that PROPS may be NULL, indicating
+ a removal of the props file. */
+ SVN_ERR(svn_wc__prop_path(&props_abspath, local_abspath, kind,
+ svn_wc__props_working, pool));
+ SVN_ERR(svn_wc__wq_build_write_old_props(&work_item,
+ props_abspath,
+ new_actual_props,
+ pool));
+
+ SVN_ERR(svn_wc__db_op_set_props(db, local_abspath, new_actual_props,
+ NULL /* conflict */,
+ work_item, pool));
+ }
+#endif
- SVN_ERR(svn_wc__wq_run(wc_ctx->db, local_abspath,
+ SVN_ERR(svn_wc__wq_run(db, local_abspath,
cancel_func, cancel_baton,
pool));
}
@@ -713,6 +773,262 @@ svn_wc_merge_props3(svn_wc_notify_state_
}
+svn_error_t *
+svn_wc_merge_props3(svn_wc_notify_state_t *state,
+ svn_wc_context_t *wc_ctx,
+ const char *local_abspath,
+ const svn_wc_conflict_version_t *left_version,
+ const svn_wc_conflict_version_t *right_version,
+ apr_hash_t *baseprops,
+ const apr_array_header_t *propchanges,
+ svn_boolean_t dry_run,
+ svn_wc_conflict_resolver_func_t conflict_func,
+ void *conflict_baton,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ apr_pool_t *scratch_pool)
+{
+ return svn_error_return(svn_wc__perform_props_merge(
+ state,
+ wc_ctx->db,
+ local_abspath,
+ left_version, right_version,
+ baseprops,
+ propchanges,
+ FALSE /* base_merge */,
+ dry_run,
+ conflict_func, conflict_baton,
+ cancel_func, cancel_baton,
+ scratch_pool));
+}
+
+
+/* Generate a message to describe the property conflict among these four
+ values.
+
+ Note that this function (currently) interprets the property values as
+ strings, but they could actually be binary values. We'll keep the
+ types as svn_string_t in case we fix this in the future. */
+static const svn_string_t *
+generate_conflict_message(const char *propname,
+ const svn_string_t *original,
+ const svn_string_t *mine,
+ const svn_string_t *incoming,
+ const svn_string_t *incoming_base,
+ apr_pool_t *result_pool)
+{
+ if (incoming_base == NULL)
+ {
+ /* Attempting to add the value INCOMING. */
+ SVN_ERR_ASSERT_NO_RETURN(incoming != NULL);
+
+ if (mine)
+ {
+ /* To have a conflict, these must be different. */
+ SVN_ERR_ASSERT_NO_RETURN(!svn_string_compare(mine, incoming));
+
+ /* Note that we don't care whether MINE is locally-added or
+ edited, or just something different that is a copy of the
+ pristine ORIGINAL. */
+ return svn_string_createf(result_pool,
+ _("Trying to add new property '%s' with "
+ "value '%s',\nbut property already "
+ "exists with value '%s'."),
+ propname, incoming->data, mine->data);
+ }
+
+ /* To have a conflict, we must have an ORIGINAL which has been
+ locally-deleted. */
+ SVN_ERR_ASSERT_NO_RETURN(original != NULL);
+ return svn_string_createf(result_pool,
+ _("Trying to create property '%s' with "
+ "value '%s',\nbut it has been locally "
+ "deleted."),
+ propname, incoming->data);
+ }
+
+ if (incoming == NULL)
+ {
+ /* Attempting to delete the value INCOMING_BASE. */
+ SVN_ERR_ASSERT_NO_RETURN(incoming_base != NULL);
+
+ /* A conflict can only occur if we originally had the property;
+ otherwise, we would have merged the property-delete into the
+ non-existent property. */
+ SVN_ERR_ASSERT_NO_RETURN(original != NULL);
+
+ if (mine && svn_string_compare(original, incoming_base))
+ {
+ /* We were trying to delete the correct property, but an edit
+ caused the conflict. */
+ return svn_string_createf(result_pool,
+ _("Trying to delete property '%s' with "
+ "value '%s'\nbut it has been modified "
+ "from '%s' to '%s'."),
+ propname, incoming_base->data,
+ original->data, mine->data);
+ }
+
+ /* We were trying to delete INCOMING_BASE but our ORIGINAL is
+ something else entirely. */
+ SVN_ERR_ASSERT_NO_RETURN(!svn_string_compare(original, incoming_base));
+
+ /* ### wait. what if we had a different property and locally
+ ### deleted it? the statement below is gonna blow up.
+ ### we could have: local-add, local-edit, local-del, or just
+ ### something different (and unchanged). */
+ return svn_string_createf(result_pool,
+ _("Trying to delete property '%s' with "
+ "value '%s'\nbut the local value is "
+ "'%s'."),
+ propname, incoming_base->data, mine->data);
+ }
+
+ /* Attempting to change the property from INCOMING_BASE to INCOMING. */
+
+ /* If we have a (current) property value, then it should be different
+ from the INCOMING_BASE; otherwise, the incoming change would have
+ been applied to it. */
+ SVN_ERR_ASSERT_NO_RETURN(!mine || !svn_string_compare(mine, incoming_base));
+
+ if (original && mine && svn_string_compare(original, mine))
+ {
+ /* We have an unchanged property, so the original values must
+ have been different. */
+ SVN_ERR_ASSERT_NO_RETURN(!svn_string_compare(original, incoming_base));
+ return svn_string_createf(result_pool,
+ _("Trying to change property '%s' from '%s' "
+ "to '%s',\nbut property already exists "
+ "with value '%s'."),
+ propname, incoming_base->data, incoming->data,
+ mine->data);
+ }
+
+ if (original && mine)
+ return svn_string_createf(result_pool,
+ _("Trying to change property '%s' from '%s' "
+ "to '%s',\nbut the property has been locally "
+ "changed from '%s' to '%s'."),
+ propname, incoming_base->data, incoming->data,
+ original->data, mine->data);
+
+ if (original)
+ return svn_string_createf(result_pool,
+ _("Trying to change property '%s' from '%s' "
+ "to '%s',\nbut it has been locally deleted."),
+ propname, incoming_base->data, incoming->data);
+
+ if (mine)
+ return svn_string_createf(result_pool,
+ _("Trying to change property '%s' from '%s' "
+ "to '%s',\nbut property has been locally "
+ "added with value '%s'."),
+ propname, incoming_base->data, incoming->data,
+ mine->data);
+
+ return svn_string_createf(result_pool,
+ _("Trying to change property '%s' from '%s' to "
+ "'%s',\nbut the property does not exist."),
+ propname, incoming_base->data, incoming->data);
+}
+
+
+/* SKEL will be one of:
+
+ ()
+ (VALUE)
+
+ Return NULL for the former (the particular property value was not
+ present), and VALUE for the second. */
+static const svn_string_t *
+maybe_prop_value(const svn_skel_t *skel,
+ apr_pool_t *result_pool)
+{
+ if (skel->children == NULL)
+ return NULL;
+
+ return svn_string_ncreate(skel->children->data,
+ skel->children->len,
+ result_pool);
+}
+
+
+/* Generate a property conflict message (see generate_conflict_message)
+ from the data contained in SKEL. The message will be allocated in
+ RESULT_POOL.
+
+ Note: SKEL is a single property conflict of the form:
+
+ ("prop" ([ORIGINAL]) ([MINE]) ([INCOMING]) ([INCOMING_BASE]))
+
+ See notes/wc-ng/conflict-storage for more information. */
+static const svn_string_t *
+message_from_skel(const svn_skel_t *skel,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ const svn_string_t *original;
+ const svn_string_t *mine;
+ const svn_string_t *incoming;
+ const svn_string_t *incoming_base;
+ const char *propname;
+
+ /* Navigate to the property name. */
+ skel = skel->children->next;
+
+ /* We need to copy these into SCRATCH_POOL in order to nul-terminate
+ the values. */
+ propname = apr_pstrmemdup(scratch_pool, skel->data, skel->len);
+ original = maybe_prop_value(skel->next, scratch_pool);
+ mine = maybe_prop_value(skel->next->next, scratch_pool);
+ incoming = maybe_prop_value(skel->next->next->next, scratch_pool);
+ incoming_base = maybe_prop_value(skel->next->next->next->next, scratch_pool);
+
+ return generate_conflict_message(propname, original, mine, incoming,
+ incoming_base, result_pool);
+}
+
+
+/* Create a property conflict file at PREJFILE based on the property
+ conflicts in CONFLICT_SKEL. */
+svn_error_t *
+svn_wc__create_prejfile(const char **tmp_prejfile_abspath,
+ svn_wc__db_t *db,
+ const char *local_abspath,
+ const svn_skel_t *conflict_skel,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ const char *tempdir_abspath;
+ svn_stream_t *stream;
+ const char *temp_abspath;
+ apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+ const svn_skel_t *scan;
+
+ SVN_ERR(svn_wc__db_temp_wcroot_tempdir(&tempdir_abspath,
+ db, local_abspath,
+ iterpool, iterpool));
+
+ SVN_ERR(svn_stream_open_unique(&stream, &temp_abspath,
+ tempdir_abspath, svn_io_file_del_none,
+ scratch_pool, iterpool));
+
+ for (scan = conflict_skel->children->next; scan != NULL; scan = scan->next)
+ {
+ svn_pool_clear(iterpool);
+
+ SVN_ERR(append_prop_conflict(stream, scan, iterpool));
+ }
+
+ SVN_ERR(svn_stream_close(stream));
+
+ svn_pool_destroy(iterpool);
+
+ *tmp_prejfile_abspath = apr_pstrdup(result_pool, temp_abspath);
+ return SVN_NO_ERROR;
+}
+
+
/* Set the value of *STATE to NEW_VALUE if STATE is not NULL
* and NEW_VALUE is a higer order value than *STATE's current value
* using this ordering (lower order first):
@@ -781,12 +1097,11 @@ set_prop_merge_state(svn_wc_notify_state
* intent-to-delete.
*
* If the callback isn't available, or if it responds with
- * 'choose_postpone', then set *CONFLICT_REMAINS to true and return.
+ * 'choose_postpone', then set *CONFLICT_REMAINS to TRUE and return.
*
* If the callback responds with a choice of 'base', 'theirs', 'mine',
* or 'merged', then install the proper value into WORKING_PROPS and
- * set *CONFLICT_REMAINS to false.
- *
+ * set *CONFLICT_REMAINS to FALSE.
*/
static svn_error_t *
maybe_generate_propconflict(svn_boolean_t *conflict_remains,
@@ -803,8 +1118,6 @@ maybe_generate_propconflict(svn_boolean_
const svn_string_t *working_val,
svn_wc_conflict_resolver_func_t conflict_func,
void *conflict_baton,
- svn_cancel_func_t cancel_func,
- void *cancel_baton,
svn_boolean_t dry_run,
apr_pool_t *scratch_pool)
{
@@ -814,9 +1127,6 @@ maybe_generate_propconflict(svn_boolean_
svn_wc_conflict_description2_t *cdesc;
const char *dirpath = svn_dirent_dirname(local_abspath, filepool);
- if (cancel_func)
- SVN_ERR(cancel_func(cancel_baton));
-
if (! conflict_func || dry_run)
{
/* Just postpone the conflict. */
@@ -1021,7 +1331,7 @@ maybe_generate_propconflict(svn_boolean_
/* Add the property with name PROPNAME to the set of WORKING_PROPS on
- * PATH, setting *STATE or *CONFLICT according to merge outcomes.
+ * PATH, setting *STATE or *CONFLICT_REMAINS according to merge outcomes.
*
* *STATE is an input and output parameter, its value is to be
* set using set_merge_prop_state().
@@ -1036,7 +1346,7 @@ maybe_generate_propconflict(svn_boolean_
*/
static svn_error_t *
apply_single_prop_add(svn_wc_notify_state_t *state,
- svn_string_t **conflict,
+ svn_boolean_t *conflict_remains,
svn_wc__db_t *db,
const char *local_abspath,
const svn_wc_conflict_version_t *left_version,
@@ -1048,17 +1358,16 @@ apply_single_prop_add(svn_wc_notify_stat
const svn_string_t *new_val,
svn_wc_conflict_resolver_func_t conflict_func,
void *conflict_baton,
- svn_cancel_func_t cancel_func,
- void *cancel_baton,
svn_boolean_t dry_run,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
- svn_boolean_t got_conflict = FALSE;
svn_string_t *working_val
= apr_hash_get(working_props, propname, APR_HASH_KEY_STRING);
+ *conflict_remains = FALSE;
+
if (working_val)
{
/* the property already exists in working_props... */
@@ -1084,41 +1393,29 @@ apply_single_prop_add(svn_wc_notify_stat
}
else
{
- SVN_ERR(maybe_generate_propconflict(&got_conflict, db,
- local_abspath,
+ SVN_ERR(maybe_generate_propconflict(conflict_remains,
+ db, local_abspath,
left_version, right_version,
is_dir,
propname, working_props,
NULL, new_val,
base_val, working_val,
- conflict_func, conflict_baton,
- cancel_func, cancel_baton,
+ conflict_func,
+ conflict_baton,
dry_run, scratch_pool));
- if (got_conflict)
- *conflict = svn_string_createf
- (result_pool,
- _("Trying to add new property '%s' with value "
- "'%s',\nbut property already exists with value '%s'."),
- propname, new_val->data, working_val->data);
}
}
}
else if (base_val)
{
- SVN_ERR(maybe_generate_propconflict(&got_conflict, db, local_abspath,
+ SVN_ERR(maybe_generate_propconflict(conflict_remains,
+ db, local_abspath,
left_version, right_version,
is_dir, propname,
working_props, NULL, new_val,
base_val, NULL,
conflict_func, conflict_baton,
- cancel_func, cancel_baton,
dry_run, scratch_pool));
- if (got_conflict)
- *conflict = svn_string_createf
- (result_pool,
- _("Trying to create property '%s' with value '%s',\n"
- "but it has been locally deleted."),
- propname, new_val->data);
}
else /* property doesn't yet exist in working_props... */
/* so just set it */
@@ -1129,7 +1426,7 @@ apply_single_prop_add(svn_wc_notify_stat
/* Delete the property with name PROPNAME from the set of
- * WORKING_PROPS on PATH, setting *STATE or *CONFLICT according to
+ * WORKING_PROPS on PATH, setting *STATE or *CONFLICT_REMAINS according to
* merge outcomes.
*
* *STATE is an input and output parameter, its value is to be
@@ -1146,7 +1443,7 @@ apply_single_prop_add(svn_wc_notify_stat
*/
static svn_error_t *
apply_single_prop_delete(svn_wc_notify_state_t *state,
- svn_string_t **conflict,
+ svn_boolean_t *conflict_remains,
svn_wc__db_t *db,
const char *local_abspath,
const svn_wc_conflict_version_t *left_version,
@@ -1158,18 +1455,19 @@ apply_single_prop_delete(svn_wc_notify_s
const svn_string_t *old_val,
svn_wc_conflict_resolver_func_t conflict_func,
void *conflict_baton,
- svn_cancel_func_t cancel_func,
- void *cancel_baton,
svn_boolean_t dry_run,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
- svn_boolean_t got_conflict = FALSE;
svn_string_t *working_val
= apr_hash_get(working_props, propname, APR_HASH_KEY_STRING);
+ *conflict_remains = FALSE;
+
if (! base_val)
{
+ /* ### what about working_val? what if we locally-added? */
+
apr_hash_set(working_props, propname, APR_HASH_KEY_STRING, NULL);
if (old_val)
/* This is a merge, merging a delete into non-existent */
@@ -1185,23 +1483,16 @@ apply_single_prop_delete(svn_wc_notify_s
apr_hash_set(working_props, propname, APR_HASH_KEY_STRING, NULL);
else
{
- SVN_ERR(maybe_generate_propconflict(&got_conflict, db,
- local_abspath,
+ SVN_ERR(maybe_generate_propconflict(conflict_remains,
+ db, local_abspath,
left_version, right_version,
is_dir,
propname, working_props,
old_val, NULL,
base_val, working_val,
- conflict_func, conflict_baton,
- cancel_func, cancel_baton,
+ conflict_func,
+ conflict_baton,
dry_run, scratch_pool));
- if (got_conflict)
- *conflict = svn_string_createf
- (result_pool,
- _("Trying to delete property '%s' with value '%s'\n"
- "but it has been modified from '%s' to '%s'."),
- propname, old_val->data,
- base_val->data, working_val->data);
}
}
else
@@ -1211,20 +1502,14 @@ apply_single_prop_delete(svn_wc_notify_s
else
{
- SVN_ERR(maybe_generate_propconflict(&got_conflict, db, local_abspath,
+ SVN_ERR(maybe_generate_propconflict(conflict_remains,
+ db, local_abspath,
left_version, right_version,
is_dir, propname,
working_props, old_val, NULL,
base_val, working_val,
conflict_func, conflict_baton,
- cancel_func, cancel_baton,
dry_run, scratch_pool));
- if (got_conflict)
- *conflict = svn_string_createf
- (result_pool,
- _("Trying to delete property '%s' with value '%s'\n"
- "but the local value is '%s'."),
- propname, base_val->data, working_val->data);
}
return SVN_NO_ERROR;
@@ -1240,7 +1525,7 @@ apply_single_prop_delete(svn_wc_notify_s
the remainder. */
static svn_error_t *
apply_single_mergeinfo_prop_change(svn_wc_notify_state_t *state,
- svn_string_t **conflict,
+ svn_boolean_t *conflict_remains,
svn_wc__db_t *db,
const char *local_abspath,
const svn_wc_conflict_version_t *left_version,
@@ -1253,13 +1538,10 @@ apply_single_mergeinfo_prop_change(svn_w
const svn_string_t *new_val,
svn_wc_conflict_resolver_func_t conflict_func,
void *conflict_baton,
- svn_cancel_func_t cancel_func,
- void *cancel_baton,
svn_boolean_t dry_run,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
- svn_boolean_t got_conflict = FALSE;
svn_string_t *working_val
= apr_hash_get(working_props, propname, APR_HASH_KEY_STRING);
@@ -1282,7 +1564,8 @@ apply_single_mergeinfo_prop_change(svn_w
them to base to get the new value. */
SVN_ERR(combine_forked_mergeinfo_props(&new_val, old_val,
working_val,
- new_val, result_pool));
+ new_val,
+ result_pool));
apr_hash_set(working_props, propname,
APR_HASH_KEY_STRING, new_val);
set_prop_merge_state(state, svn_wc_notify_state_merged);
@@ -1292,20 +1575,14 @@ apply_single_mergeinfo_prop_change(svn_w
else
{
/* There is a base_val but no working_val */
- SVN_ERR(maybe_generate_propconflict(&got_conflict, db, local_abspath,
+ SVN_ERR(maybe_generate_propconflict(conflict_remains,
+ db, local_abspath,
left_version, right_version,
is_dir, propname, working_props,
old_val, new_val,
base_val, working_val,
conflict_func, conflict_baton,
- cancel_func, cancel_baton,
dry_run, scratch_pool));
- if (got_conflict)
- *conflict = svn_string_createf
- (result_pool,
- _("Trying to change property '%s' from '%s' to '%s',\n"
- "but it has been locally deleted."),
- propname, old_val->data, new_val->data);
}
}
@@ -1316,12 +1593,15 @@ apply_single_mergeinfo_prop_change(svn_w
incoming value relative to the base, and
"combine" those with the empty WC value. */
svn_mergeinfo_t deleted_mergeinfo, added_mergeinfo;
+ svn_string_t *mergeinfo_string;
+
SVN_ERR(diff_mergeinfo_props(&deleted_mergeinfo,
&added_mergeinfo,
old_val, new_val, scratch_pool));
- SVN_ERR(svn_mergeinfo_to_string((svn_string_t **)&new_val,
+ SVN_ERR(svn_mergeinfo_to_string(&mergeinfo_string,
added_mergeinfo, result_pool));
- apr_hash_set(working_props, propname, APR_HASH_KEY_STRING, new_val);
+ apr_hash_set(working_props, propname, APR_HASH_KEY_STRING,
+ mergeinfo_string);
}
else /* means working && base && svn_string_compare(working, base) */
@@ -1354,7 +1634,7 @@ apply_single_mergeinfo_prop_change(svn_w
apply_single_prop_change(). */
static svn_error_t *
apply_single_generic_prop_change(svn_wc_notify_state_t *state,
- svn_string_t **conflict,
+ svn_boolean_t *conflict_remains,
svn_wc__db_t *db,
const char *local_abspath,
const svn_wc_conflict_version_t *left_version,
@@ -1367,20 +1647,18 @@ apply_single_generic_prop_change(svn_wc_
const svn_string_t *new_val,
svn_wc_conflict_resolver_func_t conflict_func,
void *conflict_baton,
- svn_cancel_func_t cancel_func,
- void *cancel_baton,
svn_boolean_t dry_run,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
- svn_boolean_t got_conflict = FALSE;
svn_string_t *working_val
= apr_hash_get(working_props, propname, APR_HASH_KEY_STRING);
+ SVN_ERR_ASSERT(old_val != NULL);
+
/* If working_val is the same as old_val... */
- if ((!working_val && !old_val)
- || (working_val && old_val
- && svn_string_compare(working_val, old_val)))
+ if (working_val && old_val
+ && svn_string_compare(working_val, old_val))
{
/* A trivial update: change it to new_val. */
apr_hash_set(working_props, propname, APR_HASH_KEY_STRING, new_val);
@@ -1388,60 +1666,21 @@ apply_single_generic_prop_change(svn_wc_
else
{
/* Merge the change. */
- SVN_ERR(maybe_generate_propconflict(&got_conflict, db, local_abspath,
+ SVN_ERR(maybe_generate_propconflict(conflict_remains,
+ db, local_abspath,
left_version, right_version,
is_dir, propname, working_props,
old_val, new_val,
base_val, working_val,
conflict_func, conflict_baton,
- cancel_func, cancel_baton,
dry_run, scratch_pool));
- if (got_conflict)
- {
- /* Describe the conflict, referring to base_val as well as
- working_val for the user's convenience. */
- if (working_val && base_val
- && svn_string_compare(working_val, base_val))
- *conflict = svn_string_createf
- (result_pool,
- _("Trying to change property '%s' from '%s' to '%s',\n"
- "but property already exists with value '%s'."),
- propname, old_val->data, new_val->data, working_val->data);
- else if (working_val && base_val)
- *conflict = svn_string_createf
- (result_pool,
- _("Trying to change property '%s' from '%s' to '%s',\n"
- "but the property has been locally changed from '%s' to "
- "'%s'."),
- propname, old_val->data, new_val->data,
- base_val->data, working_val->data);
- else if (working_val)
- *conflict = svn_string_createf
- (result_pool,
- _("Trying to change property '%s' from '%s' to '%s',\n"
- "but property has been locally added with value "
- "'%s'."),
- propname, old_val->data, new_val->data, working_val->data);
- else if (base_val)
- *conflict = svn_string_createf
- (result_pool,
- _("Trying to change property '%s' from '%s' to '%s',\n"
- "but it has been locally deleted."),
- propname, old_val->data, new_val->data);
- else
- *conflict = svn_string_createf
- (result_pool,
- _("Trying to change property '%s' from '%s' to '%s',\n"
- "but the property does not exist."),
- propname, old_val->data, new_val->data);
- }
}
return SVN_NO_ERROR;
}
/* Change the property with name PROPNAME in the set of WORKING_PROPS
- * on PATH, setting *STATE or *CONFLICT according to the merge outcome.
+ * on PATH, setting *STATE or *CONFLICT_REMAINS according to the merge outcome.
*
* *STATE is an input and output parameter, its value is to be
* set using set_prop_merge_state(). (May be null.).
@@ -1459,7 +1698,7 @@ apply_single_generic_prop_change(svn_wc_
*/
static svn_error_t *
apply_single_prop_change(svn_wc_notify_state_t *state,
- svn_string_t **conflict,
+ svn_boolean_t *conflict_remains,
svn_wc__db_t *db,
const char *local_abspath,
const svn_wc_conflict_version_t *left_version,
@@ -1472,12 +1711,12 @@ apply_single_prop_change(svn_wc_notify_s
const svn_string_t *new_val,
svn_wc_conflict_resolver_func_t conflict_func,
void *conflict_baton,
- svn_cancel_func_t cancel_func,
- void *cancel_baton,
svn_boolean_t dry_run,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
+ *conflict_remains = FALSE;
+
/* Note: The purpose is to apply the change (old_val -> new_val) onto
(working_val). There is no need for base_val to be involved in the
process except as a bit of context to help the user understand and
@@ -1489,32 +1728,32 @@ apply_single_prop_change(svn_wc_notify_s
{
/* We know how to merge any mergeinfo property change. */
- SVN_ERR(apply_single_mergeinfo_prop_change(state, conflict, db,
- local_abspath,
+ SVN_ERR(apply_single_mergeinfo_prop_change(state, conflict_remains,
+ db, local_abspath,
left_version, right_version,
is_dir,
working_props,
propname, base_val, old_val,
new_val,
conflict_func, conflict_baton,
- cancel_func, cancel_baton,
- dry_run, result_pool, scratch_pool));
+ dry_run,
+ result_pool, scratch_pool));
}
else
{
/* The standard method: perform a simple update automatically, but
pass any other kind of merge to maybe_generate_propconflict(). */
- SVN_ERR(apply_single_generic_prop_change(state, conflict, db,
- local_abspath,
+ SVN_ERR(apply_single_generic_prop_change(state, conflict_remains,
+ db, local_abspath,
left_version, right_version,
is_dir,
working_props,
propname, base_val, old_val,
new_val,
conflict_func, conflict_baton,
- cancel_func, cancel_baton,
- dry_run, result_pool, scratch_pool));
+ dry_run,
+ result_pool, scratch_pool));
}
return SVN_NO_ERROR;
@@ -1527,6 +1766,7 @@ svn_wc__merge_props(svn_wc_notify_state_
apr_hash_t **new_actual_props,
svn_wc__db_t *db,
const char *local_abspath,
+ svn_wc__db_kind_t kind,
const svn_wc_conflict_version_t *left_version,
const svn_wc_conflict_version_t *right_version,
apr_hash_t *server_baseprops,
@@ -1545,51 +1785,22 @@ svn_wc__merge_props(svn_wc_notify_state_
apr_pool_t *iterpool;
int i;
svn_boolean_t is_dir;
- const char *reject_path = NULL;
- svn_stream_t *reject_tmp_stream = NULL; /* the temporary conflicts stream */
- const char *reject_tmp_path = NULL;
- svn_wc__db_kind_t kind;
const char *adm_abspath;
+ svn_skel_t *conflict_skel = NULL;
+
+ SVN_ERR_ASSERT(base_props != NULL);
+ SVN_ERR_ASSERT(working_props != NULL);
*new_base_props = NULL;
*new_actual_props = NULL;
- /* ### shouldn't ALLOW_MISSING be FALSE? how can we merge props into
- ### a node that doesn't exist?! */
- /* ### BH: In some cases we allow merging into missing to create a new
- node. */
- SVN_ERR(svn_wc__db_read_kind(&kind, db, local_abspath, TRUE, scratch_pool));
+ is_dir = (kind == svn_wc__db_kind_dir);
- if (kind == svn_wc__db_kind_dir)
- {
- is_dir = TRUE;
- adm_abspath = local_abspath;
- }
+ if (is_dir)
+ adm_abspath = local_abspath;
else
- {
- is_dir = FALSE;
- adm_abspath = svn_dirent_dirname(local_abspath, scratch_pool);
- }
+ adm_abspath = svn_dirent_dirname(local_abspath, scratch_pool);
- /* If not provided, load the base & working property files into hashes */
- if (! base_props || ! working_props)
- {
- if (kind == svn_wc__db_kind_unknown)
- {
- /* No entry... no props. */
- if (base_props == NULL)
- base_props = apr_hash_make(result_pool);
- if (working_props == NULL)
- working_props = apr_hash_make(result_pool);
- }
- else
- {
- SVN_ERR(svn_wc__load_props(base_props ? NULL : &base_props,
- working_props ? NULL : &working_props,
- db, local_abspath,
- result_pool, scratch_pool));
- }
- }
if (!server_baseprops)
server_baseprops = base_props;
@@ -1607,87 +1818,88 @@ svn_wc__merge_props(svn_wc_notify_state_
for (i = 0; i < propchanges->nelts; i++)
{
const char *propname;
- svn_string_t *conflict = NULL;
+ svn_boolean_t conflict_remains;
const svn_prop_t *incoming_change;
- const svn_string_t *from_val, *to_val, *working_val, *base_val;
- svn_boolean_t is_normal;
+ const svn_string_t *from_val, *to_val, *base_val;
+ const svn_string_t *mine_val;
svn_pool_clear(iterpool);
+ /* Should we stop the prop merging process? */
+ if (cancel_func)
+ SVN_ERR(cancel_func(cancel_baton));
+
/* For the incoming propchange, figure out the TO and FROM values. */
incoming_change = &APR_ARRAY_IDX(propchanges, i, svn_prop_t);
propname = incoming_change->name;
- is_normal = svn_wc_is_normal_prop(propname);
to_val = incoming_change->value
? svn_string_dup(incoming_change->value, result_pool) : NULL;
from_val = apr_hash_get(server_baseprops, propname, APR_HASH_KEY_STRING);
- working_val = apr_hash_get(working_props, propname, APR_HASH_KEY_STRING);
base_val = apr_hash_get(base_props, propname, APR_HASH_KEY_STRING);
if (base_merge)
apr_hash_set(base_props, propname, APR_HASH_KEY_STRING, to_val);
+ /* Save MINE for later message generation. */
+ mine_val = apr_hash_get(working_props, propname, APR_HASH_KEY_STRING);
+
/* We already know that state is at least `changed', so mark
that, but remember that we may later upgrade to `merged' or
even `conflicted'. */
- if (is_normal)
- set_prop_merge_state(state, svn_wc_notify_state_changed);
+ set_prop_merge_state(state, svn_wc_notify_state_changed);
if (! from_val) /* adding a new property */
- SVN_ERR(apply_single_prop_add(is_normal ? state : NULL, &conflict,
+ SVN_ERR(apply_single_prop_add(state, &conflict_remains,
db, local_abspath,
left_version, right_version,
is_dir, working_props,
propname, base_val, to_val,
conflict_func, conflict_baton,
- cancel_func, cancel_baton,
dry_run, result_pool, iterpool));
else if (! to_val) /* delete an existing property */
- SVN_ERR(apply_single_prop_delete(is_normal ? state : NULL, &conflict,
+ SVN_ERR(apply_single_prop_delete(state, &conflict_remains,
db, local_abspath,
left_version, right_version,
is_dir,
working_props,
propname, base_val, from_val,
conflict_func, conflict_baton,
- cancel_func, cancel_baton,
dry_run, result_pool, iterpool));
else /* changing an existing property */
- SVN_ERR(apply_single_prop_change(is_normal ? state : NULL, &conflict,
+ SVN_ERR(apply_single_prop_change(state, &conflict_remains,
db, local_abspath,
left_version, right_version,
is_dir,
working_props,
propname, base_val, from_val, to_val,
conflict_func, conflict_baton,
- cancel_func, cancel_baton,
dry_run, result_pool, iterpool));
/* merging logic complete, now we need to possibly log conflict
data to tmpfiles. */
- if (conflict)
+ if (conflict_remains)
{
- if (is_normal)
- set_prop_merge_state(state, svn_wc_notify_state_conflicted);
+ set_prop_merge_state(state, svn_wc_notify_state_conflicted);
if (dry_run)
continue; /* skip to next incoming change */
- if (! reject_tmp_stream)
- /* This is the very first prop conflict found on this item. */
- SVN_ERR(open_reject_tmp_stream(&reject_tmp_stream,
- &reject_tmp_path, db,
- local_abspath,
- scratch_pool, iterpool));
+ if (conflict_skel == NULL)
+ conflict_skel = svn_wc__conflict_skel_new(scratch_pool);
- /* Append the conflict to the open tmp/PROPS/---.prej file */
- SVN_ERR(append_prop_conflict(reject_tmp_stream, conflict,
- iterpool));
+ SVN_ERR(svn_wc__conflict_skel_add_prop_conflict(conflict_skel,
+ propname,
+ base_val,
+ mine_val,
+ to_val,
+ from_val,
+ scratch_pool,
+ iterpool));
}
} /* foreach propchange ... */
@@ -1701,19 +1913,14 @@ svn_wc__merge_props(svn_wc_notify_state_
*new_base_props = base_props;
*new_actual_props = working_props;
- if (reject_tmp_stream)
+ if (conflict_skel != NULL)
{
- /* There's a temporary reject file sitting in .svn/tmp/ somewhere. Deal
- with the conflicts. */
-
- /* First, _close_ this temporary conflicts file. We've been
- appending to it all along. */
- SVN_ERR(svn_stream_close(reject_tmp_stream));
+ const char *reject_path;
/* Now try to get the name of a pre-existing .prej file from the
entries file */
- SVN_ERR(get_existing_prop_reject_file(&reject_path, db, adm_abspath,
- local_abspath, scratch_pool));
+ SVN_ERR(svn_wc__get_prejfile_abspath(&reject_path, db, local_abspath,
+ scratch_pool, scratch_pool));
if (! reject_path)
{
@@ -1743,59 +1950,58 @@ svn_wc__merge_props(svn_wc_notify_state_
disk. */
}
- /* We've now guaranteed that some kind of .prej file exists
- above the .svn/ dir. We write log entries to append our
- conflicts to it. */
- SVN_ERR(svn_wc__loggy_append(db, adm_abspath, reject_tmp_path,
- reject_path, scratch_pool));
-
- /* And of course, delete the temporary reject file. */
- {
- const svn_skel_t *work_item;
-
- SVN_ERR(svn_wc__wq_build_file_remove(&work_item,
- db, reject_tmp_path,
- scratch_pool, scratch_pool));
- /* ### we should pass WORK_ITEM to some wc_db api that records
- ### the property conflicts. */
- SVN_ERR(svn_wc__db_wq_add(db, adm_abspath, work_item, scratch_pool));
- }
-
/* Mark entry as "conflicted" with a particular .prej file. */
{
- svn_stringbuf_t *log_accum = NULL;
svn_wc_entry_t entry;
+ svn_skel_t *work_item;
entry.prejfile = svn_dirent_is_child(adm_abspath, reject_path, NULL);
- SVN_ERR(svn_wc__loggy_entry_modify(&log_accum, adm_abspath,
+ SVN_ERR(svn_wc__loggy_entry_modify(&work_item, db, adm_abspath,
local_abspath, &entry,
SVN_WC__ENTRY_MODIFY_PREJFILE,
- scratch_pool, scratch_pool));
- SVN_ERR(svn_wc__wq_add_loggy(db, adm_abspath, log_accum,
- scratch_pool));
+ scratch_pool));
+ SVN_ERR(svn_wc__db_wq_add(db, local_abspath, work_item, scratch_pool));
}
- } /* if (reject_tmp_fp) */
+ /* Once the prejfile is recorded, then install the file. */
+ {
+ svn_skel_t *work_item;
+
+ /* ### careful. CONFLICT_SKEL is NOT dup'd into the provided
+ ### result_pool at the moment. we'll get that fixed soon-ish.
+ ### this is okay for now since we immediately serialize it and
+ ### shove it into the database. */
+ SVN_ERR(svn_wc__wq_build_prej_install(&work_item,
+ db, local_abspath,
+ conflict_skel,
+ scratch_pool, scratch_pool));
+ SVN_ERR(svn_wc__db_wq_add(db, local_abspath, work_item, scratch_pool));
+ }
+ }
return SVN_NO_ERROR;
}
-
-/*** Private 'wc prop' functions ***/
-
-
-svn_error_t *
-svn_wc__wcprop_set(svn_wc__db_t *db,
- const char *local_abspath,
- const char *name,
- const svn_string_t *value,
- apr_pool_t *scratch_pool)
+/* Set a single 'wcprop' NAME to VALUE for versioned object LOCAL_ABSPATH.
+ If VALUE is null, remove property NAME. */
+static svn_error_t *
+wcprop_set(svn_wc__db_t *db,
+ const char *local_abspath,
+ const char *name,
+ const svn_string_t *value,
+ apr_pool_t *scratch_pool)
{
apr_hash_t *prophash;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
+ /* Note: this is not well-transacted. But... meh. This is merely a cache,
+ and if two processes are trying to modify this one entry at the same
+ time, then fine: we can let one be a winner, and one a loser. Of course,
+ if there are *other* state changes afoot, then the lack of a txn could
+ be a real issue, but we cannot solve that here. */
+
SVN_ERR(svn_wc__db_base_get_dav_cache(&prophash, db, local_abspath,
scratch_pool, scratch_pool));
@@ -1808,10 +2014,23 @@ svn_wc__wcprop_set(svn_wc__db_t *db,
scratch_pool));
}
-/*------------------------------------------------------------------*/
-
-/*** Public Functions ***/
+svn_error_t *
+svn_wc__get_actual_props(apr_hash_t **props,
+ svn_wc__db_t *db,
+ const char *local_abspath,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ SVN_ERR_ASSERT(props != NULL);
+ SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
+
+ /* ### perform some state checking. for example, locally-deleted nodes
+ ### should not have any ACTUAL props. */
+
+ return svn_error_return(load_actual_props(props, db, local_abspath,
+ result_pool, scratch_pool));
+}
svn_error_t *
@@ -1821,13 +2040,102 @@ svn_wc_prop_list2(apr_hash_t **props,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
+ return svn_error_return(svn_wc__get_actual_props(props,
+ wc_ctx->db,
+ local_abspath,
+ result_pool,
+ scratch_pool));
+}
+
+
+svn_error_t *
+svn_wc__get_pristine_props(apr_hash_t **props,
+ svn_wc__db_t *db,
+ const char *local_abspath,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ svn_wc__db_status_t status;
+
+ SVN_ERR_ASSERT(props != NULL);
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
- return svn_error_return(
- svn_wc__load_props(NULL, props, wc_ctx->db, local_abspath,
- result_pool, scratch_pool));
+ /* Certain node stats do not have properties defined on them. Check the
+ state, and return NULL for these situations. */
+
+ SVN_ERR(svn_wc__db_read_info(&status, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL,
+ db, local_abspath,
+ scratch_pool, scratch_pool));
+ if (status == svn_wc__db_status_added)
+ {
+ /* Resolve the status. copied and moved_here arrive with properties,
+ while a simple add does not. */
+ SVN_ERR(svn_wc__db_scan_addition(&status, NULL,
+ NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ db, local_abspath,
+ scratch_pool, scratch_pool));
+ }
+ if (status == svn_wc__db_status_added
+#if 0
+ /* ### the update editor needs to fetch properties while the directory
+ ### is still marked incomplete */
+ || status == svn_wc__db_status_incomplete
+#endif
+ || status == svn_wc__db_status_excluded
+ || status == svn_wc__db_status_absent
+ || status == svn_wc__db_status_not_present)
+ {
+ *props = NULL;
+ return SVN_NO_ERROR;
+ }
+
+ /* The node is obstructed:
+
+ - subdir is missing, obstructed by a file, or missing admin area
+ - a file is obstructed by a versioned subdir (### not reported)
+
+ Thus, properties are not available for this node. Returning NULL
+ would indicate "not defined" for its state. For obstructions, we
+ cannot *determine* whether properties should be here or not.
+
+ ### it would be nice to report an obstruction, rather than simply
+ ### PROPERTY_NOT_FOUND. but this is transitional until single-db. */
+ if (status == svn_wc__db_status_obstructed_delete
+ || status == svn_wc__db_status_obstructed
+ || status == svn_wc__db_status_obstructed_add)
+ return svn_error_createf(SVN_ERR_PROPERTY_NOT_FOUND, NULL,
+ U_("Directory '%s' is missing on disk, so the "
+ "properties are not available."),
+ svn_dirent_local_style(local_abspath,
+ scratch_pool));
+
+ /* status: normal, moved_here, copied, deleted */
+
+ /* After the above checks, these pristines should always be present. */
+ return svn_error_return(load_pristine_props(props, db, local_abspath,
+ result_pool, scratch_pool));
}
+
+svn_error_t *
+svn_wc_get_pristine_props(apr_hash_t **props,
+ svn_wc_context_t *wc_ctx,
+ const char *local_abspath,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ return svn_error_return(svn_wc__get_pristine_props(props,
+ wc_ctx->db,
+ local_abspath,
+ result_pool,
+ scratch_pool));
+}
+
+
svn_error_t *
svn_wc_prop_get2(const svn_string_t **value,
svn_wc_context_t *wc_ctx,
@@ -1906,8 +2214,8 @@ svn_wc__internal_propget(const svn_strin
else
{
/* regular prop */
- SVN_ERR_W(svn_wc__load_props(NULL, &prophash, db, local_abspath,
- result_pool, scratch_pool),
+ SVN_ERR_W(svn_wc__get_actual_props(&prophash, db, local_abspath,
+ result_pool, scratch_pool),
_("Failed to load properties from disk"));
}
@@ -2065,7 +2373,7 @@ svn_wc__internal_propset(svn_wc__db_t *d
void *notify_baton,
apr_pool_t *scratch_pool)
{
- apr_hash_t *prophash, *base_prophash;
+ apr_hash_t *prophash;
enum svn_prop_kind prop_kind = svn_property_kind(NULL, name);
svn_wc_notify_action_t notify_action;
svn_wc__db_kind_t kind;
@@ -2073,8 +2381,8 @@ svn_wc__internal_propset(svn_wc__db_t *d
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
if (prop_kind == svn_prop_wc_kind)
- return svn_error_return(svn_wc__wcprop_set(db, local_abspath,
- name, value, scratch_pool));
+ return svn_error_return(wcprop_set(db, local_abspath, name, value,
+ scratch_pool));
/* we don't do entry properties here */
if (prop_kind == svn_prop_entry_kind)
@@ -2139,9 +2447,9 @@ svn_wc__internal_propset(svn_wc__db_t *d
/* If not, we'll set the file to read-only at commit time. */
}
- SVN_ERR_W(svn_wc__load_props(&base_prophash, &prophash, db,
- local_abspath, scratch_pool, scratch_pool),
- _("Failed to load properties from disk"));
+ SVN_ERR_W(load_actual_props(&prophash, db, local_abspath,
+ scratch_pool, scratch_pool),
+ _("Failed to load current properties"));
/* If we're changing this file's list of expanded keywords, then
* we'll need to invalidate its text timestamp, since keyword
@@ -2215,8 +2523,8 @@ svn_wc__internal_propset(svn_wc__db_t *d
/* Drop it right onto the disk. We don't need loggy since we aren't
coordinating this change with anything else. */
- SVN_ERR(immediate_install_props(db, local_abspath, kind,
- base_prophash, prophash, scratch_pool));
+ SVN_ERR(immediate_install_props(db, local_abspath, kind, prophash,
+ scratch_pool));
if (notify_func)
{
@@ -2320,9 +2628,9 @@ svn_wc_canonicalize_svn_prop(const svn_s
new_value = svn_stringbuf_create_from_string(propval, pool);
svn_stringbuf_strip_whitespace(new_value);
}
- else if (strcmp(propname, SVN_PROP_EXECUTABLE) == 0
- || strcmp(propname, SVN_PROP_NEEDS_LOCK) == 0)
+ else if (svn_prop_is_boolean(propname))
{
+ /* SVN_PROP_EXECUTABLE, SVN_PROP_NEEDS_LOCK, SVN_PROP_SPECIAL */
new_value = svn_stringbuf_create_from_string(&boolean_value, pool);
}
else if (strcmp(propname, SVN_PROP_MERGEINFO) == 0)
@@ -2378,25 +2686,6 @@ svn_wc_is_entry_prop(const char *name)
svn_error_t *
-svn_wc__has_props(svn_boolean_t *has_props,
- svn_wc__db_t *db,
- const char *local_abspath,
[... 141 lines stripped ...]