You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by rh...@apache.org on 2015/11/30 11:24:23 UTC

svn commit: r1717223 [13/50] - in /subversion/branches/ra-git: ./ build/ build/ac-macros/ build/generator/ build/generator/templates/ contrib/hook-scripts/ notes/ notes/api-errata/1.9/ notes/move-tracking/ subversion/ subversion/bindings/ctypes-python/...

Modified: subversion/branches/ra-git/subversion/libsvn_diff/diff_file.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_diff/diff_file.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_diff/diff_file.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_diff/diff_file.c Mon Nov 30 10:24:16 2015
@@ -777,7 +777,6 @@ datasources_open(void *baton,
 {
   svn_diff__file_baton_t *file_baton = baton;
   struct file_info files[4];
-  apr_finfo_t finfo[4];
   apr_off_t length[4];
 #ifndef SVN_DISABLE_PREFIX_SUFFIX_SCANNING
   svn_boolean_t reached_one_eof;
@@ -792,14 +791,14 @@ datasources_open(void *baton,
   /* Open datasources and read first chunk */
   for (i = 0; i < datasources_len; i++)
     {
+      svn_filesize_t filesize;
       struct file_info *file
           = &file_baton->files[datasource_to_index(datasources[i])];
       SVN_ERR(svn_io_file_open(&file->file, file->path,
                                APR_READ, APR_OS_DEFAULT, file_baton->pool));
-      SVN_ERR(svn_io_file_info_get(&finfo[i], APR_FINFO_SIZE,
-                                   file->file, file_baton->pool));
-      file->size = finfo[i].size;
-      length[i] = finfo[i].size > CHUNK_SIZE ? CHUNK_SIZE : finfo[i].size;
+      SVN_ERR(svn_io_file_size_get(&filesize, file->file, file_baton->pool));
+      file->size = filesize;
+      length[i] = filesize > CHUNK_SIZE ? CHUNK_SIZE : filesize;
       file->buffer = apr_palloc(file_baton->pool, (apr_size_t) length[i]);
       SVN_ERR(read_chunk(file->file, file->buffer,
                          length[i], 0, file_baton->pool));
@@ -1243,17 +1242,20 @@ svn_diff_file_options_parse(svn_diff_fil
 {
   apr_getopt_t *os;
   struct opt_parsing_error_baton_t opt_parsing_error_baton;
-  /* Make room for each option (starting at index 1) plus trailing NULL. */
-  const char **argv = apr_palloc(pool, sizeof(char*) * (args->nelts + 2));
+  apr_array_header_t *argv;
 
   opt_parsing_error_baton.err = NULL;
   opt_parsing_error_baton.pool = pool;
 
-  argv[0] = "";
-  memcpy(argv + 1, args->elts, sizeof(char*) * args->nelts);
-  argv[args->nelts + 1] = NULL;
-
-  apr_getopt_init(&os, pool, args->nelts + 1, argv);
+  /* Make room for each option (starting at index 1) plus trailing NULL. */
+  argv = apr_array_make(pool, args->nelts + 2, sizeof(char*));
+  APR_ARRAY_PUSH(argv, const char *) = "";
+  apr_array_cat(argv, args);
+  APR_ARRAY_PUSH(argv, const char *) = NULL;
+
+  apr_getopt_init(&os, pool, 
+                  argv->nelts - 1 /* Exclude trailing NULL */,
+                  (const char *const *) argv->elts);
 
   /* Capture any error message from apr_getopt_long().  This will typically
    * say which option is wrong, which we would not otherwise know. */
@@ -1417,6 +1419,10 @@ typedef struct svn_diff__file_output_bat
 
   int context_size;
 
+  /* Cancel handler */
+  svn_cancel_func_t cancel_func;
+  void *cancel_baton;
+
   apr_pool_t *pool;
 } svn_diff__file_output_baton_t;
 
@@ -1598,10 +1604,15 @@ static APR_INLINE svn_error_t *
 output_unified_diff_range(svn_diff__file_output_baton_t *output_baton,
                           int source,
                           svn_diff__file_output_unified_type_e type,
-                          apr_off_t until)
+                          apr_off_t until,
+                          svn_cancel_func_t cancel_func,
+                          void *cancel_baton)
 {
   while (output_baton->current_line[source] < until)
     {
+      if (cancel_func)
+        SVN_ERR(cancel_func(cancel_baton));
+
       SVN_ERR(output_unified_line(output_baton, type, source));
     }
   return SVN_NO_ERROR;
@@ -1627,7 +1638,8 @@ output_unified_flush_hunk(svn_diff__file
   /* Add trailing context to the hunk */
   SVN_ERR(output_unified_diff_range(baton, 0 /* original */,
                                     svn_diff__file_output_unified_context,
-                                    target_line));
+                                    target_line,
+                                    baton->cancel_func, baton->cancel_baton));
 
   old_start = baton->hunk_start[0];
   new_start = baton->hunk_start[1];
@@ -1715,7 +1727,9 @@ output_unified_diff_modified(void *baton
         /* Original: Output the context preceding the changed range */
         SVN_ERR(output_unified_diff_range(output_baton, 0 /* original */,
                                           svn_diff__file_output_unified_context,
-                                          original_start));
+                                          original_start,
+                                          output_baton->cancel_func,
+                                          output_baton->cancel_baton));
       }
   }
 
@@ -1723,7 +1737,9 @@ output_unified_diff_modified(void *baton
      to display */
   SVN_ERR(output_unified_diff_range(output_baton, 0 /* original */,
                                     svn_diff__file_output_unified_skip,
-                                    original_start - context_prefix_length));
+                                    original_start - context_prefix_length,
+                                    output_baton->cancel_func,
+                                    output_baton->cancel_baton));
 
   /* Note that the above skip stores data for the show_c_function support below */
 
@@ -1769,20 +1785,28 @@ output_unified_diff_modified(void *baton
   /* Modified: Skip lines until we are at the start of the changed range */
   SVN_ERR(output_unified_diff_range(output_baton, 1 /* modified */,
                                     svn_diff__file_output_unified_skip,
-                                    modified_start));
+                                    modified_start,
+                                    output_baton->cancel_func,
+                                    output_baton->cancel_baton));
 
   /* Original: Output the context preceding the changed range */
   SVN_ERR(output_unified_diff_range(output_baton, 0 /* original */,
                                     svn_diff__file_output_unified_context,
-                                    original_start));
+                                    original_start,
+                                    output_baton->cancel_func,
+                                    output_baton->cancel_baton));
 
   /* Both: Output the changed range */
   SVN_ERR(output_unified_diff_range(output_baton, 0 /* original */,
                                     svn_diff__file_output_unified_delete,
-                                    original_start + original_length));
+                                    original_start + original_length,
+                                    output_baton->cancel_func,
+                                    output_baton->cancel_baton));
   SVN_ERR(output_unified_diff_range(output_baton, 1 /* modified */,
                                     svn_diff__file_output_unified_insert,
-                                    modified_start + modified_length));
+                                    modified_start + modified_length,
+                                    output_baton->cancel_func,
+                                    output_baton->cancel_baton));
 
   return SVN_NO_ERROR;
 }
@@ -1843,6 +1867,8 @@ svn_diff_file_output_unified4(svn_stream
 
       memset(&baton, 0, sizeof(baton));
       baton.output_stream = output_stream;
+      baton.cancel_func = cancel_func;
+      baton.cancel_baton = cancel_baton;
       baton.pool = pool;
       baton.header_encoding = header_encoding;
       baton.path[0] = original_path;
@@ -1956,7 +1982,7 @@ typedef struct context_saver_t {
   const char **data; /* const char *data[context_size] */
   apr_size_t *len;   /* apr_size_t len[context_size] */
   apr_size_t next_slot;
-  apr_size_t total_written;
+  apr_ssize_t total_writes;
 } context_saver_t;
 
 
@@ -1972,7 +1998,7 @@ context_saver_stream_write(void *baton,
       cs->data[cs->next_slot] = data;
       cs->len[cs->next_slot] = *len;
       cs->next_slot = (cs->next_slot + 1) % cs->context_size;
-      cs->total_written++;
+      cs->total_writes++;
     }
   return SVN_NO_ERROR;
 }
@@ -2252,7 +2278,7 @@ output_conflict_with_context(svn_diff3__
      trailing context)?  If so, flush it. */
   if (btn->output_stream == btn->context_saver->stream)
     {
-      if (btn->context_saver->total_written > btn->context_size)
+      if (btn->context_saver->total_writes > btn->context_size)
         SVN_ERR(svn_stream_puts(btn->real_output_stream, "@@\n"));
       SVN_ERR(flush_context_saver(btn->context_saver, btn->real_output_stream));
     }
@@ -2360,7 +2386,7 @@ svn_diff_file_output_merge3(svn_stream_t
                             svn_diff_conflict_display_style_t style,
                             svn_cancel_func_t cancel_func,
                             void *cancel_baton,
-                            apr_pool_t *pool)
+                            apr_pool_t *scratch_pool)
 {
   svn_diff3__file_output_baton_t baton;
   apr_file_t *file[3];
@@ -2376,7 +2402,7 @@ svn_diff_file_output_merge3(svn_stream_t
   baton.context_size = SVN_DIFF__UNIFIED_CONTEXT_SIZE;
   if (conflicts_only)
     {
-      baton.pool = svn_pool_create(pool);
+      baton.pool = svn_pool_create(scratch_pool);
       make_context_saver(&baton);
       baton.real_output_stream = output_stream;
     }
@@ -2387,22 +2413,22 @@ svn_diff_file_output_merge3(svn_stream_t
   baton.path[2] = latest_path;
   SVN_ERR(svn_utf_cstring_from_utf8(&baton.conflict_modified,
                                     conflict_modified ? conflict_modified
-                                    : apr_psprintf(pool, "<<<<<<< %s",
+                                    : apr_psprintf(scratch_pool, "<<<<<<< %s",
                                                    modified_path),
-                                    pool));
+                                    scratch_pool));
   SVN_ERR(svn_utf_cstring_from_utf8(&baton.conflict_original,
                                     conflict_original ? conflict_original
-                                    : apr_psprintf(pool, "||||||| %s",
+                                    : apr_psprintf(scratch_pool, "||||||| %s",
                                                    original_path),
-                                    pool));
+                                    scratch_pool));
   SVN_ERR(svn_utf_cstring_from_utf8(&baton.conflict_separator,
                                     conflict_separator ? conflict_separator
-                                    : "=======", pool));
+                                    : "=======", scratch_pool));
   SVN_ERR(svn_utf_cstring_from_utf8(&baton.conflict_latest,
                                     conflict_latest ? conflict_latest
-                                    : apr_psprintf(pool, ">>>>>>> %s",
+                                    : apr_psprintf(scratch_pool, ">>>>>>> %s",
                                                    latest_path),
-                                    pool));
+                                    scratch_pool));
 
   baton.conflict_style = style;
 
@@ -2413,7 +2439,7 @@ svn_diff_file_output_merge3(svn_stream_t
       SVN_ERR(map_or_read_file(&file[idx],
                                MMAP_T_ARG(mm[idx])
                                &baton.buffer[idx], &size,
-                               baton.path[idx], pool));
+                               baton.path[idx], scratch_pool));
 
       baton.curp[idx] = baton.buffer[idx];
       baton.endp[idx] = baton.buffer[idx];
@@ -2454,7 +2480,7 @@ svn_diff_file_output_merge3(svn_stream_t
 
       if (file[idx])
         {
-          SVN_ERR(svn_io_file_close(file[idx], pool));
+          SVN_ERR(svn_io_file_close(file[idx], scratch_pool));
         }
     }
 

Modified: subversion/branches/ra-git/subversion/libsvn_diff/diff_memory.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_diff/diff_memory.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_diff/diff_memory.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_diff/diff_memory.c Mon Nov 30 10:24:16 2015
@@ -622,7 +622,7 @@ svn_diff_mem_string_output_unified3(svn_
                                     int context_size,
                                     svn_cancel_func_t cancel_func,
                                     void *cancel_baton,
-                                    apr_pool_t *pool)
+                                    apr_pool_t *scratch_pool)
 {
 
   if (svn_diff_contains_diffs(diff))
@@ -631,9 +631,9 @@ svn_diff_mem_string_output_unified3(svn_
 
       memset(&baton, 0, sizeof(baton));
       baton.output_stream = output_stream;
-      baton.pool = svn_pool_create(pool);
+      baton.pool = svn_pool_create(scratch_pool);
       baton.header_encoding = header_encoding;
-      baton.hunk = svn_stringbuf_create_empty(pool);
+      baton.hunk = svn_stringbuf_create_empty(scratch_pool);
       baton.hunk_delimiter = hunk_delimiter;
       baton.no_newline_string
         = (hunk_delimiter == NULL || strcmp(hunk_delimiter, "##") != 0)
@@ -644,22 +644,22 @@ svn_diff_mem_string_output_unified3(svn_
 
       SVN_ERR(svn_utf_cstring_from_utf8_ex2
               (&(baton.prefix_str[unified_output_context]), " ",
-               header_encoding, pool));
+               header_encoding, scratch_pool));
       SVN_ERR(svn_utf_cstring_from_utf8_ex2
               (&(baton.prefix_str[unified_output_delete]), "-",
-               header_encoding, pool));
+               header_encoding, scratch_pool));
       SVN_ERR(svn_utf_cstring_from_utf8_ex2
               (&(baton.prefix_str[unified_output_insert]), "+",
-               header_encoding, pool));
+               header_encoding, scratch_pool));
 
-      fill_source_tokens(&baton.sources[0], original, pool);
-      fill_source_tokens(&baton.sources[1], modified, pool);
+      fill_source_tokens(&baton.sources[0], original, scratch_pool);
+      fill_source_tokens(&baton.sources[1], modified, scratch_pool);
 
       if (with_diff_header)
         {
           SVN_ERR(svn_diff__unidiff_write_header(
                     output_stream, header_encoding,
-                    original_header, modified_header, pool));
+                    original_header, modified_header, scratch_pool));
         }
 
       SVN_ERR(svn_diff_output2(diff, &baton,
@@ -688,7 +688,7 @@ typedef struct context_saver_t {
   const char **data; /* const char *data[context_size] */
   apr_size_t *len;   /* apr_size_t len[context_size] */
   apr_size_t next_slot;
-  apr_size_t total_written;
+  apr_ssize_t total_writes;
 } context_saver_t;
 
 
@@ -701,7 +701,7 @@ context_saver_stream_write(void *baton,
   cs->data[cs->next_slot] = data;
   cs->len[cs->next_slot] = *len;
   cs->next_slot = (cs->next_slot + 1) % cs->context_size;
-  cs->total_written++;
+  cs->total_writes++;
   return SVN_NO_ERROR;
 }
 
@@ -822,13 +822,11 @@ make_trailing_context_printer(merge_outp
 
 
 static svn_error_t *
-output_merge_token_range(apr_size_t *lines_printed_p,
-                         merge_output_baton_t *btn,
+output_merge_token_range(merge_output_baton_t *btn,
                          int idx, apr_off_t first,
                          apr_off_t length)
 {
   apr_array_header_t *tokens = btn->sources[idx].tokens;
-  apr_size_t lines_printed = 0;
 
   for (; length > 0 && first < tokens->nelts; length--, first++)
     {
@@ -838,12 +836,8 @@ output_merge_token_range(apr_size_t *lin
       /* Note that the trailing context printer assumes that
          svn_stream_write is called exactly once per line. */
       SVN_ERR(svn_stream_write(btn->output_stream, token->data, &len));
-      lines_printed++;
     }
 
-  if (lines_printed_p)
-    *lines_printed_p = lines_printed;
-
   return SVN_NO_ERROR;
 }
 
@@ -866,7 +860,7 @@ output_common_modified(void *baton,
                        apr_off_t modified_start, apr_off_t modified_length,
                        apr_off_t latest_start, apr_off_t latest_length)
 {
-  return output_merge_token_range(NULL, baton, 1/*modified*/,
+  return output_merge_token_range(baton, 1/*modified*/,
                                   modified_start, modified_length);
 }
 
@@ -876,7 +870,7 @@ output_latest(void *baton,
               apr_off_t modified_start, apr_off_t modified_length,
               apr_off_t latest_start, apr_off_t latest_length)
 {
-  return output_merge_token_range(NULL, baton, 2/*latest*/,
+  return output_merge_token_range(baton, 2/*latest*/,
                                   latest_start, latest_length);
 }
 
@@ -920,26 +914,26 @@ output_conflict(void *baton,
       style == svn_diff_conflict_display_modified_original_latest)
     {
       SVN_ERR(output_merge_marker(btn, 1/*modified*/));
-      SVN_ERR(output_merge_token_range(NULL, btn, 1/*modified*/,
+      SVN_ERR(output_merge_token_range(btn, 1/*modified*/,
                                        modified_start, modified_length));
 
       if (style == svn_diff_conflict_display_modified_original_latest)
         {
           SVN_ERR(output_merge_marker(btn, 0/*original*/));
-          SVN_ERR(output_merge_token_range(NULL, btn, 0/*original*/,
+          SVN_ERR(output_merge_token_range(btn, 0/*original*/,
                                            original_start, original_length));
         }
 
       SVN_ERR(output_merge_marker(btn, 2/*separator*/));
-      SVN_ERR(output_merge_token_range(NULL, btn, 2/*latest*/,
+      SVN_ERR(output_merge_token_range(btn, 2/*latest*/,
                                        latest_start, latest_length));
       SVN_ERR(output_merge_marker(btn, 3/*latest (end)*/));
     }
   else if (style == svn_diff_conflict_display_modified)
-      SVN_ERR(output_merge_token_range(NULL, btn, 1/*modified*/,
+      SVN_ERR(output_merge_token_range(btn, 1/*modified*/,
                                        modified_start, modified_length));
   else if (style == svn_diff_conflict_display_latest)
-      SVN_ERR(output_merge_token_range(NULL, btn, 2/*latest*/,
+      SVN_ERR(output_merge_token_range(btn, 2/*latest*/,
                                        latest_start, latest_length));
   else /* unknown style */
     SVN_ERR_MALFUNCTION();
@@ -983,7 +977,7 @@ output_conflict_with_context(void *baton
      trailing context)?  If so, flush it. */
   if (btn->output_stream == btn->context_saver->stream)
     {
-      if (btn->context_saver->total_written > btn->context_size)
+      if (btn->context_saver->total_writes > btn->context_size)
         SVN_ERR(svn_stream_puts(btn->real_output_stream, "@@\n"));
       SVN_ERR(flush_context_saver(btn->context_saver, btn->real_output_stream));
     }
@@ -995,17 +989,17 @@ output_conflict_with_context(void *baton
   SVN_ERR(output_conflict_with_context_marker(btn, btn->markers[1],
                                               modified_start,
                                               modified_length));
-  SVN_ERR(output_merge_token_range(NULL, btn, 1/*modified*/,
+  SVN_ERR(output_merge_token_range(btn, 1/*modified*/,
                                    modified_start, modified_length));
 
   SVN_ERR(output_conflict_with_context_marker(btn, btn->markers[0],
                                               original_start,
                                               original_length));
-  SVN_ERR(output_merge_token_range(NULL, btn, 0/*original*/,
+  SVN_ERR(output_merge_token_range(btn, 0/*original*/,
                                    original_start, original_length));
 
   SVN_ERR(output_merge_marker(btn, 2/*separator*/));
-  SVN_ERR(output_merge_token_range(NULL, btn, 2/*latest*/,
+  SVN_ERR(output_merge_token_range(btn, 2/*latest*/,
                                    latest_start, latest_length));
   SVN_ERR(output_conflict_with_context_marker(btn, btn->markers[3],
                                               latest_start,
@@ -1066,7 +1060,7 @@ svn_diff_mem_string_output_merge3(svn_st
                                   svn_diff_conflict_display_style_t style,
                                   svn_cancel_func_t cancel_func,
                                   void *cancel_baton,
-                                  apr_pool_t *pool)
+                                  apr_pool_t *scratch_pool)
 {
   merge_output_baton_t btn;
   const char *eol;
@@ -1080,16 +1074,16 @@ svn_diff_mem_string_output_merge3(svn_st
 
   if (conflicts_only)
     {
-      btn.pool = svn_pool_create(pool);
+      btn.pool = svn_pool_create(scratch_pool);
       make_context_saver(&btn);
       btn.real_output_stream = output_stream;
     }
   else
     btn.output_stream = output_stream;
 
-  fill_source_tokens(&(btn.sources[0]), original, pool);
-  fill_source_tokens(&(btn.sources[1]), modified, pool);
-  fill_source_tokens(&(btn.sources[2]), latest, pool);
+  fill_source_tokens(&(btn.sources[0]), original, scratch_pool);
+  fill_source_tokens(&(btn.sources[1]), modified, scratch_pool);
+  fill_source_tokens(&(btn.sources[2]), latest, scratch_pool);
 
   btn.conflict_style = style;
 
@@ -1110,22 +1104,22 @@ svn_diff_mem_string_output_merge3(svn_st
                                     conflict_modified
                                     ? conflict_modified
                                     : "<<<<<<< (modified)",
-                                    pool));
+                                    scratch_pool));
   SVN_ERR(svn_utf_cstring_from_utf8(&btn.markers[0],
                                     conflict_original
                                     ? conflict_original
                                     : "||||||| (original)",
-                                    pool));
+                                    scratch_pool));
   SVN_ERR(svn_utf_cstring_from_utf8(&btn.markers[2],
                                     conflict_separator
                                     ? conflict_separator
                                     : "=======",
-                                    pool));
+                                    scratch_pool));
   SVN_ERR(svn_utf_cstring_from_utf8(&btn.markers[3],
                                     conflict_latest
                                     ? conflict_latest
                                     : ">>>>>>> (latest)",
-                                    pool));
+                                    scratch_pool));
 
   SVN_ERR(svn_diff_output2(diff, &btn, vtable, cancel_func, cancel_baton));
   if (conflicts_only)

Modified: subversion/branches/ra-git/subversion/libsvn_diff/parse-diff.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_diff/parse-diff.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_diff/parse-diff.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_diff/parse-diff.c Mon Nov 30 10:24:16 2015
@@ -40,8 +40,13 @@
 
 #include "private/svn_eol_private.h"
 #include "private/svn_dep_compat.h"
+#include "private/svn_diff_private.h"
 #include "private/svn_sorts_private.h"
 
+#include "diff.h"
+
+#include "svn_private_config.h"
+
 /* Helper macro for readability */
 #define starts_with(str, start)  \
   (strncmp((str), (start), strlen(start)) == 0)
@@ -59,7 +64,7 @@ struct svn_diff__hunk_range {
 
 struct svn_diff_hunk_t {
   /* The patch this hunk belongs to. */
-  svn_patch_t *patch;
+  const svn_patch_t *patch;
 
   /* APR file handle to the patch file this hunk came from. */
   apr_file_t *apr_file;
@@ -80,8 +85,146 @@ struct svn_diff_hunk_t {
   /* Number of lines of leading and trailing hunk context. */
   svn_linenum_t leading_context;
   svn_linenum_t trailing_context;
+
+  /* Did we see a 'file does not end with eol' marker in this hunk? */
+  svn_boolean_t original_no_final_eol;
+  svn_boolean_t modified_no_final_eol;
 };
 
+struct svn_diff_binary_patch_t {
+  /* The patch this hunk belongs to. */
+  const svn_patch_t *patch;
+
+  /* APR file handle to the patch file this hunk came from. */
+  apr_file_t *apr_file;
+
+  /* Offsets inside APR_FILE representing the location of the patch */
+  apr_off_t src_start;
+  apr_off_t src_end;
+  svn_filesize_t src_filesize; /* Expanded/final size */
+
+  /* Offsets inside APR_FILE representing the location of the patch */
+  apr_off_t dst_start;
+  apr_off_t dst_end;
+  svn_filesize_t dst_filesize; /* Expanded/final size */
+};
+
+/* Common guts of svn_diff_hunk__create_adds_single_line() and
+ * svn_diff_hunk__create_deletes_single_line().
+ *
+ * ADD is TRUE if adding and FALSE if deleting.
+ */
+static svn_error_t *
+add_or_delete_single_line(svn_diff_hunk_t **hunk_out,
+                          const char *line,
+                          const svn_patch_t *patch,
+                          svn_boolean_t add,
+                          apr_pool_t *result_pool,
+                          apr_pool_t *scratch_pool)
+{
+  svn_diff_hunk_t *hunk = apr_palloc(result_pool, sizeof(*hunk));
+  static const char *hunk_header[] = { "@@ -1 +0,0 @@\n", "@@ -0,0 +1 @@\n" };
+  const apr_size_t header_len = strlen(hunk_header[add]);
+  const apr_size_t len = strlen(line);
+  const apr_size_t end = header_len + (1 + len); /* The +1 is for the \n. */
+  svn_stringbuf_t *buf = svn_stringbuf_create_ensure(end + 1, scratch_pool);
+
+  hunk->patch = patch;
+
+  /* hunk->apr_file is created below. */
+
+  hunk->diff_text_range.start = header_len;
+  hunk->diff_text_range.current = header_len;
+
+  if (add)
+    {
+      hunk->original_text_range.start = 0; /* There's no "original" text. */
+      hunk->original_text_range.current = 0;
+      hunk->original_text_range.end = 0;
+      hunk->original_no_final_eol = FALSE;
+
+      hunk->modified_text_range.start = header_len;
+      hunk->modified_text_range.current = header_len;
+      hunk->modified_text_range.end = end;
+      hunk->modified_no_final_eol = TRUE;
+
+      hunk->original_start = 0;
+      hunk->original_length = 0;
+
+      hunk->modified_start = 1;
+      hunk->modified_length = 1;
+    }
+  else /* delete */
+    {
+      hunk->original_text_range.start = header_len;
+      hunk->original_text_range.current = header_len;
+      hunk->original_text_range.end = end;
+      hunk->original_no_final_eol = TRUE;
+
+      hunk->modified_text_range.start = 0; /* There's no "original" text. */
+      hunk->modified_text_range.current = 0;
+      hunk->modified_text_range.end = 0;
+      hunk->modified_no_final_eol = FALSE;
+
+      hunk->original_start = 1;
+      hunk->original_length = 1;
+
+      hunk->modified_start = 0;
+      hunk->modified_length = 0; /* setting to '1' works too */
+    }
+
+  hunk->leading_context = 0;
+  hunk->trailing_context = 0;
+
+  /* Create APR_FILE and put just a hunk in it (without a diff header).
+   * Save the offset of the last byte of the diff line. */
+  svn_stringbuf_appendbytes(buf, hunk_header[add], header_len);
+  svn_stringbuf_appendbyte(buf, add ? '+' : '-');
+  svn_stringbuf_appendbytes(buf, line, len);
+  svn_stringbuf_appendbyte(buf, '\n');
+  svn_stringbuf_appendcstr(buf, "\\ No newline at end of hunk\n");
+
+  hunk->diff_text_range.end = buf->len;
+
+  SVN_ERR(svn_io_open_unique_file3(&hunk->apr_file, NULL /* filename */,
+                                   NULL /* system tempdir */,
+                                   svn_io_file_del_on_pool_cleanup,
+                                   result_pool, scratch_pool));
+  SVN_ERR(svn_io_file_write_full(hunk->apr_file,
+                                 buf->data, buf->len,
+                                 NULL, scratch_pool));
+  /* No need to seek. */
+
+  *hunk_out = hunk;
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_diff_hunk__create_adds_single_line(svn_diff_hunk_t **hunk_out,
+                                       const char *line,
+                                       const svn_patch_t *patch,
+                                       apr_pool_t *result_pool,
+                                       apr_pool_t *scratch_pool)
+{
+  SVN_ERR(add_or_delete_single_line(hunk_out, line, patch, 
+                                    (!patch->reverse),
+                                    result_pool, scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_diff_hunk__create_deletes_single_line(svn_diff_hunk_t **hunk_out,
+                                          const char *line,
+                                          const svn_patch_t *patch,
+                                          apr_pool_t *result_pool,
+                                          apr_pool_t *scratch_pool)
+{
+  SVN_ERR(add_or_delete_single_line(hunk_out, line, patch,
+                                    patch->reverse,
+                                    result_pool, scratch_pool));
+  return SVN_NO_ERROR;
+}
+
 void
 svn_diff_hunk_reset_diff_text(svn_diff_hunk_t *hunk)
 {
@@ -142,6 +285,217 @@ svn_diff_hunk_get_trailing_context(const
   return hunk->trailing_context;
 }
 
+/* Baton for the base85 stream implementation */
+struct base85_baton_t
+{
+  apr_file_t *file;
+  apr_pool_t *iterpool;
+  char buffer[52];        /* Bytes on current line */
+  apr_off_t next_pos;     /* Start position of next line */
+  apr_off_t end_pos;      /* Position after last line */
+  apr_size_t buf_size;    /* Bytes available (52 unless at eof) */
+  apr_size_t buf_pos;     /* Bytes in linebuffer */
+  svn_boolean_t done;     /* At eof? */
+};
+
+/* Implements svn_read_fn_t for the base85 read stream */
+static svn_error_t *
+read_handler_base85(void *baton, char *buffer, apr_size_t *len)
+{
+  struct base85_baton_t *b85b = baton;
+  apr_pool_t *iterpool = b85b->iterpool;
+  apr_size_t remaining = *len;
+  char *dest = buffer;
+
+  svn_pool_clear(iterpool);
+
+  if (b85b->done)
+    {
+      *len = 0;
+      return SVN_NO_ERROR;
+    }
+
+  while (remaining && (b85b->buf_size > b85b->buf_pos
+                       || b85b->next_pos < b85b->end_pos))
+    {
+      svn_stringbuf_t *line;
+      svn_boolean_t at_eof;
+
+      apr_size_t available = b85b->buf_size - b85b->buf_pos;
+      if (available)
+        {
+          apr_size_t n = (remaining < available) ? remaining : available;
+
+          memcpy(dest, b85b->buffer + b85b->buf_pos, n);
+          dest += n;
+          remaining -= n;
+          b85b->buf_pos += n;
+
+          if (!remaining)
+            return SVN_NO_ERROR; /* *len = OK */
+        }
+
+      if (b85b->next_pos >= b85b->end_pos)
+        break; /* At EOF */
+      SVN_ERR(svn_io_file_seek(b85b->file, APR_SET, &b85b->next_pos,
+                               iterpool));
+      SVN_ERR(svn_io_file_readline(b85b->file, &line, NULL, &at_eof,
+                                   APR_SIZE_MAX, iterpool, iterpool));
+      if (at_eof)
+        b85b->next_pos = b85b->end_pos;
+      else
+        {
+          b85b->next_pos = 0;
+          SVN_ERR(svn_io_file_seek(b85b->file, APR_CUR, &b85b->next_pos,
+                                   iterpool));
+        }
+
+      if (line->len && line->data[0] >= 'A' && line->data[0] <= 'Z')
+        b85b->buf_size = line->data[0] - 'A' + 1;
+      else if (line->len && line->data[0] >= 'a' && line->data[0] <= 'z')
+        b85b->buf_size = line->data[0] - 'a' + 26 + 1;
+      else
+        return svn_error_create(SVN_ERR_DIFF_UNEXPECTED_DATA, NULL,
+                                _("Unexpected data in base85 section"));
+
+      if (b85b->buf_size < 52)
+        b85b->next_pos = b85b->end_pos; /* Handle as EOF */
+
+      SVN_ERR(svn_diff__base85_decode_line(b85b->buffer, b85b->buf_size,
+                                           line->data + 1, line->len - 1,
+                                           iterpool));
+      b85b->buf_pos = 0;
+    }
+
+  *len -= remaining;
+  b85b->done = TRUE;
+
+  return SVN_NO_ERROR;
+}
+
+/* Implements svn_close_fn_t for the base85 read stream */
+static svn_error_t *
+close_handler_base85(void *baton)
+{
+  struct base85_baton_t *b85b = baton;
+
+  svn_pool_destroy(b85b->iterpool);
+
+  return SVN_NO_ERROR;
+}
+
+/* Gets a stream that reads decoded base85 data from a segment of a file.
+   The current implementation might assume that both start_pos and end_pos
+   are located at line boundaries. */
+static svn_stream_t *
+get_base85_data_stream(apr_file_t *file,
+                       apr_off_t start_pos,
+                       apr_off_t end_pos,
+                       apr_pool_t *result_pool)
+{
+  struct base85_baton_t *b85b = apr_pcalloc(result_pool, sizeof(*b85b));
+  svn_stream_t *base85s = svn_stream_create(b85b, result_pool);
+
+  b85b->file = file;
+  b85b->iterpool = svn_pool_create(result_pool);
+  b85b->next_pos = start_pos;
+  b85b->end_pos = end_pos;
+
+  svn_stream_set_read2(base85s, NULL /* only full read support */,
+                       read_handler_base85);
+  svn_stream_set_close(base85s, close_handler_base85);
+  return base85s;
+}
+
+/* Baton for the length verification stream functions */
+struct length_verify_baton_t
+{
+  svn_stream_t *inner;
+  svn_filesize_t remaining;
+};
+
+/* Implements svn_read_fn_t for the length verification stream */
+static svn_error_t *
+read_handler_length_verify(void *baton, char *buffer, apr_size_t *len)
+{
+  struct length_verify_baton_t *lvb = baton;
+  apr_size_t requested_len = *len;
+
+  SVN_ERR(svn_stream_read_full(lvb->inner, buffer, len));
+
+  if (*len > lvb->remaining)
+    return svn_error_create(SVN_ERR_DIFF_UNEXPECTED_DATA, NULL,
+                            _("Base85 data expands to longer than declared "
+                              "filesize"));
+  else if (requested_len > *len && *len != lvb->remaining)
+    return svn_error_create(SVN_ERR_DIFF_UNEXPECTED_DATA, NULL,
+                            _("Base85 data expands to smaller than declared "
+                              "filesize"));
+
+  lvb->remaining -= *len;
+
+  return SVN_NO_ERROR;
+}
+
+/* Implements svn_close_fn_t for the length verification stream */
+static svn_error_t *
+close_handler_length_verify(void *baton)
+{
+  struct length_verify_baton_t *lvb = baton;
+
+  return svn_error_trace(svn_stream_close(lvb->inner));
+}
+
+/* Gets a stream that verifies on reads that the inner stream is exactly
+   of the specified length */
+static svn_stream_t *
+get_verify_length_stream(svn_stream_t *inner,
+                         svn_filesize_t expected_size,
+                         apr_pool_t *result_pool)
+{
+  struct length_verify_baton_t *lvb = apr_palloc(result_pool, sizeof(*lvb));
+  svn_stream_t *len_stream = svn_stream_create(lvb, result_pool);
+
+  lvb->inner = inner;
+  lvb->remaining = expected_size;
+
+  svn_stream_set_read2(len_stream, NULL /* only full read support */,
+                       read_handler_length_verify);
+  svn_stream_set_close(len_stream, close_handler_length_verify);
+
+  return len_stream;
+}
+
+svn_stream_t *
+svn_diff_get_binary_diff_original_stream(const svn_diff_binary_patch_t *bpatch,
+                                         apr_pool_t *result_pool)
+{
+  svn_stream_t *s = get_base85_data_stream(bpatch->apr_file, bpatch->src_start,
+                                           bpatch->src_end, result_pool);
+
+  s = svn_stream_compressed(s, result_pool);
+
+  /* ### If we (ever) want to support the DELTA format, then we should hook the
+         undelta handling here */
+
+  return get_verify_length_stream(s, bpatch->src_filesize, result_pool);
+}
+
+svn_stream_t *
+svn_diff_get_binary_diff_result_stream(const svn_diff_binary_patch_t *bpatch,
+                                       apr_pool_t *result_pool)
+{
+  svn_stream_t *s = get_base85_data_stream(bpatch->apr_file, bpatch->dst_start,
+                                           bpatch->dst_end, result_pool);
+
+  s = svn_stream_compressed(s, result_pool);
+
+  /* ### If we (ever) want to support the DELTA format, then we should hook the
+  undelta handling here */
+
+  return get_verify_length_stream(s, bpatch->dst_filesize, result_pool);
+}
+
 /* Try to parse a positive number from a decimal number encoded
  * in the string NUMBER. Return parsed number in OFFSET, and return
  * TRUE if parsing was successful. */
@@ -279,7 +633,8 @@ parse_hunk_header(const char *header, sv
  * Leading unidiff symbols ('+', '-', and ' ') are removed from the line,
  * Any lines commencing with the VERBOTEN character are discarded.
  * VERBOTEN should be '+' or '-', depending on which form of hunk text
- * is being read.
+ * is being read. NO_FINAL_EOL declares if the hunk contains a no final
+ * EOL marker.
  *
  * All other parameters are as in svn_diff_hunk_readline_original_text()
  * and svn_diff_hunk_readline_modified_text().
@@ -291,6 +646,7 @@ hunk_readline_original_or_modified(apr_f
                                    const char **eol,
                                    svn_boolean_t *eof,
                                    char verboten,
+                                   svn_boolean_t no_final_eol,
                                    apr_pool_t *result_pool,
                                    apr_pool_t *scratch_pool)
 {
@@ -298,13 +654,17 @@ hunk_readline_original_or_modified(apr_f
   svn_boolean_t filtered;
   apr_off_t pos;
   svn_stringbuf_t *str;
+  const char *eol_p;
+  apr_pool_t *last_pool;
+
+  if (!eol)
+    eol = &eol_p;
 
   if (range->current >= range->end)
     {
       /* We're past the range. Indicate that no bytes can be read. */
       *eof = TRUE;
-      if (eol)
-        *eol = NULL;
+      *eol = NULL;
       *stringbuf = svn_stringbuf_create_empty(result_pool);
       return SVN_NO_ERROR;
     }
@@ -312,13 +672,19 @@ hunk_readline_original_or_modified(apr_f
   pos = 0;
   SVN_ERR(svn_io_file_seek(file, APR_CUR, &pos,  scratch_pool));
   SVN_ERR(svn_io_file_seek(file, APR_SET, &range->current, scratch_pool));
+
+  /* It's not ITERPOOL because we use data allocated in LAST_POOL out
+     of the loop. */
+  last_pool = svn_pool_create(scratch_pool);
   do
     {
+      svn_pool_clear(last_pool);
+
       max_len = range->end - range->current;
       SVN_ERR(svn_io_file_readline(file, &str, eol, eof, max_len,
-                                   result_pool, scratch_pool));
+                                   last_pool, last_pool));
       range->current = 0;
-      SVN_ERR(svn_io_file_seek(file, APR_CUR, &range->current, scratch_pool));
+      SVN_ERR(svn_io_file_seek(file, APR_CUR, &range->current, last_pool));
       filtered = (str->data[0] == verboten || str->data[0] == '\\');
     }
   while (filtered && ! *eof);
@@ -327,6 +693,7 @@ hunk_readline_original_or_modified(apr_f
     {
       /* EOF, return an empty string. */
       *stringbuf = svn_stringbuf_create_ensure(0, result_pool);
+      *eol = NULL;
     }
   else if (str->data[0] == '+' || str->data[0] == '-' || str->data[0] == ' ')
     {
@@ -335,12 +702,37 @@ hunk_readline_original_or_modified(apr_f
     }
   else
     {
-      /* Return the line as-is. */
+      /* Return the line as-is. Handle as a chopped leading spaces */
       *stringbuf = svn_stringbuf_dup(str, result_pool);
     }
 
+  if (!filtered && *eof && !*eol && *str->data)
+    {
+      /* Ok, we miss a final EOL in the patch file, but didn't see a
+         no eol marker line.
+
+         We should report that we had an EOL or the patch code will
+         misbehave (and it knows nothing about no eol markers) */
+
+      if (!no_final_eol && eol != &eol_p)
+        {
+          apr_off_t start = 0;
+
+          SVN_ERR(svn_io_file_seek(file, APR_SET, &start, scratch_pool));
+
+          SVN_ERR(svn_io_file_readline(file, &str, eol, NULL, APR_SIZE_MAX,
+                                       scratch_pool, scratch_pool));
+
+          /* Every patch file that has hunks has at least one EOL*/
+          SVN_ERR_ASSERT(*eol != NULL);
+        }
+
+      *eof = FALSE;
+      /* Fall through to seek back to the right location */
+    }
   SVN_ERR(svn_io_file_seek(file, APR_SET, &pos, scratch_pool));
 
+  svn_pool_destroy(last_pool);
   return SVN_NO_ERROR;
 }
 
@@ -359,6 +751,9 @@ svn_diff_hunk_readline_original_text(svn
                                          &hunk->original_text_range,
                                        stringbuf, eol, eof,
                                        hunk->patch->reverse ? '-' : '+',
+                                       hunk->patch->reverse
+                                          ? hunk->modified_no_final_eol
+                                          : hunk->original_no_final_eol,
                                        result_pool, scratch_pool));
 }
 
@@ -377,6 +772,9 @@ svn_diff_hunk_readline_modified_text(svn
                                          &hunk->modified_text_range,
                                        stringbuf, eol, eof,
                                        hunk->patch->reverse ? '+' : '-',
+                                       hunk->patch->reverse
+                                          ? hunk->original_no_final_eol
+                                          : hunk->modified_no_final_eol,
                                        result_pool, scratch_pool));
 }
 
@@ -391,13 +789,16 @@ svn_diff_hunk_readline_diff_text(svn_dif
   svn_stringbuf_t *line;
   apr_size_t max_len;
   apr_off_t pos;
+  const char *eol_p;
+
+  if (!eol)
+    eol = &eol_p;
 
   if (hunk->diff_text_range.current >= hunk->diff_text_range.end)
     {
       /* We're past the range. Indicate that no bytes can be read. */
       *eof = TRUE;
-      if (eol)
-        *eol = NULL;
+      *eol = NULL;
       *stringbuf = svn_stringbuf_create_empty(result_pool);
       return SVN_NO_ERROR;
     }
@@ -413,6 +814,37 @@ svn_diff_hunk_readline_diff_text(svn_dif
   hunk->diff_text_range.current = 0;
   SVN_ERR(svn_io_file_seek(hunk->apr_file, APR_CUR,
                            &hunk->diff_text_range.current, scratch_pool));
+
+  if (*eof && !*eol && *line->data)
+    {
+      /* Ok, we miss a final EOL in the patch file, but didn't see a
+          no eol marker line.
+
+          We should report that we had an EOL or the patch code will
+          misbehave (and it knows nothing about no eol markers) */
+
+      if (eol != &eol_p)
+        {
+          /* Lets pick the first eol we find in our patch file */
+          apr_off_t start = 0;
+          svn_stringbuf_t *str;
+
+          SVN_ERR(svn_io_file_seek(hunk->apr_file, APR_SET, &start,
+                                   scratch_pool));
+
+          SVN_ERR(svn_io_file_readline(hunk->apr_file, &str, eol, NULL,
+                                       APR_SIZE_MAX,
+                                       scratch_pool, scratch_pool));
+
+          /* Every patch file that has hunks has at least one EOL*/
+          SVN_ERR_ASSERT(*eol != NULL);
+        }
+
+      *eof = FALSE;
+
+      /* Fall through to seek back to the right location */
+    }
+
   SVN_ERR(svn_io_file_seek(hunk->apr_file, APR_SET, &pos, scratch_pool));
 
   if (hunk->patch->reverse)
@@ -619,6 +1051,8 @@ parse_next_hunk(svn_diff_hunk_t **hunk,
   apr_off_t start, end;
   apr_off_t original_end;
   apr_off_t modified_end;
+  svn_boolean_t original_no_final_eol = FALSE;
+  svn_boolean_t modified_no_final_eol = FALSE;
   svn_linenum_t original_lines;
   svn_linenum_t modified_lines;
   svn_linenum_t leading_context;
@@ -715,6 +1149,11 @@ parse_next_hunk(svn_diff_hunk_t **hunk,
                 }
 
               SVN_ERR(svn_io_file_seek(apr_file, APR_SET, &pos, iterpool));
+              /* Set for the type and context by using != the other type */
+              if (last_line_type != modified_line)
+                original_no_final_eol = TRUE;
+              if (last_line_type != original_line)
+                modified_no_final_eol = TRUE;
             }
 
           continue;
@@ -728,7 +1167,13 @@ parse_next_hunk(svn_diff_hunk_t **hunk,
           SVN_ERR(parse_mergeinfo(&found_mergeinfo, line, *hunk, patch,
                                   result_pool, iterpool));
           if (found_mergeinfo)
-            continue; /* Proceed to the next line in the patch. */
+            continue; /* Proceed to the next line in the svn:mergeinfo hunk. */
+          else
+            {
+              /* Perhaps we can also use original_lines/modified_lines here */
+
+              in_hunk = FALSE; /* On to next property */
+            }
         }
 
       if (in_hunk)
@@ -843,14 +1288,16 @@ parse_next_hunk(svn_diff_hunk_t **hunk,
               SVN_ERR(parse_prop_name(prop_name, line->data, "Added: ",
                                       result_pool));
               if (*prop_name)
-                *prop_operation = svn_diff_op_added;
+                *prop_operation = (patch->reverse ? svn_diff_op_deleted
+                                                  : svn_diff_op_added);
             }
           else if (starts_with(line->data, "Deleted: "))
             {
               SVN_ERR(parse_prop_name(prop_name, line->data, "Deleted: ",
                                       result_pool));
               if (*prop_name)
-                *prop_operation = svn_diff_op_deleted;
+                *prop_operation = (patch->reverse ? svn_diff_op_added
+                                                  : svn_diff_op_deleted);
             }
           else if (starts_with(line->data, "Modified: "))
             {
@@ -891,6 +1338,8 @@ parse_next_hunk(svn_diff_hunk_t **hunk,
       (*hunk)->modified_text_range.start = start;
       (*hunk)->modified_text_range.current = start;
       (*hunk)->modified_text_range.end = modified_end;
+      (*hunk)->original_no_final_eol = original_no_final_eol;
+      (*hunk)->modified_no_final_eol = modified_no_final_eol;
     }
   else
     /* Something went wrong, just discard the result. */
@@ -917,16 +1366,19 @@ compare_hunks(const void *a, const void
 /* Possible states of the diff header parser. */
 enum parse_state
 {
-   state_start,           /* initial */
-   state_git_diff_seen,   /* diff --git */
-   state_git_tree_seen,   /* a tree operation, rather then content change */
-   state_git_minus_seen,  /* --- /dev/null; or --- a/ */
-   state_git_plus_seen,   /* +++ /dev/null; or +++ a/ */
-   state_move_from_seen,  /* rename from foo.c */
-   state_copy_from_seen,  /* copy from foo.c */
-   state_minus_seen,      /* --- foo.c */
-   state_unidiff_found,   /* valid start of a regular unidiff header */
-   state_git_header_found /* valid start of a --git diff header */
+   state_start,             /* initial */
+   state_git_diff_seen,     /* diff --git */
+   state_git_tree_seen,     /* a tree operation, rather than content change */
+   state_git_minus_seen,    /* --- /dev/null; or --- a/ */
+   state_git_plus_seen,     /* +++ /dev/null; or +++ a/ */
+   state_old_mode_seen,     /* old mode 100644 */
+   state_git_mode_seen,     /* new mode 100644 */
+   state_move_from_seen,    /* rename from foo.c */
+   state_copy_from_seen,    /* copy from foo.c */
+   state_minus_seen,        /* --- foo.c */
+   state_unidiff_found,     /* valid start of a regular unidiff header */
+   state_git_header_found,  /* valid start of a --git diff header */
+   state_binary_patch_found /* valid start of binary patch */
 };
 
 /* Data type describing a valid state transition of the parser. */
@@ -1153,6 +1605,139 @@ git_plus(enum parse_state *new_state, ch
   return SVN_NO_ERROR;
 }
 
+/* Helper for git_old_mode() and git_new_mode().  Translate the git
+ * file mode MODE_STR into a binary "executable?" and "symlink?" state. */
+static svn_error_t *
+parse_git_mode_bits(svn_tristate_t *executable_p,
+                    svn_tristate_t *symlink_p,
+                    const char *mode_str)
+{
+  apr_uint64_t mode;
+  SVN_ERR(svn_cstring_strtoui64(&mode, mode_str,
+                                0 /* min */,
+                                0777777 /* max: six octal digits */,
+                                010 /* radix (octal) */));
+
+  /* Note: 0644 and 0755 are the only modes that can occur for plain files.
+   * We deliberately choose to parse only those values: we are strict in what
+   * we accept _and_ in what we produce.
+   *
+   * (Having said that, though, we could consider relaxing the parser to also
+   * map
+   *     (mode & 0111) == 0000 -> svn_tristate_false
+   *     (mode & 0111) == 0111 -> svn_tristate_true
+   *        [anything else]    -> svn_tristate_unknown
+   * .)
+   */
+
+  switch (mode & 0777)
+    {
+      case 0644:
+        *executable_p = svn_tristate_false;
+        break;
+
+      case 0755:
+        *executable_p = svn_tristate_true;
+        break;
+
+      default:
+        /* Ignore unknown values. */
+        *executable_p = svn_tristate_unknown;
+        break;
+    }
+
+  switch (mode & 0170000 /* S_IFMT */)
+    {
+      case 0120000: /* S_IFLNK */
+        *symlink_p = svn_tristate_true;
+        break;
+
+      case 0100000: /* S_IFREG */
+      case 0040000: /* S_IFDIR */
+        *symlink_p = svn_tristate_false;
+        break;
+
+      default:
+        /* Ignore unknown values.
+           (Including those generated by Subversion <= 1.9) */
+        *symlink_p = svn_tristate_unknown;
+        break;
+    }
+
+  return SVN_NO_ERROR;
+}
+
+/* Parse the 'old mode ' line of a git extended unidiff. */
+static svn_error_t *
+git_old_mode(enum parse_state *new_state, char *line, svn_patch_t *patch,
+             apr_pool_t *result_pool, apr_pool_t *scratch_pool)
+{
+  SVN_ERR(parse_git_mode_bits(&patch->old_executable_bit,
+                              &patch->old_symlink_bit,
+                              line + STRLEN_LITERAL("old mode ")));
+
+#ifdef SVN_DEBUG
+  /* If this assert trips, the "old mode" is neither ...644 nor ...755 . */
+  SVN_ERR_ASSERT(patch->old_executable_bit != svn_tristate_unknown);
+#endif
+
+  *new_state = state_old_mode_seen;
+  return SVN_NO_ERROR;
+}
+
+/* Parse the 'new mode ' line of a git extended unidiff. */
+static svn_error_t *
+git_new_mode(enum parse_state *new_state, char *line, svn_patch_t *patch,
+             apr_pool_t *result_pool, apr_pool_t *scratch_pool)
+{
+  SVN_ERR(parse_git_mode_bits(&patch->new_executable_bit,
+                              &patch->new_symlink_bit,
+                              line + STRLEN_LITERAL("new mode ")));
+
+#ifdef SVN_DEBUG
+  /* If this assert trips, the "old mode" is neither ...644 nor ...755 . */
+  SVN_ERR_ASSERT(patch->new_executable_bit != svn_tristate_unknown);
+#endif
+
+  /* Don't touch patch->operation. */
+
+  *new_state = state_git_mode_seen;
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+git_index(enum parse_state *new_state, char *line, svn_patch_t *patch,
+          apr_pool_t *result_pool, apr_pool_t *scratch_pool)
+{
+  /* We either have something like "index 33e5b38..0000000" (which we just
+     ignore as we are not interested in git specific shas) or something like
+     "index 33e5b38..0000000 120000" which tells us the mode, that isn't
+     changed by applying this patch.
+
+     If the mode would have changed then we would see 'old mode' and 'new mode'
+     lines.
+  */
+  line = strchr(line + STRLEN_LITERAL("index "), ' ');
+
+  if (line && patch->new_executable_bit == svn_tristate_unknown
+           && patch->new_symlink_bit == svn_tristate_unknown
+           && patch->operation != svn_diff_op_added
+           && patch->operation != svn_diff_op_deleted)
+    {
+      SVN_ERR(parse_git_mode_bits(&patch->new_executable_bit,
+                                  &patch->new_symlink_bit,
+                                  line + 1));
+
+      /* There is no change.. so set the old values to the new values */
+      patch->old_executable_bit = patch->new_executable_bit;
+      patch->old_symlink_bit = patch->new_symlink_bit;
+    }
+
+  /* This function doesn't change the state! */
+  /* *new_state = *new_state */
+  return SVN_NO_ERROR;
+}
+
 /* Parse the 'rename from ' line of a git extended unidiff. */
 static svn_error_t *
 git_move_from(enum parse_state *new_state, char *line, svn_patch_t *patch,
@@ -1213,6 +1798,10 @@ static svn_error_t *
 git_new_file(enum parse_state *new_state, char *line, svn_patch_t *patch,
              apr_pool_t *result_pool, apr_pool_t *scratch_pool)
 {
+  SVN_ERR(parse_git_mode_bits(&patch->new_executable_bit,
+                              &patch->new_symlink_bit,
+                              line + STRLEN_LITERAL("new file mode ")));
+
   patch->operation = svn_diff_op_added;
 
   /* Filename already retrieved from diff --git header. */
@@ -1226,6 +1815,10 @@ static svn_error_t *
 git_deleted_file(enum parse_state *new_state, char *line, svn_patch_t *patch,
                  apr_pool_t *result_pool, apr_pool_t *scratch_pool)
 {
+  SVN_ERR(parse_git_mode_bits(&patch->old_executable_bit,
+                              &patch->old_symlink_bit,
+                              line + STRLEN_LITERAL("deleted file mode ")));
+
   patch->operation = svn_diff_op_deleted;
 
   /* Filename already retrieved from diff --git header. */
@@ -1234,6 +1827,16 @@ git_deleted_file(enum parse_state *new_s
   return SVN_NO_ERROR;
 }
 
+/* Parse the 'GIT binary patch' header */
+static svn_error_t *
+binary_patch_start(enum parse_state *new_state, char *line, svn_patch_t *patch,
+             apr_pool_t *result_pool, apr_pool_t *scratch_pool)
+{
+  *new_state = state_binary_patch_found;
+  return SVN_NO_ERROR;
+}
+
+
 /* Add a HUNK associated with the property PROP_NAME to PATCH. */
 static svn_error_t *
 add_property_hunk(svn_patch_t *patch, const char *prop_name,
@@ -1346,24 +1949,165 @@ parse_hunks(svn_patch_t *patch, apr_file
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *
+parse_binary_patch(svn_patch_t *patch, apr_file_t *apr_file,
+                   svn_boolean_t reverse,
+                   apr_pool_t *result_pool, apr_pool_t *scratch_pool)
+{
+  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+  apr_off_t pos, last_line;
+  svn_stringbuf_t *line;
+  svn_boolean_t eof = FALSE;
+  svn_diff_binary_patch_t *bpatch = apr_pcalloc(result_pool, sizeof(*bpatch));
+  svn_boolean_t in_blob = FALSE;
+  svn_boolean_t in_src = FALSE;
+
+  bpatch->apr_file = apr_file;
+
+  patch->prop_patches = apr_hash_make(result_pool);
+
+  pos = 0;
+  SVN_ERR(svn_io_file_seek(apr_file, APR_CUR, &pos, scratch_pool));
+
+  while (!eof)
+    {
+      last_line = pos;
+      SVN_ERR(svn_io_file_readline(apr_file, &line, NULL, &eof, APR_SIZE_MAX,
+                               iterpool, iterpool));
+
+      /* Update line offset for next iteration. */
+      pos = 0;
+      SVN_ERR(svn_io_file_seek(apr_file, APR_CUR, &pos, iterpool));
+
+      if (in_blob)
+        {
+          char c = line->data[0];
+
+          /* 66 = len byte + (52/4*5) chars */
+          if (((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'))
+              && line->len <= 66
+              && !strchr(line->data, ':')
+              && !strchr(line->data, ' '))
+            {
+              /* One more blop line */
+              if (in_src)
+                bpatch->src_end = pos;
+              else
+                bpatch->dst_end = pos;
+            }
+          else if (svn_stringbuf_first_non_whitespace(line) < line->len
+                   && !(in_src && bpatch->src_start < last_line))
+            {
+              break; /* Bad patch */
+            }
+          else if (in_src)
+            {
+              patch->binary_patch = bpatch; /* SUCCESS! */
+              break; 
+            }
+          else
+            {
+              in_blob = FALSE;
+              in_src = TRUE;
+            }
+        }
+      else if (starts_with(line->data, "literal "))
+        {
+          apr_uint64_t expanded_size;
+          svn_error_t *err = svn_cstring_strtoui64(&expanded_size,
+                                                   &line->data[8],
+                                                   0, APR_UINT64_MAX, 10);
+
+          if (err)
+            {
+              svn_error_clear(err);
+              break;
+            }
+
+          if (in_src)
+            {
+              bpatch->src_start = pos;
+              bpatch->src_filesize = expanded_size;
+            }
+          else
+            {
+              bpatch->dst_start = pos;
+              bpatch->dst_filesize = expanded_size;
+            }
+          in_blob = TRUE;
+        }
+      else
+        break; /* We don't support GIT deltas (yet) */
+    }
+  svn_pool_destroy(iterpool);
+
+  if (!eof)
+    /* Rewind to the start of the line just read, so subsequent calls
+     * don't end up skipping the line. It may contain a patch or hunk header.*/
+    SVN_ERR(svn_io_file_seek(apr_file, APR_SET, &last_line, scratch_pool));
+  else if (in_src
+           && ((bpatch->src_end > bpatch->src_start) || !bpatch->src_filesize))
+    {
+      patch->binary_patch = bpatch; /* SUCCESS */
+    }
+
+  /* Reverse patch if requested */
+  if (reverse && patch->binary_patch)
+    {
+      apr_off_t tmp_start = bpatch->src_start;
+      apr_off_t tmp_end = bpatch->src_end;
+      svn_filesize_t tmp_filesize = bpatch->src_filesize;
+
+      bpatch->src_start = bpatch->dst_start;
+      bpatch->src_end = bpatch->dst_end;
+      bpatch->src_filesize = bpatch->dst_filesize;
+
+      bpatch->dst_start = tmp_start;
+      bpatch->dst_end = tmp_end;
+      bpatch->dst_filesize = tmp_filesize;
+    }
+
+  return SVN_NO_ERROR;
+}
+
 /* State machine for the diff header parser.
  * Expected Input   Required state          Function to call */
 static struct transition transitions[] =
 {
-  {"--- ",          state_start,            diff_minus},
-  {"+++ ",          state_minus_seen,       diff_plus},
-  {"diff --git",    state_start,            git_start},
-  {"--- a/",        state_git_diff_seen,    git_minus},
-  {"--- a/",        state_git_tree_seen,    git_minus},
-  {"--- /dev/null", state_git_tree_seen,    git_minus},
-  {"+++ b/",        state_git_minus_seen,   git_plus},
-  {"+++ /dev/null", state_git_minus_seen,   git_plus},
-  {"rename from ",  state_git_diff_seen,    git_move_from},
-  {"rename to ",    state_move_from_seen,   git_move_to},
-  {"copy from ",    state_git_diff_seen,    git_copy_from},
-  {"copy to ",      state_copy_from_seen,   git_copy_to},
-  {"new file ",     state_git_diff_seen,    git_new_file},
-  {"deleted file ", state_git_diff_seen,    git_deleted_file},
+  {"--- ",              state_start,            diff_minus},
+  {"+++ ",              state_minus_seen,       diff_plus},
+
+  {"diff --git",        state_start,            git_start},
+  {"--- a/",            state_git_diff_seen,    git_minus},
+  {"--- a/",            state_git_mode_seen,    git_minus},
+  {"--- a/",            state_git_tree_seen,    git_minus},
+  {"--- /dev/null",     state_git_mode_seen,    git_minus},
+  {"--- /dev/null",     state_git_tree_seen,    git_minus},
+  {"+++ b/",            state_git_minus_seen,   git_plus},
+  {"+++ /dev/null",     state_git_minus_seen,   git_plus},
+
+  {"old mode ",         state_git_diff_seen,    git_old_mode},
+  {"new mode ",         state_old_mode_seen,    git_new_mode},
+
+  {"rename from ",      state_git_diff_seen,    git_move_from},
+  {"rename from ",      state_git_mode_seen,    git_move_from},
+  {"rename to ",        state_move_from_seen,   git_move_to},
+
+  {"copy from ",        state_git_diff_seen,    git_copy_from},
+  {"copy from ",        state_git_mode_seen,    git_copy_from},
+  {"copy to ",          state_copy_from_seen,   git_copy_to},
+
+  {"new file ",         state_git_diff_seen,    git_new_file},
+
+  {"deleted file ",     state_git_diff_seen,    git_deleted_file},
+
+  {"index ",            state_git_diff_seen,    git_index},
+  {"index ",            state_git_tree_seen,    git_index},
+  {"index ",            state_git_mode_seen,    git_index},
+
+  {"GIT binary patch",  state_git_diff_seen,    binary_patch_start},
+  {"GIT binary patch",  state_git_tree_seen,    binary_patch_start},
+  {"GIT binary patch",  state_git_mode_seen,    binary_patch_start},
 };
 
 svn_error_t *
@@ -1389,6 +2133,10 @@ svn_diff_parse_next_patch(svn_patch_t **
     }
 
   patch = apr_pcalloc(result_pool, sizeof(*patch));
+  patch->old_executable_bit = svn_tristate_unknown;
+  patch->new_executable_bit = svn_tristate_unknown;
+  patch->old_symlink_bit = svn_tristate_unknown;
+  patch->new_symlink_bit = svn_tristate_unknown;
 
   pos = patch_file->next_patch_offset;
   SVN_ERR(svn_io_file_seek(patch_file->apr_file, APR_SET, &pos, scratch_pool));
@@ -1428,32 +2176,32 @@ svn_diff_parse_next_patch(svn_patch_t **
             }
         }
 
-      if (state == state_unidiff_found || state == state_git_header_found)
+      if (state == state_unidiff_found
+          || state == state_git_header_found
+          || state == state_binary_patch_found)
         {
           /* We have a valid diff header, yay! */
           break;
         }
-      else if (state == state_git_tree_seen && line_after_tree_header_read)
+      else if ((state == state_git_tree_seen || state == state_git_mode_seen)
+               && line_after_tree_header_read
+               && !valid_header_line)
         {
-          /* git patches can contain an index line after the file mode line */
-          if (!starts_with(line->data, "index "))
-          {
-            /* We have a valid diff header for a patch with only tree changes.
-             * Rewind to the start of the line just read, so subsequent calls
-             * to this function don't end up skipping the line -- it may
-             * contain a patch. */
-            SVN_ERR(svn_io_file_seek(patch_file->apr_file, APR_SET, &last_line,
-                    scratch_pool));
-            break;
-          }
+          /* We have a valid diff header for a patch with only tree changes.
+           * Rewind to the start of the line just read, so subsequent calls
+           * to this function don't end up skipping the line -- it may
+           * contain a patch. */
+          SVN_ERR(svn_io_file_seek(patch_file->apr_file, APR_SET, &last_line,
+                                   scratch_pool));
+          break;
         }
-      else if (state == state_git_tree_seen)
+      else if (state == state_git_tree_seen
+               || state == state_git_mode_seen)
         {
           line_after_tree_header_read = TRUE;
         }
       else if (! valid_header_line && state != state_start
-               && state != state_git_diff_seen
-               && !starts_with(line->data, "index "))
+               && state != state_git_diff_seen)
         {
           /* We've encountered an invalid diff header.
            *
@@ -1471,9 +2219,35 @@ svn_diff_parse_next_patch(svn_patch_t **
   if (reverse)
     {
       const char *temp;
+      svn_tristate_t ts_tmp;
+
       temp = patch->old_filename;
       patch->old_filename = patch->new_filename;
       patch->new_filename = temp;
+
+      switch (patch->operation)
+        {
+          case svn_diff_op_added:
+            patch->operation = svn_diff_op_deleted;
+            break;
+          case svn_diff_op_deleted:
+            patch->operation = svn_diff_op_added;
+            break;
+
+          /* ### case svn_diff_op_copied:
+             ### case svn_diff_op_moved:*/
+
+          case svn_diff_op_modified:
+            break; /* Stays modify */
+        }
+
+      ts_tmp = patch->old_executable_bit;
+      patch->old_executable_bit = patch->new_executable_bit;
+      patch->new_executable_bit = ts_tmp;
+
+      ts_tmp = patch->old_symlink_bit;
+      patch->old_symlink_bit = patch->new_symlink_bit;
+      patch->new_symlink_bit = ts_tmp;
     }
 
   if (patch->old_filename == NULL || patch->new_filename == NULL)
@@ -1482,8 +2256,17 @@ svn_diff_parse_next_patch(svn_patch_t **
       patch = NULL;
     }
   else
-    SVN_ERR(parse_hunks(patch, patch_file->apr_file, ignore_whitespace,
-                        result_pool, iterpool));
+    {
+      if (state == state_binary_patch_found)
+        {
+          SVN_ERR(parse_binary_patch(patch, patch_file->apr_file, reverse,
+                                     result_pool, iterpool));
+          /* And fall through in property parsing */
+        }
+
+      SVN_ERR(parse_hunks(patch, patch_file->apr_file, ignore_whitespace,
+                          result_pool, iterpool));
+    }
 
   svn_pool_destroy(iterpool);
 
@@ -1491,7 +2274,7 @@ svn_diff_parse_next_patch(svn_patch_t **
   SVN_ERR(svn_io_file_seek(patch_file->apr_file, APR_CUR,
                            &patch_file->next_patch_offset, scratch_pool));
 
-  if (patch)
+  if (patch && patch->hunks)
     {
       /* Usually, hunks appear in the patch sorted by their original line
        * offset. But just in case they weren't parsed in this order for

Modified: subversion/branches/ra-git/subversion/libsvn_fs/deprecated.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs/deprecated.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs/deprecated.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs/deprecated.c Mon Nov 30 10:24:16 2015
@@ -64,6 +64,28 @@ svn_fs_begin_txn(svn_fs_txn_t **txn_p, s
 }
 
 svn_error_t *
+svn_fs_revision_prop(svn_string_t **value_p,
+                     svn_fs_t *fs,
+                     svn_revnum_t rev,
+                     const char *propname,
+                     apr_pool_t *pool)
+{
+  return svn_error_trace(
+           svn_fs_revision_prop2(value_p, fs, rev, propname, TRUE, pool,
+                                 pool));
+}
+
+svn_error_t *
+svn_fs_revision_proplist(apr_hash_t **table_p,
+                         svn_fs_t *fs,
+                         svn_revnum_t rev,
+                         apr_pool_t *pool)
+{
+  return svn_error_trace(
+           svn_fs_revision_proplist2(table_p, fs, rev, TRUE, pool, pool));
+}
+
+svn_error_t *
 svn_fs_change_rev_prop(svn_fs_t *fs, svn_revnum_t rev, const char *name,
                        const svn_string_t *value, apr_pool_t *pool)
 {
@@ -81,6 +103,55 @@ svn_fs_get_locks(svn_fs_t *fs, const cha
                                            pool));
 }
 
+svn_error_t *
+svn_fs_create(svn_fs_t **fs_p,
+              const char *path,
+              apr_hash_t *fs_config,
+              apr_pool_t *pool)
+{
+  return svn_fs_create2(fs_p, path, fs_config, pool, pool);
+}
+
+svn_error_t *
+svn_fs_open(svn_fs_t **fs_p,
+            const char *path,
+            apr_hash_t *fs_config,
+            apr_pool_t *pool)
+{
+  return svn_fs_open2(fs_p, path, fs_config, pool, pool);
+}
+
+svn_error_t *
+svn_fs_node_history(svn_fs_history_t **history_p, svn_fs_root_t *root,
+                    const char *path, apr_pool_t *pool)
+{
+  return svn_error_trace(svn_fs_node_history2(history_p, root, path,
+                                              pool, pool));
+}
+
+svn_error_t *
+svn_fs_get_mergeinfo(svn_mergeinfo_catalog_t *catalog,
+                     svn_fs_root_t *root,
+                     const apr_array_header_t *paths,
+                     svn_mergeinfo_inheritance_t inherit,
+                     svn_boolean_t include_descendants,
+                     apr_pool_t *pool)
+{
+  return svn_error_trace(svn_fs_get_mergeinfo2(catalog, root, paths,
+                                               inherit,
+                                               include_descendants,
+                                               TRUE, pool, pool));
+}
+
+svn_error_t *
+svn_fs_history_prev(svn_fs_history_t **prev_history_p,
+                    svn_fs_history_t *history, svn_boolean_t cross_copies,
+                    apr_pool_t *pool)
+{
+  return svn_error_trace(svn_fs_history_prev2(prev_history_p, history,
+                                              cross_copies, pool, pool));
+}
+
 /*** From access.c ***/
 svn_error_t *
 svn_fs_access_add_lock_token(svn_fs_access_t *access_ctx,

Modified: subversion/branches/ra-git/subversion/libsvn_fs/editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs/editor.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs/editor.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs/editor.c Mon Nov 30 10:24:16 2015
@@ -249,7 +249,7 @@ can_modify(svn_fs_root_t *txn_root,
       svn_fs_close_root(rev_root);
 
       /* Has the target node changed in the future?  */
-      if (relation != svn_fs_node_same)
+      if (relation != svn_fs_node_unchanged)
         {
           /* Restarting the commit will base the txn on the future/new
              revision, allowing the modification at REVISION.  */

Modified: subversion/branches/ra-git/subversion/libsvn_fs/fs-loader.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs/fs-loader.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs/fs-loader.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs/fs-loader.c Mon Nov 30 10:24:16 2015
@@ -27,7 +27,6 @@
 #include <apr_atomic.h>
 #include <apr_hash.h>
 #include <apr_md5.h>
-#include <apr_thread_mutex.h>
 #include <apr_uuid.h>
 #include <apr_strings.h>
 
@@ -140,7 +139,7 @@ load_module(fs_init_func_t *initfunc, co
                                  _("Invalid name for FS type '%s'"),
                                  name);
 
-    libname = apr_psprintf(pool, "libsvn_fs_%s-%d.so.%d",
+    libname = apr_psprintf(pool, "libsvn_fs_%s-" SVN_DSO_SUFFIX_FMT,
                            name, SVN_VER_MAJOR, SVN_SOVERSION);
     funcname = apr_psprintf(pool, "svn_fs_%s__init", name);
 
@@ -507,24 +506,28 @@ svn_fs_set_warning_func(svn_fs_t *fs, sv
 }
 
 svn_error_t *
-svn_fs_create(svn_fs_t **fs_p, const char *path, apr_hash_t *fs_config,
-              apr_pool_t *pool)
+svn_fs_create2(svn_fs_t **fs_p,
+               const char *path,
+               apr_hash_t *fs_config,
+               apr_pool_t *result_pool,
+               apr_pool_t *scratch_pool)
 {
   fs_library_vtable_t *vtable;
 
   const char *fs_type = svn_hash__get_cstring(fs_config,
                                               SVN_FS_CONFIG_FS_TYPE,
                                               DEFAULT_FS_TYPE);
-  SVN_ERR(get_library_vtable(&vtable, fs_type, pool));
+  SVN_ERR(get_library_vtable(&vtable, fs_type, scratch_pool));
 
   /* Create the FS directory and write out the fsap-name file. */
-  SVN_ERR(svn_io_dir_make_sgid(path, APR_OS_DEFAULT, pool));
-  SVN_ERR(write_fs_type(path, fs_type, pool));
+  SVN_ERR(svn_io_dir_make_sgid(path, APR_OS_DEFAULT, scratch_pool));
+  SVN_ERR(write_fs_type(path, fs_type, scratch_pool));
 
   /* Perform the actual creation. */
-  *fs_p = fs_new(fs_config, pool);
+  *fs_p = fs_new(fs_config, result_pool);
 
-  SVN_ERR(vtable->create(*fs_p, path, common_pool_lock, pool, common_pool));
+  SVN_ERR(vtable->create(*fs_p, path, common_pool_lock, scratch_pool,
+                         common_pool));
   SVN_ERR(vtable->set_svn_fs_open(*fs_p, svn_fs_open2));
 
   return SVN_NO_ERROR;
@@ -547,33 +550,24 @@ svn_fs_open2(svn_fs_t **fs_p, const char
 }
 
 svn_error_t *
-svn_fs_open(svn_fs_t **fs_p,
-            const char *path,
-            apr_hash_t *fs_config,
-            apr_pool_t *pool)
-{
-  return svn_fs_open2(fs_p, path, fs_config, pool, pool);
-}
-
-svn_error_t *
 svn_fs_upgrade2(const char *path,
                 svn_fs_upgrade_notify_t notify_func,
                 void *notify_baton,
                 svn_cancel_func_t cancel_func,
                 void *cancel_baton,
-                apr_pool_t *pool)
+                apr_pool_t *scratch_pool)
 {
   fs_library_vtable_t *vtable;
   svn_fs_t *fs;
 
-  SVN_ERR(fs_library_vtable(&vtable, path, pool));
-  fs = fs_new(NULL, pool);
+  SVN_ERR(fs_library_vtable(&vtable, path, scratch_pool));
+  fs = fs_new(NULL, scratch_pool);
 
   SVN_ERR(vtable->upgrade_fs(fs, path,
                              notify_func, notify_baton,
                              cancel_func, cancel_baton,
                              common_pool_lock,
-                             pool, common_pool));
+                             scratch_pool, common_pool));
   return SVN_NO_ERROR;
 }
 
@@ -1101,14 +1095,6 @@ svn_fs_node_history2(svn_fs_history_t **
 }
 
 svn_error_t *
-svn_fs_node_history(svn_fs_history_t **history_p, svn_fs_root_t *root,
-                    const char *path, apr_pool_t *pool)
-{
-  return svn_error_trace(root->vtable->node_history(history_p, root, path,
-                                                    pool, pool));
-}
-
-svn_error_t *
 svn_fs_is_dir(svn_boolean_t *is_dir, svn_fs_root_t *root, const char *path,
               apr_pool_t *pool)
 {
@@ -1141,7 +1127,7 @@ svn_error_t *
 svn_fs_node_relation(svn_fs_node_relation_t *relation,
                      svn_fs_root_t *root_a, const char *path_a,
                      svn_fs_root_t *root_b, const char *path_b,
-                     apr_pool_t *pool)
+                     apr_pool_t *scratch_pool)
 {
   /* Different repository types? */
   if (root_a->fs != root_b->fs)
@@ -1150,9 +1136,10 @@ svn_fs_node_relation(svn_fs_node_relatio
       return SVN_NO_ERROR;
     }
 
-  return svn_error_trace(root_a->vtable->node_relation(relation, root_a,
-                                                       path_a, root_b,
-                                                       path_b, pool));
+  return svn_error_trace(root_a->vtable->node_relation(relation,
+                                                       root_a, path_a,
+                                                       root_b, path_b,
+                                                       scratch_pool));
 }
 
 svn_error_t *
@@ -1196,6 +1183,16 @@ svn_fs_node_proplist(apr_hash_t **table_
 }
 
 svn_error_t *
+svn_fs_node_has_props(svn_boolean_t *has_props,
+                      svn_fs_root_t *root,
+                      const char *path,
+                      apr_pool_t *scratch_pool)
+{
+  return svn_error_trace(root->vtable->node_has_props(has_props, root, path,
+                                                      scratch_pool));
+}
+
+svn_error_t *
 svn_fs_change_node_prop(svn_fs_root_t *root, const char *path,
                         const char *name, const svn_string_t *value,
                         apr_pool_t *pool)
@@ -1207,12 +1204,12 @@ svn_fs_change_node_prop(svn_fs_root_t *r
 svn_error_t *
 svn_fs_props_different(svn_boolean_t *changed_p, svn_fs_root_t *root1,
                        const char *path1, svn_fs_root_t *root2,
-                       const char *path2, apr_pool_t *pool)
+                       const char *path2, apr_pool_t *scratch_pool)
 {
   return svn_error_trace(root1->vtable->props_changed(changed_p,
                                                       root1, path1,
                                                       root2, path2,
-                                                      TRUE, pool));
+                                                      TRUE, scratch_pool));
 }
 
 svn_error_t *
@@ -1258,20 +1255,6 @@ svn_fs_get_mergeinfo2(svn_mergeinfo_cata
 }
 
 svn_error_t *
-svn_fs_get_mergeinfo(svn_mergeinfo_catalog_t *catalog,
-                     svn_fs_root_t *root,
-                     const apr_array_header_t *paths,
-                     svn_mergeinfo_inheritance_t inherit,
-                     svn_boolean_t include_descendants,
-                     apr_pool_t *pool)
-{
-  return svn_error_trace(root->vtable->get_mergeinfo(catalog, root, paths,
-                                                     inherit,
-                                                     include_descendants,
-                                                     TRUE, pool, pool));
-}
-
-svn_error_t *
 svn_fs__get_mergeinfo_for_path(svn_mergeinfo_t *mergeinfo,
                                svn_fs_root_t *root,
                                const char *path,
@@ -1320,10 +1303,13 @@ svn_error_t *
 svn_fs_dir_optimal_order(apr_array_header_t **ordered_p,
                          svn_fs_root_t *root,
                          apr_hash_t *entries,
-                         apr_pool_t *pool)
+                         apr_pool_t *result_pool,
+                         apr_pool_t *scratch_pool)
 {
   return svn_error_trace(root->vtable->dir_optimal_order(ordered_p, root,
-                                                         entries, pool));
+                                                         entries,
+                                                         result_pool,
+                                                         scratch_pool));
 }
 
 svn_error_t *
@@ -1484,12 +1470,13 @@ svn_fs_apply_text(svn_stream_t **content
 svn_error_t *
 svn_fs_contents_different(svn_boolean_t *changed_p, svn_fs_root_t *root1,
                           const char *path1, svn_fs_root_t *root2,
-                          const char *path2, apr_pool_t *pool)
+                          const char *path2, apr_pool_t *scratch_pool)
 {
   return svn_error_trace(root1->vtable->contents_changed(changed_p,
                                                          root1, path1,
                                                          root2, path2,
-                                                         TRUE, pool));
+                                                         TRUE,
+                                                         scratch_pool));
 }
 
 svn_error_t *
@@ -1539,19 +1526,39 @@ svn_fs_deltify_revision(svn_fs_t *fs, sv
 }
 
 svn_error_t *
-svn_fs_revision_prop(svn_string_t **value_p, svn_fs_t *fs, svn_revnum_t rev,
-                     const char *propname, apr_pool_t *pool)
+svn_fs_refresh_revision_props(svn_fs_t *fs,
+                              apr_pool_t *scratch_pool)
+{
+  return svn_error_trace(fs->vtable->refresh_revprops(fs, scratch_pool));
+}
+
+svn_error_t *
+svn_fs_revision_prop2(svn_string_t **value_p,
+                      svn_fs_t *fs,
+                      svn_revnum_t rev,
+                      const char *propname,
+                      svn_boolean_t refresh,
+                      apr_pool_t *result_pool,
+                      apr_pool_t *scratch_pool)
 {
   return svn_error_trace(fs->vtable->revision_prop(value_p, fs, rev,
-                                                   propname, pool));
+                                                   propname, refresh,
+                                                   result_pool,
+                                                   scratch_pool));
 }
 
 svn_error_t *
-svn_fs_revision_proplist(apr_hash_t **table_p, svn_fs_t *fs, svn_revnum_t rev,
-                         apr_pool_t *pool)
+svn_fs_revision_proplist2(apr_hash_t **table_p,
+                          svn_fs_t *fs,
+                          svn_revnum_t rev,
+                          svn_boolean_t refresh,
+                          apr_pool_t *result_pool,
+                          apr_pool_t *scratch_pool)
 {
   return svn_error_trace(fs->vtable->revision_proplist(table_p, fs, rev,
-                                                       pool));
+                                                       refresh,
+                                                       result_pool,
+                                                       scratch_pool));
 }
 
 svn_error_t *
@@ -1757,9 +1764,9 @@ svn_fs_generate_lock_token(const char **
 svn_fs_lock_target_t *
 svn_fs_lock_target_create(const char *token,
                           svn_revnum_t current_rev,
-                          apr_pool_t *pool)
+                          apr_pool_t *result_pool)
 {
-  svn_fs_lock_target_t *target = apr_palloc(pool, sizeof(svn_fs_lock_target_t));
+  svn_fs_lock_target_t *target = apr_palloc(result_pool, sizeof(*target));
 
   target->token = token;
   target->current_rev = current_rev;
@@ -1846,15 +1853,6 @@ svn_fs_history_prev2(svn_fs_history_t **
 }
 
 svn_error_t *
-svn_fs_history_prev(svn_fs_history_t **prev_history_p,
-                    svn_fs_history_t *history, svn_boolean_t cross_copies,
-                    apr_pool_t *pool)
-{
-  return svn_error_trace(history->vtable->prev(prev_history_p, history,
-                                               cross_copies, pool, pool));
-}
-
-svn_error_t *
 svn_fs_history_location(const char **path, svn_revnum_t *revision,
                         svn_fs_history_t *history, apr_pool_t *pool)
 {
@@ -1897,7 +1895,7 @@ svn_fs_compare_ids(const svn_fs_id_t *a,
 {
   switch (a->vtable->compare(a, b))
     {
-    case svn_fs_node_same:
+    case svn_fs_node_unchanged:
       return 0;
     case svn_fs_node_common_ancestor:
       return 1;

Modified: subversion/branches/ra-git/subversion/libsvn_fs/fs-loader.h
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs/fs-loader.h?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs/fs-loader.h (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs/fs-loader.h Mon Nov 30 10:24:16 2015
@@ -22,8 +22,8 @@
  */
 
 
-#ifndef LIBSVN_FS_FS_H
-#define LIBSVN_FS_FS_H
+#ifndef LIBSVN_FS_LOADER_H
+#define LIBSVN_FS_LOADER_H
 
 #include "svn_types.h"
 #include "svn_fs.h"
@@ -79,11 +79,11 @@ typedef struct fs_library_vtable_t
      parameter for allocating fs-global objects such as an env cache. */
   svn_error_t *(*create)(svn_fs_t *fs, const char *path,
                          svn_mutex__t *common_pool_lock,
-                         apr_pool_t *pool,
+                         apr_pool_t *scratch_pool,
                          apr_pool_t *common_pool);
   svn_error_t *(*open_fs)(svn_fs_t *fs, const char *path,
                           svn_mutex__t *common_pool_lock,
-                          apr_pool_t *pool,
+                          apr_pool_t *scratch_pool,
                           apr_pool_t *common_pool);
   /* open_for_recovery() is like open(), but used to fill in an fs pointer
      that will be passed to recover().  We assume that the open() method
@@ -99,7 +99,7 @@ typedef struct fs_library_vtable_t
                              svn_cancel_func_t cancel_func,
                              void *cancel_baton,
                              svn_mutex__t *common_pool_lock,
-                             apr_pool_t *pool,
+                             apr_pool_t *scratch_pool,
                              apr_pool_t *common_pool);
   svn_error_t *(*verify_fs)(svn_fs_t *fs, const char *path,
                             svn_revnum_t start,
@@ -184,15 +184,9 @@ typedef svn_error_t *(*fs_init_func_t)(c
    to the create and open functions and these init functions (as well
    as the open and create functions) are globally serialized so that
    they have exclusive access to the common_pool. */
-svn_error_t *svn_fs_base__init(const svn_version_t *loader_version,
-                               fs_library_vtable_t **vtable,
-                               apr_pool_t* common_pool);
-svn_error_t *svn_fs_fs__init(const svn_version_t *loader_version,
-                             fs_library_vtable_t **vtable,
-                             apr_pool_t* common_pool);
-svn_error_t *svn_fs_x__init(const svn_version_t *loader_version,
-                            fs_library_vtable_t **vtable,
-                            apr_pool_t* common_pool);
+#include "../libsvn_fs_base/fs_init.h"
+#include "../libsvn_fs_fs/fs_init.h"
+#include "../libsvn_fs_x/fs_init.h"
 
 
 
@@ -202,11 +196,17 @@ typedef struct fs_vtable_t
 {
   svn_error_t *(*youngest_rev)(svn_revnum_t *youngest_p, svn_fs_t *fs,
                                apr_pool_t *pool);
+  svn_error_t *(*refresh_revprops)(svn_fs_t *fs, apr_pool_t *scratch_pool);
   svn_error_t *(*revision_prop)(svn_string_t **value_p, svn_fs_t *fs,
                                 svn_revnum_t rev, const char *propname,
-                                apr_pool_t *pool);
+                                svn_boolean_t refresh,
+                                apr_pool_t *result_pool, 
+                                apr_pool_t *scratch_pool);
   svn_error_t *(*revision_proplist)(apr_hash_t **table_p, svn_fs_t *fs,
-                                    svn_revnum_t rev, apr_pool_t *pool);
+                                    svn_revnum_t rev,
+                                    svn_boolean_t refresh,
+                                    apr_pool_t *result_pool, 
+                                    apr_pool_t *scratch_pool);
   svn_error_t *(*change_rev_prop)(svn_fs_t *fs, svn_revnum_t rev,
                                   const char *name,
                                   const svn_string_t *const *old_value_p,
@@ -314,7 +314,7 @@ typedef struct root_vtable_t
   svn_error_t *(*node_relation)(svn_fs_node_relation_t *relation,
                                 svn_fs_root_t *root_a, const char *path_a,
                                 svn_fs_root_t *root_b, const char *path_b,
-                                apr_pool_t *pool);
+                                apr_pool_t *scratch_pool);
   svn_error_t *(*node_created_rev)(svn_revnum_t *revision,
                                    svn_fs_root_t *root, const char *path,
                                    apr_pool_t *pool);
@@ -346,6 +346,8 @@ typedef struct root_vtable_t
                             apr_pool_t *pool);
   svn_error_t *(*node_proplist)(apr_hash_t **table_p, svn_fs_root_t *root,
                                 const char *path, apr_pool_t *pool);
+  svn_error_t *(*node_has_props)(svn_boolean_t *has_props, svn_fs_root_t *root,
+                                 const char *path, apr_pool_t *scratch_pool);
   svn_error_t *(*change_node_prop)(svn_fs_root_t *root, const char *path,
                                    const char *name,
                                    const svn_string_t *value,
@@ -353,7 +355,7 @@ typedef struct root_vtable_t
   svn_error_t *(*props_changed)(int *changed_p, svn_fs_root_t *root1,
                                 const char *path1, svn_fs_root_t *root2,
                                 const char *path2, svn_boolean_t strict,
-                                apr_pool_t *pool);
+                                apr_pool_t *scratch_pool);
 
   /* Directories */
   svn_error_t *(*dir_entries)(apr_hash_t **entries_p, svn_fs_root_t *root,
@@ -361,7 +363,8 @@ typedef struct root_vtable_t
   svn_error_t *(*dir_optimal_order)(apr_array_header_t **ordered_p,
                                     svn_fs_root_t *root,
                                     apr_hash_t *entries,
-                                    apr_pool_t *pool);
+                                    apr_pool_t *result_pool,
+                                    apr_pool_t *scratch_pool);
   svn_error_t *(*make_dir)(svn_fs_root_t *root, const char *path,
                            apr_pool_t *pool);
 
@@ -394,7 +397,7 @@ typedef struct root_vtable_t
   svn_error_t *(*contents_changed)(int *changed_p, svn_fs_root_t *root1,
                                    const char *path1, svn_fs_root_t *root2,
                                    const char *path2, svn_boolean_t strict,
-                                   apr_pool_t *pool);
+                                   apr_pool_t *scratch_pool);
   svn_error_t *(*get_file_delta_stream)(svn_txdelta_stream_t **stream_p,
                                         svn_fs_root_t *source_root,
                                         const char *source_path,
@@ -566,4 +569,4 @@ struct svn_fs_lock_target_t
 }
 #endif /* __cplusplus */
 
-#endif
+#endif /* LIBSVN_FS_LOADER_H */

Modified: subversion/branches/ra-git/subversion/libsvn_fs_base/bdb/rev-table.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_base/bdb/rev-table.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_base/bdb/rev-table.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_base/bdb/rev-table.c Mon Nov 30 10:24:16 2015
@@ -79,6 +79,9 @@ svn_fs_bdb__get_rev(revision_t **revisio
      numbers begin with one.  */
   db_recno_t recno = (db_recno_t) rev + 1;
 
+  if (!SVN_IS_VALID_REVNUM(rev))
+    return svn_fs_base__err_dangling_rev(fs, rev);
+
   svn_fs_base__trail_debug(trail, "revisions", "get");
   db_err = bfd->revisions->get(bfd->revisions, trail->db_txn,
                                svn_fs_base__set_dbt(&key, &recno,