Index: subversion/include/svn_error_codes.h
===================================================================
--- subversion/include/svn_error_codes.h	(revision 4912)
+++ subversion/include/svn_error_codes.h	(working copy)
@@ -746,6 +746,10 @@
               SVN_ERR_MISC_CATEGORY_START + 14,
               "A checksum mismatch occurred")
 
+  SVN_ERRDEF (SVN_ERR_CANCELLED,
+              SVN_ERR_MISC_CATEGORY_START + 15,
+              "The operation was canceled")
+
   /* command-line client errors */
 
   SVN_ERRDEF (SVN_ERR_CL_ARG_PARSING_ERROR,
Index: subversion/include/svn_cancel.h
===================================================================
--- subversion/include/svn_cancel.h	(working copy)
+++ subversion/include/svn_cancel.h	(working copy)
@@ -0,0 +1,51 @@
+/**
+ * @copyright
+ * ====================================================================
+ * Copyright (c) 2000-2003 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_cancel.h
+ * @brief Routines to support cancelation of running subversion functions.
+ */
+
+#include "svn_delta.h"
+
+#ifndef SVN_CANCEL_H
+#define SVN_CANCEL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/** A user defined callback that subversion will call with a user defined 
+ * baton to see if the current operation should be continued.  If the operation 
+ * should continue, the function should return @c SVN_NO_ERROR, if not, it 
+ * should return @c SVN_ERR_CANCELLED.
+ */
+typedef svn_error_t *(*svn_cancel_func_t) (void *cancel_baton);
+
+svn_error_t *
+svn_cancel_get_cancellation_editor (svn_cancel_func_t cancel_func,
+                                    void *cancel_baton,
+                                    const svn_delta_editor_t *wrapped_editor,
+                                    void *wrapped_baton,
+                                    const svn_delta_editor_t **editor,
+                                    void **edit_baton,
+                                    apr_pool_t *pool);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* SVN_CANCEL_H */
Index: subversion/include/svn_wc.h
===================================================================
--- subversion/include/svn_wc.h	(revision 4912)
+++ subversion/include/svn_wc.h	(working copy)
@@ -44,6 +44,7 @@
 #include "svn_delta.h"
 #include "svn_error.h"
 #include "svn_ra.h"    /* for svn_ra_reporter_t type */
+#include "svn_cancel.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -1598,12 +1599,17 @@
  * @a recurse determines whether to descend into subdirectories when @a target
  * is a directory.  If @a recurse is @c TRUE then @a anchor should be part of 
  * an access baton set for the @a target hierarchy.
+ *
+ * If @a cancel_func is non-null, it will be used along with @a cancel_baton 
+ * to periodically check if the client has canceled the operation.
  */
 svn_error_t *svn_wc_get_diff_editor (svn_wc_adm_access_t *anchor,
                                      const char *target,
                                      const svn_wc_diff_callbacks_t *callbacks,
                                      void *callback_baton,
                                      svn_boolean_t recurse,
+                                     svn_cancel_func_t cancel_func,
+                                     void *cancel_baton,
                                      const svn_delta_editor_t **editor,
                                      void **edit_baton,
                                      apr_pool_t *pool);
Index: subversion/include/svn_client.h
===================================================================
--- subversion/include/svn_client.h	(revision 4912)
+++ subversion/include/svn_client.h	(working copy)
@@ -39,6 +39,7 @@
 #include "svn_string.h"
 #include "svn_error.h"
 #include "svn_opt.h"
+#include "svn_cancel.h"
 
 
 #ifdef __cplusplus
@@ -275,6 +276,13 @@
    */
   apr_hash_t *config;
 
+  /** a callback to be used to see if the client wishes to cancel the running 
+   * operation. */
+  svn_cancel_func_t cancel_func;
+
+  /** a baton to pass to the cancellation callback. */
+  void *cancel_baton;
+
 } svn_client_ctx_t;
 
 
Index: subversion/libsvn_wc/diff.c
===================================================================
--- subversion/libsvn_wc/diff.c	(revision 4912)
+++ subversion/libsvn_wc/diff.c	(working copy)
@@ -1090,6 +1090,8 @@
                         const svn_wc_diff_callbacks_t *callbacks,
                         void *callback_baton,
                         svn_boolean_t recurse,
+                        svn_cancel_func_t cancel_func,
+                        void *cancel_baton,
                         const svn_delta_editor_t **editor,
                         void **edit_baton,
                         apr_pool_t *pool)
@@ -1115,8 +1117,13 @@
   tree_editor->close_file = close_file;
   tree_editor->close_edit = close_edit;
 
-  *edit_baton = eb;
-  *editor = tree_editor;
+  SVN_ERR (svn_cancel_get_cancellation_editor (cancel_func,
+                                               cancel_baton,
+                                               tree_editor,
+                                               eb,
+                                               editor,
+                                               edit_baton,
+                                               pool));
 
   return SVN_NO_ERROR;
 }
Index: subversion/libsvn_subr/cancel.c
===================================================================
--- subversion/libsvn_subr/cancel.c	(working copy)
+++ subversion/libsvn_subr/cancel.c	(working copy)
@@ -0,0 +1,352 @@
+/*
+ * cancel.c :  Routines to support cancelation of running subversion functions.
+ *
+ * ====================================================================
+ * Copyright (c) 2000-2003 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/.
+ * ====================================================================
+ */
+
+#include <svn_pools.h>
+#include <svn_cancel.h>
+
+struct edit_baton
+{
+  const svn_delta_editor_t *wrapped_editor;
+  void *wrapped_edit_baton;
+
+  svn_cancel_func_t cancel_func;
+  void *cancel_baton;
+};
+
+struct dir_baton
+{
+  void *edit_baton;
+  void *wrapped_dir_baton;
+};
+
+struct file_baton
+{
+  void *edit_baton;
+  void *wrapped_file_baton;
+};
+
+static svn_error_t *
+set_target_revision (void *edit_baton,
+                     svn_revnum_t target_revision,
+                     apr_pool_t *pool)
+{
+  struct edit_baton *eb = edit_baton;
+
+  SVN_ERR (eb->cancel_func (eb->cancel_baton));
+
+  SVN_ERR (eb->wrapped_editor->set_target_revision (eb->wrapped_edit_baton,
+                                                    target_revision,
+                                                    pool));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+open_root (void *edit_baton,
+           svn_revnum_t base_revision,
+           apr_pool_t *pool,
+           void **root_baton)
+{
+  struct edit_baton *eb = edit_baton;
+  struct dir_baton *dir_baton = apr_palloc (pool, sizeof (*dir_baton));
+
+  SVN_ERR (eb->cancel_func (eb->cancel_baton));
+
+  SVN_ERR (eb->wrapped_editor->open_root (eb->wrapped_edit_baton,
+                                          base_revision,
+                                          pool,
+                                          &dir_baton->wrapped_dir_baton));
+
+  dir_baton->edit_baton = edit_baton;
+
+  *root_baton = dir_baton;
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+delete_entry (const char *path,
+              svn_revnum_t base_revision,
+              void *parent_baton,
+              apr_pool_t *pool)
+{
+  struct dir_baton *pb = parent_baton;
+  struct edit_baton *eb = pb->edit_baton;
+
+  SVN_ERR (eb->cancel_func (eb->cancel_baton));
+
+  SVN_ERR (eb->wrapped_editor->delete_entry (path,
+                                             base_revision,
+                                             pb->wrapped_dir_baton,
+                                             pool));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+add_directory (const char *path,
+               void *parent_baton,
+               const char *copyfrom_path,
+               svn_revnum_t copyfrom_revision,
+               apr_pool_t *pool,
+               void **child_baton)
+{
+  struct dir_baton *pb = parent_baton;
+  struct edit_baton *eb = pb->edit_baton;
+  struct dir_baton *b = apr_palloc (pool, sizeof (*b));
+
+  SVN_ERR (eb->cancel_func (eb->cancel_baton));
+
+  SVN_ERR (eb->wrapped_editor->add_directory (path,
+                                              pb->wrapped_dir_baton,
+                                              copyfrom_path,
+                                              copyfrom_revision,
+                                              pool,
+                                              &b->wrapped_dir_baton));
+
+  b->edit_baton = eb;
+  *child_baton = b;
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+open_directory (const char *path,
+                void *parent_baton,
+                svn_revnum_t base_revision,
+                apr_pool_t *pool,
+                void **child_baton)
+{
+  struct dir_baton *pb = parent_baton;
+  struct edit_baton *eb = pb->edit_baton;
+  struct dir_baton *db = apr_palloc (pool, sizeof (*db));
+
+  SVN_ERR (eb->cancel_func (eb->cancel_baton));
+
+  SVN_ERR (eb->wrapped_editor->open_directory (path,
+                                               pb->wrapped_dir_baton,
+                                               base_revision,
+                                               pool,
+                                               &db->wrapped_dir_baton));
+
+  db->edit_baton = eb;
+  *child_baton = db;
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+add_file (const char *path,
+          void *parent_baton,
+          const char *copyfrom_path,
+          svn_revnum_t copyfrom_revision,
+          apr_pool_t *pool,
+          void **file_baton)
+{
+  struct dir_baton *pb = parent_baton;
+  struct edit_baton *eb = pb->edit_baton;
+  struct file_baton *fb = apr_palloc (pool, sizeof (*fb));
+
+  SVN_ERR (eb->cancel_func (eb->cancel_baton));
+
+  SVN_ERR (eb->wrapped_editor->add_file (path,
+                                         pb->wrapped_dir_baton,
+                                         copyfrom_path,
+                                         copyfrom_revision,
+                                         pool,
+                                         &fb->wrapped_file_baton));
+
+  fb->edit_baton = eb;
+  *file_baton = fb;
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+open_file (const char *path,
+           void *parent_baton,
+           svn_revnum_t base_revision,
+           apr_pool_t *pool,
+           void **file_baton)
+{
+  struct dir_baton *pb = parent_baton;
+  struct edit_baton *eb = pb->edit_baton;
+  struct file_baton *fb = apr_palloc (pool, sizeof (*fb));
+
+  SVN_ERR (eb->cancel_func (eb->cancel_baton));
+
+  SVN_ERR (eb->wrapped_editor->open_file (path,
+                                          pb->wrapped_dir_baton,
+                                          base_revision,
+                                          pool,
+                                          &fb->wrapped_file_baton));
+
+  fb->edit_baton = eb;
+  *file_baton = fb;
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+apply_textdelta (void *file_baton,
+                 const char *base_checksum,
+                 const char *result_checksum,
+                 apr_pool_t *pool,
+                 svn_txdelta_window_handler_t *handler,
+                 void **handler_baton)
+{
+  struct file_baton *fb = file_baton;
+  struct edit_baton *eb = fb->edit_baton;
+
+  SVN_ERR (eb->cancel_func (eb->cancel_baton));
+
+  SVN_ERR (eb->wrapped_editor->apply_textdelta (fb->wrapped_file_baton,
+                                                base_checksum,
+                                                result_checksum,
+                                                pool,
+                                                handler,
+                                                handler_baton));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+close_file (void *file_baton,
+            apr_pool_t *pool)
+{
+  struct file_baton *fb = file_baton;
+  struct edit_baton *eb = fb->edit_baton;
+
+  SVN_ERR (eb->cancel_func (eb->cancel_baton));
+
+  SVN_ERR (eb->wrapped_editor->close_file (fb->wrapped_file_baton,
+                                           pool));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+close_directory (void *dir_baton,
+                 apr_pool_t *pool)
+{
+  struct dir_baton *db = dir_baton;
+  struct edit_baton *eb = db->edit_baton;
+
+  SVN_ERR (eb->cancel_func (eb->cancel_baton));
+
+  SVN_ERR (eb->wrapped_editor->close_directory (db->wrapped_dir_baton,
+                                                pool));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+change_file_prop (void *file_baton,
+                  const char *name,
+                  const svn_string_t *value,
+                  apr_pool_t *pool)
+{
+  struct file_baton *fb = file_baton;
+  struct edit_baton *eb = fb->edit_baton;
+
+  SVN_ERR (eb->cancel_func (eb->cancel_baton));
+
+  SVN_ERR (eb->wrapped_editor->change_file_prop (fb->wrapped_file_baton,
+                                                 name,
+                                                 value,
+                                                 pool));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+change_dir_prop (void *dir_baton,
+                 const char *name,
+                 const svn_string_t *value,
+                 apr_pool_t *pool)
+{
+  struct dir_baton *db = dir_baton;
+  struct edit_baton *eb = db->edit_baton;
+
+  SVN_ERR (eb->cancel_func (eb->cancel_baton));
+
+  SVN_ERR (eb->wrapped_editor->change_dir_prop (db->wrapped_dir_baton,
+                                                name,
+                                                value,
+                                                pool));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+close_edit (void *edit_baton,
+            apr_pool_t *pool)
+{
+  struct edit_baton *eb = edit_baton;
+
+  SVN_ERR (eb->cancel_func (eb->cancel_baton));
+
+  SVN_ERR (eb->wrapped_editor->close_edit (eb->wrapped_edit_baton, pool));
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_cancel_get_cancellation_editor (svn_cancel_func_t cancel_func,
+                                    void *cancel_baton,
+                                    const svn_delta_editor_t *wrapped_editor,
+                                    void *wrapped_edit_baton,
+                                    const svn_delta_editor_t **editor,
+                                    void **edit_baton,
+                                    apr_pool_t *pool)
+{
+  if (cancel_func)
+    {
+      svn_delta_editor_t *tree_editor = svn_delta_default_editor (pool);
+      struct edit_baton *eb = apr_palloc (pool, sizeof (*eb));
+
+      eb->wrapped_editor = wrapped_editor;
+      eb->wrapped_edit_baton = wrapped_edit_baton;
+      eb->cancel_func = cancel_func;
+      eb->cancel_baton = cancel_baton;
+
+      tree_editor->set_target_revision = set_target_revision;
+      tree_editor->open_root = open_root;
+      tree_editor->delete_entry = delete_entry;
+      tree_editor->add_directory = add_directory;
+      tree_editor->open_directory = open_directory;
+      tree_editor->add_file = add_file;
+      tree_editor->open_file = open_file;
+      tree_editor->apply_textdelta = apply_textdelta;
+      tree_editor->close_file = close_file;
+      tree_editor->close_directory = close_directory;
+      tree_editor->change_file_prop = change_file_prop;
+      tree_editor->change_dir_prop = change_dir_prop;
+      tree_editor->close_edit = close_edit;
+
+      *editor = tree_editor;
+      *edit_baton = eb;
+    }
+  else
+    {
+      *editor = wrapped_editor;
+      *edit_baton = wrapped_edit_baton;
+    }
+
+  return SVN_NO_ERROR;
+}
Index: subversion/libsvn_client/diff.c
===================================================================
--- subversion/libsvn_client/diff.c	(revision 4912)
+++ subversion/libsvn_client/diff.c	(working copy)
@@ -841,6 +841,8 @@
                                         start_revnum,
                                         ctx->notify_func,
                                         ctx->notify_baton,
+                                        ctx->cancel_func,
+                                        ctx->cancel_baton,
                                         &diff_editor,
                                         &diff_edit_baton,
                                         pool));
@@ -1117,6 +1119,7 @@
       SVN_ERR (svn_wc_get_diff_editor (adm_access, target,
                                        callbacks, callback_baton,
                                        recurse,
+                                       ctx->cancel_func, ctx->cancel_baton,
                                        &diff_editor, &diff_edit_baton,
                                        pool));
 
@@ -1277,6 +1280,8 @@
                                             start_revnum,
                                             NULL, /* no notify_func */
                                             NULL, /* no notify_baton */
+                                            ctx->cancel_func,
+                                            ctx->cancel_baton,
                                             &diff_editor,
                                             &diff_edit_baton,
                                             pool));
Index: subversion/libsvn_client/repos_diff.c
===================================================================
--- subversion/libsvn_client/repos_diff.c	(revision 4912)
+++ subversion/libsvn_client/repos_diff.c	(working copy)
@@ -835,6 +835,8 @@
                              svn_revnum_t revision,
                              svn_wc_notify_func_t notify_func,
                              void *notify_baton,
+                             svn_cancel_func_t cancel_func,
+                             void *cancel_baton,
                              const svn_delta_editor_t **editor,
                              void **edit_baton,
                              apr_pool_t *pool)
@@ -871,8 +873,13 @@
   tree_editor->change_dir_prop = change_dir_prop;
   tree_editor->close_edit = close_edit;
 
-  *edit_baton = eb;
-  *editor = tree_editor;
+  SVN_ERR (svn_cancel_get_cancellation_editor (cancel_func,
+                                               cancel_baton,
+                                               tree_editor,
+                                               eb,
+                                               editor,
+                                               edit_baton,
+                                               pool));
 
   return SVN_NO_ERROR;
 }
Index: subversion/libsvn_client/client.h
===================================================================
--- subversion/libsvn_client/client.h	(revision 4912)
+++ subversion/libsvn_client/client.h	(working copy)
@@ -314,6 +314,8 @@
                              svn_revnum_t revision,
                              svn_wc_notify_func_t notify_func,
                              void *notify_baton,
+                             svn_cancel_func_t cancel_func,
+                             void *cancel_baton,
                              const svn_delta_editor_t **editor,
                              void **edit_baton,
                              apr_pool_t *pool);
Index: subversion/clients/cmdline/main.c
===================================================================
--- subversion/clients/cmdline/main.c	(revision 4912)
+++ subversion/clients/cmdline/main.c	(working copy)
@@ -29,6 +29,7 @@
 #include <apr_tables.h>
 #include <apr_general.h>
 #include <apr_lib.h>
+#include <apr_signal.h>
 
 #include "svn_pools.h"
 #include "svn_wc.h"
@@ -506,7 +507,23 @@
   { NULL, NULL, {0}, NULL, {0} }
 };
 
+static volatile sig_atomic_t interrupted = 0;
 
+static void
+sig_int (int unused)
+{
+  interrupted = 1;
+}
+
+static svn_error_t *
+check_cancel (void *baton)
+{
+  if (interrupted)
+    return svn_error_create (SVN_ERR_CANCELLED, NULL, "caught SIGINT");
+  else
+    return SVN_NO_ERROR;
+}
+
 
 /*** Main. ***/
 
@@ -945,6 +962,10 @@
   ctx.log_msg_baton = svn_cl__make_log_msg_baton (&opt_state, NULL, 
                                                   ctx.config, pool);
 
+  apr_signal (SIGINT, sig_int);
+
+  ctx.cancel_func = check_cancel;
+
   err = (*subcommand->cmd_func) (os, &command_baton, pool);
   if (err)
     {

