You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2014/12/14 12:44:04 UTC

svn commit: r1645439 [2/8] - in /subversion/branches/1.7.x-issue4340-repos: ./ build/ac-macros/ build/generator/ build/generator/templates/ contrib/hook-scripts/ subversion/bindings/javahl/native/ subversion/bindings/javahl/src/org/apache/subversion/ja...

Modified: subversion/branches/1.7.x-issue4340-repos/build/generator/gen_win.py
URL: http://svn.apache.org/viewvc/subversion/branches/1.7.x-issue4340-repos/build/generator/gen_win.py?rev=1645439&r1=1645438&r2=1645439&view=diff
==============================================================================
--- subversion/branches/1.7.x-issue4340-repos/build/generator/gen_win.py (original)
+++ subversion/branches/1.7.x-issue4340-repos/build/generator/gen_win.py Sun Dec 14 11:44:03 2014
@@ -382,14 +382,21 @@ class WinGeneratorBase(GeneratorBase):
       install_targets = [x for x in install_targets if not (isinstance(x, gen_base.TargetExe)
                                                             and x.install == 'bdb-test')]
 
+    # Don't build serf when we don't have it or for 1.3+
+    if not self.serf_lib or (self.serf_ver_maj, self.serf_ver_min) >= (1, 3):
+      install_targets = [x for x in install_targets if x.name != 'serf']      
+      
     # Drop the serf target if we don't have both serf and openssl
     if not self.serf_lib:
-      install_targets = [x for x in install_targets if x.name != 'serf']
       install_targets = [x for x in install_targets if x.name != 'libsvn_ra_serf']
     if self.without_neon:
       install_targets = [x for x in install_targets if x.name != 'neon']
       install_targets = [x for x in install_targets if x.name != 'libsvn_ra_neon']
 
+    # Don't build zlib if we have an already compiled serf
+    if self.serf_lib and (self.serf_ver_maj, self.serf_ver_min) >= (1, 3):
+      install_targets = [x for x in install_targets if x.name != 'zlib']
+
     # Drop the swig targets if we don't have swig
     if not self.swig_path and not self.swig_libdir:
       install_targets = [x for x in install_targets
@@ -712,7 +719,9 @@ class WinGeneratorBase(GeneratorBase):
 
     # Build ZLib as a dependency of Neon or Serf if we have it
     if self.zlib_path and (name == 'neon' or name == 'serf'):
-      depends.extend(self.sections['zlib'].get_targets())
+      # Don't add a dependency to zlib, when we don't build zlib.
+      if not self.serf_lib or (self.serf_ver_maj, self.serf_ver_min) < (1, 3):
+        depends.extend(self.sections['zlib'].get_targets())
 
     # To set the correct build order of the JavaHL targets, the javahl-javah
     # and libsvnjavahl targets are defined with extra dependencies in build.conf
@@ -942,6 +951,9 @@ class WinGeneratorBase(GeneratorBase):
 
     if self.serf_lib:
       fakeincludes.append(self.apath(self.serf_path))
+      
+      if self.openssl_path and self.openssl_inc_dir:
+        fakeincludes.append(self.apath(self.openssl_inc_dir))
 
     if self.swig_libdir \
        and (isinstance(target, gen_base.TargetSWIG)
@@ -993,7 +1005,13 @@ class WinGeneratorBase(GeneratorBase):
     if self.sasl_path:
       fakelibdirs.append(self.apath(self.sasl_path, "lib"))
     if self.serf_lib:
-      fakelibdirs.append(self.apath(msvc_path_join(self.serf_path, cfg)))
+      if (self.serf_ver_maj, self.serf_ver_min) >= (1, 3):
+        fakelibdirs.append(self.apath(self.serf_path))
+        
+        if self.openssl_path and self.openssl_lib_dir:
+          fakelibdirs.append(self.apath(self.openssl_lib_dir))
+      else:
+        fakelibdirs.append(self.apath(msvc_path_join(self.serf_path, cfg)))
 
     fakelibdirs.append(self.apath(self.apr_path, cfg))
     fakelibdirs.append(self.apath(self.apr_util_path, cfg))
@@ -1033,7 +1051,14 @@ class WinGeneratorBase(GeneratorBase):
       else:
         serflib = 'serf.lib'
 
-    zlib = (cfg == 'Debug' and 'zlibstatD.lib' or 'zlibstat.lib')
+    if self.serf_lib and (self.serf_ver_maj, self.serf_ver_min) >= (1, 3):
+      # We don't build zlib ourselves, so use the standard name
+      # (zdll.lib would link to zlib.dll)
+      zlib = 'zlib.lib'
+    else:
+      # We compile zlib ourselves to these explicit (non-standard) names
+      zlib = (cfg == 'Debug' and 'zlibstatD.lib' or 'zlibstat.lib')
+      
     sasllib = None
     if self.sasl_path:
       sasllib = 'libsasl.lib'
@@ -1080,6 +1105,9 @@ class WinGeneratorBase(GeneratorBase):
 
       if self.serf_lib and dep.external_lib == '$(SVN_SERF_LIBS)':
         nondeplibs.append(serflib)
+        if (self.serf_ver_maj, self.serf_ver_min) >= (1, 3):
+          nondeplibs.append('ssleay32.lib')
+          nondeplibs.append('libeay32.lib')
 
       if dep.external_lib == '$(SVN_SASL_LIBS)':
         nondeplibs.append(sasllib)
@@ -1487,6 +1515,21 @@ class WinGeneratorBase(GeneratorBase):
     "Check if serf and its dependencies are available"
 
     minimal_serf_version = (0, 3, 0)
+    
+    if self.openssl_path and os.path.exists(self.openssl_path):
+      version_path = os.path.join(self.openssl_path, 'inc32/openssl/opensslv.h')
+      if os.path.isfile(version_path):
+        # We have an OpenSSL Source location (legacy handling)
+        self.openssl_inc_dir = os.path.join(self.openssl_path, 'inc32')
+        self.openssl_lib_dir = os.path.join(self.openssl_path, 'out32dll')
+      elif os.path.isfile(os.path.join(self.openssl_path,
+                          'include/openssl/opensslv.h')):
+        self.openssl_inc_dir = os.path.join(self.openssl_path, 'include')
+        self.openssl_lib_dir = os.path.join(self.openssl_path, 'lib')
+      else:
+        print('WARNING: \'opensslv.h\' not found')
+        self.openssl_path = None
+    
     self.serf_lib = None
     if self.serf_path and os.path.exists(self.serf_path):
       if self.openssl_path and os.path.exists(self.openssl_path):

Modified: subversion/branches/1.7.x-issue4340-repos/build/generator/templates/build_zlib.ezt
URL: http://svn.apache.org/viewvc/subversion/branches/1.7.x-issue4340-repos/build/generator/templates/build_zlib.ezt?rev=1645439&r1=1645438&r2=1645439&view=diff
==============================================================================
--- subversion/branches/1.7.x-issue4340-repos/build/generator/templates/build_zlib.ezt (original)
+++ subversion/branches/1.7.x-issue4340-repos/build/generator/templates/build_zlib.ezt Sun Dec 14 11:44:03 2014
@@ -44,25 +44,6 @@ if /i "%2" == "x64" goto PX64
 goto pIIerr
 
 :checkrebuild
-
-[if-any use_ml]
-@rem **************************************************************************
-@rem Compile ASM sources with ML
-set ASFLAGS=-nologo -Zi -coff
-set LOC=-DASMV -DASMINF
-[is zlib_version "1.2.4"]
-set OBJA=contrib\masmx86\gvmat32c.obj contrib\masmx86\gvmat32.obj contrib\masmx86\inffas32.obj
-set ASM_OPTS=ASFLAGS="%ASFLAGS%" LOC="%LOC%" OBJA="%OBJA%"
-[else]
-if /i "%2" == "Win32" (
-  set ASM_OPTS=LOC="-DASMV -DASMINF" OBJA="inffas32.obj match686.obj"
-) else if /i "%2" == "x64" (
-  set ASM_OPTS=LOC="-DASMV -DASMINF" OBJA="inffasx64.obj gvmat64.obj inffas8664.obj" AS=ml64 
-)
-[end]
-[end]
-
-
 if /i "%3" == "rebuild" goto rebuild
 if /i "%3" == "clean" goto clean
 if not "%3" == "" goto pIIIerr

Modified: subversion/branches/1.7.x-issue4340-repos/build/generator/templates/vcnet_vcproj.ezt
URL: http://svn.apache.org/viewvc/subversion/branches/1.7.x-issue4340-repos/build/generator/templates/vcnet_vcproj.ezt?rev=1645439&r1=1645438&r2=1645439&view=diff
==============================================================================
--- subversion/branches/1.7.x-issue4340-repos/build/generator/templates/vcnet_vcproj.ezt (original)
+++ subversion/branches/1.7.x-issue4340-repos/build/generator/templates/vcnet_vcproj.ezt Sun Dec 14 11:44:03 2014
@@ -32,7 +32,7 @@
 			Name="[configs.name]|[platforms]"
 			OutputDirectory="..\..\..\[configs.name]\[target.output_dir]"
 			BuildLogFile="$(IntDir)\BuildLog_$(ProjectName).htm"
-			IntermediateDirectory="..\..\..\[configs.name]\[target.intermediate_dir]"
+			IntermediateDirectory="..\..\..\[configs.name]\[target.intermediate_dir]\[target.proj_name]"
 			ConfigurationType="[target_type]"[is configs.name "Release"]
 			WholeProgramOptimization="FALSE"[end]>
 			<Tool

Modified: subversion/branches/1.7.x-issue4340-repos/configure.ac
URL: http://svn.apache.org/viewvc/subversion/branches/1.7.x-issue4340-repos/configure.ac?rev=1645439&r1=1645438&r2=1645439&view=diff
==============================================================================
--- subversion/branches/1.7.x-issue4340-repos/configure.ac (original)
+++ subversion/branches/1.7.x-issue4340-repos/configure.ac Sun Dec 14 11:44:03 2014
@@ -118,7 +118,7 @@ AC_PATH_PROG(PKG_CONFIG, pkg-config)
 
 # Either a space-separated list of allowable Neon versions, or "any" to
 # mean allow anything.
-NEON_ALLOWED_LIST="0\.25 0\.26 0\.27\.2 0\.28 0\.29"
+NEON_ALLOWED_LIST="0\.25 0\.26 0\.27\.2 0\.28 0\.29 0\.30"
 NEON_RECOMMENDED_VER="0.29.6"
 NEON_URL="http://www.webdav.org/neon/neon-${NEON_RECOMMENDED_VER}.tar.gz"
 dnl You can skip the neon version check only if you know what you are doing 
@@ -721,7 +721,7 @@ AC_ARG_WITH(libmagic,AS_HELP_STRING([--w
     CPPFLAGS="$CPPFLAGS -I$libmagic_prefix/include"
     AC_CHECK_HEADERS(magic.h,[
       save_ldflags="$LDFLAGS"
-      LDFLAGS="-L$libmagic_prefix/lib"
+      LDFLAGS="-L$libmagic_prefix/lib $LDFLAGS"
       AC_CHECK_LIB(magic, magic_open, [libmagic_found="yes"])
       LDFLAGS="$save_ldflags"
     ])

Modified: subversion/branches/1.7.x-issue4340-repos/contrib/hook-scripts/check-mime-type.pl
URL: http://svn.apache.org/viewvc/subversion/branches/1.7.x-issue4340-repos/contrib/hook-scripts/check-mime-type.pl?rev=1645439&r1=1645438&r2=1645439&view=diff
==============================================================================
--- subversion/branches/1.7.x-issue4340-repos/contrib/hook-scripts/check-mime-type.pl (original)
+++ subversion/branches/1.7.x-issue4340-repos/contrib/hook-scripts/check-mime-type.pl Sun Dec 14 11:44:03 2014
@@ -120,7 +120,7 @@ foreach my $path ( @files_added )
 		# Parse the complete list of property values of the file $path to extract
 		# the mime-type and eol-style
 		foreach my $prop (&read_from_process($svnlook, 'proplist', $repos, '-t',
-		                  $txn, '--verbose', $path))
+		                  $txn, '--verbose', '--', $path))
 			{
 				if ($prop =~ /^\s*svn:mime-type : (\S+)/)
 					{
@@ -187,7 +187,7 @@ sub safe_read_from_pipe
       croak "$0: safe_read_from_pipe passed no arguments.\n";
     }
   print "Running @_\n";
-  my $pid = open(SAFE_READ, '-|');
+  my $pid = open(SAFE_READ, '-|', @_);
   unless (defined $pid)
     {
       die "$0: cannot fork: $!\n";

Modified: subversion/branches/1.7.x-issue4340-repos/contrib/hook-scripts/svn-keyword-check.pl
URL: http://svn.apache.org/viewvc/subversion/branches/1.7.x-issue4340-repos/contrib/hook-scripts/svn-keyword-check.pl?rev=1645439&r1=1645438&r2=1645439&view=diff
==============================================================================
--- subversion/branches/1.7.x-issue4340-repos/contrib/hook-scripts/svn-keyword-check.pl (original)
+++ subversion/branches/1.7.x-issue4340-repos/contrib/hook-scripts/svn-keyword-check.pl Sun Dec 14 11:44:03 2014
@@ -141,7 +141,7 @@ sub check {
                 return 1;
             } else {
                 my @keywords = get_svnkeywords($file);
-                my $fh = _pipe("$svnlook cat $flag $value $repos $file");
+                my $fh = _pipe($svnlook, qw/cat/, $flag, $value, $repos, '--', $file);
                 while (my $line = <$fh>) {
                     foreach my $keyword (@keywords) {
                         if ($line =~ m/$keyword/) {
@@ -168,7 +168,7 @@ sub file_is_binary {
         return 0;
     }
     if (has_svn_property($file, "svn:mime-type")) {
-        my ($mimetype) = read_from_process("$svnlook propget $flag $value $repos svn:mime-type $file");
+        my ($mimetype) = read_from_process($svnlook, qw/propget/, $flag, $value, $repos, 'svn:mime-type', '--', $file);
         chomp($mimetype);
         $mimetype =~ s/^\s*(.*)/$1/;
         if ($mimetype =~ m/^text\//) {
@@ -186,7 +186,7 @@ sub file_is_binary {
 # Return a list of svn:keywords on a file
 sub get_svnkeywords {
     my $file = shift;
-    my @lines = read_from_process("$svnlook propget $flag $value $repos svn:keywords $file");
+    my @lines = read_from_process($svnlook, qw/propget/, $flag, $value, $repos, 'svn:keywords', '--', $file);
     my @returnlines;
     foreach my $line (@lines) {
         $line =~ s/\s+/ /;
@@ -199,7 +199,7 @@ sub get_svnkeywords {
 sub has_svn_property {
     my $file = shift;
     my $keyword = shift;
-    my @proplist = read_from_process("$svnlook proplist $flag $value $repos $file");
+    my @proplist = read_from_process($svnlook, qw/proplist/, $flag, $value, $repos, '--', $file);
     foreach my $prop (@proplist) {
         chomp($prop);
         if ($prop =~ m/\b$keyword\b/) {
@@ -241,7 +241,7 @@ sub safe_read_from_pipe {
 # Return the filehandle as a glob so we can loop over it elsewhere.
 sub _pipe {
     local *SAFE_READ;
-    my $pid = open(SAFE_READ, '-|');
+    my $pid = open(SAFE_READ, '-|', @_);
     unless (defined $pid) {
         die "$0: cannot fork: $!\n";
     }

Modified: subversion/branches/1.7.x-issue4340-repos/get-deps.sh
URL: http://svn.apache.org/viewvc/subversion/branches/1.7.x-issue4340-repos/get-deps.sh?rev=1645439&r1=1645438&r2=1645439&view=diff
==============================================================================
--- subversion/branches/1.7.x-issue4340-repos/get-deps.sh (original)
+++ subversion/branches/1.7.x-issue4340-repos/get-deps.sh Sun Dec 14 11:44:03 2014
@@ -27,12 +27,13 @@ APR=apr-1.4.5
 APR_UTIL=apr-util-1.3.12
 NEON=neon-0.29.6
 SERF=serf-0.7.2
-ZLIB=zlib-1.2.7
+ZLIB=zlib-1.2.8
 SQLITE_VERSION=3.7.6.3
-SQLITE=sqlite-amalgamation-$(printf %d%02d%02d%02d $(echo $SQLITE_VERSION | sed -e 's/\./ /g'))
+SQLITE_VERSION_LIST=`echo $SQLITE_VERSION | sed -e 's/\./ /g'`
+SQLITE=sqlite-amalgamation-`printf %d%02d%02d%02d $SQLITE_VERSION_LIST`
 
 
-HTTPD=httpd-2.2.19
+HTTPD=httpd-2.2.25
 APR_ICONV=apr-iconv-1.2.1
 
 BASEDIR=`pwd`
@@ -90,10 +91,10 @@ get_serf() {
 
 get_zlib() {
     cd $TEMPDIR
-    $HTTP_FETCH http://www.zlib.net/$ZLIB.tar.bz2
+    $HTTP_FETCH http://www.zlib.net/$ZLIB.tar.gz
     cd $BASEDIR
 
-    bzip2 -dc $TEMPDIR/$ZLIB.tar.bz2 | tar -xf -
+    gzip -dc $TEMPDIR/$ZLIB.tar.gz | tar -xf -
 
     mv $ZLIB zlib
 }
@@ -120,8 +121,12 @@ get_deps() {
     done
 
     if [ $# -gt 0 ]; then
-      for target; do
-        get_$target || usage
+      for target in "$@"; do
+        if [ "$target" != "deps" ]; then
+          get_$target || usage
+        else
+          usage
+        fi
       done
     else
       get_apr

Modified: subversion/branches/1.7.x-issue4340-repos/subversion/bindings/javahl/native/ClientContext.cpp
URL: http://svn.apache.org/viewvc/subversion/branches/1.7.x-issue4340-repos/subversion/bindings/javahl/native/ClientContext.cpp?rev=1645439&r1=1645438&r2=1645439&view=diff
==============================================================================
--- subversion/branches/1.7.x-issue4340-repos/subversion/bindings/javahl/native/ClientContext.cpp (original)
+++ subversion/branches/1.7.x-issue4340-repos/subversion/bindings/javahl/native/ClientContext.cpp Sun Dec 14 11:44:03 2014
@@ -422,6 +422,7 @@ ClientContext::resolve(svn_wc_conflict_r
 {
   jobject jctx = (jobject) baton;
   JNIEnv *env = JNIUtil::getEnv();
+  *result = NULL;
 
   // Create a local frame for our references
   env->PushLocalFrame(LOCAL_FRAME_SIZE);

Modified: subversion/branches/1.7.x-issue4340-repos/subversion/bindings/javahl/native/JNIUtil.cpp
URL: http://svn.apache.org/viewvc/subversion/branches/1.7.x-issue4340-repos/subversion/bindings/javahl/native/JNIUtil.cpp?rev=1645439&r1=1645438&r2=1645439&view=diff
==============================================================================
--- subversion/branches/1.7.x-issue4340-repos/subversion/bindings/javahl/native/JNIUtil.cpp (original)
+++ subversion/branches/1.7.x-issue4340-repos/subversion/bindings/javahl/native/JNIUtil.cpp Sun Dec 14 11:44:03 2014
@@ -376,7 +376,7 @@ JNIUtil::putErrorsInTrace(svn_error_t *e
     return;
 
   char *tmp_path;
-  char *path = svn_relpath_dirname(err->file, err->pool);
+  char *path = svn_dirent_dirname(err->file, err->pool);
   while (tmp_path = strchr(path, '/'))
     *tmp_path = '.';
 
@@ -384,7 +384,7 @@ JNIUtil::putErrorsInTrace(svn_error_t *e
   if (isJavaExceptionThrown())
     return;
 
-  jstring jfileName = makeJString(svn_relpath_basename(err->file, err->pool));
+  jstring jfileName = makeJString(svn_dirent_basename(err->file, err->pool));
   if (isJavaExceptionThrown())
     return;
 
@@ -399,7 +399,7 @@ JNIUtil::putErrorsInTrace(svn_error_t *e
   env->DeleteLocalRef(jfileName);
 }
 
-void JNIUtil::handleSVNError(svn_error_t *err)
+void JNIUtil::wrappedHandleSVNError(svn_error_t *err)
 {
   std::string msg;
   assembleErrorMessage(svn_error_purge_tracing(err), 0, APR_SUCCESS, msg);
@@ -521,7 +521,16 @@ void JNIUtil::handleSVNError(svn_error_t
 #endif
 
   env->Throw(static_cast<jthrowable>(env->PopLocalFrame(nativeException)));
+}
 
+void JNIUtil::handleSVNError(svn_error_t *err)
+{
+  try {
+    wrappedHandleSVNError(err);
+  } catch (...) {
+    svn_error_clear(err);
+    throw;
+  }
   svn_error_clear(err);
 }
 
@@ -621,28 +630,42 @@ bool JNIUtil::isJavaExceptionThrown()
 const char *
 JNIUtil::thrownExceptionToCString(SVN::Pool &in_pool)
 {
-  const char *msg;
+  const char *msg = NULL;
   JNIEnv *env = getEnv();
+  apr_pool_t *pool = in_pool.getPool();
   if (env->ExceptionCheck())
     {
       jthrowable t = env->ExceptionOccurred();
-      static jmethodID getMessage = 0;
-      if (getMessage == 0)
+      jclass cls = env->GetObjectClass(t);
+
+      jstring jclass_name;
+      {
+        jmethodID mid = env->GetMethodID(cls, "getClass", "()Ljava/lang/Class;");
+        jobject clsobj = env->CallObjectMethod(t, mid);
+        jclass basecls = env->GetObjectClass(clsobj);
+        mid = env->GetMethodID(basecls, "getName", "()Ljava/lang/String;");
+        jclass_name = (jstring) env->CallObjectMethod(clsobj, mid);
+      }
+
+      jstring jmessage;
+      {
+        jmethodID mid = env->GetMethodID(cls, "getMessage",
+                                         "()Ljava/lang/String;");
+        jmessage = (jstring) env->CallObjectMethod(t, mid);
+      }
+
+      JNIStringHolder class_name(jclass_name);
+      if (jmessage)
         {
-          jclass clazz = env->FindClass("java/lang/Throwable");
-          getMessage = env->GetMethodID(clazz, "getMessage",
-                                        "(V)Ljava/lang/String;");
-          env->DeleteLocalRef(clazz);
+          JNIStringHolder message(jmessage);
+          msg = apr_pstrcat(pool,
+                            static_cast<const char*>(class_name), ": ",
+                            static_cast<const char*>(message), NULL);
         }
-      jstring jmsg = (jstring) env->CallObjectMethod(t, getMessage);
-      JNIStringHolder tmp(jmsg);
-      msg = tmp.pstrdup(in_pool.getPool());
+      else
+        msg = class_name.pstrdup(pool);
       // ### Conditionally add t.printStackTrace() to msg?
     }
-  else
-    {
-      msg = NULL;
-    }
   return msg;
 }
 

Modified: subversion/branches/1.7.x-issue4340-repos/subversion/bindings/javahl/native/JNIUtil.h
URL: http://svn.apache.org/viewvc/subversion/branches/1.7.x-issue4340-repos/subversion/bindings/javahl/native/JNIUtil.h?rev=1645439&r1=1645438&r2=1645439&view=diff
==============================================================================
--- subversion/branches/1.7.x-issue4340-repos/subversion/bindings/javahl/native/JNIUtil.h (original)
+++ subversion/branches/1.7.x-issue4340-repos/subversion/bindings/javahl/native/JNIUtil.h Sun Dec 14 11:44:03 2014
@@ -138,6 +138,7 @@ class JNIUtil
   enum { noLog, errorLog, exceptionLog, entryLog } LogLevel;
 
  private:
+  static void wrappedHandleSVNError(svn_error_t *err);
   static void assembleErrorMessage(svn_error_t *err, int depth,
                                    apr_status_t parent_apr_err,
                                    std::string &buffer);

Modified: subversion/branches/1.7.x-issue4340-repos/subversion/bindings/javahl/native/SVNClient.cpp
URL: http://svn.apache.org/viewvc/subversion/branches/1.7.x-issue4340-repos/subversion/bindings/javahl/native/SVNClient.cpp?rev=1645439&r1=1645438&r2=1645439&view=diff
==============================================================================
--- subversion/branches/1.7.x-issue4340-repos/subversion/bindings/javahl/native/SVNClient.cpp (original)
+++ subversion/branches/1.7.x-issue4340-repos/subversion/bindings/javahl/native/SVNClient.cpp Sun Dec 14 11:44:03 2014
@@ -1138,7 +1138,7 @@ void SVNClient::streamFileContent(const
         return;
 
     SVN_JNI_ERR(svn_client_cat2(outputStream.getStream(subPool),
-                                path, pegRevision.revision(),
+                                intPath.c_str(), pegRevision.revision(),
                                 revision.revision(), ctx, subPool.getPool()),
                 );
 }

Modified: subversion/branches/1.7.x-issue4340-repos/subversion/bindings/javahl/src/org/apache/subversion/javahl/types/LogDate.java
URL: http://svn.apache.org/viewvc/subversion/branches/1.7.x-issue4340-repos/subversion/bindings/javahl/src/org/apache/subversion/javahl/types/LogDate.java?rev=1645439&r1=1645438&r2=1645439&view=diff
==============================================================================
--- subversion/branches/1.7.x-issue4340-repos/subversion/bindings/javahl/src/org/apache/subversion/javahl/types/LogDate.java (original)
+++ subversion/branches/1.7.x-issue4340-repos/subversion/bindings/javahl/src/org/apache/subversion/javahl/types/LogDate.java Sun Dec 14 11:44:03 2014
@@ -51,7 +51,11 @@ public class LogDate implements java.io.
         {
             throw new ParseException("String is not a valid Subversion date", 0);
         }
-        Date date = formatter.parse(datestr.substring(0, 23) + " UTC");
+        Date date;
+        synchronized(formatter)
+        {
+            date = formatter.parse(datestr.substring(0, 23) + " UTC");
+        }
         this.cachedString = datestr;
         cachedDate = Calendar.getInstance(UTC);
         cachedDate.setTime(date);

Modified: subversion/branches/1.7.x-issue4340-repos/subversion/bindings/javahl/src/org/tigris/subversion/javahl/LogDate.java
URL: http://svn.apache.org/viewvc/subversion/branches/1.7.x-issue4340-repos/subversion/bindings/javahl/src/org/tigris/subversion/javahl/LogDate.java?rev=1645439&r1=1645438&r2=1645439&view=diff
==============================================================================
--- subversion/branches/1.7.x-issue4340-repos/subversion/bindings/javahl/src/org/tigris/subversion/javahl/LogDate.java (original)
+++ subversion/branches/1.7.x-issue4340-repos/subversion/bindings/javahl/src/org/tigris/subversion/javahl/LogDate.java Sun Dec 14 11:44:03 2014
@@ -53,7 +53,11 @@ public class LogDate implements java.io.
         {
             throw new ParseException("String is not a valid Subversion date", 0);
         }
-        Date date = formatter.parse(datestr.substring(0, 23) + " UTC");
+        Date date;
+        synchronized(formatter)
+        {
+            date = formatter.parse(datestr.substring(0, 23) + " UTC");
+        }
         this.cachedString = datestr;
         cachedDate = Calendar.getInstance(UTC);
         cachedDate.setTime(date);

Modified: subversion/branches/1.7.x-issue4340-repos/subversion/bindings/swig/include/svn_types.swg
URL: http://svn.apache.org/viewvc/subversion/branches/1.7.x-issue4340-repos/subversion/bindings/swig/include/svn_types.swg?rev=1645439&r1=1645438&r2=1645439&view=diff
==============================================================================
--- subversion/branches/1.7.x-issue4340-repos/subversion/bindings/swig/include/svn_types.swg (original)
+++ subversion/branches/1.7.x-issue4340-repos/subversion/bindings/swig/include/svn_types.swg Sun Dec 14 11:44:03 2014
@@ -901,6 +901,12 @@ svn_ ## TYPE ## _swig_rb_closed(VALUE se
   $2 = (void *)baton;
 }
 #endif
+#ifdef SWIGPERL
+%ignore svn_fs_set_warning_func;
+#endif
+#ifdef SWIGPYTHON
+%ignore svn_fs_set_warning_func;
+#endif
 
 /* -----------------------------------------------------------------------
    svn_stream_t interoperability with language native io handles

Modified: subversion/branches/1.7.x-issue4340-repos/subversion/bindings/swig/perl/libsvn_swig_perl/swigutil_pl.c
URL: http://svn.apache.org/viewvc/subversion/branches/1.7.x-issue4340-repos/subversion/bindings/swig/perl/libsvn_swig_perl/swigutil_pl.c?rev=1645439&r1=1645438&r2=1645439&view=diff
==============================================================================
--- subversion/branches/1.7.x-issue4340-repos/subversion/bindings/swig/perl/libsvn_swig_perl/swigutil_pl.c (original)
+++ subversion/branches/1.7.x-issue4340-repos/subversion/bindings/swig/perl/libsvn_swig_perl/swigutil_pl.c Sun Dec 14 11:44:03 2014
@@ -114,9 +114,9 @@ static apr_hash_t *svn_swig_pl_to_hash(S
     h = (HV *)SvRV(source);
     cnt = hv_iterinit(h);
     while (cnt--) {
-	SV* item = hv_iternextsv(h, &key, &retlen);
-	void *val = cv(item, ctx, pool);
-	apr_hash_set(hash, key, APR_HASH_KEY_STRING, val);
+        SV* item = hv_iternextsv(h, &key, &retlen);
+        void *val = cv(item, ctx, pool);
+        apr_hash_set(hash, apr_pstrmemdup(pool, key, retlen), retlen, val);
     }
 
     return hash;

Propchange: subversion/branches/1.7.x-issue4340-repos/subversion/include/private/svn_adler32.h
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Sun Dec 14 11:44:03 2014
@@ -1,5 +1,7 @@
 /subversion/branches/1.5.x-r30215/subversion/libsvn_diff/diff.h:870312
+/subversion/branches/1.7.x/subversion/include/private/svn_adler32.h:1480943-1645438
 /subversion/branches/1.7.x-issue4087/subversion/include/private/svn_adler32.h:1243707-1336073
+/subversion/branches/1.7.x-issue4153/subversion/include/private/svn_adler32.h:1309894-1539233
 /subversion/branches/1.7.x-issue4169/subversion/include/private/svn_adler32.h:1330537-1336116
 /subversion/branches/1.7.x-r1210147/subversion/include/private/svn_adler32.h:1213310-1293110
 /subversion/branches/1.7.x-r1423646/subversion/include/private/svn_adler32.h:1423647-1424282

Propchange: subversion/branches/1.7.x-issue4340-repos/subversion/include/private/svn_string_private.h
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Sun Dec 14 11:44:03 2014
@@ -1,5 +1,7 @@
 /subversion/branches/1.5.x-r30215/subversion/include/svn_string.h:870312
+/subversion/branches/1.7.x/subversion/include/private/svn_string_private.h:1480943-1645438
 /subversion/branches/1.7.x-issue4087/subversion/include/private/svn_string_private.h:1243707-1336073
+/subversion/branches/1.7.x-issue4153/subversion/include/private/svn_string_private.h:1309894-1539233
 /subversion/branches/1.7.x-issue4169/subversion/include/private/svn_string_private.h:1330537-1336116
 /subversion/branches/1.7.x-r1210147/subversion/include/private/svn_string_private.h:1213310-1293110
 /subversion/branches/1.7.x-r1423646/subversion/include/private/svn_string_private.h:1423647-1424282

Propchange: subversion/branches/1.7.x-issue4340-repos/subversion/include/private/svn_temp_serializer.h
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Sun Dec 14 11:44:03 2014
@@ -1,4 +1,6 @@
+/subversion/branches/1.7.x/subversion/include/private/svn_temp_serializer.h:1480943-1645438
 /subversion/branches/1.7.x-issue4087/subversion/include/private/svn_temp_serializer.h:1243707-1336073
+/subversion/branches/1.7.x-issue4153/subversion/include/private/svn_temp_serializer.h:1309894-1539233
 /subversion/branches/1.7.x-issue4169/subversion/include/private/svn_temp_serializer.h:1330537-1336116
 /subversion/branches/1.7.x-r1210147/subversion/include/private/svn_temp_serializer.h:1213310-1293110
 /subversion/branches/1.7.x-r1423646/subversion/include/private/svn_temp_serializer.h:1423647-1424282

Modified: subversion/branches/1.7.x-issue4340-repos/subversion/include/svn_io.h
URL: http://svn.apache.org/viewvc/subversion/branches/1.7.x-issue4340-repos/subversion/include/svn_io.h?rev=1645439&r1=1645438&r2=1645439&view=diff
==============================================================================
--- subversion/branches/1.7.x-issue4340-repos/subversion/include/svn_io.h (original)
+++ subversion/branches/1.7.x-issue4340-repos/subversion/include/svn_io.h Sun Dec 14 11:44:03 2014
@@ -1064,6 +1064,8 @@ svn_stream_read(svn_stream_t *stream,
  * of reads or a simple seek operation. If the stream implementation has
  * not provided a skip function, this will read from the stream and
  * discard the data.
+ *
+ * @since New in 1.7.
  */
 svn_error_t *
 svn_stream_skip(svn_stream_t *stream,

Modified: subversion/branches/1.7.x-issue4340-repos/subversion/include/svn_types.h
URL: http://svn.apache.org/viewvc/subversion/branches/1.7.x-issue4340-repos/subversion/include/svn_types.h?rev=1645439&r1=1645438&r2=1645439&view=diff
==============================================================================
--- subversion/branches/1.7.x-issue4340-repos/subversion/include/svn_types.h (original)
+++ subversion/branches/1.7.x-issue4340-repos/subversion/include/svn_types.h Sun Dec 14 11:44:03 2014
@@ -186,6 +186,16 @@ svn__apr_hash_index_val(const apr_hash_i
                       || ((s) == APR_OS_START_SYSERR + ERROR_INVALID_NAME))
 #endif
 
+/** On Windows, APR_STATUS_IS_EPIPE does not include ERROR_NO_DATA error.
+ * So we include it.*/
+/* ### These fixes should go into APR. */
+#ifndef WIN32
+#define SVN__APR_STATUS_IS_EPIPE(s)  APR_STATUS_IS_EPIPE(s)
+#else
+#define SVN__APR_STATUS_IS_EPIPE(s)  (APR_STATUS_IS_EPIPE(s) \
+                      || ((s) == APR_OS_START_SYSERR + ERROR_NO_DATA))
+#endif
+
 /** @} */
 
 /** The various types of nodes in the Subversion filesystem. */

Modified: subversion/branches/1.7.x-issue4340-repos/subversion/include/svn_version.h
URL: http://svn.apache.org/viewvc/subversion/branches/1.7.x-issue4340-repos/subversion/include/svn_version.h?rev=1645439&r1=1645438&r2=1645439&view=diff
==============================================================================
--- subversion/branches/1.7.x-issue4340-repos/subversion/include/svn_version.h (original)
+++ subversion/branches/1.7.x-issue4340-repos/subversion/include/svn_version.h Sun Dec 14 11:44:03 2014
@@ -71,7 +71,7 @@ extern "C" {
  *
  * @since New in 1.1.
  */
-#define SVN_VER_PATCH      10
+#define SVN_VER_PATCH      20
 
 
 /** @deprecated Provided for backward compatibility with the 1.0 API. */

Modified: subversion/branches/1.7.x-issue4340-repos/subversion/libsvn_auth_gnome_keyring/gnome_keyring.c
URL: http://svn.apache.org/viewvc/subversion/branches/1.7.x-issue4340-repos/subversion/libsvn_auth_gnome_keyring/gnome_keyring.c?rev=1645439&r1=1645438&r2=1645439&view=diff
==============================================================================
--- subversion/branches/1.7.x-issue4340-repos/subversion/libsvn_auth_gnome_keyring/gnome_keyring.c (original)
+++ subversion/branches/1.7.x-issue4340-repos/subversion/libsvn_auth_gnome_keyring/gnome_keyring.c Sun Dec 14 11:44:03 2014
@@ -28,6 +28,7 @@
 /*** Includes. ***/
 
 #include <apr_pools.h>
+#include <apr_strings.h>
 #include "svn_auth.h"
 #include "svn_config.h"
 #include "svn_error.h"
@@ -46,120 +47,19 @@
 /*-----------------------------------------------------------------------*/
 
 
-struct gnome_keyring_baton
-{
-  const char *keyring_name;
-  GnomeKeyringInfo *info;
-  GMainLoop *loop;
-};
-
-
-/* Callback function to destroy gnome_keyring_baton. */
-static void
-callback_destroy_data_keyring(void *data)
-{
-  struct gnome_keyring_baton *key_info = data;
-
-  if (data == NULL)
-    return;
-
-  free((void*)key_info->keyring_name);
-  key_info->keyring_name = NULL;
-
-  if (key_info->info)
-    {
-      gnome_keyring_info_free(key_info->info);
-      key_info->info = NULL;
-    }
-
-  return;
-}
-
-
-/* Callback function to complete the keyring operation. */
-static void
-callback_done(GnomeKeyringResult result,
-              gpointer data)
-{
-  struct gnome_keyring_baton *key_info = data;
-
-  g_main_loop_quit(key_info->loop);
-  return;
-}
-
-
-/* Callback function to get the keyring info. */
-static void
-callback_get_info_keyring(GnomeKeyringResult result,
-                          GnomeKeyringInfo *info,
-                          void *data)
-{
-  struct gnome_keyring_baton *key_info = data;
-
-  if (result == GNOME_KEYRING_RESULT_OK && info != NULL)
-    {
-      key_info->info = gnome_keyring_info_copy(info);
-    }
-  else
-    {
-      if (key_info->info != NULL)
-        gnome_keyring_info_free(key_info->info);
-
-      key_info->info = NULL;
-    }
-
-  g_main_loop_quit(key_info->loop);
-
-  return;
-}
-
-
-/* Callback function to get the default keyring string name. */
-static void
-callback_default_keyring(GnomeKeyringResult result,
-                         const char *string,
-                         void *data)
-{
-  struct gnome_keyring_baton *key_info = data;
-
-  if (result == GNOME_KEYRING_RESULT_OK && string != NULL)
-    {
-      key_info->keyring_name = strdup(string);
-    }
-  else
-    {
-      free((void*)key_info->keyring_name);
-      key_info->keyring_name = NULL;
-    }
-
-  g_main_loop_quit(key_info->loop);
-
-  return;
-}
-
-/* Returns the default keyring name. */
+/* Returns the default keyring name, allocated in RESULT_POOL. */
 static char*
-get_default_keyring_name(apr_pool_t *pool)
+get_default_keyring_name(apr_pool_t *result_pool)
 {
-  char *def = NULL;
-  struct gnome_keyring_baton key_info;
-
-  key_info.info = NULL;
-  key_info.keyring_name = NULL;
+  char *name, *def;
+  GnomeKeyringResult gkr;
 
-  /* Finds default keyring. */
-  key_info.loop = g_main_loop_new(NULL, FALSE);
-  gnome_keyring_get_default_keyring(callback_default_keyring, &key_info, NULL);
-  g_main_loop_run(key_info.loop);
-
-  if (key_info.keyring_name == NULL)
-    {
-      callback_destroy_data_keyring(&key_info);
-      return NULL;
-    }
+  gkr = gnome_keyring_get_default_keyring_sync(&name);
+  if (gkr != GNOME_KEYRING_RESULT_OK)
+    return NULL;
 
-  def = strdup(key_info.keyring_name);
-  callback_destroy_data_keyring(&key_info);
+  def = apr_pstrdup(result_pool, name);
+  g_free(name);
 
   return def;
 }
@@ -168,28 +68,22 @@ get_default_keyring_name(apr_pool_t *poo
 static svn_boolean_t
 check_keyring_is_locked(const char *keyring_name)
 {
-  struct gnome_keyring_baton key_info;
+  GnomeKeyringInfo *info;
+  svn_boolean_t locked;
+  GnomeKeyringResult gkr;
 
-  key_info.info = NULL;
-  key_info.keyring_name = NULL;
+  gkr = gnome_keyring_get_info_sync(keyring_name, &info);
+  if (gkr != GNOME_KEYRING_RESULT_OK)
+    return FALSE;
 
-  /* Get details about the default keyring. */
-  key_info.loop = g_main_loop_new(NULL, FALSE);
-  gnome_keyring_get_info(keyring_name, callback_get_info_keyring, &key_info,
-                         NULL);
-  g_main_loop_run(key_info.loop);
-
-  if (key_info.info == NULL)
-    {
-      callback_destroy_data_keyring(&key_info);
-      return FALSE;
-    }
-
-  /* Check if keyring is locked. */
-  if (gnome_keyring_info_get_is_locked(key_info.info))
-    return TRUE;
+  if (gnome_keyring_info_get_is_locked(info))
+    locked = TRUE;
   else
-    return FALSE;
+    locked = FALSE;
+
+  gnome_keyring_info_free(info);
+
+  return locked;
 }
 
 /* Unlock the KEYRING_NAME with the KEYRING_PASSWORD. If KEYRING was
@@ -199,34 +93,19 @@ unlock_gnome_keyring(const char *keyring
                      const char *keyring_password,
                      apr_pool_t *pool)
 {
-  struct gnome_keyring_baton key_info;
+  GnomeKeyringInfo *info;
+  GnomeKeyringResult gkr;
 
-  key_info.info = NULL;
-  key_info.keyring_name = NULL;
+  gkr = gnome_keyring_get_info_sync(keyring_name, &info);
+  if (gkr != GNOME_KEYRING_RESULT_OK)
+    return FALSE;
 
-  /* Get details about the default keyring. */
-  key_info.loop = g_main_loop_new(NULL, FALSE);
-  gnome_keyring_get_info(keyring_name, callback_get_info_keyring,
-                         &key_info, NULL);
-  g_main_loop_run(key_info.loop);
-
-  if (key_info.info == NULL)
-    {
-      callback_destroy_data_keyring(&key_info);
-      return FALSE;
-    }
-  else
-    {
-      key_info.loop = g_main_loop_new(NULL, FALSE);
-      gnome_keyring_unlock(keyring_name, keyring_password,
-                           callback_done, &key_info, NULL);
-      g_main_loop_run(key_info.loop);
-    }
-  callback_destroy_data_keyring(&key_info);
-  if (check_keyring_is_locked(keyring_name))
+  gkr = gnome_keyring_unlock_sync(keyring_name, keyring_password);
+  gnome_keyring_info_free(info);
+  if (gkr != GNOME_KEYRING_RESULT_OK)
     return FALSE;
 
-  return TRUE;
+  return check_keyring_is_locked(keyring_name);
 }
 
 

Modified: subversion/branches/1.7.x-issue4340-repos/subversion/libsvn_client/blame.c
URL: http://svn.apache.org/viewvc/subversion/branches/1.7.x-issue4340-repos/subversion/libsvn_client/blame.c?rev=1645439&r1=1645438&r2=1645439&view=diff
==============================================================================
--- subversion/branches/1.7.x-issue4340-repos/subversion/libsvn_client/blame.c (original)
+++ subversion/branches/1.7.x-issue4340-repos/subversion/libsvn_client/blame.c Sun Dec 14 11:44:03 2014
@@ -675,28 +675,41 @@ svn_client_blame5(const char *target,
       SVN_ERR(svn_wc_status3(&status, ctx->wc_ctx, target_abspath_or_url, pool,
                              pool));
 
-      if (status->text_status != svn_wc_status_normal)
+      if (status->text_status != svn_wc_status_normal
+          || (status->prop_status != svn_wc_status_normal
+              && status->prop_status != svn_wc_status_none))
         {
-          apr_hash_t *props;
           svn_stream_t *wcfile;
-          svn_string_t *keywords;
           svn_stream_t *tempfile;
+          svn_opt_revision_t rev;
+          svn_boolean_t normalize_eols = FALSE;
           const char *temppath;
-          apr_hash_t *kw = NULL;
 
-          SVN_ERR(svn_wc_prop_list2(&props, ctx->wc_ctx, target_abspath_or_url,
-                                    pool, pool));
-          SVN_ERR(svn_stream_open_readonly(&wcfile, target, pool, pool));
-
-          keywords = apr_hash_get(props, SVN_PROP_KEYWORDS,
-                                  APR_HASH_KEY_STRING);
-
-          if (keywords)
-            SVN_ERR(svn_subst_build_keywords2(&kw, keywords->data, NULL, NULL,
-                                              0, NULL, pool));
-
-          wcfile = svn_subst_stream_translated(wcfile, "\n", TRUE, kw, FALSE,
-                                               pool);
+          if (status->prop_status != svn_wc_status_none)
+            {
+              const svn_string_t *eol_style;
+              SVN_ERR(svn_wc_prop_get2(&eol_style, ctx->wc_ctx,
+                                       target_abspath_or_url,
+                                       SVN_PROP_EOL_STYLE,
+                                       pool, pool));
+
+              if (eol_style)
+                {
+                  svn_subst_eol_style_t style;
+                  const char *eol;
+                  svn_subst_eol_style_from_value(&style, &eol, eol_style->data);
+
+                  normalize_eols = (style == svn_subst_eol_style_native);
+                }
+            }
+
+          rev.kind = svn_opt_revision_working;
+          SVN_ERR(svn_client__get_normalized_stream(&wcfile, ctx->wc_ctx,
+                                                    target_abspath_or_url, &rev,
+                                                    FALSE, normalize_eols,
+                                                    ctx->cancel_func,
+                                                    ctx->cancel_baton,
+                                                    pool, pool));
 
           SVN_ERR(svn_stream_open_unique(&tempfile, &temppath, NULL,
                                          svn_io_file_del_on_pool_cleanup,

Modified: subversion/branches/1.7.x-issue4340-repos/subversion/libsvn_client/client.h
URL: http://svn.apache.org/viewvc/subversion/branches/1.7.x-issue4340-repos/subversion/libsvn_client/client.h?rev=1645439&r1=1645438&r2=1645439&view=diff
==============================================================================
--- subversion/branches/1.7.x-issue4340-repos/subversion/libsvn_client/client.h (original)
+++ subversion/branches/1.7.x-issue4340-repos/subversion/libsvn_client/client.h Sun Dec 14 11:44:03 2014
@@ -609,6 +609,24 @@ svn_client__get_diff_summarize_editor(co
                                       void **edit_baton,
                                       apr_pool_t *pool);
 
+/* Set *CALLBACKS and *CALLBACK_BATON to a set of diff callbacks that will
+   report a diff summary, i.e. only providing information about the changed
+   items without the text deltas.
+
+   TARGET is the target path, relative to the anchor, of the diff.
+
+   SUMMARIZE_FUNC is called with SUMMARIZE_BATON as parameter by the
+   created callbacks for each changed item.
+*/
+svn_error_t *
+svn_client__get_diff_summarize_callbacks(
+                        svn_wc_diff_callbacks4_t **callbacks,
+                        void **callback_baton,
+                        const char *target,
+                        svn_client_diff_summarize_func_t summarize_func,
+                        void *summarize_baton,
+                        apr_pool_t *pool);
+
 /* ---------------------------------------------------------------- */
 
 /*** Copy Stuff ***/
@@ -929,7 +947,11 @@ svn_client__export_externals(apr_hash_t
 
 /* Perform status operations on each external in EXTERNAL_MAP, a const char *
    local_abspath of all externals mapping to the const char* defining_abspath.
-   All other options are the same as those passed to svn_client_status(). */
+   All other options are the same as those passed to svn_client_status().
+
+   If ANCHOR_ABSPATH and ANCHOR-RELPATH are not null, use them to provide
+   properly formatted relative paths
+ */
 svn_error_t *
 svn_client__do_external_status(svn_client_ctx_t *ctx,
                                apr_hash_t *external_map,
@@ -937,9 +959,11 @@ svn_client__do_external_status(svn_clien
                                svn_boolean_t get_all,
                                svn_boolean_t update,
                                svn_boolean_t no_ignore,
+                               const char *anchor_abspath,
+                               const char *anchor_relpath,
                                svn_client_status_func_t status_func,
                                void *status_baton,
-                               apr_pool_t *pool);
+                               apr_pool_t *scratch_pool);
 
 /* Baton type for svn_wc__external_info_gatherer(). */
 typedef struct svn_client__external_func_baton_t

Modified: subversion/branches/1.7.x-issue4340-repos/subversion/libsvn_client/copy.c
URL: http://svn.apache.org/viewvc/subversion/branches/1.7.x-issue4340-repos/subversion/libsvn_client/copy.c?rev=1645439&r1=1645438&r2=1645439&view=diff
==============================================================================
--- subversion/branches/1.7.x-issue4340-repos/subversion/libsvn_client/copy.c (original)
+++ subversion/branches/1.7.x-issue4340-repos/subversion/libsvn_client/copy.c Sun Dec 14 11:44:03 2014
@@ -374,6 +374,8 @@ do_wc_to_wc_moves(const apr_array_header
     {
       const char *src_parent_abspath;
       struct do_wc_to_wc_moves_with_locks_baton baton;
+      const char *src_wcroot_abspath;
+      const char *dst_wcroot_abspath;
 
       svn_client__copy_pair_t *pair = APR_ARRAY_IDX(copy_pairs, i,
                                                     svn_client__copy_pair_t *);
@@ -386,6 +388,13 @@ do_wc_to_wc_moves(const apr_array_header
       src_parent_abspath = svn_dirent_dirname(pair->src_abspath_or_url,
                                               iterpool);
 
+      SVN_ERR(svn_wc__get_wc_root(&src_wcroot_abspath,
+                                 ctx->wc_ctx, src_parent_abspath,
+                                 iterpool, iterpool));
+      SVN_ERR(svn_wc__get_wc_root(&dst_wcroot_abspath,
+                                 ctx->wc_ctx, pair->dst_parent_abspath,
+                                 iterpool, iterpool));
+
       /* We now need to lock the right combination of batons.
          Four cases:
            1) src_parent == dst_parent
@@ -394,14 +403,18 @@ do_wc_to_wc_moves(const apr_array_header
            4) src_parent and dst_parent are disjoint
          We can handle 1) as either 2) or 3) */
       if (strcmp(src_parent_abspath, pair->dst_parent_abspath) == 0
-          || svn_dirent_is_child(src_parent_abspath, pair->dst_parent_abspath,
-                                 iterpool))
+          || (svn_dirent_is_child(src_parent_abspath, pair->dst_parent_abspath,
+                                  NULL)
+              && !svn_dirent_is_child(src_parent_abspath, dst_wcroot_abspath,
+                                      NULL)))
         {
           baton.lock_src = TRUE;
           baton.lock_dst = FALSE;
         }
-      else if (svn_dirent_is_child(pair->dst_parent_abspath, src_parent_abspath,
-                                   iterpool))
+      else if (svn_dirent_is_child(pair->dst_parent_abspath,
+                                   src_parent_abspath, NULL)
+               && !svn_dirent_is_child(pair->dst_parent_abspath,
+                                       src_wcroot_abspath, NULL))
         {
           baton.lock_src = FALSE;
           baton.lock_dst = TRUE;

Modified: subversion/branches/1.7.x-issue4340-repos/subversion/libsvn_client/delete.c
URL: http://svn.apache.org/viewvc/subversion/branches/1.7.x-issue4340-repos/subversion/libsvn_client/delete.c?rev=1645439&r1=1645438&r2=1645439&view=diff
==============================================================================
--- subversion/branches/1.7.x-issue4340-repos/subversion/libsvn_client/delete.c (original)
+++ subversion/branches/1.7.x-issue4340-repos/subversion/libsvn_client/delete.c Sun Dec 14 11:44:03 2014
@@ -143,7 +143,7 @@ path_driver_cb_func(void **dir_baton,
 
 static svn_error_t *
 single_repos_delete(svn_ra_session_t *ra_session,
-                    const char *repos_root,
+                    const char *base_uri,
                     const apr_array_header_t *relpaths,
                     const apr_hash_t *revprop_table,
                     svn_commit_callback2_t commit_callback,
@@ -171,7 +171,7 @@ single_repos_delete(svn_ra_session_t *ra
           const char *relpath = APR_ARRAY_IDX(relpaths, i, const char *);
 
           item = svn_client_commit_item3_create(pool);
-          item->url = svn_path_url_add_component2(repos_root, relpath, pool);
+          item->url = svn_path_url_add_component2(base_uri, relpath, pool);
           item->state_flags = SVN_CLIENT_COMMIT_ITEM_DELETE;
           APR_ARRAY_PUSH(commit_items, svn_client_commit_item3_t *) = item;
         }
@@ -311,7 +311,6 @@ delete_urls_multi_repos(const apr_array_
   iterpool = svn_pool_create(pool);
   for (hi = apr_hash_first(pool, deletables); hi; hi = apr_hash_next(hi))
     {
-      const char *repos_root = svn__apr_hash_index_key(hi);
       struct repos_deletables_t *repos_deletables = svn__apr_hash_index_val(hi);
       const char *base_uri;
       apr_array_header_t *target_relpaths;
@@ -348,7 +347,7 @@ delete_urls_multi_repos(const apr_array_
         }
           
       SVN_ERR(svn_ra_reparent(repos_deletables->ra_session, base_uri, pool));
-      SVN_ERR(single_repos_delete(repos_deletables->ra_session, repos_root,
+      SVN_ERR(single_repos_delete(repos_deletables->ra_session, base_uri,
                                   target_relpaths,
                                   revprop_table, commit_callback,
                                   commit_baton, ctx, iterpool));

Modified: subversion/branches/1.7.x-issue4340-repos/subversion/libsvn_client/diff.c
URL: http://svn.apache.org/viewvc/subversion/branches/1.7.x-issue4340-repos/subversion/libsvn_client/diff.c?rev=1645439&r1=1645438&r2=1645439&view=diff
==============================================================================
--- subversion/branches/1.7.x-issue4340-repos/subversion/libsvn_client/diff.c (original)
+++ subversion/branches/1.7.x-issue4340-repos/subversion/libsvn_client/diff.c Sun Dec 14 11:44:03 2014
@@ -1494,11 +1494,55 @@ check_diff_target_exists(const char *url
   return SVN_NO_ERROR;
 }
 
+/* Resolve PATH_OR_URL@PEG_REVISION to a possibly different *RESOLVED_URL
+ * which the corresponding object has in REVISION. If the object has no
+ * location in REVISION, set *RESOLVED_URL to NULL. */
+static svn_error_t *
+resolve_pegged_diff_target_url(const char **resolved_url,
+                               svn_ra_session_t *ra_session,
+                               const char *path_or_url,
+                               const svn_opt_revision_t *peg_revision,
+                               const svn_opt_revision_t *revision,
+                               svn_client_ctx_t *ctx,
+                               apr_pool_t *scratch_pool)
+{
+  svn_opt_revision_t *start_rev_ignore, *end_rev_ignore;
+  const char *end_url_ignore;
+  static const svn_opt_revision_t unspecified_rev =
+    { svn_opt_revision_unspecified, { 0 } };
+  svn_error_t *err;
+
+  /* Check if the PATH_OR_URL exists at REVISION. */
+  err = svn_client__repos_locations(resolved_url, &start_rev_ignore,
+                                    &end_url_ignore, &end_rev_ignore,
+                                    ra_session,
+                                    path_or_url,
+                                    peg_revision,
+                                    revision,
+                                    &unspecified_rev,
+                                    ctx, scratch_pool);
+  if (err)
+    {
+      if (err->apr_err == SVN_ERR_CLIENT_UNRELATED_RESOURCES ||
+          err->apr_err == SVN_ERR_FS_NOT_FOUND)
+        {
+          svn_error_clear(err);
+          *resolved_url = NULL;
+        }
+      else
+        return svn_error_trace(err);
+    }
+
+  return SVN_NO_ERROR;
+}
+
 /** Prepare a repos repos diff between PATH1 and PATH2@PEG_REVISION,
  * in the revision range REVISION1:REVISION2.
  * Return URLs and peg revisions in *URL1, *REV1 and in *URL2, *REV2.
  * Return suitable anchors in *ANCHOR1 and *ANCHOR2, and targets in
  * *TARGET1 and *TARGET2, based on *URL1 and *URL2.
+ * Indicate the corresponding node kinds in *KIND1 and *KIND2, and verify
+ * that at least one of the diff targets exists.
  * Set *BASE_PATH corresponding to the URL opened in the new *RA_SESSION
  * which is pointing at *ANCHOR1.
  * Use client context CTX. Do all allocations in POOL. */
@@ -1512,6 +1556,8 @@ diff_prepare_repos_repos(const char **ur
                          const char **anchor2,
                          const char **target1,
                          const char **target2,
+                         svn_node_kind_t *kind1,
+                         svn_node_kind_t *kind2,
                          svn_ra_session_t **ra_session,
                          svn_client_ctx_t *ctx,
                          const char *path1,
@@ -1521,7 +1567,6 @@ diff_prepare_repos_repos(const char **ur
                          const svn_opt_revision_t *peg_revision,
                          apr_pool_t *pool)
 {
-  svn_node_kind_t kind1, kind2;
   const char *path2_abspath;
   const char *path1_abspath;
 
@@ -1560,53 +1605,56 @@ diff_prepare_repos_repos(const char **ur
      actual URLs will be. */
   if (peg_revision->kind != svn_opt_revision_unspecified)
     {
-      svn_opt_revision_t *start_ignore, *end_ignore;
-      svn_error_t *err;
+      const char *resolved_url1;
+      const char *resolved_url2;
 
-      err = svn_client__repos_locations(url1, &start_ignore,
-                                        url2, &end_ignore,
-                                        *ra_session,
-                                        path2,
-                                        peg_revision,
-                                        revision1,
-                                        revision2,
-                                        ctx, pool);
-      if (err)
-        {
-          if (err->apr_err == SVN_ERR_CLIENT_UNRELATED_RESOURCES)
-            {
-              /* Don't give up just yet. A missing path might translate
-               * into an addition in the diff. Below, we verify that each
-               * URL exists on at least one side of the diff. */
-              svn_error_clear(err);
-            }
-          else
-            return svn_error_trace(err);
+      SVN_ERR(resolve_pegged_diff_target_url(&resolved_url2, *ra_session,
+                                             path2, peg_revision,
+                                             revision2, ctx, pool));
+
+      SVN_ERR(svn_ra_reparent(*ra_session, *url1, pool));
+      SVN_ERR(resolve_pegged_diff_target_url(&resolved_url1, *ra_session,
+                                             path1, peg_revision,
+                                             revision1, ctx, pool));
+
+      /* Either or both URLs might have changed as a result of resolving
+       * the PATH_OR_URL@PEG_REVISION's history. If only one of the URLs
+       * could be resolved, use the same URL for URL1 and URL2, so we can
+       * show diff that 'adds' the object (see issue #4153). */
+      if (resolved_url2)
+        {
+          *url2 = resolved_url2;
+          if (!resolved_url1)
+            *url1 = resolved_url2;
         }
-      else
+      if (resolved_url1)
         {
-          /* Reparent the session, since *URL2 might have changed as a result
-             the above call. */
-          SVN_ERR(svn_ra_reparent(*ra_session, *url2, pool));
+          *url1 = resolved_url1;
+          if (!resolved_url2)
+            *url2 = resolved_url1;
         }
+
+      /* Reparent the session, since *URL2 might have changed as a result
+         the above call. */
+      SVN_ERR(svn_ra_reparent(*ra_session, *url2, pool));
     }
 
   /* Resolve revision and get path kind for the second target. */
   SVN_ERR(svn_client__get_revision_number(rev2, NULL, ctx->wc_ctx,
            (path2 == *url2) ? NULL : path2_abspath,
            *ra_session, revision2, pool));
-  SVN_ERR(svn_ra_check_path(*ra_session, "", *rev2, &kind2, pool));
+  SVN_ERR(svn_ra_check_path(*ra_session, "", *rev2, kind2, pool));
 
   /* Do the same for the first target. */
   SVN_ERR(svn_ra_reparent(*ra_session, *url1, pool));
   SVN_ERR(svn_client__get_revision_number(rev1, NULL, ctx->wc_ctx,
            (strcmp(path1, *url1) == 0) ? NULL : path1_abspath,
            *ra_session, revision1, pool));
-  SVN_ERR(svn_ra_check_path(*ra_session, "", *rev1, &kind1, pool));
+  SVN_ERR(svn_ra_check_path(*ra_session, "", *rev1, kind1, pool));
 
   /* Either both URLs must exist at their respective revisions,
    * or one of them may be missing from one side of the diff. */
-  if (kind1 == svn_node_none && kind2 == svn_node_none)
+  if (*kind1 == svn_node_none && *kind2 == svn_node_none)
     {
       if (strcmp(*url1, *url2) == 0)
         return svn_error_createf(SVN_ERR_FS_NOT_FOUND, NULL,
@@ -1620,9 +1668,9 @@ diff_prepare_repos_repos(const char **ur
                                    "'%ld'"),
                                  *url1, *url2, *rev1, *rev2);
     }
-  else if (kind1 == svn_node_none)
+  else if (*kind1 == svn_node_none)
     SVN_ERR(check_diff_target_exists(*url1, *rev2, *rev1, *ra_session, pool));
-  else if (kind2 == svn_node_none)
+  else if (*kind2 == svn_node_none)
     SVN_ERR(check_diff_target_exists(*url2, *rev1, *rev2, *ra_session, pool));
 
   /* Choose useful anchors and targets for our two URLs. */
@@ -1630,57 +1678,9 @@ diff_prepare_repos_repos(const char **ur
   *anchor2 = *url2;
   *target1 = "";
   *target2 = "";
-  if ((kind1 == svn_node_none) || (kind2 == svn_node_none))
-    {
-      svn_node_kind_t kind;
-      const char *repos_root;
-      const char *new_anchor;
-      svn_revnum_t rev;
-
-      /* The diff target does not exist on one side of the diff.
-       * This can happen if the target was added or deleted within the
-       * revision range being diffed.
-       * However, we don't know how deep within a added/deleted subtree the
-       * diff target is. Find a common parent that exists on both sides of
-       * the diff and use it as anchor for the diff operation.
-       *
-       * ### This can fail due to authz restrictions (like in issue #3242).
-       * ### But it is the only option we have right now to try to get
-       * ### a usable diff in this situation. */
-
-      SVN_ERR(svn_ra_get_repos_root2(*ra_session, &repos_root, pool));
-
-      /* Since we already know that one of the URLs does exist,
-       * look for an existing parent of the URL which doesn't exist. */
-      new_anchor = (kind1 == svn_node_none ? *anchor1 : *anchor2);
-      rev = (kind1 == svn_node_none ? *rev1 : *rev2);
-      do
-        {
-          if (strcmp(new_anchor, repos_root) != 0)
-            {
-              new_anchor = svn_path_uri_decode(svn_uri_dirname(new_anchor,
-                                                               pool),
-                                               pool);
-              if (*base_path)
-                *base_path = svn_dirent_dirname(*base_path, pool);
-            }
-
-          SVN_ERR(svn_ra_reparent(*ra_session, new_anchor, pool));
-          SVN_ERR(svn_ra_check_path(*ra_session, "", rev, &kind, pool));
-
-        }
-      while (kind != svn_node_dir);
-      *anchor1 = *anchor2 = new_anchor;
-      /* Diff targets must be relative to the new anchor. */
-      *target1 = svn_uri_skip_ancestor(new_anchor, *url1, pool);
-      *target2 = svn_uri_skip_ancestor(new_anchor, *url2, pool);
-      SVN_ERR_ASSERT(*target1 && *target2);
-      if (kind1 == svn_node_none)
-        kind1 = svn_node_dir;
-      else
-        kind2 = svn_node_dir;
-    }
-  else if ((kind1 == svn_node_file) || (kind2 == svn_node_file))
+
+  /* If one of the targets is a file, use the parent directory as anchor. */
+  if (*kind1 == svn_node_file || *kind2 == svn_node_file)
     {
       svn_uri_split(anchor1, target1, *url1, pool);
       svn_uri_split(anchor2, target2, *url2, pool);
@@ -1811,6 +1811,299 @@ diff_wc_wc(const char *path1,
   return SVN_NO_ERROR;
 }
 
+/* Create an array of regular properties in PROP_HASH, filtering entry-props
+ * and wc-props. Allocate the returned array in RESULT_POOL.
+ * Use SCRATCH_POOL for temporary allocations. */
+static apr_array_header_t *
+make_regular_props_array(apr_hash_t *prop_hash,
+                         apr_pool_t *result_pool,
+                         apr_pool_t *scratch_pool)
+{
+  apr_array_header_t *regular_props;
+  apr_hash_index_t *hi;
+
+  regular_props = apr_array_make(result_pool, 0, sizeof(svn_prop_t));
+  for (hi = apr_hash_first(scratch_pool, prop_hash); hi;
+       hi = apr_hash_next(hi))
+    {
+      const char *name = svn__apr_hash_index_key(hi);
+      svn_string_t *value = svn__apr_hash_index_val(hi);
+      svn_prop_kind_t prop_kind = svn_property_kind(NULL, name);
+
+      if (prop_kind == svn_prop_regular_kind)
+        {
+          svn_prop_t *prop = apr_palloc(scratch_pool, sizeof(svn_prop_t));
+
+          prop->name = name;
+          prop->value = value;
+          APR_ARRAY_PUSH(regular_props, svn_prop_t) = *prop;
+        }
+    }
+
+  return regular_props;
+}
+
+/* Create a hash of regular properties from PROP_HASH, filtering entry-props
+ * and wc-props. Allocate the returned hash in RESULT_POOL.
+ * Use SCRATCH_POOL for temporary allocations. */
+static apr_hash_t *
+make_regular_props_hash(apr_hash_t *prop_hash,
+                        apr_pool_t *result_pool,
+                        apr_pool_t *scratch_pool)
+{
+  apr_hash_t *regular_props;
+  apr_hash_index_t *hi;
+
+  regular_props = apr_hash_make(result_pool);
+  for (hi = apr_hash_first(scratch_pool, prop_hash); hi;
+       hi = apr_hash_next(hi))
+    {
+      const char *name = svn__apr_hash_index_key(hi);
+      svn_string_t *value = svn__apr_hash_index_val(hi);
+      svn_prop_kind_t prop_kind = svn_property_kind(NULL, name);
+
+      if (prop_kind == svn_prop_regular_kind)
+        apr_hash_set(regular_props, name, APR_HASH_KEY_STRING, value);
+    }
+
+  return regular_props;
+}
+
+/* Handle an added or deleted diff target file for a repos<->repos diff.
+ *
+ * Using the provided diff CALLBACKS and the CALLBACK_BATON, show the file
+ * TARGET@PEG_REVISION as added or deleted, depending on SHOW_DELETION.
+ * TARGET is a path relative to RA_SESSION's URL.
+ * REV1 and REV2 are the revisions being compared.
+ * Use SCRATCH_POOL for temporary allocations. */
+static svn_error_t *
+diff_repos_repos_added_or_deleted_file(const char *target,
+                                       svn_revnum_t peg_revision,
+                                       svn_revnum_t rev1,
+                                       svn_revnum_t rev2,
+                                       svn_boolean_t show_deletion,
+                                      const char *empty_file,
+                                       const svn_wc_diff_callbacks4_t
+                                         *callbacks,
+                                       struct diff_cmd_baton *callback_baton,
+                                       svn_ra_session_t *ra_session,
+                                       apr_pool_t *scratch_pool)
+{
+  const char *file_abspath;
+  svn_stream_t *content;
+  apr_hash_t *prop_hash;
+  svn_string_t *mimetype;
+
+  SVN_ERR(svn_stream_open_unique(&content, &file_abspath, NULL,
+                                 svn_io_file_del_on_pool_cleanup,
+                                 scratch_pool, scratch_pool));
+  SVN_ERR(svn_ra_get_file(ra_session, target, peg_revision, content, NULL,
+                          &prop_hash, scratch_pool));
+  SVN_ERR(svn_stream_close(content));
+
+  mimetype = apr_hash_get(prop_hash, SVN_PROP_MIME_TYPE, APR_HASH_KEY_STRING);
+
+  if (show_deletion)
+    {
+      SVN_ERR(callbacks->file_deleted(NULL, NULL,
+                                      target, file_abspath, empty_file,
+                                      mimetype ? mimetype->data : NULL,
+                                      NULL,
+                                      make_regular_props_hash(
+                                        prop_hash, scratch_pool, scratch_pool),
+                                      callback_baton, scratch_pool));
+    }
+  else
+    {
+      SVN_ERR(callbacks->file_added(NULL, NULL, NULL,
+                                    target, empty_file, file_abspath,
+                                    rev1, rev2, NULL,
+                                    mimetype ? mimetype->data : NULL,
+                                    NULL, SVN_INVALID_REVNUM,
+                                    make_regular_props_array(prop_hash,
+                                                             scratch_pool,
+                                                             scratch_pool),
+                                    NULL, callback_baton, scratch_pool));
+    }
+    
+  return SVN_NO_ERROR;
+}
+
+/* Handle an added or deleted diff target directory for a repos<->repos diff.
+ *
+ * Using the provided diff CALLBACKS and the CALLBACK_BATON, show the
+ * directory TARGET@PEG_REVISION, and all of its children, as added or deleted,
+ * depending on SHOW_DELETION. TARGET is a path relative to RA_SESSION's URL.
+ * REV1 and REV2 are the revisions being compared.
+ * Use SCRATCH_POOL for temporary allocations. */
+static svn_error_t *
+diff_repos_repos_added_or_deleted_dir(const char *target,
+                                      svn_revnum_t revision,
+                                      svn_revnum_t rev1,
+                                      svn_revnum_t rev2,
+                                      svn_boolean_t show_deletion,
+                                      const char *empty_file,
+                                      const svn_wc_diff_callbacks4_t
+                                        *callbacks,
+                                      struct diff_cmd_baton *callback_baton,
+                                      svn_ra_session_t *ra_session,
+                                      apr_pool_t *scratch_pool)
+{
+  apr_hash_t *dirents;
+  apr_hash_t *props;
+  apr_pool_t *iterpool;
+  apr_hash_index_t *hi;
+
+  SVN_ERR(svn_ra_get_dir2(ra_session, &dirents, NULL, &props,
+                          target, revision, SVN_DIRENT_KIND,
+                          scratch_pool));
+
+  if (show_deletion)
+    SVN_ERR(callbacks->dir_deleted(NULL, NULL, target, callback_baton,
+                                   scratch_pool));
+  else
+    SVN_ERR(callbacks->dir_added(NULL, NULL, NULL, NULL,
+                                 target, revision,
+                                 NULL, SVN_INVALID_REVNUM,
+                                 callback_baton, scratch_pool));
+  if (props)
+    {
+      if (show_deletion)
+        SVN_ERR(callbacks->dir_props_changed(NULL, NULL, target, FALSE,
+                                             apr_array_make(scratch_pool, 0,
+                                                            sizeof(svn_prop_t)),
+                                             make_regular_props_hash(
+                                               props, scratch_pool,
+                                               scratch_pool),
+                                             callback_baton, scratch_pool));
+      else
+        SVN_ERR(callbacks->dir_props_changed(NULL, NULL, target, TRUE,
+                                             make_regular_props_array(
+                                               props, scratch_pool,
+                                               scratch_pool),
+                                             NULL,
+                                             callback_baton, scratch_pool));
+    }
+
+  iterpool = svn_pool_create(scratch_pool);
+  for (hi = apr_hash_first(scratch_pool, dirents); hi; hi = apr_hash_next(hi))
+    {
+      const char *name = svn__apr_hash_index_key(hi);
+      svn_dirent_t *dirent = svn__apr_hash_index_val(hi);
+      const char *child_target;
+
+      svn_pool_clear(iterpool);
+
+      child_target = svn_relpath_join(target, name, iterpool);
+
+      if (dirent->kind == svn_node_dir)
+        SVN_ERR(diff_repos_repos_added_or_deleted_dir(child_target,
+                                                      revision, rev1, rev2,
+                                                      show_deletion,
+                                                      empty_file,
+                                                      callbacks,
+                                                      callback_baton,
+                                                      ra_session,
+                                                      iterpool));
+      else if (dirent->kind == svn_node_file)
+        SVN_ERR(diff_repos_repos_added_or_deleted_file(child_target,
+                                                       revision, rev1, rev2,
+                                                       show_deletion,
+                                                       empty_file,
+                                                       callbacks,
+                                                       callback_baton,
+                                                       ra_session,
+                                                       iterpool));
+    }
+  svn_pool_destroy(iterpool);
+
+  if (!show_deletion)
+    SVN_ERR(callbacks->dir_closed(NULL, NULL, NULL, target, TRUE,
+                                  callback_baton, scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+
+/* Handle an added or deleted diff target for a repos<->repos diff.
+ *
+ * Using the provided diff CALLBACKS and the CALLBACK_BATON, show
+ * TARGET@PEG_REVISION, and all of its children, if any, as added or deleted.
+ * TARGET is a path relative to RA_SESSION's URL.
+ * REV1 and REV2 are the revisions being compared.
+ * Use SCRATCH_POOL for temporary allocations. */
+static svn_error_t *
+diff_repos_repos_added_or_deleted_target(const char *target1,
+                                         const char *target2,
+                                         svn_revnum_t rev1,
+                                         svn_revnum_t rev2,
+                                         svn_node_kind_t kind1,
+                                         svn_node_kind_t kind2,
+                                         const svn_wc_diff_callbacks4_t
+                                           *callbacks,
+                                         struct diff_cmd_baton *callback_baton,
+                                         svn_ra_session_t *ra_session,
+                                         apr_pool_t *scratch_pool)
+{
+  const char *existing_target;
+  svn_revnum_t existing_rev;
+  svn_node_kind_t existing_kind;
+  svn_boolean_t show_deletion;
+  const char *empty_file;
+
+  SVN_ERR_ASSERT(kind1 == svn_node_none || kind2 == svn_node_none);
+
+  /* Are we showing an addition or deletion? */
+  show_deletion = (kind2 == svn_node_none);
+
+  /* Which target is being added/deleted? Is it a file or a directory? */
+  if (show_deletion)
+    {
+      existing_target = target1;
+      existing_rev = rev1;
+      existing_kind = kind1;
+    }
+  else
+    {
+      existing_target = target2;
+      existing_rev = rev2;
+      existing_kind = kind2;
+    }
+
+  /* All file content will be diffed against the empty file. */
+  SVN_ERR(svn_io_open_unique_file3(NULL, &empty_file, NULL,
+                                   svn_io_file_del_on_pool_cleanup,
+                                   scratch_pool, scratch_pool));
+
+  if (existing_kind == svn_node_file)
+    {
+      /* Get file content and show a diff against the empty file. */
+      SVN_ERR(diff_repos_repos_added_or_deleted_file(existing_target,
+                                                     existing_rev,
+                                                     rev1, rev2,
+                                                     show_deletion,
+                                                     empty_file,
+                                                     callbacks,
+                                                     callback_baton,
+                                                     ra_session,
+                                                     scratch_pool));
+    }
+  else
+    {
+      /* Walk the added/deleted tree and show a diff for each child. */
+      SVN_ERR(diff_repos_repos_added_or_deleted_dir(existing_target,
+                                                    existing_rev,
+                                                    rev1, rev2,
+                                                    show_deletion,
+                                                    empty_file,
+                                                    callbacks,
+                                                    callback_baton,
+                                                    ra_session,
+                                                    scratch_pool));
+    }
+
+  return SVN_NO_ERROR;
+}
 
 /* Perform a diff between two repository paths.
 
@@ -1847,6 +2140,8 @@ diff_repos_repos(const svn_wc_diff_callb
   const char *base_path;
   svn_revnum_t rev1;
   svn_revnum_t rev2;
+  svn_node_kind_t kind1;
+  svn_node_kind_t kind2;
   const char *anchor1;
   const char *anchor2;
   const char *target1;
@@ -1856,7 +2151,8 @@ diff_repos_repos(const svn_wc_diff_callb
   /* Prepare info for the repos repos diff. */
   SVN_ERR(diff_prepare_repos_repos(&url1, &url2, &base_path, &rev1, &rev2,
                                    &anchor1, &anchor2, &target1, &target2,
-                                   &ra_session, ctx, path1, path2,
+                                   &kind1, &kind2, &ra_session,
+                                   ctx, path1, path2,
                                    revision1, revision2, peg_revision,
                                    pool));
 
@@ -1871,6 +2167,21 @@ diff_repos_repos(const svn_wc_diff_callb
   callback_baton->ra_session = ra_session;
   callback_baton->anchor = base_path;
 
+  if (kind1 == svn_node_none || kind2 == svn_node_none)
+    {
+      /* One side of the diff does not exist.
+       * Walk the tree that does exist, showing a series of additions
+       * or deletions. */
+      SVN_ERR(diff_repos_repos_added_or_deleted_target(target1, target2,
+                                                       rev1, rev2,
+                                                       kind1, kind2,
+                                                       callbacks,
+                                                       callback_baton,
+                                                       ra_session,
+                                                       pool));
+      return SVN_NO_ERROR;
+    }
+
   /* Now, we open an extra RA session to the correct anchor
      location for URL1.  This is used during the editor calls to fetch file
      contents.  */
@@ -1904,6 +2215,204 @@ diff_repos_repos(const svn_wc_diff_callb
 }
 
 
+/* Using CALLBACKS, show a REPOS->WC diff for a file TARGET, which in the
+ * working copy is at FILE2_ABSPATH. KIND1 is the node kind of the repository
+ * target (either svn_node_file or svn_node_none). REV is the revision the
+ * working file is diffed against. RA_SESSION points at the URL of the file
+ * in the repository and is used to get the file's repository-version content,
+ * if necessary. If DIFF_WITH_BASE is set, diff against the BASE version of
+ * the local file instead of WORKING.
+ * The other parameters are as in diff_repos_wc(). */
+static svn_error_t *
+diff_repos_wc_file_target(const char *target,
+                          const char *file2_abspath,
+                          svn_node_kind_t kind1,
+                          svn_revnum_t rev,
+                          svn_boolean_t reverse,
+                          svn_boolean_t show_copies_as_adds,
+                          svn_boolean_t diff_with_base,
+                          const svn_wc_diff_callbacks4_t *callbacks,
+                          void *callback_baton,
+                          svn_ra_session_t *ra_session,
+                          svn_client_ctx_t *ctx,
+                          apr_pool_t *scratch_pool)
+{
+  const char *file1_abspath;
+  svn_stream_t *file1_content;
+  svn_stream_t *file2_content;
+  apr_hash_t *file1_props = NULL;
+  apr_hash_t *file2_props;
+  svn_boolean_t is_copy = FALSE;
+  svn_string_t *mimetype1, *mimetype2;
+
+  /* Get content and props of file 1 (the remote file). */
+  SVN_ERR(svn_stream_open_unique(&file1_content, &file1_abspath, NULL,
+                                 svn_io_file_del_on_pool_cleanup,
+                                 scratch_pool, scratch_pool));
+  if (kind1 == svn_node_file)
+    {
+      if (show_copies_as_adds)
+        SVN_ERR(svn_wc__node_get_origin(&is_copy, 
+                                        NULL, NULL, NULL, NULL, NULL,
+                                        ctx->wc_ctx, file2_abspath,
+                                        FALSE, scratch_pool, scratch_pool));
+      /* If showing copies as adds, diff against the empty file. */
+      if (!(show_copies_as_adds && is_copy))
+        SVN_ERR(svn_ra_get_file(ra_session, "", rev, file1_content,
+                                NULL, &file1_props, scratch_pool));
+    }
+
+  SVN_ERR(svn_stream_close(file1_content));
+
+  /* Get content and props of file 2 (the local file). */
+  if (diff_with_base)
+    {
+      svn_stream_t *pristine_content;
+
+      SVN_ERR(svn_wc_get_pristine_props(&file2_props, ctx->wc_ctx,
+                                        file2_abspath, scratch_pool,
+                                        scratch_pool));
+
+      /* ### We need a filename, but this API returns an opaque stream.
+       * ### This requires us to copy to a temporary file. Maybe libsvn_wc
+       * ### should also provide an API that returns a path to a file that
+       * ### contains pristine content, possibly temporary? */
+      SVN_ERR(svn_wc_get_pristine_contents2(&pristine_content,
+                                            ctx->wc_ctx,
+                                            file2_abspath,
+                                            scratch_pool, scratch_pool));
+
+      SVN_ERR(svn_stream_open_unique(&file2_content, &file2_abspath, NULL,
+                                     svn_io_file_del_on_pool_cleanup,
+                                     scratch_pool, scratch_pool));
+      SVN_ERR(svn_stream_copy3(pristine_content, file2_content,
+                               ctx->cancel_func, ctx->cancel_baton,
+                               scratch_pool));
+    }
+  else
+    {
+      apr_hash_t *keywords = NULL;
+      svn_string_t *keywords_prop;
+      svn_string_t *eol_prop;
+      svn_subst_eol_style_t eol_style;
+      const char *eol_str;
+
+      SVN_ERR(svn_wc_prop_list2(&file2_props, ctx->wc_ctx, file2_abspath,
+                                scratch_pool, scratch_pool));
+
+      /* We might have to create a normalised version of the working file. */
+      eol_prop = apr_hash_get(file2_props, SVN_PROP_EOL_STYLE,
+                              APR_HASH_KEY_STRING);
+      svn_subst_eol_style_from_value(&eol_style, &eol_str,
+                                     eol_prop ? eol_prop->data : NULL);
+      keywords_prop = apr_hash_get(file2_props, SVN_PROP_KEYWORDS,
+                                   APR_HASH_KEY_STRING);
+      if (keywords_prop)
+        SVN_ERR(svn_subst_build_keywords2(&keywords, keywords_prop->data,
+                                          NULL, NULL, 0, NULL,
+                                          scratch_pool));
+      if (svn_subst_translation_required(eol_style, eol_str,
+                                         keywords, FALSE, TRUE))
+        {
+          svn_stream_t *working_content;
+          svn_stream_t *normalized_content;
+
+          if (eol_style == svn_subst_eol_style_native)
+            eol_str = SVN_SUBST_NATIVE_EOL_STR;
+          else if (! (eol_style == svn_subst_eol_style_fixed
+                      || eol_style == svn_subst_eol_style_none))
+            return svn_error_create(SVN_ERR_IO_UNKNOWN_EOL, NULL, NULL);
+
+          SVN_ERR(svn_stream_open_readonly(&working_content, file2_abspath,
+                                           scratch_pool, scratch_pool));
+
+          /* Create a temporary file and copy normalised data into it. */
+          SVN_ERR(svn_stream_open_unique(&file2_content, &file2_abspath, NULL,
+                                         svn_io_file_del_on_pool_cleanup,
+                                         scratch_pool, scratch_pool));
+          normalized_content = svn_subst_stream_translated(
+                                 file2_content, eol_str,
+                                 eol_style == svn_subst_eol_style_fixed,
+                                 keywords, FALSE, scratch_pool);
+          SVN_ERR(svn_stream_copy3(working_content, normalized_content,
+                                   ctx->cancel_func, ctx->cancel_baton,
+                                   scratch_pool));
+        }
+    }
+
+  mimetype1 = file1_props ? apr_hash_get(file1_props, SVN_PROP_MIME_TYPE,
+                                         APR_HASH_KEY_STRING)
+                          : NULL;
+  mimetype2 = apr_hash_get(file2_props, SVN_PROP_MIME_TYPE,
+                           APR_HASH_KEY_STRING);
+
+  if (kind1 == svn_node_file && !(show_copies_as_adds && is_copy))
+    {
+      apr_array_header_t *propchanges;
+
+      SVN_ERR(callbacks->file_opened(NULL, NULL, target,
+                                     reverse ? SVN_INVALID_REVNUM : rev,
+                                     callback_baton, scratch_pool));
+
+      if (reverse)
+        {
+          SVN_ERR(svn_prop_diffs(&propchanges, file1_props, file2_props,
+                                 scratch_pool));
+
+          SVN_ERR(callbacks->file_changed(NULL, NULL, NULL, target,
+                                          file2_abspath, file1_abspath,
+                                          SVN_INVALID_REVNUM, rev,
+                                          mimetype2 ? mimetype2->data : NULL,
+                                          mimetype1 ? mimetype1->data : NULL,
+                                          propchanges, file2_props,
+                                          callback_baton, scratch_pool));
+        }
+      else
+        {
+          SVN_ERR(svn_prop_diffs(&propchanges, file2_props, file1_props,
+                                 scratch_pool));
+
+          SVN_ERR(callbacks->file_changed(NULL, NULL, NULL, target,
+                                          file1_abspath, file2_abspath,
+                                          rev, SVN_INVALID_REVNUM,
+                                          mimetype1 ? mimetype1->data : NULL,
+                                          mimetype2 ? mimetype2->data : NULL,
+                                          propchanges, file1_props,
+                                          callback_baton, scratch_pool));
+        }
+    }
+  else
+    {
+      if (reverse)
+        {
+          SVN_ERR(callbacks->file_deleted(NULL, NULL,
+                                          target, file2_abspath, file1_abspath,
+                                          mimetype2 ? mimetype2->data : NULL,
+                                          NULL,
+                                          make_regular_props_hash(
+                                            file2_props, scratch_pool,
+                                            scratch_pool),
+                                          callback_baton, scratch_pool));
+        }
+      else
+        {
+          SVN_ERR(callbacks->file_added(NULL, NULL, NULL, target,
+                                        file1_abspath, file2_abspath,
+                                        rev, SVN_INVALID_REVNUM,
+                                        NULL,
+                                        mimetype2 ? mimetype2->data : NULL,
+                                        NULL, SVN_INVALID_REVNUM,
+                                        make_regular_props_array(
+                                          file2_props, scratch_pool,
+                                          scratch_pool),
+                                        NULL,
+                                        callback_baton, scratch_pool));
+        }
+    }
+
+  return SVN_NO_ERROR;
+}
+
 /* Perform a diff between a repository path and a working-copy path.
 
    PATH1 may be either a URL or a working copy path.  PATH2 is a
@@ -1944,6 +2453,8 @@ diff_repos_wc(const char *path1,
   const char *abspath1;
   const char *abspath2;
   const char *anchor_abspath;
+  svn_node_kind_t kind1;
+  svn_node_kind_t kind2;
 
   SVN_ERR_ASSERT(! svn_path_is_url(path2));
 
@@ -2000,22 +2511,53 @@ diff_repos_wc(const char *path1,
         }
     }
 
-  /* Establish RA session to path2's anchor */
-  SVN_ERR(svn_client__open_ra_session_internal(&ra_session, NULL, anchor_url,
-                                               NULL, NULL, FALSE, TRUE,
-                                               ctx, pool));
-  callback_baton->ra_session = ra_session;
   if (use_git_diff_format)
     {
       SVN_ERR(svn_wc__get_wc_root(&callback_baton->wc_root_abspath,
                                   ctx->wc_ctx, anchor_abspath,
                                   pool, pool));
     }
+
+  /* Open an RA session to URL1 to figure out its node kind. */
+  SVN_ERR(svn_client__open_ra_session_internal(&ra_session, NULL, url1,
+                                               NULL, NULL, FALSE, TRUE,
+                                               ctx, pool));
+  /* Resolve the revision to use for URL1. */
+  SVN_ERR(svn_client__get_revision_number(&rev, NULL, ctx->wc_ctx,
+                                          (strcmp(path1, url1) == 0)
+                                                    ? NULL : abspath1,
+                                          ra_session, revision1, pool));
+  SVN_ERR(svn_ra_check_path(ra_session, "", rev, &kind1, pool));
+
+  /* Figure out the node kind of the local target. */
+  SVN_ERR(svn_io_check_resolved_path(abspath2, &kind2, pool));
+
+  callback_baton->ra_session = ra_session;
   callback_baton->anchor = anchor;
 
+  if (!reverse)
+    callback_baton->revnum1 = rev;
+  else
+    callback_baton->revnum2 = rev;
+
+  /* If both diff targets can be diffed as files, fetch the file from the
+   * repository and generate a diff against the local version of the file. */
+  if ((kind1 == svn_node_file || kind1 == svn_node_none)
+       && kind2 == svn_node_file)
+    {
+      SVN_ERR(diff_repos_wc_file_target(target, abspath2, kind1, rev,
+                                        reverse, show_copies_as_adds,
+                                        rev2_is_base,
+                                        callbacks, callback_baton,
+                                        ra_session, ctx, pool));
+
+      return SVN_NO_ERROR;
+    }
+
+  /* Else, use the diff editor to generate the diff. */
+  SVN_ERR(svn_ra_reparent(ra_session, anchor_url, pool));
   SVN_ERR(svn_ra_has_capability(ra_session, &server_supports_depth,
                                 SVN_RA_CAPABILITY_DEPTH, pool));
-
   SVN_ERR(svn_wc_get_diff_editor6(&diff_editor, &diff_edit_baton,
                                   ctx->wc_ctx,
                                   anchor_abspath,
@@ -2032,22 +2574,12 @@ diff_repos_wc(const char *path1,
                                   ctx->cancel_func, ctx->cancel_baton,
                                   pool, pool));
 
-  /* Tell the RA layer we want a delta to change our txn to URL1 */
-  SVN_ERR(svn_client__get_revision_number(&rev, NULL, ctx->wc_ctx,
-                                          (strcmp(path1, url1) == 0)
-                                                    ? NULL : abspath1,
-                                          ra_session, revision1, pool));
-
-  if (!reverse)
-    callback_baton->revnum1 = rev;
-  else
-    callback_baton->revnum2 = rev;
-
   if (depth != svn_depth_infinity)
     diff_depth = depth;
   else
     diff_depth = svn_depth_unknown;
 
+  /* Tell the RA layer we want a delta to change our txn to URL1 */ 
   SVN_ERR(svn_ra_do_diff3(ra_session,
                           &reporter, &reporter_baton,
                           rev,
@@ -2136,6 +2668,7 @@ do_diff(const svn_wc_diff_callbacks4_t *
   return SVN_NO_ERROR;
 }
 
+
 /* Perform a diff summary between two repository paths. */
 static svn_error_t *
 diff_summarize_repos_repos(svn_client_diff_summarize_func_t summarize_func,
@@ -2163,6 +2696,8 @@ diff_summarize_repos_repos(svn_client_di
   const char *base_path;
   svn_revnum_t rev1;
   svn_revnum_t rev2;
+  svn_node_kind_t kind1;
+  svn_node_kind_t kind2;
   const char *anchor1;
   const char *anchor2;
   const char *target1;
@@ -2172,10 +2707,32 @@ diff_summarize_repos_repos(svn_client_di
   /* Prepare info for the repos repos diff. */
   SVN_ERR(diff_prepare_repos_repos(&url1, &url2, &base_path, &rev1, &rev2,
                                    &anchor1, &anchor2, &target1, &target2,
-                                   &ra_session, ctx,
-                                   path1, path2, revision1, revision2,
+                                   &kind1, &kind2, &ra_session,
+                                   ctx, path1, path2,
+                                   revision1, revision2,
                                    peg_revision, pool));
 
+  if (kind1 == svn_node_none || kind2 == svn_node_none)
+    {
+      svn_wc_diff_callbacks4_t *callbacks;
+      void *callback_baton;
+
+      /* One side of the diff does not exist.
+       * Walk the tree that does exist, showing a series of additions
+       * or deletions. */
+      SVN_ERR(svn_client__get_diff_summarize_callbacks(
+                &callbacks, &callback_baton, target1,
+                summarize_func, summarize_baton, pool));
+      SVN_ERR(diff_repos_repos_added_or_deleted_target(target1, target2,
+                                                       rev1, rev2,
+                                                       kind1, kind2,
+                                                       callbacks,
+                                                       callback_baton,
+                                                       ra_session,
+                                                       pool));
+      return SVN_NO_ERROR;
+    }
+
   /* Now, we open an extra RA session to the correct anchor
      location for URL1.  This is used to get the kind of deleted paths.  */
   SVN_ERR(svn_client__open_ra_session_internal(&extra_ra_session, NULL,