Index: subversion/include/private/svn_client_private.h
===================================================================
--- subversion/include/private/svn_client_private.h	(revision 0)
+++ subversion/include/private/svn_client_private.h	(revision 0)
@@ -0,0 +1,43 @@
+/**
+ * @copyright
+ * ====================================================================
+ * Copyright (c) 2007 CollabNet.  All rights reserved.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution.  The terms
+ * are also available at http://subversion.tigris.org/license-1.html.
+ * If newer versions of this license are posted there, you may use a
+ * newer version instead, at your option.
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals.  For exact contribution history, see the revision
+ * history and logs, available at http://subversion.tigris.org/.
+ * ====================================================================
+ * @endcopyright
+ *
+ * @file svn_client_private.h
+ * @brief The internal (protected) interface for Subversion's client library
+ */
+
+#ifndef SVN_CLIENT_PRIVATE_H
+#define SVN_CLIENT_PRIVATE_H
+
+#include "svn_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+svn_error_t *
+svn_client_copyfrom_info(const char *path_or_url,
+                         const svn_opt_revision_t *rev,
+                         const char **copyfrom_path,
+                         svn_revnum_t *copyfrom_rev,
+                         svn_client_ctx_t *ctx,
+                         apr_pool_t *pool);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* SVN_CLIENT_PRIVATE_H */
Index: subversion/libsvn_client/log.c
===================================================================
--- subversion/libsvn_client/log.c	(revision 24276)
+++ subversion/libsvn_client/log.c	(working copy)
@@ -35,12 +35,120 @@
 #include "svn_path.h"
 
 #include "svn_private_config.h"
+#include "private/svn_client_private.h"
 #include "private/svn_wc_private.h"
 
 
-/*** Getting update information ***/
+/*** Getting misc. information ***/
 
+/* The baton for use with copyfrom_receiver. */
+typedef struct
+{
+  const char *target_path;
+  const char *path;
+  svn_revnum_t rev;
+} copyfrom_info_t;
 
+/* A log callback conforming to the svn_log_message_receiver_t
+   interface for obtaining the last revision of a node at a path and
+   storing it in *BATON (an svn_revnum_t). */
+static svn_error_t *
+copyfrom_receiver(void *baton,
+                  apr_hash_t *changed_paths,
+                  svn_revnum_t revision,
+                  const char *author,
+                  const char *date,
+                  const char *message,
+                  apr_pool_t *pool)
+{
+  copyfrom_info_t *copyfrom_info = baton;
+  if (copyfrom_info->path)
+    return SVN_NO_ERROR;
+
+  printf("Processing revision %ld for target path '%s'\n", revision,
+         copyfrom_info->target_path);
+
+  if (changed_paths)
+    {
+      apr_hash_index_t *hi;
+      char *path;
+      svn_log_changed_path_t *log_item;
+
+      for (hi = apr_hash_first(NULL, changed_paths);
+           hi;
+           hi = apr_hash_next(hi))
+        {
+          void *val;
+          apr_hash_this(hi, (void *) &path, NULL, &val);
+          log_item = val;
+
+          /* ### FIXME: Look for moved parent paths of target_path. */
+          if (log_item->copyfrom_path &&
+              SVN_IS_VALID_REVNUM(log_item->copyfrom_rev) &&
+              strcmp(copyfrom_info->target_path, path) == 0)
+            {
+              copyfrom_info->path = log_item->copyfrom_path;
+              copyfrom_info->rev = log_item->copyfrom_rev;
+            }
+        }
+    }
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_client_copyfrom_info(const char *path_or_url,
+                         const svn_opt_revision_t *rev,
+                         const char **copyfrom_path,
+                         svn_revnum_t *copyfrom_rev,
+                         svn_client_ctx_t *ctx,
+                         apr_pool_t *pool)
+{
+  svn_error_t *err;
+  copyfrom_info_t copyfrom_info = { NULL, NULL, SVN_INVALID_REVNUM };
+  apr_array_header_t *rel_paths = apr_array_make(pool, 1, sizeof(path_or_url));
+  svn_opt_revision_t oldest_rev;
+
+  oldest_rev.kind = svn_opt_revision_number;
+  oldest_rev.value.number = 1;
+
+  {
+    svn_ra_session_t *ra_session;
+    svn_revnum_t at_rev;
+    const char *at_url;
+    SVN_ERR(svn_client__ra_session_from_path(&ra_session, &at_rev, &at_url,
+                                             path_or_url, rev, rev, ctx,
+                                             pool));
+
+    SVN_ERR(svn_client__path_relative_to_root(&copyfrom_info.target_path,
+                                              path_or_url, NULL, ra_session,
+                                              NULL, pool));
+  }
+
+  APR_ARRAY_PUSH(rel_paths, const char *) = path_or_url;
+
+  /* Find the copy source. */
+  err = svn_client_log3(rel_paths, rev, rev, &oldest_rev, 0, TRUE, TRUE,
+                        copyfrom_receiver, &copyfrom_info, ctx, pool);
+  if (err)
+    {
+      if (err->apr_err == SVN_ERR_FS_NOT_FOUND ||
+          err->apr_err == SVN_ERR_RA_DAV_REQUEST_FAILED)
+        {
+          /* A locally-added but uncommitted versioned resource won't
+             exist in the repository. */
+          svn_error_clear(err);
+          err = SVN_NO_ERROR;
+        }
+
+      return err;
+    }
+
+  *copyfrom_path = copyfrom_info.path;
+  *copyfrom_rev = copyfrom_info.rev;
+  return SVN_NO_ERROR;
+}
+
 
 /*** Public Interface. ***/
 
@@ -257,13 +365,16 @@
           {
             const char *target = APR_ARRAY_IDX(targets, i, const char *);
 
+printf("DLR: 1\n");
             if (start_is_local)
               SVN_ERR(svn_client__get_revision_number
                       (&start_revnum, ra_session, start, target, pool));
+printf("DLR: 2\n");
             
             if (end_is_local)
               SVN_ERR(svn_client__get_revision_number
                       (&end_revnum, ra_session, end, target, pool));
+printf("DLR: 3\n");
 
             err = svn_ra_get_log(ra_session,
                                  condensed_targets,
Index: subversion/bindings/java/javahl/native/Revision.cpp
===================================================================
--- subversion/bindings/java/javahl/native/Revision.cpp	(revision 24276)
+++ subversion/bindings/java/javahl/native/Revision.cpp	(working copy)
@@ -195,7 +195,32 @@
 {
 
 }
+
 const svn_opt_revision_t *Revision::revision () const
 {
     return &m_revision;
 }
+
+jobject
+Revision::makeJRevision(svn_revnum_t rev)
+{
+    JNIEnv *env = JNIUtil::getEnv();
+    jclass clazz = env->FindClass(JAVA_PACKAGE "/Revision");
+    if (JNIUtil::isJavaExceptionThrown())
+        return NULL;
+
+    static jmethodID getInstance = 0;
+    if (getInstance == 0)
+    {
+        getInstance = env->GetStaticMethodID(clazz, "getInstance",
+                                             "(J)L" JAVA_PACKAGE "/Revision;");
+        if (JNIUtil::isExceptionThrown())
+            return NULL;
+    }
+
+    jobject jrevision = env->CallStaticObjectMethod(clazz, getInstance,
+                                                    (jlong) rev);
+    if (JNIUtil::isExceptionThrown())
+        return NULL;
+    return jrevision;
+}
Index: subversion/bindings/java/javahl/native/SVNClient.cpp
===================================================================
--- subversion/bindings/java/javahl/native/SVNClient.cpp	(revision 24276)
+++ subversion/bindings/java/javahl/native/SVNClient.cpp	(working copy)
@@ -28,7 +28,7 @@
 #include "ProgressListener.h"
 #include "Prompter.h"
 #include "Pool.h"
-#include "Targets.h"
+ #include "Targets.h"
 #include "Revision.h"
 #include "BlameCallback.h"
 #include "ProplistCallback.h"
@@ -45,6 +45,7 @@
 #include "svn_io.h"
 #include "svn_path.h"
 #include "svn_utf.h"
+#include "private/svn_client_private.h"
 #include "svn_private_config.h"
 #include "../include/org_tigris_subversion_javahl_Revision.h"
 #include "../include/org_tigris_subversion_javahl_NodeKind.h"
@@ -2638,3 +2639,24 @@
     }
     return ret;
 }
+
+jobject
+SVNClient::getCopySource(const char *path, Revision &revision)
+{
+    Pool requestPool;
+    svn_client_ctx_t *ctx = getContext(NULL);
+    if (ctx == NULL)
+        return NULL;
+    const char *copyfromPath;
+    svn_revnum_t copyfromRev;
+    svn_error_t *err = svn_client_copyfrom_info(path, revision.revision(),
+                                                &copyfromPath, &copyfromRev,
+                                                ctx, requestPool.pool());
+    if (err)
+    {
+        JNIUtil::handleSVNError(err);
+        return NULL;
+    }
+    return CopySources::makeJCopySource(copyfromPath, copyfromRev,
+                                        requestPool);
+}
Index: subversion/bindings/java/javahl/native/CopySources.h
===================================================================
--- subversion/bindings/java/javahl/native/CopySources.h	(revision 24276)
+++ subversion/bindings/java/javahl/native/CopySources.h	(working copy)
@@ -54,6 +54,12 @@
      */
     apr_array_header_t *array(Pool &pool);
 
+    /**
+     * Make a (single) CopySource Java object.
+     */
+    static jobject makeJCopySource(const char *path, svn_revnum_t rev,
+                                   Pool &pool);
+
 private:
     /**
      * A local reference to the Java CopySources peer.
Index: subversion/bindings/java/javahl/native/org_tigris_subversion_javahl_SVNClient.cpp
===================================================================
--- subversion/bindings/java/javahl/native/org_tigris_subversion_javahl_SVNClient.cpp	(revision 24276)
+++ subversion/bindings/java/javahl/native/org_tigris_subversion_javahl_SVNClient.cpp	(working copy)
@@ -1695,7 +1695,7 @@
 
 JNIEXPORT jobject JNICALL
 Java_org_tigris_subversion_javahl_SVNClient_getCopySource
-  (JNIEnv *env, jobject jthis, jstring path)
+  (JNIEnv *env, jobject jthis, jstring jpath, jobject jrevision)
 {
     JNIEntry(SVNClient, getCopySource);
     SVNClient *cl = SVNClient::getCppObject(jthis);
@@ -1704,8 +1704,15 @@
         JNIUtil::throwError("bad c++ this");
         return NULL;
     }
-    // ### TODO: Implement me!
-    return NULL;
+
+    JNIStringHolder path(jpath);
+    if (JNIUtil::isExceptionThrown())
+        return NULL;
+    Revision rev(jrevision);
+    if (JNIUtil::isExceptionThrown())
+        return NULL;
+
+    return cl->getCopySource(path, rev);
 }
 
 JNIEXPORT void JNICALL
Index: subversion/bindings/java/javahl/native/Revision.h
===================================================================
--- subversion/bindings/java/javahl/native/Revision.h	(revision 24276)
+++ subversion/bindings/java/javahl/native/Revision.h	(working copy)
@@ -36,12 +36,18 @@
 public:
     static const svn_opt_revision_kind START;
     static const svn_opt_revision_kind HEAD;
+
     Revision(jobject jthis, bool headIfUnspecified = false,
              bool oneIfUnspecified = false);
     Revision(const svn_opt_revision_kind kind = svn_opt_revision_unspecified);
     ~Revision();
+
     const svn_opt_revision_t *revision() const;
 
+    /**
+     * Make a Revision Java object.
+     */
+    static jobject makeJRevision(svn_revnum_t rev);
 };
 // !defined(AFX_REVISION_H__BEAA0788_C9D9_4A67_B94E_761ABC68ACFE__INCLUDED_)
 #endif
Index: subversion/bindings/java/javahl/native/SVNClient.h
===================================================================
--- subversion/bindings/java/javahl/native/SVNClient.h	(revision 24276)
+++ subversion/bindings/java/javahl/native/SVNClient.h	(working copy)
@@ -49,6 +49,7 @@
 public:
     jobjectArray info2(const char *path, Revision &revision,
                        Revision &pegRevision, bool recurse);
+    jobject getCopySource(const char *path, Revision &revision);
     void unlock(Targets &targets, bool force);
     void lock(Targets &targets, const char *comment, bool force);
     jobjectArray revProperties(jobject jthis, const char *path,
Index: subversion/bindings/java/javahl/native/CopySources.cpp
===================================================================
--- subversion/bindings/java/javahl/native/CopySources.cpp	(revision 24276)
+++ subversion/bindings/java/javahl/native/CopySources.cpp	(working copy)
@@ -40,6 +40,37 @@
     // explicitly managed.
 }
 
+jobject
+CopySources::makeJCopySource(const char *path, svn_revnum_t rev, Pool &pool)
+{
+    JNIEnv *env = JNIUtil::getEnv();
+
+    jobject jpath = JNIUtil::makeJString(path);
+    if (JNIUtil::isJavaExceptionThrown())
+        return NULL;
+    jobject jrevision = Revision::makeJRevision(rev);
+    if (JNIUtil::isJavaExceptionThrown())
+        return NULL;
+
+    jclass clazz = env->FindClass(JAVA_PACKAGE "/CopySource");
+    if (JNIUtil::isJavaExceptionThrown())
+        return NULL;
+    static jmethodID ctor = 0;
+    if (ctor == 0)
+    {
+        ctor = env->GetMethodID(clazz, "<init>", "(Ljava/lang/String;"
+                                "L" JAVA_PACKAGE "/Revision;"
+                                "L" JAVA_PACKAGE "/Revision;)V");
+        if (JNIUtil::isExceptionThrown())
+            return NULL;
+    }
+
+    jobject jcopySource = env->NewObject(clazz, ctor, jpath, jrevision, NULL);
+    env->DeleteLocalRef(jpath);
+    env->DeleteLocalRef(jrevision);
+    return jcopySource;
+}
+
 apr_array_header_t *
 CopySources::array(Pool &pool)
 {

