You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by gb...@apache.org on 2013/11/05 13:53:29 UTC

svn commit: r1538976 [1/2] - in /subversion/branches/invoke-diff-merge-feature: ./ subversion/bindings/javahl/native/ subversion/bindings/javahl/src/org/apache/subversion/javahl/ subversion/bindings/javahl/src/org/apache/subversion/javahl/util/ subvers...

Author: gbg
Date: Tue Nov  5 12:53:28 2013
New Revision: 1538976

URL: http://svn.apache.org/r1538976
Log:
On the invoke-diff-merge-feature branch: trunk revision 1538962 merged
into branch revision 1538927.

Added:
    subversion/branches/invoke-diff-merge-feature/subversion/bindings/javahl/native/org_apache_subversion_javahl_util_PropLib.cpp
      - copied unchanged from r1538975, subversion/trunk/subversion/bindings/javahl/native/org_apache_subversion_javahl_util_PropLib.cpp
    subversion/branches/invoke-diff-merge-feature/subversion/bindings/javahl/src/org/apache/subversion/javahl/util/PropLib.java
      - copied unchanged from r1538975, subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/util/PropLib.java
Modified:
    subversion/branches/invoke-diff-merge-feature/   (props changed)
    subversion/branches/invoke-diff-merge-feature/build.conf
    subversion/branches/invoke-diff-merge-feature/subversion/bindings/javahl/src/org/apache/subversion/javahl/SVNUtil.java
    subversion/branches/invoke-diff-merge-feature/subversion/bindings/javahl/src/org/apache/subversion/javahl/util/DiffLib.java
    subversion/branches/invoke-diff-merge-feature/subversion/bindings/javahl/tests/org/apache/subversion/javahl/UtilTests.java
    subversion/branches/invoke-diff-merge-feature/subversion/include/private/svn_repos_private.h
    subversion/branches/invoke-diff-merge-feature/subversion/include/private/svn_subr_private.h
    subversion/branches/invoke-diff-merge-feature/subversion/include/svn_repos.h
    subversion/branches/invoke-diff-merge-feature/subversion/libsvn_client/iprops.c
    subversion/branches/invoke-diff-merge-feature/subversion/libsvn_repos/authz.c
    subversion/branches/invoke-diff-merge-feature/subversion/libsvn_repos/config_pool.c
    subversion/branches/invoke-diff-merge-feature/subversion/libsvn_repos/repos.c
    subversion/branches/invoke-diff-merge-feature/subversion/libsvn_subr/config.c
    subversion/branches/invoke-diff-merge-feature/subversion/libsvn_subr/config_file.c
    subversion/branches/invoke-diff-merge-feature/subversion/libsvn_subr/config_impl.h
    subversion/branches/invoke-diff-merge-feature/subversion/libsvn_wc/conflicts.c
    subversion/branches/invoke-diff-merge-feature/subversion/libsvn_wc/diff.h
    subversion/branches/invoke-diff-merge-feature/subversion/libsvn_wc/diff_local.c
    subversion/branches/invoke-diff-merge-feature/subversion/libsvn_wc/upgrade.c
    subversion/branches/invoke-diff-merge-feature/subversion/libsvn_wc/wc-queries.sql
    subversion/branches/invoke-diff-merge-feature/subversion/libsvn_wc/wc_db.c
    subversion/branches/invoke-diff-merge-feature/subversion/libsvn_wc/wc_db_update_move.c
    subversion/branches/invoke-diff-merge-feature/subversion/tests/cmdline/diff_tests.py
    subversion/branches/invoke-diff-merge-feature/subversion/tests/libsvn_repos/repos-test.c
    subversion/branches/invoke-diff-merge-feature/subversion/tests/libsvn_subr/   (props changed)
    subversion/branches/invoke-diff-merge-feature/subversion/tests/libsvn_wc/op-depth-test.c
    subversion/branches/invoke-diff-merge-feature/subversion/tests/libsvn_wc/utils.c
    subversion/branches/invoke-diff-merge-feature/subversion/tests/libsvn_wc/wc-queries-test.c
    subversion/branches/invoke-diff-merge-feature/subversion/tests/svn_test_main.c

Propchange: subversion/branches/invoke-diff-merge-feature/
------------------------------------------------------------------------------
  Merged /subversion/trunk:r1538071-1538975

Modified: subversion/branches/invoke-diff-merge-feature/build.conf
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-merge-feature/build.conf?rev=1538976&r1=1538975&r2=1538976&view=diff
==============================================================================
--- subversion/branches/invoke-diff-merge-feature/build.conf (original)
+++ subversion/branches/invoke-diff-merge-feature/build.conf Tue Nov  5 12:53:28 2013
@@ -79,6 +79,7 @@ private-built-includes =
         subversion/bindings/javahl/include/org_apache_subversion_javahl_util_ConfigImpl_Category.h
         subversion/bindings/javahl/include/org_apache_subversion_javahl_util_ConfigLib.h
         subversion/bindings/javahl/include/org_apache_subversion_javahl_util_DiffLib.h
+        subversion/bindings/javahl/include/org_apache_subversion_javahl_util_PropLib.h
         subversion/bindings/javahl/include/org_apache_subversion_javahl_util_TunnelChannel.h
         subversion/bindings/javahl/include/org_apache_subversion_javahl_util_RequestChannel.h
         subversion/bindings/javahl/include/org_apache_subversion_javahl_util_ResponseChannel.h

Modified: subversion/branches/invoke-diff-merge-feature/subversion/bindings/javahl/src/org/apache/subversion/javahl/SVNUtil.java
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-merge-feature/subversion/bindings/javahl/src/org/apache/subversion/javahl/SVNUtil.java?rev=1538976&r1=1538975&r2=1538976&view=diff
==============================================================================
--- subversion/branches/invoke-diff-merge-feature/subversion/bindings/javahl/src/org/apache/subversion/javahl/SVNUtil.java (original)
+++ subversion/branches/invoke-diff-merge-feature/subversion/bindings/javahl/src/org/apache/subversion/javahl/SVNUtil.java Tue Nov  5 12:53:28 2013
@@ -24,8 +24,10 @@
 package org.apache.subversion.javahl;
 
 import org.apache.subversion.javahl.callback.*;
+import org.apache.subversion.javahl.types.*;
 import org.apache.subversion.javahl.util.*;
 
+import java.io.InputStream;
 import java.io.OutputStream;
 
 public class SVNUtil
@@ -281,4 +283,61 @@ public class SVNUtil
                                        conflictLatest, conflictSeparator,
                                        conflictStyle, resultStream);
     }
+
+    //
+    // Property validation and parsing
+    //
+
+    /**
+     * Validate the value of an <code>svn:</code> property on file or
+     * directory and return a canonical representation of its value.
+     * @param name The name of the property (must be a valid svn: property)
+     * @param value The property's value
+     * @param path The path or URL of the file or directory that
+     *        owns the property; only used for error messages
+     * @param kind The node kind of the file or dir that owns the property
+     * @param mimeType If <code>kind</code> is {@link NodeKind.file}, this is
+     *        tye file's mime-type, used for extra validation for the
+     *        <code>svn:eol-style</code> property. If it is <code>null</code>,
+     *        the extra validation will be skipped.
+     * @return a canonicalized representation of the property value
+     * @see http://subversion.apache.org/docs/api/latest/group__svn__wc__properties.html#ga83296313ec59cc825176224ac8282ec2
+     */
+    public static byte[] canonicalizeNodeProperty(
+        String name, byte[] value, String path, NodeKind kind,
+        String mimeType)
+        throws ClientException
+    {
+        return new PropLib().canonicalizeNodeProperty(
+            name, value, path, kind, mimeType, null);
+    }
+
+    /**
+     * Validate the value of an <code>svn:</code> property on file or
+     * directory and return a canonical representation of its value.
+     * @param name The name of the property (must be a valid svn: property)
+     * @param value The property's value
+     * @param path The path or URL of the file or directory that
+     *        owns the property; only used for error messages
+     * @param kind The node kind of the file or dir that owns the property
+     * @param mimeType If <code>kind</code> is {@link NodeKind.file}, this is
+     *        tye file's mime-type, used for extra validation for the
+     *        <code>svn:eol-style</code> property. If it is <code>null</code>,
+     *        the extra validation will be skipped.
+     * @param fileContents A stream with the file's contents. Only used
+     *        to check for line-ending consistency when validating the
+     *        <code>svn:eol-style</code> property, and only when
+     *        <code>kind</code> is {@link NodeKind.file} and
+     *        <code>mimeType</code> is not <code>null</code>.
+     * @return a canonicalized representation of the property value
+     * @see http://subversion.apache.org/docs/api/latest/group__svn__wc__properties.html#ga83296313ec59cc825176224ac8282ec2
+     */
+    public static byte[] canonicalizeNodeProperty(
+        String name, byte[] value, String path, NodeKind kind,
+        String mimeType, InputStream fileContents)
+        throws ClientException
+    {
+        return new PropLib().canonicalizeNodeProperty(
+            name, value, path, kind, mimeType, fileContents);
+    }
 }

Modified: subversion/branches/invoke-diff-merge-feature/subversion/bindings/javahl/src/org/apache/subversion/javahl/util/DiffLib.java
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-merge-feature/subversion/bindings/javahl/src/org/apache/subversion/javahl/util/DiffLib.java?rev=1538976&r1=1538975&r2=1538976&view=diff
==============================================================================
--- subversion/branches/invoke-diff-merge-feature/subversion/bindings/javahl/src/org/apache/subversion/javahl/util/DiffLib.java (original)
+++ subversion/branches/invoke-diff-merge-feature/subversion/bindings/javahl/src/org/apache/subversion/javahl/util/DiffLib.java Tue Nov  5 12:53:28 2013
@@ -43,7 +43,7 @@ public class DiffLib
         NativeResources.loadNativeLibrary();
     }
 
-    /** @see ISVNUtil.fileDiff */
+    /** @see SVNUtil.fileDiff */
     public boolean fileDiff(String originalFile,
                             String modifiedFile,
                             SVNUtil.DiffOptions diffOptions,
@@ -88,7 +88,7 @@ public class DiffLib
                                OutputStream resultStream)
         throws ClientException;
 
-    /** @see ISVNUtil.fileMerge */
+    /** @see SVNUtil.fileMerge */
     public boolean fileMerge(String originalFile,
                              String modifiedFile,
                              String latestFile,

Modified: subversion/branches/invoke-diff-merge-feature/subversion/bindings/javahl/tests/org/apache/subversion/javahl/UtilTests.java
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-merge-feature/subversion/bindings/javahl/tests/org/apache/subversion/javahl/UtilTests.java?rev=1538976&r1=1538975&r2=1538976&view=diff
==============================================================================
--- subversion/branches/invoke-diff-merge-feature/subversion/bindings/javahl/tests/org/apache/subversion/javahl/UtilTests.java (original)
+++ subversion/branches/invoke-diff-merge-feature/subversion/bindings/javahl/tests/org/apache/subversion/javahl/UtilTests.java Tue Nov  5 12:53:28 2013
@@ -23,7 +23,10 @@
 
 package org.apache.subversion.javahl;
 
+import org.apache.subversion.javahl.types.NodeKind;
+
 import java.io.File;
+import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.ByteArrayOutputStream;
 import java.util.Arrays;
@@ -135,4 +138,54 @@ public class UtilTests extends SVNTests
                                  "\nN-3\nN-2\nN-1\nN\n").getBytes();
         assertTrue(Arrays.equals(expected, result.toByteArray()));
     }
+
+    public void testValidateProp() throws Throwable
+    {
+        File temp = File.createTempFile("propcheck", ".file", localTmp);
+        FileOutputStream out = new FileOutputStream(temp);
+        out.write("normal text\n".getBytes());
+        out.close();
+
+        byte[] prop = SVNUtil.canonicalizeNodeProperty(
+                           "svn:eol-style", "  native".getBytes(),
+                           "propcheck.file", NodeKind.file,
+                           "text/plain");
+        assertEquals("native", new String(prop));
+
+        prop = SVNUtil.canonicalizeNodeProperty(
+                    "svn:eol-style", " native  ".getBytes(),
+                    "propcheck.file", NodeKind.file,
+                    "text/plain", new FileInputStream(temp));
+        assertEquals("native", new String(prop));
+
+        boolean caught_exception = false;
+        try {
+            prop = SVNUtil.canonicalizeNodeProperty(
+                        "svn:eol-style", " weird  ".getBytes(),
+                        "propcheck.file", NodeKind.file,
+                        "text/plain");
+        } catch (ClientException ex) {
+            assertEquals("Unrecognized line ending style",
+                         ex.getAllMessages().get(0).getMessage());
+            caught_exception = true;
+        }
+        assertTrue(caught_exception);
+
+        out = new FileOutputStream(temp);
+        out.write("inconsistent\r\ntext\n".getBytes());
+        out.close();
+
+        caught_exception = false;
+        try {
+            prop = SVNUtil.canonicalizeNodeProperty(
+                        "svn:eol-style", " native  ".getBytes(),
+                        "propcheck.file", NodeKind.file,
+                        "text/plain", new FileInputStream(temp));
+        } catch (ClientException ex) {
+            assertEquals("Inconsistent line ending style",
+                         ex.getAllMessages().get(2).getMessage());
+            caught_exception = true;
+        }
+        assertTrue(caught_exception);
+    }
 }

Modified: subversion/branches/invoke-diff-merge-feature/subversion/include/private/svn_repos_private.h
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-merge-feature/subversion/include/private/svn_repos_private.h?rev=1538976&r1=1538975&r2=1538976&view=diff
==============================================================================
--- subversion/branches/invoke-diff-merge-feature/subversion/include/private/svn_repos_private.h (original)
+++ subversion/branches/invoke-diff-merge-feature/subversion/include/private/svn_repos_private.h Tue Nov  5 12:53:28 2013
@@ -134,7 +134,8 @@ svn_repos__replay_ev2(svn_fs_root_t *roo
  *
  * If PATH cannot be parsed as a config file then an error is returned.  The
  * contents of CFG_P is then undefined.  If MUST_EXIST is TRUE, a missing
- * authz file is also an error.
+ * authz file is also an error.  The CASE_SENSITIVE controls the lookup
+ * behavior for section and option names alike.
  *
  * REPOS_ROOT points at the root of the repos you are
  * going to apply the authz against, can be NULL if you are sure that you
@@ -143,6 +144,7 @@ svn_error_t *
 svn_repos__retrieve_config(svn_config_t **cfg_p,
                            const char *path,
                            svn_boolean_t must_exist,
+                           svn_boolean_t case_sensitive,
                            apr_pool_t *pool);
 
 /**
@@ -172,6 +174,15 @@ svn_repos__config_pool_create(svn_repos_
  * CONFIG_POOL will store the configuration and make further callers use
  * the same instance if the content matches.
  *
+ * If MUST_EXIST is TRUE, a missing config file is also an error, *CFG
+ * is otherwise simply NULL.  The CASE_SENSITIVE controls the lookup
+ * behavior for section and option names alike.
+ *
+ * PREFERRED_REPOS is only used if it is not NULL and PATH is a URL.
+ * If it matches the URL, access the repository through this object
+ * instead of creating a new repo instance.  Note that this might not
+ * return the latest content.
+ *
  * POOL determines the minimum lifetime of *CFG.
  *
  * Note: The read-only behavior is not enforced, yet. 
@@ -180,6 +191,9 @@ svn_error_t *
 svn_repos__config_pool_get(svn_config_t **cfg,
                            svn_repos__config_pool_t *config_pool,
                            const char *path,
+                           svn_boolean_t must_exist,
+                           svn_boolean_t case_sensitive,
+                           svn_repos_t *preferred_repos,
                            apr_pool_t *pool);
 
 /** @} */

Modified: subversion/branches/invoke-diff-merge-feature/subversion/include/private/svn_subr_private.h
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-merge-feature/subversion/include/private/svn_subr_private.h?rev=1538976&r1=1538975&r2=1538976&view=diff
==============================================================================
--- subversion/branches/invoke-diff-merge-feature/subversion/include/private/svn_subr_private.h (original)
+++ subversion/branches/invoke-diff-merge-feature/subversion/include/private/svn_subr_private.h Tue Nov  5 12:53:28 2013
@@ -485,6 +485,16 @@ svn_config__is_expanded(svn_config_t *cf
                         const char *section,
                         const char *option);
 
+/* Return a shallow copy of SCR in POOL.  If SRC is read-only, different
+ * shallow copies may be used from different threads.
+ *
+ * Any single r/o svn_config_t or shallow copy is not thread-safe because
+ * it contains shared buffers for tempoary data.
+ */
+svn_config_t *
+svn_config__shallow_copy(svn_config_t *src,
+                         apr_pool_t *pool);
+
 /** @} */
 
 #ifdef __cplusplus

Modified: subversion/branches/invoke-diff-merge-feature/subversion/include/svn_repos.h
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-merge-feature/subversion/include/svn_repos.h?rev=1538976&r1=1538975&r2=1538976&view=diff
==============================================================================
--- subversion/branches/invoke-diff-merge-feature/subversion/include/svn_repos.h (original)
+++ subversion/branches/invoke-diff-merge-feature/subversion/include/svn_repos.h Tue Nov  5 12:53:28 2013
@@ -558,6 +558,13 @@ svn_repos_capabilities(apr_hash_t **capa
 svn_fs_t *
 svn_repos_fs(svn_repos_t *repos);
 
+/** Return the type of filesystem associated with repository object
+ * @a repos allocated in @a pool.
+ *
+ * @since New in 1.9.
+ */
+const char *
+svn_repos_fs_type(svn_repos_t *repos, apr_pool_t *pool);
 
 /** Make a hot copy of the Subversion repository found at @a src_path
  * to @a dst_path.

Modified: subversion/branches/invoke-diff-merge-feature/subversion/libsvn_client/iprops.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-merge-feature/subversion/libsvn_client/iprops.c?rev=1538976&r1=1538975&r2=1538976&view=diff
==============================================================================
--- subversion/branches/invoke-diff-merge-feature/subversion/libsvn_client/iprops.c (original)
+++ subversion/branches/invoke-diff-merge-feature/subversion/libsvn_client/iprops.c Tue Nov  5 12:53:28 2013
@@ -244,6 +244,8 @@ svn_client__get_inheritable_props(apr_ha
   const char *old_session_url;
   svn_error_t *err;
 
+  *wcroot_iprops = NULL;
+
   if (!SVN_IS_VALID_REVNUM(revision))
     return SVN_NO_ERROR;
 

Modified: subversion/branches/invoke-diff-merge-feature/subversion/libsvn_repos/authz.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-merge-feature/subversion/libsvn_repos/authz.c?rev=1538976&r1=1538975&r2=1538976&view=diff
==============================================================================
--- subversion/branches/invoke-diff-merge-feature/subversion/libsvn_repos/authz.c (original)
+++ subversion/branches/invoke-diff-merge-feature/subversion/libsvn_repos/authz.c Tue Nov  5 12:53:28 2013
@@ -773,13 +773,17 @@ authz_validate(svn_authz_t *authz, apr_p
  *
  * If DIRENT cannot be parsed as a config file then an error is returned.  The
  * contents of CFG_P is then undefined.  If MUST_EXIST is TRUE, a missing
- * authz file is also an error.
+ * authz file is also an error.  The CASE_SENSITIVE controls the lookup
+ * behavior for section and option names alike.
  *
  * SCRATCH_POOL will be used for temporary allocations. */
 static svn_error_t *
-authz_retrieve_config_repo(svn_config_t **cfg_p, const char *dirent,
-                          svn_boolean_t must_exist,
-                          apr_pool_t *result_pool, apr_pool_t *scratch_pool)
+authz_retrieve_config_repo(svn_config_t **cfg_p,
+                           const char *dirent,
+                           svn_boolean_t must_exist,
+                           svn_boolean_t case_sensitive,
+                           apr_pool_t *result_pool,
+                           apr_pool_t *scratch_pool)
 {
   svn_error_t *err;
   svn_repos_t *repos;
@@ -826,7 +830,8 @@ authz_retrieve_config_repo(svn_config_t 
     {
       if (!must_exist)
         {
-          SVN_ERR(svn_config_create2(cfg_p, TRUE, TRUE, result_pool));
+          SVN_ERR(svn_config_create2(cfg_p, case_sensitive, case_sensitive,
+                                     result_pool));
           return SVN_NO_ERROR;
         }
       else
@@ -844,7 +849,8 @@ authz_retrieve_config_repo(svn_config_t 
     }
 
   SVN_ERR(svn_fs_file_contents(&contents, root, fs_path, scratch_pool));
-  err = svn_config_parse(cfg_p, contents, TRUE, TRUE, result_pool);
+  err = svn_config_parse(cfg_p, contents, case_sensitive, case_sensitive,
+                         result_pool);
 
   /* Add the URL to the error stack since the parser doesn't have it. */
   if (err != SVN_NO_ERROR)
@@ -856,8 +862,11 @@ authz_retrieve_config_repo(svn_config_t 
 }
 
 svn_error_t *
-svn_repos__retrieve_config(svn_config_t **cfg_p, const char *path,
-                           svn_boolean_t must_exist, apr_pool_t *pool)
+svn_repos__retrieve_config(svn_config_t **cfg_p,
+                           const char *path,
+                           svn_boolean_t must_exist,
+                           svn_boolean_t case_sensitive,
+                           apr_pool_t *pool)
 {
   if (svn_path_is_url(path))
     {
@@ -868,8 +877,8 @@ svn_repos__retrieve_config(svn_config_t 
       err = svn_uri_get_dirent_from_file_url(&dirent, path, scratch_pool);
 
       if (err == SVN_NO_ERROR)
-        err = authz_retrieve_config_repo(cfg_p, dirent, must_exist, pool,
-                                         scratch_pool);
+        err = authz_retrieve_config_repo(cfg_p, dirent, must_exist,
+                                         case_sensitive, pool, scratch_pool);
 
       /* Close the repos and streams we opened. */
       svn_pool_destroy(scratch_pool);
@@ -879,7 +888,8 @@ svn_repos__retrieve_config(svn_config_t 
   else
     {
       /* Outside of repo file or Windows registry*/
-      SVN_ERR(svn_config_read3(cfg_p, path, must_exist, TRUE, TRUE, pool));
+      SVN_ERR(svn_config_read3(cfg_p, path, must_exist, case_sensitive,
+                               case_sensitive, pool));
     }
 
   return SVN_NO_ERROR;
@@ -930,9 +940,11 @@ svn_repos__authz_read(svn_authz_t **auth
 
   /* Load the authz file */
   if (accept_urls)
-    SVN_ERR(svn_repos__retrieve_config(&authz->cfg, path, must_exist, pool));
+    SVN_ERR(svn_repos__retrieve_config(&authz->cfg, path, must_exist, TRUE,
+                                       pool));
   else
-    SVN_ERR(svn_config_read3(&authz->cfg, path, must_exist, TRUE, TRUE, pool));
+    SVN_ERR(svn_config_read3(&authz->cfg, path, must_exist, TRUE, TRUE,
+                             pool));
 
   if (groups_path)
     {
@@ -942,7 +954,7 @@ svn_repos__authz_read(svn_authz_t **auth
       /* Load the groups file */
       if (accept_urls)
         SVN_ERR(svn_repos__retrieve_config(&groups_cfg, groups_path,
-                                           must_exist, pool));
+                                           must_exist, TRUE, pool));
       else
         SVN_ERR(svn_config_read3(&groups_cfg, groups_path, must_exist,
                                  TRUE, TRUE, pool));

Modified: subversion/branches/invoke-diff-merge-feature/subversion/libsvn_repos/config_pool.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-merge-feature/subversion/libsvn_repos/config_pool.c?rev=1538976&r1=1538975&r2=1538976&view=diff
==============================================================================
--- subversion/branches/invoke-diff-merge-feature/subversion/libsvn_repos/config_pool.c (original)
+++ subversion/branches/invoke-diff-merge-feature/subversion/libsvn_repos/config_pool.c Tue Nov  5 12:53:28 2013
@@ -54,8 +54,14 @@ typedef struct config_ref_t
    * This is a SHA1 checksum of the parsed textual representation of CFG. */
   svn_checksum_t *key;
 
-  /* Parsed and expanded configuration */
-  svn_config_t *cfg;
+  /* Parsed and expanded configuration.  At least one of the following
+   * must not be NULL. */
+
+  /* Case-sensitive config. May be NULL */
+  svn_config_t *cs_cfg;
+
+  /* Case-insensitive config. May be NULL */
+  svn_config_t *ci_cfg;
 
   /* private pool. This instance and its other members got allocated in it.
    * Will be destroyed when this instance is cleaned up. */
@@ -217,21 +223,27 @@ config_ref_cleanup(void *baton)
 }
 
 /* Return an automatic reference to the CFG member in CONFIG that will be
- * released when POOL gets cleaned up.
+ * released when POOL gets cleaned up.  CASE_SENSITIVE controls option and
+ * section name matching.
  */
 static svn_config_t *
 return_config_ref(config_ref_t *config,
+                  svn_boolean_t case_sensitive,
                   apr_pool_t *pool)
 {
   if (svn_atomic_inc(&config->ref_count) == 0)
     svn_atomic_inc(&config->config_pool->used_config_count);
+
   apr_pool_cleanup_register(pool, config, config_ref_cleanup,
                             apr_pool_cleanup_null);
-  return config->cfg;
+  return svn_config__shallow_copy(case_sensitive ? config->cs_cfg
+                                                 : config->ci_cfg,
+                                  pool);
 }
 
 /* Set *CFG to the configuration with a parsed textual matching CHECKSUM.
  * Set *CFG to NULL if no such config can be found in CONFIG_POOL.
+ * CASE_SENSITIVE controls option and section name matching.
  * 
  * RESULT_POOL determines the lifetime of the returned reference.
  *
@@ -241,12 +253,15 @@ static svn_error_t *
 config_by_checksum(svn_config_t **cfg,
                    svn_repos__config_pool_t *config_pool,
                    svn_checksum_t *checksum,
+                   svn_boolean_t case_sensitive,
                    apr_pool_t *result_pool)
 {
   config_ref_t *config_ref = apr_hash_get(config_pool->configs,
                                           checksum->digest,
                                           svn_checksum_size(checksum));
-  *cfg = config_ref ? return_config_ref(config_ref, result_pool) : NULL;
+  *cfg = config_ref
+       ? return_config_ref(config_ref, case_sensitive, result_pool)
+       : NULL;
 
   return SVN_NO_ERROR;
 }
@@ -283,6 +298,7 @@ remove_unused_configs(svn_repos__config_
 
 /* Cache config_ref* in CONFIG_POOL and return a reference to it in *CFG.
  * RESULT_POOL determines the lifetime of that reference.
+ * CASE_SENSITIVE controls option and section name matching.
  *
  * Requires external serialization on CONFIG_POOL.
  */
@@ -290,6 +306,7 @@ static svn_error_t *
 config_add(svn_config_t **cfg,
            svn_repos__config_pool_t *config_pool,
            config_ref_t *config_ref,
+           svn_boolean_t case_sensitive,
            apr_pool_t *result_pool)
 {
   config_ref_t *config = apr_hash_get(config_ref->config_pool->configs,
@@ -297,8 +314,23 @@ config_add(svn_config_t **cfg,
                                       svn_checksum_size(config_ref->key));
   if (config)
     {
-      /* entry already exists (e.g. race condition)
-       * Destroy the new one and return a reference to the existing one
+      /* entry already exists (e.g. race condition) */
+
+      /* Maybe, we created a variant with different case sensitivity? */
+      if (case_sensitive && config->cs_cfg == NULL)
+        {
+          SVN_ERR(svn_config_dup(&config->cs_cfg, config_ref->cs_cfg,
+                                 config->pool));
+          svn_config__set_read_only(config->cs_cfg, config_ref->pool);
+        }
+      else if (!case_sensitive && config->ci_cfg == NULL)
+        {
+          SVN_ERR(svn_config_dup(&config->ci_cfg, config_ref->ci_cfg,
+                                 config->pool));
+          svn_config__set_read_only(config->ci_cfg, config_ref->pool);
+        }
+
+      /* Destroy the new one and return a reference to the existing one
        * because the existing one may already have references on it.
        */
       svn_pool_destroy(config_ref->pool);
@@ -320,14 +352,14 @@ config_add(svn_config_t **cfg,
                    config_ref);
     }
 
-  *cfg = return_config_ref(config_ref, result_pool);
+  *cfg = return_config_ref(config_ref, case_sensitive, result_pool);
 
   return SVN_NO_ERROR;
 }
 
 /* Set *CFG to the configuration passed in as text in CONTENTS.  If no such
  * configuration exists in CONFIG_POOL, yet, parse CONTENTS and cache the
- * result.
+ * result.  CASE_SENSITIVE controls option and section name matching.
  * 
  * RESULT_POOL determines the lifetime of the returned reference and 
  * SCRATCH_POOL is being used for temporary allocations.
@@ -336,6 +368,7 @@ static svn_error_t *
 auto_parse(svn_config_t **cfg,
            svn_repos__config_pool_t *config_pool,
            svn_stringbuf_t *contents,
+           svn_boolean_t case_sensitive,
            apr_pool_t *result_pool,
            apr_pool_t *scratch_pool)
 {
@@ -353,7 +386,7 @@ auto_parse(svn_config_t **cfg,
   *cfg = NULL;
   SVN_MUTEX__WITH_LOCK(config_pool->mutex,
                        config_by_checksum(cfg, config_pool, checksum,
-                                          result_pool));
+                                          case_sensitive, result_pool));
 
   if (*cfg)
     return SVN_NO_ERROR;
@@ -369,16 +402,20 @@ auto_parse(svn_config_t **cfg,
   config_ref->pool = cfg_pool;
   config_ref->ref_count = 0;
 
-  SVN_ERR(svn_config_parse(&config_ref->cfg,
+  SVN_ERR(svn_config_parse(case_sensitive ? &config_ref->cs_cfg
+                                          : &config_ref->ci_cfg,
                            svn_stream_from_stringbuf(contents, scratch_pool),
-                           TRUE, TRUE, cfg_pool));
+                           case_sensitive, case_sensitive, cfg_pool));
 
   /* switch config data to r/o mode to guarantee thread-safe access */
-  svn_config__set_read_only(config_ref->cfg, cfg_pool);
+  svn_config__set_read_only(case_sensitive ? config_ref->cs_cfg
+                                           : config_ref->ci_cfg,
+                            cfg_pool);
 
   /* add config in pool, handle loads races and return the right config */
   SVN_MUTEX__WITH_LOCK(config_pool->mutex,
-                       config_add(cfg, config_pool, config_ref, result_pool));
+                       config_add(cfg, config_pool, config_ref,
+                                  case_sensitive, result_pool));
 
   return SVN_NO_ERROR;
 }
@@ -439,7 +476,9 @@ add_checksum(svn_repos__config_pool_t *c
 }
 
 /* Set *CFG to the configuration stored in URL@HEAD and cache it in 
- * CONFIG_POOL. ### Always returns a NULL CFG.
+ * CONFIG_POOL. ### Always returns a NULL CFG.  CASE_SENSITIVE controls
+ * option and section name matching.  If PREFERRED_REPOS is given,
+ * use that if it also matches URL.
  * 
  * RESULT_POOL determines the lifetime of the returned reference and 
  * SCRATCH_POOL is being used for temporary allocations.
@@ -448,10 +487,12 @@ static svn_error_t *
 find_repos_config(svn_config_t **cfg,
                   svn_repos__config_pool_t *config_pool,
                   const char *url,
+                  svn_boolean_t case_sensitive,
+                  svn_repos_t *preferred_repos,
                   apr_pool_t *result_pool,
                   apr_pool_t *scratch_pool)
 {
-  svn_repos_t *repos;
+  svn_repos_t *repos = NULL;
   svn_fs_t *fs;
   svn_fs_root_t *root;
   svn_revnum_t youngest_rev;
@@ -466,11 +507,29 @@ find_repos_config(svn_config_t **cfg,
   *cfg = NULL;
   SVN_ERR(svn_uri_get_dirent_from_file_url(&dirent, url, scratch_pool));
 
-  /* Search for a repository in the full path. */
-  repos_root_dirent = svn_repos_find_root_path(dirent, scratch_pool);
+  /* maybe we can use the preferred repos instance instead of creating a
+   * new one */
+  if (preferred_repos)
+    {
+      repos_root_dirent = svn_repos_path(preferred_repos, scratch_pool);
+      if (!svn_dirent_is_absolute(repos_root_dirent))
+        SVN_ERR(svn_dirent_get_absolute(&repos_root_dirent,
+                                        repos_root_dirent,
+                                        scratch_pool));
+
+      if (svn_dirent_is_ancestor(repos_root_dirent, dirent))
+        repos = preferred_repos;
+    }
+
+  /* open repos if no suitable preferred repos was provided. */
+  if (!repos)
+    {
+      /* Search for a repository in the full path. */
+      repos_root_dirent = svn_repos_find_root_path(dirent, scratch_pool);
 
-  /* Attempt to open a repository at repos_root_dirent. */
-  SVN_ERR(svn_repos_open2(&repos, repos_root_dirent, NULL, scratch_pool));
+      /* Attempt to open a repository at repos_root_dirent. */
+      SVN_ERR(svn_repos_open2(&repos, repos_root_dirent, NULL, scratch_pool));
+    }
 
   fs_path = &dirent[strlen(repos_root_dirent)];
 
@@ -487,7 +546,7 @@ find_repos_config(svn_config_t **cfg,
   if (checksum)
     SVN_MUTEX__WITH_LOCK(config_pool->mutex,
                          config_by_checksum(cfg, config_pool, checksum,
-                                            result_pool));
+                                            case_sensitive, result_pool));
 
   /* not parsed, yet? */
   if (!*cfg)
@@ -505,8 +564,8 @@ find_repos_config(svn_config_t **cfg,
                                         (apr_size_t)length, scratch_pool));
 
       /* handle it like ordinary file contents and cache it */
-      SVN_ERR(auto_parse(cfg, config_pool, contents, result_pool,
-                         scratch_pool));
+      SVN_ERR(auto_parse(cfg, config_pool, contents, case_sensitive,
+                         result_pool, scratch_pool));
     }
 
   /* store the (path,rev) -> checksum mapping as well */
@@ -520,7 +579,7 @@ find_repos_config(svn_config_t **cfg,
 
 /* Set *CFG to the configuration cached in CONFIG_POOL for URL.  If no
  * suitable config has been cached or if it is potentially outdated, set
- * *CFG to NULL.
+ * *CFG to NULL.  CASE_SENSITIVE controls option and section name matching.
  *
  * RESULT_POOL determines the lifetime of the returned reference and 
  * SCRATCH_POOL is being used for temporary allocations.
@@ -531,6 +590,7 @@ static svn_error_t *
 config_by_url(svn_config_t **cfg,
               svn_repos__config_pool_t *config_pool,
               const char *url,
+              svn_boolean_t case_sensitive,
               apr_pool_t *result_pool,
               apr_pool_t *scratch_pool)
 {
@@ -541,7 +601,7 @@ config_by_url(svn_config_t **cfg,
 
   /* hash lookup url -> sha1 -> config */
   in_repo_config_t *config = svn_hash_gets(config_pool->in_repo_configs, url);
-  *cfg = 0;
+  *cfg = NULL;
   if (config)
     config_ref = apr_hash_get(config_pool->configs,
                               config->key->digest,
@@ -549,6 +609,12 @@ config_by_url(svn_config_t **cfg,
   if (!config_ref)
     return SVN_NO_ERROR;
 
+  /* available with the desired case sensitivity? */
+  if (case_sensitive && config_ref->cs_cfg == NULL)
+    return SVN_NO_ERROR;
+  if (!case_sensitive && config_ref->ci_cfg == NULL)
+    return SVN_NO_ERROR;
+
   /* found *some* configuration. 
    * Verify that it is still current.  Will fail for BDB repos. */
   err = svn_stringbuf_from_file2(&contents, 
@@ -561,7 +627,7 @@ config_by_url(svn_config_t **cfg,
   if (err)
     svn_error_clear(err);
   else if (current == config->revision)
-    *cfg = return_config_ref(config_ref, result_pool);
+    *cfg = return_config_ref(config_ref, case_sensitive, result_pool);
 
   return SVN_NO_ERROR;
 }
@@ -600,6 +666,9 @@ svn_error_t *
 svn_repos__config_pool_get(svn_config_t **cfg,
                            svn_repos__config_pool_t *config_pool,
                            const char *path,
+                           svn_boolean_t must_exist,
+                           svn_boolean_t case_sensitive,
+                           svn_repos_t *preferred_repos,
                            apr_pool_t *pool)
 {
   svn_error_t *err = SVN_NO_ERROR;
@@ -610,18 +679,24 @@ svn_repos__config_pool_get(svn_config_t 
       /* Read config file from repository.
        * Attempt a quick lookup first. */
       SVN_MUTEX__WITH_LOCK(config_pool->mutex,
-                           config_by_url(cfg, config_pool, path, pool,
+                           config_by_url(cfg, config_pool, path, 
+                                         case_sensitive, pool,
                                          scratch_pool));
       if (*cfg)
-        return SVN_NO_ERROR;
+        {
+          svn_pool_destroy(scratch_pool);
+          return SVN_NO_ERROR;
+        }
 
       /* Read and cache the configuration.  This may fail. */
-      err = find_repos_config(cfg, config_pool, path, pool, scratch_pool);
+      err = find_repos_config(cfg, config_pool, path, case_sensitive,
+                              preferred_repos, pool, scratch_pool);
       if (err || !*cfg)
         {
           /* let the standard implementation handle all the difficult cases */
           svn_error_clear(err);
-          err = svn_repos__retrieve_config(cfg, path, TRUE, pool);
+          err = svn_repos__retrieve_config(cfg, path, must_exist,
+                                           case_sensitive, pool);
         }
     }
   else
@@ -633,12 +708,14 @@ svn_repos__config_pool_get(svn_config_t 
         {
           /* let the standard implementation handle all the difficult cases */
           svn_error_clear(err);
-          err = svn_config_read3(cfg, path, TRUE, TRUE, TRUE, pool);
+          err = svn_config_read3(cfg, path, must_exist, case_sensitive,
+                                 case_sensitive, pool);
         }
       else
         {
           /* parsing and caching will always succeed */
-          err = auto_parse(cfg, config_pool, contents, pool, scratch_pool);
+          err = auto_parse(cfg, config_pool, contents, case_sensitive,
+                           pool, scratch_pool);
         }
     }
 

Modified: subversion/branches/invoke-diff-merge-feature/subversion/libsvn_repos/repos.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-merge-feature/subversion/libsvn_repos/repos.c?rev=1538976&r1=1538975&r2=1538976&view=diff
==============================================================================
--- subversion/branches/invoke-diff-merge-feature/subversion/libsvn_repos/repos.c (original)
+++ subversion/branches/invoke-diff-merge-feature/subversion/libsvn_repos/repos.c Tue Nov  5 12:53:28 2013
@@ -1796,6 +1796,11 @@ svn_repos_fs(svn_repos_t *repos)
   return repos->fs;
 }
 
+const char *
+svn_repos_fs_type(svn_repos_t *repos, apr_pool_t *pool)
+{
+  return apr_pstrdup(pool, repos->fs_type);
+}
 
 /* For historical reasons, for the Berkeley DB backend, this code uses
  * repository locking, which is motivated by the need to support the

Modified: subversion/branches/invoke-diff-merge-feature/subversion/libsvn_subr/config.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-merge-feature/subversion/libsvn_subr/config.c?rev=1538976&r1=1538975&r2=1538976&view=diff
==============================================================================
--- subversion/branches/invoke-diff-merge-feature/subversion/libsvn_subr/config.c (original)
+++ subversion/branches/invoke-diff-merge-feature/subversion/libsvn_subr/config.c Tue Nov  5 12:53:28 2013
@@ -703,11 +703,11 @@ svn_config_get(svn_config_t *cfg, const 
         }
       else
         /* before attempting to expand an option, check for the placeholder.
-         * If none is there, there is no point in calling expand_option_value.
+         * If there is none, there is no point in calling expand_option_value.
          */
         if (default_value && strchr(default_value, '%'))
           {
-            apr_pool_t *tmp_pool = svn_pool_create(cfg->x_pool);
+            apr_pool_t *tmp_pool = svn_pool_create(cfg->pool);
             const char *x_default;
             expand_option_value(cfg, sec, default_value, &x_default, tmp_pool);
             if (x_default)
@@ -985,7 +985,7 @@ svn_config_enumerate(svn_config_t *cfg, 
   if (sec == NULL)
     return 0;
 
-  subpool = svn_pool_create(cfg->x_pool);
+  subpool = svn_pool_create(cfg->pool);
   count = 0;
   for (opt_ndx = apr_hash_first(subpool, sec->options);
        opt_ndx != NULL;

Modified: subversion/branches/invoke-diff-merge-feature/subversion/libsvn_subr/config_file.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-merge-feature/subversion/libsvn_subr/config_file.c?rev=1538976&r1=1538975&r2=1538976&view=diff
==============================================================================
--- subversion/branches/invoke-diff-merge-feature/subversion/libsvn_subr/config_file.c (original)
+++ subversion/branches/invoke-diff-merge-feature/subversion/libsvn_subr/config_file.c Tue Nov  5 12:53:28 2013
@@ -469,6 +469,26 @@ svn_config__is_read_only(svn_config_t *c
   return cfg->read_only;
 }
 
+svn_config_t *
+svn_config__shallow_copy(svn_config_t *src,
+                         apr_pool_t *pool)
+{
+  svn_config_t *cfg = apr_palloc(pool, sizeof(*cfg));
+
+  cfg->sections = src->sections;
+  cfg->pool = pool;
+
+  /* r/o configs are fully expanded and don't need the x_pool anymore */
+  cfg->x_pool = src->read_only ? NULL : svn_pool_create(pool);
+  cfg->x_values = src->x_values;
+  cfg->tmp_key = svn_stringbuf_create_empty(pool);
+  cfg->tmp_value = svn_stringbuf_create_empty(pool);
+  cfg->section_names_case_sensitive = src->section_names_case_sensitive;
+  cfg->option_names_case_sensitive = src->option_names_case_sensitive;
+  cfg->read_only = src->read_only;
+
+  return cfg;
+}
 
 
 svn_error_t *

Modified: subversion/branches/invoke-diff-merge-feature/subversion/libsvn_subr/config_impl.h
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-merge-feature/subversion/libsvn_subr/config_impl.h?rev=1538976&r1=1538975&r2=1538976&view=diff
==============================================================================
--- subversion/branches/invoke-diff-merge-feature/subversion/libsvn_subr/config_impl.h (original)
+++ subversion/branches/invoke-diff-merge-feature/subversion/libsvn_subr/config_impl.h Tue Nov  5 12:53:28 2013
@@ -47,7 +47,8 @@ struct svn_config_t
   /* Table of cfg_section_t's. */
   apr_hash_t *sections;
 
-  /* Pool for hash tables, table entries and unexpanded values */
+  /* Pool for hash tables, table entries and unexpanded values.
+     Also, parent pool for temporary pools. */
   apr_pool_t *pool;
 
   /* Pool for expanded values -- this is separate, so that we can

Modified: subversion/branches/invoke-diff-merge-feature/subversion/libsvn_wc/conflicts.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-merge-feature/subversion/libsvn_wc/conflicts.c?rev=1538976&r1=1538975&r2=1538976&view=diff
==============================================================================
--- subversion/branches/invoke-diff-merge-feature/subversion/libsvn_wc/conflicts.c (original)
+++ subversion/branches/invoke-diff-merge-feature/subversion/libsvn_wc/conflicts.c Tue Nov  5 12:53:28 2013
@@ -2709,12 +2709,17 @@ resolve_prop_conflict_on_node(svn_boolea
  * existed and was resolved, set *DID_RESOLVE to TRUE, else set it to FALSE.
  *
  * It is not an error if there is no tree conflict.
+ *
+ * If the conflict can't be resolved yet because another tree conflict is
+ * blocking a storage location, store the tree conflict in the RESOLVE_LATER
+ * hash.
  */
 static svn_error_t *
 resolve_tree_conflict_on_node(svn_boolean_t *did_resolve,
                               svn_wc__db_t *db,
                               const char *local_abspath,
                               svn_wc_conflict_choice_t conflict_choice,
+                              apr_hash_t *resolve_later,
                               svn_wc_notify_func2_t notify_func,
                               void *notify_baton,
                               svn_cancel_func_t cancel_func,
@@ -2748,6 +2753,7 @@ resolve_tree_conflict_on_node(svn_boolea
   if (operation == svn_wc_operation_update
       || operation == svn_wc_operation_switch)
     {
+      svn_error_t *err;
       if (reason == svn_wc_conflict_reason_deleted ||
           reason == svn_wc_conflict_reason_replaced)
         {
@@ -2766,10 +2772,26 @@ resolve_tree_conflict_on_node(svn_boolea
                * this directory, and leave this directory deleted.
                * The newly conflicted moved-away children will be updated
                * if they are resolved with 'mine_conflict' as well. */
-              SVN_ERR(svn_wc__db_resolve_delete_raise_moved_away(
+              err = svn_wc__db_resolve_delete_raise_moved_away(
                         db, local_abspath, notify_func, notify_baton,
-                        scratch_pool));
-              *did_resolve = TRUE;
+                        scratch_pool);
+
+              if (err)
+                {
+                  const char *dup_abspath;
+                  if (err && err->apr_err != SVN_ERR_WC_OBSTRUCTED_UPDATE)
+                    return svn_error_trace(err);
+
+                  svn_error_clear(err);
+                  dup_abspath = apr_pstrdup(apr_hash_pool_get(resolve_later),
+                                            local_abspath);
+
+                  svn_hash_sets(resolve_later, dup_abspath, dup_abspath);
+
+                  return SVN_NO_ERROR; /* Retry after other conflicts */
+                }
+              else
+                *did_resolve = TRUE;
             }
           else
             return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE,
@@ -2789,12 +2811,28 @@ resolve_tree_conflict_on_node(svn_boolea
            * move (theirs-conflict). */
           if (conflict_choice == svn_wc_conflict_choose_mine_conflict)
             {
-              SVN_ERR(svn_wc__db_update_moved_away_conflict_victim(
+              err = svn_wc__db_update_moved_away_conflict_victim(
                         db, local_abspath,
                         notify_func, notify_baton,
                         cancel_func, cancel_baton,
-                        scratch_pool));
-              *did_resolve = TRUE;
+                        scratch_pool);
+
+              if (err)
+                {
+                  const char *dup_abspath;
+                  if (err && err->apr_err != SVN_ERR_WC_OBSTRUCTED_UPDATE)
+                    return svn_error_trace(err);
+
+                  svn_error_clear(err);
+                  dup_abspath = apr_pstrdup(apr_hash_pool_get(resolve_later),
+                                            local_abspath);
+
+                  svn_hash_sets(resolve_later, dup_abspath, dup_abspath);
+
+                  return SVN_NO_ERROR; /* Retry after other conflicts */
+                }
+              else
+                *did_resolve = TRUE;
             }
           else if (conflict_choice == svn_wc_conflict_choose_merged)
             {
@@ -2822,20 +2860,27 @@ resolve_tree_conflict_on_node(svn_boolea
         }
     }
 
-  if (! *did_resolve && conflict_choice != svn_wc_conflict_choose_merged)
+  if (! *did_resolve)
     {
-      /* For other tree conflicts, there is no way to pick
-       * theirs-full or mine-full, etc. Throw an error if the
-       * user expects us to be smarter than we really are. */
-      return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE,
-                               NULL,
-                               _("Tree conflict can only be "
-                                 "resolved to 'working' state; "
-                                 "'%s' not resolved"),
-                               svn_dirent_local_style(local_abspath,
-                                                      scratch_pool));
+      if (conflict_choice != svn_wc_conflict_choose_merged)
+        {
+          /* For other tree conflicts, there is no way to pick
+           * theirs-full or mine-full, etc. Throw an error if the
+           * user expects us to be smarter than we really are. */
+          return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE,
+                                   NULL,
+                                   _("Tree conflict can only be "
+                                     "resolved to 'working' state; "
+                                     "'%s' not resolved"),
+                                   svn_dirent_local_style(local_abspath,
+                                                          scratch_pool));
+        }
+      else
+        *did_resolve = TRUE;
     }
 
+  SVN_ERR_ASSERT(*did_resolve);
+
   SVN_ERR(svn_wc__db_op_mark_resolved(db, local_abspath, FALSE, FALSE, TRUE,
                                       NULL, scratch_pool));
   SVN_ERR(svn_wc__wq_run(db, local_abspath, cancel_func, cancel_baton,
@@ -2888,6 +2933,7 @@ struct conflict_status_walker_baton
   void *cancel_baton;
   svn_wc_notify_func2_t notify_func;
   void *notify_baton;
+  apr_hash_t *resolve_later;
 };
 
 /* Implements svn_wc_status4_t to walk all conflicts to resolve.
@@ -2957,13 +3003,15 @@ conflict_status_walker(void *baton,
                                                   db,
                                                   local_abspath,
                                                   my_choice,
+                                                  cswb->resolve_later,
                                                   cswb->notify_func,
                                                   cswb->notify_baton,
                                                   cswb->cancel_func,
                                                   cswb->cancel_baton,
                                                   iterpool));
 
-            resolved = TRUE;
+            if (did_resolve)
+              resolved = TRUE;
             break;
 
           case svn_wc_conflict_kind_text:
@@ -3045,6 +3093,8 @@ svn_wc__resolve_conflicts(svn_wc_context
   svn_node_kind_t kind;
   svn_boolean_t conflicted;
   struct conflict_status_walker_baton cswb;
+  apr_pool_t *iterpool = NULL;
+  svn_error_t *err;
 
   /* ### the underlying code does NOT support resolving individual
      ### properties. bail out if the caller tries it.  */
@@ -3084,6 +3134,8 @@ svn_wc__resolve_conflicts(svn_wc_context
   cswb.notify_func = notify_func;
   cswb.notify_baton = notify_baton;
 
+  cswb.resolve_later = apr_hash_make(scratch_pool);
+
   if (notify_func)
     notify_func(notify_baton,
                 svn_wc_create_notify(local_abspath,
@@ -3091,16 +3143,66 @@ svn_wc__resolve_conflicts(svn_wc_context
                                     scratch_pool),
                 scratch_pool);
 
-  SVN_ERR(svn_wc_walk_status(wc_ctx,
-                             local_abspath,
-                             depth,
-                             FALSE /* get_all */,
-                             FALSE /* no_ignore */,
-                             TRUE /* ignore_text_mods */,
-                             NULL /* ignore_patterns */,
-                             conflict_status_walker, &cswb,
-                             cancel_func, cancel_baton,
-                             scratch_pool));
+  err = svn_wc_walk_status(wc_ctx,
+                           local_abspath,
+                           depth,
+                           FALSE /* get_all */,
+                           FALSE /* no_ignore */,
+                           TRUE /* ignore_text_mods */,
+                           NULL /* ignore_patterns */,
+                           conflict_status_walker, &cswb,
+                           cancel_func, cancel_baton,
+                           scratch_pool);
+
+  while (!err && apr_hash_count(cswb.resolve_later))
+    {
+      apr_hash_index_t *hi;
+      svn_boolean_t cleared_one = FALSE;
+      const char *tc_abspath = NULL;
+
+      if (iterpool)
+        svn_pool_clear(iterpool);
+      else
+        iterpool = svn_pool_create(scratch_pool);
+
+      for (hi = apr_hash_first(scratch_pool, cswb.resolve_later);
+          hi && !err;
+          hi = apr_hash_next(hi))
+        {
+          tc_abspath = svn__apr_hash_index_key(hi);
+          svn_pool_clear(iterpool);
+
+          svn_hash_sets(cswb.resolve_later, tc_abspath, NULL);
+
+          err = svn_wc_walk_status(wc_ctx, tc_abspath, depth, FALSE, FALSE,
+                                   TRUE, NULL, conflict_status_walker, &cswb,
+                                   cancel_func, cancel_baton,
+                                   iterpool);
+
+          if (!err && !svn_hash_gets(cswb.resolve_later, tc_abspath))
+            cleared_one = TRUE;
+        }
+
+      if (!cleared_one && !err)
+        {
+          /* Return the error on one of the paths: The last one. */
+          err = svn_error_createf(
+                    SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL,
+                    _("Unable to resolve pending conflict on '%s'"),
+                    svn_dirent_local_style(tc_abspath, scratch_pool));
+        }
+    }
+
+  if (iterpool)
+    svn_pool_destroy(iterpool);
+
+  if (err && err->apr_err != SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE)
+    err = svn_error_createf(
+                SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, err,
+                _("Unable to resolve conflicts on '%s'"),
+                svn_dirent_local_style(local_abspath, scratch_pool));
+
+  SVN_ERR(err);
 
   if (notify_func)
     notify_func(notify_baton,

Modified: subversion/branches/invoke-diff-merge-feature/subversion/libsvn_wc/diff.h
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-merge-feature/subversion/libsvn_wc/diff.h?rev=1538976&r1=1538975&r2=1538976&view=diff
==============================================================================
--- subversion/branches/invoke-diff-merge-feature/subversion/libsvn_wc/diff.h (original)
+++ subversion/branches/invoke-diff-merge-feature/subversion/libsvn_wc/diff.h Tue Nov  5 12:53:28 2013
@@ -38,7 +38,9 @@
 extern "C" {
 #endif /* __cplusplus */
 
-/* Reports the file LOCAL_ABSPATH as ADDED file with relpath RELPATH to
+/* A function to diff locally added and locally copied files.
+  
+   Reports the file LOCAL_ABSPATH as ADDED file with relpath RELPATH to
    PROCESSOR with as parent baton PROCESSOR_PARENT_BATON.
 
    The node is expected to have status svn_wc__db_status_normal, or
@@ -61,7 +63,9 @@ svn_wc__diff_local_only_file(svn_wc__db_
                              void *cancel_baton,
                              apr_pool_t *scratch_pool);
 
-/* Reports the directory LOCAL_ABSPATH and everything below it (limited by
+/* A function to diff locally added and locally copied directories.
+  
+   Reports the directory LOCAL_ABSPATH and everything below it (limited by
    DEPTH) as added with relpath RELPATH to PROCESSOR with as parent baton
    PROCESSOR_PARENT_BATON.
 

Modified: subversion/branches/invoke-diff-merge-feature/subversion/libsvn_wc/diff_local.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-merge-feature/subversion/libsvn_wc/diff_local.c?rev=1538976&r1=1538975&r2=1538976&view=diff
==============================================================================
--- subversion/branches/invoke-diff-merge-feature/subversion/libsvn_wc/diff_local.c (original)
+++ subversion/branches/invoke-diff-merge-feature/subversion/libsvn_wc/diff_local.c Tue Nov  5 12:53:28 2013
@@ -390,7 +390,7 @@ diff_status_callback(void *baton,
           }
       }
 
-    if (local_only)
+    if (local_only && (db_status != svn_wc__db_status_deleted))
       {
         if (db_kind == svn_node_file)
           SVN_ERR(svn_wc__diff_local_only_file(db, child_abspath,

Modified: subversion/branches/invoke-diff-merge-feature/subversion/libsvn_wc/upgrade.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-merge-feature/subversion/libsvn_wc/upgrade.c?rev=1538976&r1=1538975&r2=1538976&view=diff
==============================================================================
--- subversion/branches/invoke-diff-merge-feature/subversion/libsvn_wc/upgrade.c (original)
+++ subversion/branches/invoke-diff-merge-feature/subversion/libsvn_wc/upgrade.c Tue Nov  5 12:53:28 2013
@@ -755,13 +755,13 @@ migrate_single_tree_conflict_data(svn_sq
         {
           /* There is an existing ACTUAL row, so just update it. */
           SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
-                                            STMT_UPDATE_ACTUAL_CONFLICT_DATA));
+                                            STMT_UPDATE_ACTUAL_CONFLICT));
         }
       else
         {
           /* We need to insert an ACTUAL row with the tree conflict data. */
           SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
-                                            STMT_INSERT_ACTUAL_CONFLICT_DATA));
+                                            STMT_INSERT_ACTUAL_CONFLICT));
         }
 
       SVN_ERR(svn_sqlite__bindf(stmt, "iss", wc_id, conflict_relpath,

Modified: subversion/branches/invoke-diff-merge-feature/subversion/libsvn_wc/wc-queries.sql
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-merge-feature/subversion/libsvn_wc/wc-queries.sql?rev=1538976&r1=1538975&r2=1538976&view=diff
==============================================================================
--- subversion/branches/invoke-diff-merge-feature/subversion/libsvn_wc/wc-queries.sql (original)
+++ subversion/branches/invoke-diff-merge-feature/subversion/libsvn_wc/wc-queries.sql Tue Nov  5 12:53:28 2013
@@ -198,7 +198,7 @@ WHERE wc_id = ?1
 -- STMT_DELETE_NODE
 DELETE
 FROM NODES
-WHERE wc_id = ?1 AND local_relpath = ?2
+WHERE wc_id = ?1 AND local_relpath = ?2 AND op_depth = ?3
 
 -- STMT_DELETE_ACTUAL_FOR_BASE_RECURSIVE
 /* The ACTUAL_NODE applies to BASE, unless there is in at least one op_depth
@@ -468,13 +468,6 @@ WHERE u.wc_id = ?1
   AND IS_STRICT_DESCENDANT_OF(u.local_relpath, ?2)
   AND u.op_depth = ?4
 
--- STMT_DELETE_MOVED_BACK
-DELETE FROM nodes
-WHERE wc_id = ?1
-  AND (local_relpath = ?2
-       OR IS_STRICT_DESCENDANT_OF(local_relpath, ?2))
-  AND op_depth = ?3
-
 -- STMT_DELETE_LOCK
 DELETE FROM lock
 WHERE repos_id = ?1 AND repos_relpath = ?2
@@ -718,7 +711,7 @@ WHERE wc_id = ?1 AND local_relpath = ?2
                   WHERE wc_id = ?1 AND local_relpath = ?2 AND op_depth > ?3)
   AND presence = MAP_BASE_DELETED
 
--- STMT_DELETE_ALL_LAYERS
+-- STMT_DELETE_NODE_ALL_LAYERS
 DELETE FROM nodes
 WHERE wc_id = ?1 AND local_relpath = ?2
 
@@ -1214,14 +1207,6 @@ VALUES (?1, ?2, ?3, ?4, ?5, ?6)
 
 /* these are used in upgrade.c  */
 
--- STMT_UPDATE_ACTUAL_CONFLICT_DATA
-UPDATE actual_node SET conflict_data = ?3
-WHERE wc_id = ?1 AND local_relpath = ?2
-
--- STMT_INSERT_ACTUAL_CONFLICT_DATA
-INSERT INTO actual_node (wc_id, local_relpath, conflict_data, parent_relpath)
-VALUES (?1, ?2, ?3, ?4)
-
 -- STMT_SELECT_ALL_FILES
 SELECT local_relpath FROM nodes_current
 WHERE wc_id = ?1 AND parent_relpath = ?2 AND kind = MAP_FILE
@@ -1574,20 +1559,6 @@ UPDATE nodes SET moved_to = NULL
  WHERE wc_id = ?1
    AND IS_STRICT_DESCENDANT_OF(moved_to, ?2)
 
-
-/* This statement returns pairs of move-roots below the path ?2 in WC_ID ?1,
- * where the source of the move is within the subtree rooted at path ?2, and
- * the destination of the move is outside the subtree rooted at path ?2. */
--- STMT_SELECT_MOVED_PAIR2
-SELECT local_relpath, moved_to, op_depth FROM nodes
-WHERE wc_id = ?1
-  AND (local_relpath = ?2 OR IS_STRICT_DESCENDANT_OF(local_relpath, ?2))
-  AND moved_to IS NOT NULL
-  AND NOT IS_STRICT_DESCENDANT_OF(moved_to, ?2)
-  AND op_depth >= (SELECT MAX(op_depth) FROM nodes o
-                    WHERE o.wc_id = ?1
-                      AND o.local_relpath = ?2)
-
 -- STMT_SELECT_MOVED_PAIR3
 SELECT local_relpath, moved_to, op_depth, kind FROM nodes
 WHERE wc_id = ?1
@@ -1604,12 +1575,17 @@ WHERE wc_id = ?1
   AND NOT IS_STRICT_DESCENDANT_OF(moved_to, ?2)
 
 -- STMT_SELECT_OP_DEPTH_MOVED_PAIR
-SELECT n.local_relpath, n.moved_to,
-       (SELECT o.repos_path FROM nodes AS o
-        WHERE o.wc_id = n.wc_id
-          AND o.local_relpath = n.local_relpath
-          AND o.op_depth < ?3 ORDER BY o.op_depth DESC LIMIT 1)
+SELECT n.local_relpath, p.kind, n.moved_to, p.repos_path
 FROM nodes AS n
+JOIN (SELECT local_relpath, kind, repos_path
+      FROM nodes AS o
+        WHERE o.wc_id = ?1
+          AND o.op_depth=(SELECT MAX(d.op_depth)
+                          FROM nodes AS d
+                          WHERE d.wc_id = ?1
+                            AND d.local_relpath = o.local_relpath
+                            AND d.op_depth < ?3)) AS p
+  ON n.local_relpath = p.local_relpath
 WHERE n.wc_id = ?1
   AND IS_STRICT_DESCENDANT_OF(n.local_relpath, ?2)
   AND n.op_depth = ?3

Modified: subversion/branches/invoke-diff-merge-feature/subversion/libsvn_wc/wc_db.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-merge-feature/subversion/libsvn_wc/wc_db.c?rev=1538976&r1=1538975&r2=1538976&view=diff
==============================================================================
--- subversion/branches/invoke-diff-merge-feature/subversion/libsvn_wc/wc_db.c (original)
+++ subversion/branches/invoke-diff-merge-feature/subversion/libsvn_wc/wc_db.c Tue Nov  5 12:53:28 2013
@@ -627,6 +627,10 @@ svn_wc__db_extend_parent_delete(svn_wc__
    When removing a node if the parent has a higher working node then
    the parent node and this node are both deleted or replaced and any
    delete over this node must be removed.
+
+   This function (like most wcroot functions) assumes that its caller
+   only uses this function within an sqlite transaction if atomic
+   behavior is needed.
  */
 svn_error_t *
 svn_wc__db_retract_parent_delete(svn_wc__db_wcroot_t *wcroot,
@@ -635,14 +639,60 @@ svn_wc__db_retract_parent_delete(svn_wc_
                                  apr_pool_t *scratch_pool)
 {
   svn_sqlite__stmt_t *stmt;
+  svn_boolean_t have_row;
+  int working_depth;
+  svn_wc__db_status_t presence;
+  const char *moved_to;
 
   SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
-                                    STMT_DELETE_LOWEST_WORKING_NODE));
+                                    STMT_SELECT_LOWEST_WORKING_NODE));
   SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
                             op_depth));
-  SVN_ERR(svn_sqlite__step_done(stmt));
+  SVN_ERR(svn_sqlite__step(&have_row, stmt));
 
-  return SVN_NO_ERROR;
+  if (!have_row)
+    return svn_error_trace(svn_sqlite__reset(stmt));
+
+  working_depth = svn_sqlite__column_int(stmt, 0);
+  presence = svn_sqlite__column_token(stmt, 1, presence_map);
+  moved_to = svn_sqlite__column_text(stmt, 3, scratch_pool);
+
+  SVN_ERR(svn_sqlite__reset(stmt));
+
+  if (moved_to)
+    {
+      /* Turn the move into a copy to keep the NODES table valid */
+      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+                                        STMT_CLEAR_MOVED_HERE_RECURSIVE));
+      SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id,
+                                moved_to, relpath_depth(moved_to)));
+      SVN_ERR(svn_sqlite__step_done(stmt));
+
+      /* This leaves just the moved_to information on the origin,
+         which we will remove in the next step */
+    }
+
+  if (presence == svn_wc__db_status_base_deleted)
+    {
+      /* Nothing left to shadow; remove the base-deleted node */
+      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_DELETE_NODE));
+    }
+  else if (moved_to)
+    {
+      /* Clear moved to information, as this node is no longer base-deleted */
+      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+                                        STMT_CLEAR_MOVED_TO_RELPATH));
+      }
+  else
+    {
+      /* Nothing to update */
+      return SVN_NO_ERROR;
+    }
+
+  SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
+                            working_depth));
+
+  return svn_error_trace(svn_sqlite__update(NULL, stmt));
 }
 
 
@@ -4843,7 +4893,7 @@ handle_move_back(svn_boolean_t *moved_ba
              generally these values should be the same anyway as it was
              a no-op move. */
       SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
-                                        STMT_DELETE_MOVED_BACK));
+                                        STMT_DELETE_WORKING_OP_DEPTH));
 
       SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id,
                                              local_relpath,
@@ -6322,36 +6372,36 @@ svn_wc__db_op_mark_resolved(svn_wc__db_t
   return SVN_NO_ERROR;
 }
 
-/* Clear moved-to information at the delete-half of the move which
- * moved LOCAL_RELPATH here. This transforms the move into a simple delete. */
+/* Clear moved-to information at the delete-half of the move which moved
+ * MOVED_TO_RELPATH here. This transforms the delete part of the move into a
+ * normal delete.
+ *
+ * Note that the moved-to location is always an op-root, while this is not the
+ * case for a moved-from location.
+ */
 static svn_error_t *
-clear_moved_to(const char *local_relpath,
-               svn_wc__db_wcroot_t *wcroot,
+clear_moved_to(svn_wc__db_wcroot_t *wcroot,
+               const char *moved_to_relpath,
                apr_pool_t *scratch_pool)
 {
   svn_sqlite__stmt_t *stmt;
-  svn_boolean_t have_row;
   const char *moved_from_relpath;
+  int moved_from_op_depth;
 
   SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
                                     STMT_SELECT_MOVED_FROM_RELPATH));
-  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
-  SVN_ERR(svn_sqlite__step(&have_row, stmt));
-  if (!have_row)
-    {
-      SVN_ERR(svn_sqlite__reset(stmt));
-      return SVN_NO_ERROR;
-    }
+  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, moved_to_relpath));
+  SVN_ERR(svn_sqlite__step_row(stmt));
 
   moved_from_relpath = svn_sqlite__column_text(stmt, 0, scratch_pool);
+  moved_from_op_depth = svn_sqlite__column_int(stmt, 1);
   SVN_ERR(svn_sqlite__reset(stmt));
 
   SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
                                     STMT_CLEAR_MOVED_TO_RELPATH));
   SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id,
-                            moved_from_relpath,
-                            relpath_depth(moved_from_relpath)));
-  SVN_ERR(svn_sqlite__step_done(stmt));
+                            moved_from_relpath, moved_from_op_depth));
+  SVN_ERR(svn_sqlite__update(NULL, stmt));
 
   return SVN_NO_ERROR;
 }
@@ -6507,7 +6557,7 @@ op_revert_txn(void *baton,
 
       /* If this node was moved-here, clear moved-to at the move source. */
       if (moved_here)
-        SVN_ERR(clear_moved_to(local_relpath, wcroot, scratch_pool));
+        SVN_ERR(clear_moved_to(wcroot, local_relpath, scratch_pool));
     }
 
   SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
@@ -6650,7 +6700,7 @@ op_revert_recursive_txn(void *baton,
       svn_pool_clear(iterpool);
 
       moved_here_child_relpath = svn_sqlite__column_text(stmt, 0, iterpool);
-      err = clear_moved_to(moved_here_child_relpath, wcroot, iterpool);
+      err = clear_moved_to(wcroot, moved_here_child_relpath, iterpool);
       if (err)
         return svn_error_trace(svn_error_compose_create(
                                         err,
@@ -6664,7 +6714,7 @@ op_revert_recursive_txn(void *baton,
   /* Clear potential moved-to pointing at the target node itself. */
   if (op_depth > 0 && op_depth == relpath_depth(local_relpath)
       && moved_here)
-    SVN_ERR(clear_moved_to(local_relpath, wcroot, scratch_pool));
+    SVN_ERR(clear_moved_to(wcroot, local_relpath, scratch_pool));
 
   return SVN_NO_ERROR;
 }
@@ -7180,7 +7230,7 @@ remove_node_txn(svn_boolean_t *left_chan
   if (local_relpath[0] != '\0')
     {
       SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
-                                        STMT_DELETE_NODE));
+                                        STMT_DELETE_NODE_ALL_LAYERS));
       SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
       SVN_ERR(svn_sqlite__step_done(stmt));
     }
@@ -10878,7 +10928,7 @@ commit_node(svn_wc__db_wcroot_t *wcroot,
          if we need to remove shadowed layers below our descendants. */
 
       SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
-                                        STMT_DELETE_ALL_LAYERS));
+                                        STMT_DELETE_NODE_ALL_LAYERS));
       SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
       SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
 

Modified: subversion/branches/invoke-diff-merge-feature/subversion/libsvn_wc/wc_db_update_move.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-merge-feature/subversion/libsvn_wc/wc_db_update_move.c?rev=1538976&r1=1538975&r2=1538976&view=diff
==============================================================================
--- subversion/branches/invoke-diff-merge-feature/subversion/libsvn_wc/wc_db_update_move.c (original)
+++ subversion/branches/invoke-diff-merge-feature/subversion/libsvn_wc/wc_db_update_move.c Tue Nov  5 12:53:28 2013
@@ -251,11 +251,14 @@ mark_tree_conflict(const char *local_rel
     : NULL;
 
   if (!new_repos_relpath)
-    new_repos_relpath
-      = svn_relpath_join(new_version->path_in_repos,
-                         svn_relpath_skip_ancestor(move_root_dst_relpath,
-                                                   local_relpath),
-                         scratch_pool);
+    {
+      const char *child_relpath = svn_relpath_skip_ancestor(
+                                            move_root_dst_relpath,
+                                            local_relpath);
+      SVN_ERR_ASSERT(child_relpath != NULL);
+      new_repos_relpath = svn_relpath_join(new_version->path_in_repos,
+                                           child_relpath, scratch_pool);
+    }
 
   err = svn_wc__db_read_conflict_internal(&conflict, wcroot, local_relpath,
                                           scratch_pool, scratch_pool);
@@ -303,7 +306,7 @@ mark_tree_conflict(const char *local_rel
                   && strcmp(move_src_op_root_relpath,
                             svn_dirent_skip_ancestor(wcroot->abspath,
                                                      existing_abspath))))
-            return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL,
+            return svn_error_createf(SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL,
                                      _("'%s' already in conflict"),
                                      svn_dirent_local_style(local_relpath,
                                                             scratch_pool));
@@ -835,6 +838,7 @@ tc_editor_alter_directory(void *baton,
       apr_hash_t *actual_props;
       apr_array_header_t *propchanges;
 
+      /* ### TODO: Only do this when there is no higher WORKING layer */
       SVN_ERR(update_working_props(&prop_state, &conflict_skel,
                                    &propchanges, &actual_props,
                                    b->db, dst_abspath,
@@ -905,6 +909,7 @@ update_working_file(const char *local_re
   svn_wc_notify_state_t prop_state, content_state;
   svn_skel_t *work_item, *work_items = NULL;
 
+  /* ### TODO: Only do this when there is no higher WORKING layer */
   SVN_ERR(update_working_props(&prop_state, &conflict_skel, &propchanges,
                                &actual_props, db, local_abspath,
                                old_version, new_version,
@@ -1407,9 +1412,9 @@ get_tc_info(svn_wc_operation_t *operatio
 
 /* Return *PROPS, *CHECKSUM, *CHILDREN and *KIND for LOCAL_RELPATH at
    OP_DEPTH provided the row exists.  Return *KIND of svn_node_none if
-   the row does not exist. *CHILDREN is a sorted array of basenames of
-   type 'const char *', rather than a hash, to allow the driver to
-   process children in a defined order. */
+   the row does not exist, or only describes a delete of a lower op-depth.
+   *CHILDREN is a sorted array of basenames of type 'const char *', rather
+   than a hash, to allow the driver to process children in a defined order. */
 static svn_error_t *
 get_info(apr_hash_t **props,
          const svn_checksum_t **checksum,
@@ -1424,16 +1429,36 @@ get_info(apr_hash_t **props,
   apr_hash_t *hash_children;
   apr_array_header_t *sorted_children;
   svn_error_t *err;
+  svn_wc__db_status_t status;
+  const char *repos_relpath;
   int i;
 
-  err = svn_wc__db_depth_get_info(NULL, kind, NULL, NULL, NULL, NULL, NULL,
-                                  NULL, NULL, checksum, NULL, NULL, props,
+  err = svn_wc__db_depth_get_info(&status, kind, NULL, &repos_relpath, NULL,
+                                  NULL, NULL, NULL, NULL, checksum, NULL,
+                                  NULL, props,
                                   wcroot, local_relpath, op_depth,
                                   result_pool, scratch_pool);
-  if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
+
+  /* If there is no node at this depth, or only a node that describes a delete
+     of a lower layer we report this node as not existing.
+
+     But when a node is reported as DELETED, but has a repository location it
+     is really a not-present node that must be reported as being there */
+  if ((err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
+      || (!err && status == svn_wc__db_status_deleted))
     {
       svn_error_clear(err);
-      *kind = svn_node_none;
+
+      if (kind && (err || !repos_relpath))
+        *kind = svn_node_none;
+      if (checksum)
+        *checksum = NULL;
+      if (props)
+        *props = NULL;
+      if (children)
+        *children = apr_array_make(result_pool, 0, sizeof(const char *));
+
+      return SVN_NO_ERROR;
     }
   else
     SVN_ERR(err);
@@ -2324,7 +2349,6 @@ resolve_delete_raise_moved_away(svn_wc__
 {
   svn_sqlite__stmt_t *stmt;
   svn_boolean_t have_row;
-  int op_depth = relpath_depth(local_relpath);
   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
 
   SVN_ERR(svn_sqlite__exec_statements(wcroot->sdb,
@@ -2333,26 +2357,31 @@ resolve_delete_raise_moved_away(svn_wc__
   SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
                                     STMT_SELECT_OP_DEPTH_MOVED_PAIR));
   SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
-                            op_depth));
+                            relpath_depth(local_relpath)));
   SVN_ERR(svn_sqlite__step(&have_row, stmt));
   while(have_row)
     {
-      const char *moved_relpath = svn_sqlite__column_text(stmt, 0, NULL);
-      const char *move_root_dst_relpath = svn_sqlite__column_text(stmt, 1,
-                                                                  NULL);
-      const char *moved_dst_repos_relpath = svn_sqlite__column_text(stmt, 2,
-                                                                    NULL);
+      svn_error_t *err;
+      const char *src_relpath = svn_sqlite__column_text(stmt, 0, NULL);
+      svn_node_kind_t src_kind = svn_sqlite__column_token(stmt, 1, kind_map);
+      const char *dst_relpath = svn_sqlite__column_text(stmt, 2, NULL);
+      const char *src_repos_relpath = svn_sqlite__column_text(stmt, 3, NULL);
       svn_pool_clear(iterpool);
 
-      SVN_ERR(mark_tree_conflict(moved_relpath,
-                                 wcroot, db, old_version, new_version,
-                                 move_root_dst_relpath, operation,
-                                 svn_node_dir /* ### ? */,
-                                 svn_node_dir /* ### ? */,
-                                 moved_dst_repos_relpath,
-                                 svn_wc_conflict_reason_moved_away,
-                                 action, local_relpath,
-                                 iterpool));
+      SVN_ERR_ASSERT(src_repos_relpath != NULL);
+
+      err = mark_tree_conflict(src_relpath,
+                               wcroot, db, old_version, new_version,
+                               dst_relpath, operation,
+                               src_kind /* ### old kind */,
+                               src_kind /* ### new kind */,
+                               src_repos_relpath,
+                               svn_wc_conflict_reason_moved_away,
+                               action, local_relpath,
+                               iterpool);
+
+      if (err)
+        return svn_error_compose_create(err, svn_sqlite__reset(stmt));
 
       SVN_ERR(svn_sqlite__step(&have_row, stmt));
     }
@@ -2411,7 +2440,6 @@ break_move(svn_wc__db_wcroot_t *wcroot,
            const char *src_relpath,
            int src_op_depth,
            const char *dst_relpath,
-           int dst_op_depth,
            apr_pool_t *scratch_pool)
 {
   svn_sqlite__stmt_t *stmt;
@@ -2422,11 +2450,12 @@ break_move(svn_wc__db_wcroot_t *wcroot,
                             src_op_depth));
   SVN_ERR(svn_sqlite__step_done(stmt));
 
-  /* This statement clears moved_here. */
+  /* The destination is always an op-root, so we can calculate the depth
+     from there. */
   SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
-                                    STMT_UPDATE_OP_DEPTH_RECURSIVE));
-  SVN_ERR(svn_sqlite__bindf(stmt, "isdd", wcroot->wc_id,
-                            dst_relpath, dst_op_depth, dst_op_depth));
+                                    STMT_CLEAR_MOVED_HERE_RECURSIVE));
+  SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id,
+                            dst_relpath, relpath_depth(dst_relpath)));
   SVN_ERR(svn_sqlite__step_done(stmt));
 
   return SVN_NO_ERROR;
@@ -2455,7 +2484,6 @@ svn_wc__db_resolve_break_moved_away_inte
   SVN_ERR(break_move(wcroot, local_relpath,
                      relpath_depth(move_src_op_root_relpath),
                      move_dst_op_root_relpath,
-                     relpath_depth(move_dst_op_root_relpath),
                      scratch_pool));
 
   return SVN_NO_ERROR;
@@ -2474,8 +2502,9 @@ break_moved_away_children_internal(svn_w
                                       STMT_CREATE_UPDATE_MOVE_LIST));
 
   SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
-                                    STMT_SELECT_MOVED_PAIR2));
-  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
+                                    STMT_SELECT_MOVED_DESCENDANTS));
+  SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
+                            relpath_depth(local_relpath)));
   SVN_ERR(svn_sqlite__step(&have_row, stmt));
 
   iterpool = svn_pool_create(scratch_pool);
@@ -2488,7 +2517,7 @@ break_moved_away_children_internal(svn_w
       svn_pool_clear(iterpool);
 
       SVN_ERR(break_move(wcroot, src_relpath, src_op_depth, dst_relpath,
-                         relpath_depth(dst_relpath), iterpool));
+                         iterpool));
       SVN_ERR(update_move_list_add(wcroot, src_relpath,
                                    svn_wc_notify_move_broken,
                                    svn_node_unknown,

Modified: subversion/branches/invoke-diff-merge-feature/subversion/tests/cmdline/diff_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-merge-feature/subversion/tests/cmdline/diff_tests.py?rev=1538976&r1=1538975&r2=1538976&view=diff
==============================================================================
--- subversion/branches/invoke-diff-merge-feature/subversion/tests/cmdline/diff_tests.py (original)
+++ subversion/branches/invoke-diff-merge-feature/subversion/tests/cmdline/diff_tests.py Tue Nov  5 12:53:28 2013
@@ -4696,6 +4696,26 @@ def diff_local_missing_obstruction(sbox)
                                      'diff', wc_dir)
 
 
+@Issue(4444)
+def diff_move_inside_copy(sbox):
+  "diff copied-along child that contains a moved file"
+  sbox.build(read_only=True)
+  wc_dir = sbox.wc_dir
+
+  d_path = 'A/D'
+  d_copy = 'A/D-copy'
+  h_path = 'A/D-copy/H'
+  chi_path = '%s/chi' % h_path
+  chi_moved = '%s/chi-moved' % h_path
+
+  sbox.simple_copy(d_path, d_copy)
+  sbox.simple_move(chi_path, chi_moved)
+  sbox.simple_append(chi_moved, 'a new line')
+
+  # Bug: Diffing the copied-along parent directory asserts
+  svntest.actions.run_and_verify_svn(None, svntest.verify.AnyOutput, [],
+                                     'diff', sbox.ospath(h_path))
+
 ########################################################################
 #Run the tests
 
@@ -4778,6 +4798,7 @@ test_list = [ None,
               diff_repos_empty_file_addition,
               diff_missing_tree_conflict_victim,
               diff_local_missing_obstruction,
+              diff_move_inside_copy,
               ]
 
 if __name__ == '__main__':

Modified: subversion/branches/invoke-diff-merge-feature/subversion/tests/libsvn_repos/repos-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-merge-feature/subversion/tests/libsvn_repos/repos-test.c?rev=1538976&r1=1538975&r2=1538976&view=diff
==============================================================================
--- subversion/branches/invoke-diff-merge-feature/subversion/tests/libsvn_repos/repos-test.c (original)
+++ subversion/branches/invoke-diff-merge-feature/subversion/tests/libsvn_repos/repos-test.c Tue Nov  5 12:53:28 2013
@@ -39,6 +39,9 @@
 #include "svn_version.h"
 #include "private/svn_repos_private.h"
 
+/* be able to look into svn_config_t */
+#include "../../libsvn_subr/config_impl.h"
+
 #include "../svn_test_fs.h"
 
 #include "dir-delta-editor.h"
@@ -3311,7 +3314,8 @@ test_config_pool(const svn_test_opts_t *
   const char *repo_name = "test-repo-config-pool";
   svn_repos_t *repos;
   svn_stringbuf_t *cfg_buffer1, *cfg_buffer2;
-  svn_config_t *cfg, *cfg1, *cfg2;
+  svn_config_t *cfg;
+  apr_hash_t *sections1, *sections2;
   int i;
   svn_boolean_t bvalue;
   svn_fs_txn_t *txn;
@@ -3367,7 +3371,7 @@ test_config_pool(const svn_test_opts_t *
 
   /* requesting a config over and over again should return the same
      (even though it is not being referenced) */
-  cfg1 = NULL;
+  sections1 = NULL;
   for (i = 0; i < 4; ++i)
     {
       SVN_ERR(svn_repos__config_pool_get(
@@ -3375,12 +3379,12 @@ test_config_pool(const svn_test_opts_t *
                                     svn_dirent_join(wrk_dir,
                                                     "config-pool-test1.cfg",
                                                     pool),
-                                    subpool));
+                                    TRUE, TRUE, NULL, subpool));
 
-      if (cfg1 == NULL)
-        cfg1 = cfg;
+      if (sections1 == NULL)
+        sections1 = cfg->sections;
       else
-        SVN_TEST_ASSERT(cfg == cfg1);
+        SVN_TEST_ASSERT(cfg->sections == sections1);
 
       svn_pool_clear(subpool);
     }
@@ -3394,15 +3398,15 @@ test_config_pool(const svn_test_opts_t *
                                     svn_dirent_join(wrk_dir,
                                                     "config-pool-test2.cfg",
                                                     pool),
-                                    subpool));
+                                    TRUE, TRUE, NULL, subpool));
 
-      SVN_TEST_ASSERT(cfg == cfg1);
+      SVN_TEST_ASSERT(cfg->sections == sections1);
 
       svn_pool_clear(subpool);
     }
 
   /* reading a different configuration should return a different pointer */
-  cfg2 = NULL;
+  sections2 = NULL;
   for (i = 0; i < 2; ++i)
     {
       SVN_ERR(svn_repos__config_pool_get(
@@ -3410,14 +3414,14 @@ test_config_pool(const svn_test_opts_t *
                                     svn_dirent_join(wrk_dir,
                                                     "config-pool-test3.cfg",
                                                     pool),
-                                    subpool));
+                                    TRUE, TRUE, NULL, subpool));
 
-      if (cfg2 == NULL)
-        cfg2 = cfg;
+      if (sections2 == NULL)
+        sections2 = cfg->sections;
       else
-        SVN_TEST_ASSERT(cfg == cfg2);
+        SVN_TEST_ASSERT(cfg->sections == sections2);
 
-      SVN_TEST_ASSERT(cfg1 != cfg2);
+      SVN_TEST_ASSERT(sections1 != sections2);
       svn_pool_clear(subpool);
     }
 
@@ -3440,8 +3444,8 @@ test_config_pool(const svn_test_opts_t *
                                      svn_path_url_add_component2(
                                                     repo_root_url,
                                                     "dir/config", pool),
-                                     subpool));
-  SVN_TEST_ASSERT(cfg == cfg1);
+                                     TRUE, TRUE, NULL, subpool));
+  SVN_TEST_ASSERT(cfg->sections == sections1);
   svn_pool_clear(subpool);
 
   /* create another in-repo config */
@@ -3458,8 +3462,8 @@ test_config_pool(const svn_test_opts_t *
                                      svn_path_url_add_component2(
                                                     repo_root_url,
                                                     "dir/config", pool),
-                                     subpool));
-  SVN_TEST_ASSERT(cfg == cfg2);
+                                     TRUE, TRUE, NULL, subpool));
+  SVN_TEST_ASSERT(cfg->sections == sections2);
   svn_pool_clear(subpool);
 
   /* reading the copied config should still give cfg1 */
@@ -3468,8 +3472,8 @@ test_config_pool(const svn_test_opts_t *
                                                     repo_root_url,
                                                     "another-dir/config",
                                                     pool),
-                                     subpool));
-  SVN_TEST_ASSERT(cfg == cfg1);
+                                     TRUE, TRUE, NULL, subpool));
+  SVN_TEST_ASSERT(cfg->sections == sections1);
   svn_pool_clear(subpool);
 
   /* once again: repeated reads.  This triggers a different code path. */
@@ -3477,46 +3481,67 @@ test_config_pool(const svn_test_opts_t *
                                      svn_path_url_add_component2(
                                                     repo_root_url,
                                                     "dir/config", pool),
-                                     subpool));
-  SVN_TEST_ASSERT(cfg == cfg2);
+                                     TRUE, TRUE, NULL, subpool));
+  SVN_TEST_ASSERT(cfg->sections == sections2);
   SVN_ERR(svn_repos__config_pool_get(&cfg, config_pool,
                                      svn_path_url_add_component2(
                                                     repo_root_url,
                                                     "another-dir/config",
                                                     pool),
-                                     subpool));
-  SVN_TEST_ASSERT(cfg == cfg1);
+                                     TRUE, TRUE, NULL, subpool));
+  SVN_TEST_ASSERT(cfg->sections == sections1);
   svn_pool_clear(subpool);
 
   /* access paths that don't exist */
   SVN_TEST_ASSERT_ERROR(svn_repos__config_pool_get(&cfg, config_pool,
                           svn_path_url_add_component2(repo_root_url, "X",
                                                       pool),
-                          subpool),
+                          TRUE, TRUE, NULL, subpool),
                         SVN_ERR_ILLEGAL_TARGET);
-  err = svn_repos__config_pool_get(&cfg, config_pool, "X.cfg", subpool);
+  err = svn_repos__config_pool_get(&cfg, config_pool, "X.cfg", TRUE, TRUE,
+                                   NULL, subpool);
   SVN_TEST_ASSERT(err && APR_STATUS_IS_ENOENT(err->apr_err));
   svn_error_clear(err);
   svn_pool_clear(subpool);
 
   /* as long as we keep a reference to a config, clearing the config pool
      should not invalidate that reference */
-  SVN_ERR(svn_repos__config_pool_get(&cfg1, config_pool,
+  SVN_ERR(svn_repos__config_pool_get(&cfg, config_pool,
                                      svn_dirent_join(wrk_dir,
                                                      "config-pool-test1.cfg",
                                                      pool),
-                                     pool));
+                                     TRUE, TRUE, NULL, pool));
   svn_pool_clear(config_pool_pool);
   for (i = 0; i < 64000; ++i)
     apr_pcalloc(config_pool_pool, 80);
 
-  SVN_ERR(svn_config_get_bool(cfg1, &bvalue, "booleans", "true3", FALSE));
+  SVN_ERR(svn_config_get_bool(cfg, &bvalue, "booleans", "true3", FALSE));
   SVN_TEST_ASSERT(bvalue);
 
   return SVN_NO_ERROR;
 }
 
-
+
+static svn_error_t *
+test_repos_fs_type(const svn_test_opts_t *opts,
+                   apr_pool_t *pool)
+{
+  svn_repos_t *repos;
+
+  /* Create test repository. */
+  SVN_ERR(svn_test__create_repos(&repos, "test-repo-repos_fs_type",
+                                 opts, pool));
+
+  SVN_TEST_STRING_ASSERT(svn_repos_fs_type(repos, pool), opts->fs_type);
+
+  /* Re-open repository and verify fs-type again. */
+  SVN_ERR(svn_repos_open2(&repos, svn_repos_path(repos, pool), NULL, pool));
+
+  SVN_TEST_STRING_ASSERT(svn_repos_fs_type(repos, pool), opts->fs_type);
+
+  return SVN_NO_ERROR;
+}
+
 /* The test table.  */
 
 struct svn_test_descriptor_t test_funcs[] =
@@ -3566,5 +3591,7 @@ struct svn_test_descriptor_t test_funcs[
                        "test svn_repos_info_*"),
     SVN_TEST_OPTS_PASS(test_config_pool,
                        "test svn_repos__config_pool_*"),
+    SVN_TEST_OPTS_PASS(test_repos_fs_type,
+                       "test test_repos_fs_type"),
     SVN_TEST_NULL
   };