Index: subversion/include/svn_repos.h
===================================================================
--- subversion/include/svn_repos.h	(revision 9914)
+++ subversion/include/svn_repos.h	(arbetskopia)
@@ -64,7 +64,18 @@
                                                 void *baton,
                                                 apr_pool_t *pool);
 
+/** This has the same semantics as @c svn_ra_file_rev_handler_t. */
+typedef svn_error_t *(*svn_repos_file_rev_handler_t)
+       (void *baton,
+        const char *path,
+        svn_revnum_t rev,
+        apr_hash_t *rev_props,
+        svn_txdelta_stream_t *contents_delta,
+        apr_hash_t *props,
+        apr_pool_t *pool);
 
+
+
 
 /** The repository object. */
 typedef struct svn_repos_t svn_repos_t;
@@ -607,6 +618,20 @@
 
 /* ---------------------------------------------------------------*/
 
+/* Retreiving multiple revisions of a file. */
+
+/** This has the same semantics as the rA layer function get_file_revs. */
+svn_error_t *svn_repos_get_file_revs (svn_repos_t *repos,
+                                      const char *path,
+                                      svn_revnum_t start,
+                                      svn_revnum_t end,
+                                      svn_repos_file_rev_handler_t handler,
+                                      void *handler_baton,
+                                      apr_pool_t *pool);
+
+
+/* ---------------------------------------------------------------*/
+
 /**
  * @defgroup svn_repos_hook_wrappers Hook-sensitive wrappers for libsvn_fs 
  * routines.
Index: subversion/include/svn_ra.h
===================================================================
--- subversion/include/svn_ra.h	(revision 9914)
+++ subversion/include/svn_ra.h	(arbetskopia)
@@ -109,6 +109,23 @@
        (void *session_baton,
         svn_revnum_t *latest_revnum);
 
+/** A callback function type for use in @c get_file_revs.
+ * @a baton is provided by the caller, @a path is the pathname of the file
+ * in revision @a rev and @a rev_props are the revision properties.
+ * @a delta_stream provides a text delta for the contents against the contents
+ * of the the previous call (or the empty file of this is the first call)
+ * and @a props are the file properties.
+ * @a pool may be used for temporary allocations, but you can't rely
+ * on object allocated to live outside of this particular call. */
+typedef svn_error_t *(*svn_ra_file_rev_handler_t)
+       (void *baton,
+        const char *path,
+        svn_revnum_t rev,
+        apr_hash_t *rev_props,
+        svn_txdelta_stream_t *delta_stream,
+        apr_hash_t *props,
+        apr_pool_t *pool);
+
 
 /** The update Reporter.
  *
@@ -711,6 +728,28 @@
                                   const char **url,
                                   apr_pool_t *pool);
 
+  /** Retrieve a subset of the interesting revisions for a file @a path
+   * as seen in revision @a end.  Invoke @a handler with @a handler_baton
+   * as its first argument for each such revision.  @a sesson_baton is
+   * an open RA session.  @a pool is used for all allocations.
+   *
+   * If there is an interesting revision of the file that is less than or
+   * equal to start, the iteration will start at that revision.  Else, the
+   * iteration will start at the first revision of the file in the repository,
+   * whic has to be less than or equal to end.  Note that if the function
+   * succeeds, @a handler will have been called at least once.
+   *
+   * In a series of calls, the file contents for the first interesting revision
+   * will be provided as a text delta against the empty file.  IN the following
+   * calls, the delta will be against the contents for the previous call. */
+  svn_error_t *(*get_file_revs) (void *session_baton,
+                                 const char *path,
+                                 svn_revnum_t start,
+                                 svn_revnum_t end,
+                                 svn_ra_file_rev_handler_t handler,
+                                 void *handler_baton,
+                                 apr_pool_t *pool);
+
 } svn_ra_plugin_t;
 
 
Index: subversion/libsvn_ra_local/ra_plugin.c
===================================================================
--- subversion/libsvn_ra_local/ra_plugin.c	(revision 9914)
+++ subversion/libsvn_ra_local/ra_plugin.c	(arbetskopia)
@@ -23,10 +23,13 @@
 #include "svn_repos.h"
 #include "svn_pools.h"
 #include "svn_time.h"
+#include "svn_private_config.h"
 
 #define APR_WANT_STRFUNC
 #include <apr_want.h>
 
+#include <assert.h>
+
 /*----------------------------------------------------------------*/
 
 
@@ -840,8 +843,26 @@
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *
+svn_ra_local__get_file_revs (void *session_baton,
+                             const char *path,
+                             svn_revnum_t start,
+                             svn_revnum_t end,
+                             svn_ra_file_rev_handler_t handler,
+                             void *handler_baton,
+                             apr_pool_t *pool)
+{
+  svn_ra_local__session_baton_t *sbaton = session_baton;
+  const char *abs_path = sbaton->fs_path;
 
+  /* Concatenate paths */
+  if (path)
+    abs_path = svn_path_join (abs_path, path, pool);
 
+  return svn_repos_get_file_revs (sbaton->repos, abs_path, start, end,
+                                  handler, handler_baton, pool);
+}
+
 /*----------------------------------------------------------------*/
 
 /** The ra_plugin **/
@@ -866,7 +887,8 @@
   svn_ra_local__get_log,
   svn_ra_local__do_check_path,
   svn_ra_local__get_uuid,
-  svn_ra_local__get_repos_root
+  svn_ra_local__get_repos_root,
+  svn_ra_local__get_file_revs
 };
 
 
Index: subversion/libsvn_client/blame.c
===================================================================
--- subversion/libsvn_client/blame.c	(revision 9914)
+++ subversion/libsvn_client/blame.c	(arbetskopia)
@@ -29,12 +29,15 @@
 #include "svn_path.h"
 #include "svn_sorts.h"
 
+#include <assert.h>
+
 /* The metadata associated with a particular revision. */
 struct rev
 {
   svn_revnum_t revision; /* the revision number */
   const char *author;    /* the author of the revision */
   const char *date;      /* the date of the revision */
+  /* ### Only used by the old code. */
   const char *path;      /* the absolute repository path */
   struct rev *next;      /* the next revision */
 };
@@ -47,19 +50,44 @@
   struct blame *next; /* the next chunk */
 };
 
-/* The baton used for svn_diff operations */
-struct diff_baton
-{
-  struct rev *rev;     /* the rev for which blame is being assigned */
+/* The baton used for a file revision. Also used for the diff output
+   routine. */
+struct file_rev_baton {
+  svn_revnum_t start_rev, end_rev;
+  svn_client_ctx_t *ctx;
+  const char *last_filename;
+  struct rev *rev;     /* the rev for which blame is being assigned
+                          during a diff */
   struct blame *blame; /* linked list of blame chunks */
   struct blame *avail; /* linked list of free blame chunks */
-  apr_pool_t *pool;
+  apr_pool_t *main_pool; /* lives during the whole sequence of calls */
+  apr_pool_t *last_pool;  /* pool used during previous call */
+  apr_pool_t *cur_pool;  /* pool used during this call */
 };
 
+static apr_status_t
+cleanup_tempfile (void *f)
+{
+  apr_file_t *file = f;
+  apr_status_t apr_err;
+  const char *fname;
+
+  /* the file may or may not have been closed; try it */
+  apr_file_close (file);
+
+  apr_err = apr_file_name_get (&fname, file);
+  if (apr_err == APR_SUCCESS)
+    apr_err = apr_file_remove (fname, apr_file_pool_get (file));
+
+  return apr_err;
+}
+
+
+
 /* Create a blame chunk associated with REV for a change starting
    at token START. */
 static struct blame *
-blame_create (struct diff_baton *baton, struct rev *rev, apr_off_t start)
+blame_create (struct file_rev_baton *baton, struct rev *rev, apr_off_t start)
 {
   struct blame *blame;
   if (baton->avail)
@@ -68,7 +96,7 @@
       baton->avail = blame->next;
     }
   else
-    blame = apr_palloc (baton->pool, sizeof (*blame));
+    blame = apr_palloc (baton->main_pool, sizeof (*blame));
   blame->rev = rev;
   blame->start = start;       
   blame->next = NULL;
@@ -77,7 +105,7 @@
 
 /* Destroy a blame chunk. */
 static void
-blame_destroy (struct diff_baton *baton, struct blame *blame)
+blame_destroy (struct file_rev_baton *baton, struct blame *blame)
 {
   blame->next = baton->avail;
   baton->avail = blame;
@@ -113,7 +141,7 @@
 /* Delete the blame associated with the region from token START to
    START + LENGTH */
 static svn_error_t *
-blame_delete_range (struct diff_baton *db, apr_off_t start, apr_off_t length)
+blame_delete_range (struct file_rev_baton *db, apr_off_t start, apr_off_t length)
 {
   struct blame *first = blame_find (db->blame, start);
   struct blame *last = blame_find (db->blame, start + length);
@@ -153,7 +181,7 @@
 /* Insert a chunk of blame associated with DB->REV starting
    at token START and continuing for LENGTH tokens */
 static svn_error_t *
-blame_insert_range (struct diff_baton *db, apr_off_t start, apr_off_t length)
+blame_insert_range (struct file_rev_baton *db, apr_off_t start, apr_off_t length)
 {
   struct blame *head = db->blame;
   struct blame *point = blame_find (head, start);
@@ -196,7 +224,7 @@
                       apr_off_t latest_start,
                       apr_off_t latest_length)
 {
-  struct diff_baton *db = baton;
+  struct file_rev_baton *db = baton;
 
   if (original_length)
     SVN_ERR (blame_delete_range (db, modified_start, original_length));
@@ -207,6 +235,7 @@
   return SVN_NO_ERROR;
 }
 
+/* ### Used only by the old code. */
 /* The baton used for RA->get_log */
 struct log_message_baton {
   const char *path;        /* The path to be processed */
@@ -257,23 +286,152 @@
   return SVN_NO_ERROR;
 }
 
-static apr_status_t
-cleanup_tempfile (void *f)
+static svn_error_t *
+file_rev_handler (void *baton, const char *path, svn_revnum_t revnum,
+                  apr_hash_t *rev_props,
+                  svn_txdelta_stream_t *delta_stream, apr_hash_t *props,
+                  apr_pool_t *pool)
 {
-  apr_file_t *file = f;
-  apr_status_t apr_err;
-  const char *fname;
+  struct file_rev_baton *frb = baton;
+  struct rev *rev;
+  svn_string_t *mimetype;
+  apr_file_t *last_file;
+  apr_file_t *cur_file;
+  svn_stream_t *last_stream;
+  svn_stream_t *cur_stream;
+  svn_txdelta_window_handler_t window_handler;
+  void *window_baton;
+  const char *temp_dir;
+  const char *cur_filename;
 
-  /* the file may or may not have been closed; try it */
-  apr_file_close (file);
+  /* Clear the current pool. */
+  svn_pool_clear (frb->cur_pool);
 
-  apr_err = apr_file_name_get (&fname, file);
-  if (apr_err == APR_SUCCESS)
-    apr_err = apr_file_remove (fname, apr_file_pool_get (file));
+  /* If this file has a non-textual mime-type, bail out. */
+  if (props && 
+      ((mimetype = apr_hash_get (props, SVN_PROP_MIME_TYPE, 
+                                 sizeof (SVN_PROP_MIME_TYPE) - 1))))
+    {
+      if (svn_mime_type_is_binary (mimetype->data))
+        return svn_error_createf 
+          (SVN_ERR_CLIENT_IS_BINARY_FILE, 0,
+           _("Cannot calculate blame information for binary file '%s'"),
+           path);
+    }
 
-  return apr_err;
+  if (frb->ctx->notify_func)
+    frb->ctx->notify_func (frb->ctx->notify_baton,
+                           path,
+                           svn_wc_notify_blame_revision,
+                           svn_node_none,
+                           NULL,
+                           svn_wc_notify_state_inapplicable,
+                           svn_wc_notify_state_inapplicable,
+                           revnum);
+
+  if (frb->ctx->cancel_func)
+    SVN_ERR (frb->ctx->cancel_func (frb->ctx->cancel_baton));
+
+  /* Reconstruct the contents. */
+  if (frb->last_filename)
+    SVN_ERR (svn_io_file_open (&last_file, frb->last_filename, APR_READ,
+                               APR_OS_DEFAULT, frb->cur_pool));
+  else
+    last_file = NULL;
+  last_stream = svn_stream_from_aprfile (last_file, pool);
+
+  SVN_ERR (svn_io_temp_dir (&temp_dir, frb->cur_pool));
+  SVN_ERR (svn_io_open_unique_file (&cur_file, &cur_filename,
+                                    svn_path_join (temp_dir, "tmp", frb->cur_pool),
+                                    ".tmp", FALSE, frb->cur_pool));
+
+  apr_pool_cleanup_register (frb->cur_pool, cur_file, cleanup_tempfile,
+                             apr_pool_cleanup_null);
+  cur_stream = svn_stream_from_aprfile (cur_file, frb->cur_pool);
+
+  /* Apply the text delta. */
+  svn_txdelta_apply (last_stream, cur_stream, NULL, NULL,
+                     frb->cur_pool,
+                     &window_handler, &window_baton);
+  SVN_ERR (svn_txdelta_send_txstream (delta_stream, window_handler,
+                                      window_baton, frb->cur_pool));
+
+  /* Important to close the files, so the buffers of cur_file get flushed. */
+  if (last_file)
+    SVN_ERR (svn_io_file_close (last_file, frb->cur_pool));
+  SVN_ERR (svn_io_file_close (cur_file, frb->cur_pool));
+
+  if (revnum < frb->start_rev)
+    {
+      /* We shouldn't get more than one revision before start. */
+      assert (frb->last_filename == NULL);
+
+      /* The file existed before start_rev; generate no blame info for
+         lines from this revision (or before). */
+      rev = apr_palloc (frb->main_pool, sizeof (*rev));
+      rev->revision = SVN_INVALID_REVNUM;
+      rev->author = NULL;
+      rev->date = NULL;
+      frb->blame = blame_create (frb, rev, 0);
+    }
+  else
+    {
+      svn_string_t *str;
+      assert (revnum <= frb->end_rev);
+
+      /* Create a rev structure with the revision properties. */
+      rev = apr_palloc (frb->main_pool, sizeof (*rev));
+      rev->revision = revnum;
+
+      if ((str = apr_hash_get (rev_props, SVN_PROP_REVISION_AUTHOR,
+                               sizeof (SVN_PROP_REVISION_AUTHOR) - 1)))
+        rev->author = apr_pstrdup (frb->main_pool, str->data);
+      else
+        rev->author = NULL;
+
+      if ((str = apr_hash_get (rev_props, SVN_PROP_REVISION_DATE,
+                               sizeof (SVN_PROP_REVISION_DATE) - 1)))
+        rev->date = apr_pstrdup (frb->main_pool, str->data);
+
+      if (!frb->last_filename)
+        {
+          /* File must have been created after start_rev.  We create blame
+             information for all of this file. */
+          assert (!frb->blame);
+          frb->blame = blame_create (frb, rev, 0);
+        } else {
+          svn_diff_t *diff;
+
+          /* We have a previous file.  Get the diff and adjust blame info. */
+          frb->rev = rev;
+          SVN_ERR (svn_diff_file_diff (&diff, frb->last_filename, cur_filename,
+                                       pool));
+          SVN_ERR (svn_diff_output (diff, frb, &output_fns));
+        }
+    }
+
+  /* Remember the file name so we can diff it with the next revision. */
+  frb->last_filename = cur_filename;
+
+  /* Switch pools. */
+  {
+    apr_pool_t *tmp_pool = frb->last_pool;
+    frb->last_pool = frb->cur_pool;
+    frb->cur_pool = tmp_pool;
+  }
+
+  return SVN_NO_ERROR;
 }
 
+static svn_error_t *
+old_blame (const char *target,
+           const svn_opt_revision_t *start,
+           const svn_opt_revision_t *end,
+           svn_client_blame_receiver_t receiver,
+           void *receiver_baton,
+           svn_client_ctx_t *ctx,
+           apr_pool_t *pool);
+
 svn_error_t *
 svn_client_blame (const char *target,
                   const svn_opt_revision_t *start,
@@ -283,6 +441,117 @@
                   svn_client_ctx_t *ctx,
                   apr_pool_t *pool)
 {
+  struct file_rev_baton frb;
+  svn_ra_plugin_t *ra_lib; 
+  void *session;
+  const char *url;
+  svn_revnum_t start_revnum, end_revnum;
+  struct blame *walk;
+  apr_file_t *file;
+  apr_pool_t *iterpool;
+  svn_stream_t *stream;
+
+  if (start->kind == svn_opt_revision_unspecified
+      || end->kind == svn_opt_revision_unspecified)
+    return svn_error_create
+      (SVN_ERR_CLIENT_BAD_REVISION, NULL, NULL);
+
+  /* Get an RA plugin for this filesystem object. */
+  SVN_ERR (svn_client__ra_lib_from_path (&ra_lib, &session, &end_revnum,
+                                         &url, target, end,
+                                         ctx, pool));
+
+  /* ## This is temporary until all RA implementations support
+     get_file_revs. */
+  if (!ra_lib->get_file_revs)
+    /* Let the old code take over. */
+    return old_blame (target, start, end, receiver, receiver_baton, ctx,
+                      pool);
+  SVN_ERR (svn_client__get_revision_number (&start_revnum, ra_lib, session,
+                                            start, target, pool));
+
+  if (end_revnum < start_revnum)
+    return svn_error_create
+      (SVN_ERR_CLIENT_BAD_REVISION, NULL,
+       _("Start revision must precede end revision"));
+
+  /* Collect all blame information.
+     We need to ensure that we get one revision before the start_rev,
+     if available so that we can know what was actually changed in the start
+     revision. */
+
+  frb.start_rev = start_revnum;
+  frb.end_rev = end_revnum;
+  frb.ctx = ctx;
+  frb.last_filename = NULL;
+  frb.blame = NULL;
+  frb.avail = NULL;
+  frb.main_pool = pool;
+  /* The callback will flip the following two pools, because it needs
+     information from the previous call.  Obviously, it can't rely on
+     the lifetime of the pool provided by get_file_revs. */
+  frb.last_pool = svn_pool_create (pool);
+  frb.cur_pool = svn_pool_create (pool);
+  SVN_ERR (ra_lib->get_file_revs (session, "",
+                                  start_revnum - (start_revnum > 0 ? 1 : 0),
+                                  end_revnum,
+                                  file_rev_handler, &frb, pool));
+
+  /* Report the blame to the caller. */
+
+  /* The callback has to have been called at least once. */
+  assert (frb.last_filename != NULL);
+
+  /* Create a pool for the iteration below. */
+  iterpool = svn_pool_create (pool);
+
+  /* Open the last file and get a stream. */
+  SVN_ERR (svn_io_file_open (&file, frb.last_filename, APR_READ,
+                             APR_OS_DEFAULT, pool));
+  stream = svn_stream_from_aprfile (file, pool);
+
+  /* Process each blame item. */
+  for (walk = frb.blame; walk; walk = walk->next)
+    {
+      apr_off_t line_no;
+      for (line_no = walk->start;
+           !walk->next || line_no < walk->next->start;
+           ++line_no)
+        {
+          svn_boolean_t eof;
+          svn_stringbuf_t *sb;
+          apr_pool_clear (iterpool);
+          SVN_ERR (svn_stream_readline (stream, &sb, "\n", &eof, iterpool));
+          if (ctx->cancel_func)
+            SVN_ERR (ctx->cancel_func (ctx->cancel_baton));
+          if (!eof || sb->len)
+            SVN_ERR (receiver (receiver_baton, line_no, walk->rev->revision,
+                               walk->rev->author, walk->rev->date,
+                               sb->data, iterpool));
+          if (eof) break;
+        }
+    }
+
+  SVN_ERR (svn_stream_close (stream));
+
+  /* We don't need the temp file any more. */
+  SVN_ERR (svn_io_file_close (file, pool));
+
+  return SVN_NO_ERROR;
+}
+
+
+/* This is used when there is no get_file_revs avaliable. */
+
+static svn_error_t *
+old_blame (const char *target,
+           const svn_opt_revision_t *start,
+           const svn_opt_revision_t *end,
+           svn_client_blame_receiver_t receiver,
+           void *receiver_baton,
+           svn_client_ctx_t *ctx,
+           apr_pool_t *pool)
+{
   const char *reposURL;
   struct log_message_baton lmb;
   apr_array_header_t *condensed_targets;
@@ -297,7 +566,7 @@
   struct rev *rev;
   apr_status_t apr_err;
   svn_node_kind_t kind;
-  struct diff_baton db;
+  struct file_rev_baton db;
   const char *last = NULL;
 
   if (start->kind == svn_opt_revision_unspecified
@@ -319,7 +588,7 @@
   if (end_revnum < start_revnum)
     return svn_error_create
       (SVN_ERR_CLIENT_BAD_REVISION, NULL,
-       "Start revision must precede end revision");
+       _("Start revision must precede end revision"));
 
   SVN_ERR (ra_lib->check_path (session, "", end_revnum, &kind, pool));
 
@@ -359,7 +628,7 @@
                                         ctx, pool));
 
   db.avail = NULL;
-  db.pool = pool;
+  db.main_pool = pool;
 
   /* Inspect the first revision's change metadata; if there are any
      prior revisions, compute a new starting revision/path.  If no
@@ -443,7 +712,7 @@
           if (svn_mime_type_is_binary (mimetype->data))
             return svn_error_createf 
               (SVN_ERR_CLIENT_IS_BINARY_FILE, 0,
-               "Cannot calculate blame information for binary file '%s'",
+               _("Cannot calculate blame information for binary file '%s'"),
                target);
         }
 
Index: subversion/libsvn_repos/rev_hunt.c
===================================================================
--- subversion/libsvn_repos/rev_hunt.c	(revision 9914)
+++ subversion/libsvn_repos/rev_hunt.c	(arbetskopia)
@@ -27,6 +27,7 @@
 #include "svn_time.h"
 #include "repos.h"
 
+#include <assert.h>
 
 
 /* Note:  this binary search assumes that the datestamp properties on
@@ -251,4 +252,117 @@
   return SVN_NO_ERROR;
 }
 
-                             
+
+
+svn_error_t *
+svn_repos_get_file_revs (svn_repos_t *repos,
+                         const char *path,
+                         svn_revnum_t start,
+                         svn_revnum_t end,
+                         svn_repos_file_rev_handler_t handler,
+                         void *handler_baton,
+                         apr_pool_t *pool)
+{
+  apr_pool_t *iter_pool, *last_pool;
+  svn_fs_history_t *history;
+  apr_array_header_t *revnums = apr_array_make (pool, 0,
+                                                sizeof (svn_revnum_t));
+  apr_array_header_t *paths = apr_array_make (pool, 0, sizeof (char *));
+  svn_fs_root_t *root, *last_root;
+  const char *last_path;
+  int i;
+
+  /* We switch betwwen two pools while looping, since we need information from
+     the last iteration to be available. */
+  iter_pool = svn_pool_create (pool);
+  last_pool = svn_pool_create (pool);
+
+  /* Open revision root for path@end. */
+  /* ### Can we use last_pool for this? */
+  SVN_ERR (svn_fs_revision_root (&root, repos->fs, end, pool));
+
+  /* Open a history object. */
+  SVN_ERR (svn_fs_node_history (&history, root, path, last_pool));
+  
+  /* Get the revisions we are interested in. */
+  /* ### Ignore revisions where path wasn't changed and there was no content
+     or prop changes.  Do we get such revisions?  What about copied parents?
+  */
+  while (1)
+    {
+      const char* rev_path;
+      svn_revnum_t rev;
+      apr_pool_t *tmp_pool;
+
+      svn_pool_clear (iter_pool);
+
+      SVN_ERR (svn_fs_history_prev (&history, history, TRUE, iter_pool));
+      if (!history)
+        break;
+      SVN_ERR (svn_fs_history_location (&rev_path, &rev, history, iter_pool));
+      *(svn_revnum_t*) apr_array_push (revnums) = rev;
+      *(char **) apr_array_push (paths) = apr_pstrdup (pool, rev_path);
+      if (rev <= start)
+        break;
+
+      /* Swap pools. */
+      tmp_pool = iter_pool;
+      iter_pool = last_pool;
+      last_pool = tmp_pool;
+    }
+
+  /* We must have at least one revision to get. */
+  assert (revnums->nelts > 0);
+
+  /* We want the first txdelta to be against the empty file. */
+  last_root = NULL;
+  last_path = NULL;
+
+  /* Walk through the revisions in chronological order. */
+  for (i = revnums->nelts; i > 0; --i)
+    {
+      svn_revnum_t rev = APR_ARRAY_IDX (revnums, i - 1, svn_revnum_t);
+      const char *rev_path = APR_ARRAY_IDX (paths, i - 1, const char *);
+      apr_hash_t *rev_props;
+      apr_hash_t *file_props;
+      svn_txdelta_stream_t *delta_stream;
+      apr_pool_t *tmp_pool;
+
+      svn_pool_clear (iter_pool);
+
+      /* Get the revision properties. */
+      SVN_ERR (svn_fs_revision_proplist (&rev_props, repos->fs,
+                                         rev, iter_pool));
+
+      /* Open the revision root. */
+      SVN_ERR (svn_fs_revision_root (&root, repos->fs, rev, iter_pool));
+
+      /* Get the content delta. */
+      SVN_ERR (svn_fs_get_file_delta_stream (&delta_stream,
+                                             last_root, last_path,
+                                             root, rev_path,
+                                             iter_pool));
+
+      /* Get the file's properties for this revision. */
+      /* ### Give only property diffs? */
+      SVN_ERR (svn_fs_node_proplist (&file_props, root, rev_path, iter_pool));
+
+      /* We have all we need, give to the handler. */
+      SVN_ERR (handler (handler_baton, rev_path, rev, rev_props,
+               delta_stream, file_props, iter_pool));
+
+      /* Remember root and path for next iteration. */
+      last_root = root;
+      last_path = rev_path;
+
+      /* Swap the pools. */
+      tmp_pool = iter_pool;
+      iter_pool = last_pool;
+      last_pool = tmp_pool;
+    }
+
+  svn_pool_destroy (last_pool);
+  svn_pool_destroy (iter_pool);
+
+  return SVN_NO_ERROR;
+}
