rugged 0.23.0b2 → 0.23.0b4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. checksums.yaml +4 -4
  2. data/ext/rugged/rugged_blob.c +39 -0
  3. data/ext/rugged/rugged_diff.c +7 -3
  4. data/ext/rugged/rugged_index.c +2 -2
  5. data/ext/rugged/rugged_remote.c +27 -148
  6. data/ext/rugged/rugged_remote_collection.c +134 -12
  7. data/ext/rugged/rugged_repo.c +74 -5
  8. data/ext/rugged/rugged_submodule.c +18 -208
  9. data/ext/rugged/rugged_submodule_collection.c +148 -0
  10. data/lib/rugged/version.rb +1 -1
  11. data/vendor/libgit2/AUTHORS +1 -0
  12. data/vendor/libgit2/CMakeLists.txt +33 -25
  13. data/vendor/libgit2/deps/winhttp/winhttp.def +29 -29
  14. data/vendor/libgit2/include/git2.h +1 -1
  15. data/vendor/libgit2/include/git2/blob.h +4 -6
  16. data/vendor/libgit2/include/git2/checkout.h +10 -1
  17. data/vendor/libgit2/include/git2/clone.h +6 -7
  18. data/vendor/libgit2/include/git2/commit.h +11 -0
  19. data/vendor/libgit2/include/git2/cred_helpers.h +2 -2
  20. data/vendor/libgit2/include/git2/describe.h +1 -1
  21. data/vendor/libgit2/include/git2/diff.h +68 -11
  22. data/vendor/libgit2/include/git2/errors.h +4 -1
  23. data/vendor/libgit2/include/git2/filter.h +16 -0
  24. data/vendor/libgit2/include/git2/index.h +38 -11
  25. data/vendor/libgit2/include/git2/odb.h +1 -1
  26. data/vendor/libgit2/include/git2/odb_backend.h +2 -2
  27. data/vendor/libgit2/include/git2/remote.h +300 -207
  28. data/vendor/libgit2/include/git2/reset.h +1 -0
  29. data/vendor/libgit2/include/git2/stash.h +135 -4
  30. data/vendor/libgit2/include/git2/status.h +1 -0
  31. data/vendor/libgit2/include/git2/submodule.h +46 -75
  32. data/vendor/libgit2/include/git2/sys/odb_backend.h +1 -1
  33. data/vendor/libgit2/include/git2/sys/stream.h +2 -0
  34. data/vendor/libgit2/include/git2/sys/transport.h +1 -21
  35. data/vendor/libgit2/include/git2/transport.h +27 -0
  36. data/vendor/libgit2/include/git2/types.h +20 -10
  37. data/vendor/libgit2/include/git2/version.h +3 -3
  38. data/vendor/libgit2/libgit2.pc.in +4 -2
  39. data/vendor/libgit2/src/attr.c +2 -1
  40. data/vendor/libgit2/src/attr_file.c +18 -37
  41. data/vendor/libgit2/src/blame.c +2 -2
  42. data/vendor/libgit2/src/blob.c +4 -3
  43. data/vendor/libgit2/src/branch.c +6 -3
  44. data/vendor/libgit2/src/buf_text.c +4 -6
  45. data/vendor/libgit2/src/buf_text.h +1 -2
  46. data/vendor/libgit2/src/buffer.c +8 -6
  47. data/vendor/libgit2/src/buffer.h +1 -1
  48. data/vendor/libgit2/src/cache.c +1 -0
  49. data/vendor/libgit2/src/checkout.c +34 -20
  50. data/vendor/libgit2/src/clone.c +29 -29
  51. data/vendor/libgit2/src/commit.c +65 -0
  52. data/vendor/libgit2/src/common.h +5 -0
  53. data/vendor/libgit2/src/config.c +20 -0
  54. data/vendor/libgit2/src/config.h +6 -0
  55. data/vendor/libgit2/src/config_file.c +2 -2
  56. data/vendor/libgit2/src/crlf.c +39 -17
  57. data/vendor/libgit2/src/curl_stream.c +257 -0
  58. data/vendor/libgit2/src/curl_stream.h +14 -0
  59. data/vendor/libgit2/src/diff.c +223 -88
  60. data/vendor/libgit2/src/diff.h +21 -1
  61. data/vendor/libgit2/src/diff_file.c +23 -13
  62. data/vendor/libgit2/src/diff_file.h +4 -2
  63. data/vendor/libgit2/src/diff_patch.c +266 -71
  64. data/vendor/libgit2/src/diff_patch.h +36 -0
  65. data/vendor/libgit2/src/diff_print.c +156 -126
  66. data/vendor/libgit2/src/diff_tform.c +32 -54
  67. data/vendor/libgit2/src/fetch.c +27 -10
  68. data/vendor/libgit2/src/fetch.h +2 -2
  69. data/vendor/libgit2/src/filebuf.c +1 -1
  70. data/vendor/libgit2/src/fileops.c +6 -2
  71. data/vendor/libgit2/src/filter.c +28 -7
  72. data/vendor/libgit2/src/fnmatch.c +5 -5
  73. data/vendor/libgit2/src/global.c +16 -0
  74. data/vendor/libgit2/src/ident.c +2 -2
  75. data/vendor/libgit2/src/ignore.c +1 -0
  76. data/vendor/libgit2/src/index.c +338 -80
  77. data/vendor/libgit2/src/index.h +4 -1
  78. data/vendor/libgit2/src/indexer.c +19 -5
  79. data/vendor/libgit2/src/iterator.c +118 -11
  80. data/vendor/libgit2/src/iterator.h +25 -0
  81. data/vendor/libgit2/src/merge.c +96 -106
  82. data/vendor/libgit2/src/merge.h +14 -4
  83. data/vendor/libgit2/src/netops.c +3 -3
  84. data/vendor/libgit2/src/odb.c +17 -9
  85. data/vendor/libgit2/src/odb.h +1 -1
  86. data/vendor/libgit2/src/odb_loose.c +2 -2
  87. data/vendor/libgit2/src/odb_pack.c +1 -1
  88. data/vendor/libgit2/src/openssl_stream.c +118 -27
  89. data/vendor/libgit2/src/pack-objects.c +28 -0
  90. data/vendor/libgit2/src/pack-objects.h +1 -0
  91. data/vendor/libgit2/src/pack.c +18 -10
  92. data/vendor/libgit2/src/path.c +16 -11
  93. data/vendor/libgit2/src/path.h +1 -1
  94. data/vendor/libgit2/src/push.c +26 -42
  95. data/vendor/libgit2/src/push.h +2 -34
  96. data/vendor/libgit2/src/rebase.c +1 -1
  97. data/vendor/libgit2/src/refs.c +1 -1
  98. data/vendor/libgit2/src/refspec.c +6 -0
  99. data/vendor/libgit2/src/remote.c +381 -274
  100. data/vendor/libgit2/src/remote.h +0 -4
  101. data/vendor/libgit2/src/repository.c +33 -12
  102. data/vendor/libgit2/src/repository.h +0 -1
  103. data/vendor/libgit2/src/reset.c +1 -0
  104. data/vendor/libgit2/src/stash.c +439 -17
  105. data/vendor/libgit2/src/status.c +6 -0
  106. data/vendor/libgit2/src/stransport_stream.c +58 -21
  107. data/vendor/libgit2/src/stream.h +15 -0
  108. data/vendor/libgit2/src/submodule.c +410 -664
  109. data/vendor/libgit2/src/submodule.h +0 -24
  110. data/vendor/libgit2/src/transaction.c +1 -0
  111. data/vendor/libgit2/src/transports/cred.c +55 -1
  112. data/vendor/libgit2/src/transports/http.c +18 -2
  113. data/vendor/libgit2/src/transports/local.c +60 -59
  114. data/vendor/libgit2/src/transports/smart.h +1 -1
  115. data/vendor/libgit2/src/transports/smart_protocol.c +11 -11
  116. data/vendor/libgit2/src/transports/ssh.c +46 -7
  117. data/vendor/libgit2/src/unix/posix.h +4 -0
  118. data/vendor/libgit2/src/util.c +9 -9
  119. data/vendor/libgit2/src/util.h +9 -0
  120. data/vendor/libgit2/src/win32/posix.h +3 -0
  121. data/vendor/libgit2/src/win32/posix_w32.c +38 -0
  122. data/vendor/libgit2/src/win32/w32_util.h +10 -0
  123. metadata +4 -3
  124. data/vendor/libgit2/include/git2/push.h +0 -94
@@ -64,6 +64,7 @@ struct git_diff {
64
64
  git_iterator_type_t new_src;
65
65
  uint32_t diffcaps;
66
66
  git_diff_perfdata perf;
67
+ bool index_updated;
67
68
 
68
69
  int (*strcomp)(const char *, const char *);
69
70
  int (*strncomp)(const char *, const char *, size_t);
@@ -94,7 +95,7 @@ extern int git_diff_delta__format_file_header(
94
95
  extern int git_diff__oid_for_file(
95
96
  git_oid *out, git_diff *, const char *, uint16_t, git_off_t);
96
97
  extern int git_diff__oid_for_entry(
97
- git_oid *out, git_diff *, const git_index_entry *, const git_oid *update);
98
+ git_oid *out, git_diff *, const git_index_entry *, uint16_t, const git_oid *update);
98
99
 
99
100
  extern int git_diff__from_iterators(
100
101
  git_diff **diff_ptr,
@@ -123,6 +124,25 @@ extern int git_diff_find_similar__calc_similarity(
123
124
  extern int git_diff__commit(
124
125
  git_diff **diff, git_repository *repo, const git_commit *commit, const git_diff_options *opts);
125
126
 
127
+ /* Merge two `git_diff`s according to the callback given by `cb`. */
128
+
129
+ typedef git_diff_delta *(*git_diff__merge_cb)(
130
+ const git_diff_delta *left,
131
+ const git_diff_delta *right,
132
+ git_pool *pool);
133
+
134
+ extern int git_diff__merge(
135
+ git_diff *onto, const git_diff *from, git_diff__merge_cb cb);
136
+
137
+ extern git_diff_delta *git_diff__merge_like_cgit(
138
+ const git_diff_delta *a,
139
+ const git_diff_delta *b,
140
+ git_pool *pool);
141
+
142
+ /* Duplicate a `git_diff_delta` out of the `git_pool` */
143
+ extern git_diff_delta *git_diff__delta_dup(
144
+ const git_diff_delta *d, git_pool *pool);
145
+
126
146
  /*
127
147
  * Sometimes a git_diff_file will have a zero size; this attempts to
128
148
  * fill in the size without loading the blob if possible. If that is
@@ -89,10 +89,9 @@ static int diff_file_content_init_common(
89
89
  int git_diff_file_content__init_from_diff(
90
90
  git_diff_file_content *fc,
91
91
  git_diff *diff,
92
- size_t delta_index,
92
+ git_diff_delta *delta,
93
93
  bool use_old)
94
94
  {
95
- git_diff_delta *delta = git_vector_get(&diff->deltas, delta_index);
96
95
  bool has_data = true;
97
96
 
98
97
  memset(fc, 0, sizeof(*fc));
@@ -187,7 +186,7 @@ static int diff_file_content_commit_to_str(
187
186
  return error;
188
187
  }
189
188
 
190
- if ((error = git_submodule_status(&sm_status, sm)) < 0) {
189
+ if ((error = git_submodule_status(&sm_status, fc->repo, fc->file->path, GIT_SUBMODULE_IGNORE_UNSPECIFIED)) < 0) {
191
190
  git_submodule_free(sm);
192
191
  return error;
193
192
  }
@@ -218,7 +217,9 @@ static int diff_file_content_commit_to_str(
218
217
  return 0;
219
218
  }
220
219
 
221
- static int diff_file_content_load_blob(git_diff_file_content *fc)
220
+ static int diff_file_content_load_blob(
221
+ git_diff_file_content *fc,
222
+ git_diff_options *opts)
222
223
  {
223
224
  int error = 0;
224
225
  git_odb_object *odb_obj = NULL;
@@ -236,7 +237,8 @@ static int diff_file_content_load_blob(git_diff_file_content *fc)
236
237
  return error;
237
238
  }
238
239
 
239
- if (diff_file_content_binary_by_size(fc))
240
+ if ((opts->flags & GIT_DIFF_SHOW_BINARY) == 0 &&
241
+ diff_file_content_binary_by_size(fc))
240
242
  return 0;
241
243
 
242
244
  if (odb_obj != NULL) {
@@ -283,7 +285,9 @@ static int diff_file_content_load_workdir_symlink(
283
285
  }
284
286
 
285
287
  static int diff_file_content_load_workdir_file(
286
- git_diff_file_content *fc, git_buf *path)
288
+ git_diff_file_content *fc,
289
+ git_buf *path,
290
+ git_diff_options *diff_opts)
287
291
  {
288
292
  int error = 0;
289
293
  git_filter_list *fl = NULL;
@@ -297,7 +301,8 @@ static int diff_file_content_load_workdir_file(
297
301
  !(fc->file->size = git_futils_filesize(fd)))
298
302
  goto cleanup;
299
303
 
300
- if (diff_file_content_binary_by_size(fc))
304
+ if ((diff_opts->flags & GIT_DIFF_SHOW_BINARY) == 0 &&
305
+ diff_file_content_binary_by_size(fc))
301
306
  goto cleanup;
302
307
 
303
308
  if ((error = git_filter_list_load(
@@ -339,7 +344,9 @@ cleanup:
339
344
  return error;
340
345
  }
341
346
 
342
- static int diff_file_content_load_workdir(git_diff_file_content *fc)
347
+ static int diff_file_content_load_workdir(
348
+ git_diff_file_content *fc,
349
+ git_diff_options *diff_opts)
343
350
  {
344
351
  int error = 0;
345
352
  git_buf path = GIT_BUF_INIT;
@@ -357,7 +364,7 @@ static int diff_file_content_load_workdir(git_diff_file_content *fc)
357
364
  if (S_ISLNK(fc->file->mode))
358
365
  error = diff_file_content_load_workdir_symlink(fc, &path);
359
366
  else
360
- error = diff_file_content_load_workdir_file(fc, &path);
367
+ error = diff_file_content_load_workdir_file(fc, &path, diff_opts);
361
368
 
362
369
  /* once data is loaded, update OID if we didn't have it previously */
363
370
  if (!error && (fc->file->flags & GIT_DIFF_FLAG_VALID_ID) == 0) {
@@ -370,20 +377,23 @@ static int diff_file_content_load_workdir(git_diff_file_content *fc)
370
377
  return error;
371
378
  }
372
379
 
373
- int git_diff_file_content__load(git_diff_file_content *fc)
380
+ int git_diff_file_content__load(
381
+ git_diff_file_content *fc,
382
+ git_diff_options *diff_opts)
374
383
  {
375
384
  int error = 0;
376
385
 
377
386
  if ((fc->flags & GIT_DIFF_FLAG__LOADED) != 0)
378
387
  return 0;
379
388
 
380
- if ((fc->file->flags & GIT_DIFF_FLAG_BINARY) != 0)
389
+ if ((fc->file->flags & GIT_DIFF_FLAG_BINARY) != 0 &&
390
+ (diff_opts->flags & GIT_DIFF_SHOW_BINARY) == 0)
381
391
  return 0;
382
392
 
383
393
  if (fc->src == GIT_ITERATOR_TYPE_WORKDIR)
384
- error = diff_file_content_load_workdir(fc);
394
+ error = diff_file_content_load_workdir(fc, diff_opts);
385
395
  else
386
- error = diff_file_content_load_blob(fc);
396
+ error = diff_file_content_load_blob(fc, diff_opts);
387
397
  if (error)
388
398
  return error;
389
399
 
@@ -28,7 +28,7 @@ typedef struct {
28
28
  extern int git_diff_file_content__init_from_diff(
29
29
  git_diff_file_content *fc,
30
30
  git_diff *diff,
31
- size_t delta_index,
31
+ git_diff_delta *delta,
32
32
  bool use_old);
33
33
 
34
34
  typedef struct {
@@ -49,7 +49,9 @@ extern int git_diff_file_content__init_from_src(
49
49
  git_diff_file *as_file);
50
50
 
51
51
  /* this loads the blob/file-on-disk as needed */
52
- extern int git_diff_file_content__load(git_diff_file_content *fc);
52
+ extern int git_diff_file_content__load(
53
+ git_diff_file_content *fc,
54
+ git_diff_options *diff_opts);
53
55
 
54
56
  /* this releases the blob/file-in-memory */
55
57
  extern void git_diff_file_content__unload(git_diff_file_content *fc);
@@ -11,41 +11,13 @@
11
11
  #include "diff_driver.h"
12
12
  #include "diff_patch.h"
13
13
  #include "diff_xdiff.h"
14
+ #include "delta.h"
15
+ #include "zstream.h"
14
16
  #include "fileops.h"
15
17
 
16
- /* cached information about a hunk in a diff */
17
- typedef struct diff_patch_hunk {
18
- git_diff_hunk hunk;
19
- size_t line_start;
20
- size_t line_count;
21
- } diff_patch_hunk;
22
-
23
- struct git_patch {
24
- git_refcount rc;
25
- git_diff *diff; /* for refcount purposes, maybe NULL for blob diffs */
26
- git_diff_delta *delta;
27
- size_t delta_index;
28
- git_diff_file_content ofile;
29
- git_diff_file_content nfile;
30
- uint32_t flags;
31
- git_array_t(diff_patch_hunk) hunks;
32
- git_array_t(git_diff_line) lines;
33
- size_t content_size, context_size, header_size;
34
- git_pool flattened;
35
- };
36
-
37
- enum {
38
- GIT_DIFF_PATCH_ALLOCATED = (1 << 0),
39
- GIT_DIFF_PATCH_INITIALIZED = (1 << 1),
40
- GIT_DIFF_PATCH_LOADED = (1 << 2),
41
- GIT_DIFF_PATCH_DIFFABLE = (1 << 3),
42
- GIT_DIFF_PATCH_DIFFED = (1 << 4),
43
- GIT_DIFF_PATCH_FLATTENED = (1 << 5),
44
- };
45
-
46
18
  static void diff_output_init(
47
- git_diff_output*, const git_diff_options*,
48
- git_diff_file_cb, git_diff_hunk_cb, git_diff_line_cb, void*);
19
+ git_diff_output*, const git_diff_options*, git_diff_file_cb,
20
+ git_diff_binary_cb, git_diff_hunk_cb, git_diff_line_cb, void*);
49
21
 
50
22
  static void diff_output_to_patch(git_diff_output *, git_patch *);
51
23
 
@@ -67,15 +39,38 @@ static void diff_patch_init_common(git_patch *patch)
67
39
  {
68
40
  diff_patch_update_binary(patch);
69
41
 
70
- if ((patch->delta->flags & GIT_DIFF_FLAG_BINARY) != 0)
71
- patch->flags |= GIT_DIFF_PATCH_LOADED; /* LOADED but not DIFFABLE */
72
-
73
42
  patch->flags |= GIT_DIFF_PATCH_INITIALIZED;
74
43
 
75
44
  if (patch->diff)
76
45
  git_diff_addref(patch->diff);
77
46
  }
78
47
 
48
+ static int diff_patch_normalize_options(
49
+ git_diff_options *out,
50
+ const git_diff_options *opts)
51
+ {
52
+ if (opts) {
53
+ GITERR_CHECK_VERSION(opts, GIT_DIFF_OPTIONS_VERSION, "git_diff_options");
54
+ memcpy(out, opts, sizeof(git_diff_options));
55
+ } else {
56
+ git_diff_options default_opts = GIT_DIFF_OPTIONS_INIT;
57
+ memcpy(out, &default_opts, sizeof(git_diff_options));
58
+ }
59
+
60
+ out->old_prefix = opts && opts->old_prefix ?
61
+ git__strdup(opts->old_prefix) :
62
+ git__strdup(DIFF_OLD_PREFIX_DEFAULT);
63
+
64
+ out->new_prefix = opts && opts->new_prefix ?
65
+ git__strdup(opts->new_prefix) :
66
+ git__strdup(DIFF_NEW_PREFIX_DEFAULT);
67
+
68
+ GITERR_CHECK_ALLOC(out->old_prefix);
69
+ GITERR_CHECK_ALLOC(out->new_prefix);
70
+
71
+ return 0;
72
+ }
73
+
79
74
  static int diff_patch_init_from_diff(
80
75
  git_patch *patch, git_diff *diff, size_t delta_index)
81
76
  {
@@ -86,10 +81,12 @@ static int diff_patch_init_from_diff(
86
81
  patch->delta = git_vector_get(&diff->deltas, delta_index);
87
82
  patch->delta_index = delta_index;
88
83
 
89
- if ((error = git_diff_file_content__init_from_diff(
90
- &patch->ofile, diff, delta_index, true)) < 0 ||
84
+ if ((error = diff_patch_normalize_options(
85
+ &patch->diff_opts, &diff->opts)) < 0 ||
86
+ (error = git_diff_file_content__init_from_diff(
87
+ &patch->ofile, diff, patch->delta, true)) < 0 ||
91
88
  (error = git_diff_file_content__init_from_diff(
92
- &patch->nfile, diff, delta_index, false)) < 0)
89
+ &patch->nfile, diff, patch->delta, false)) < 0)
93
90
  return error;
94
91
 
95
92
  diff_patch_init_common(patch);
@@ -116,6 +113,43 @@ static int diff_patch_alloc_from_diff(
116
113
  return error;
117
114
  }
118
115
 
116
+ GIT_INLINE(bool) should_skip_binary(git_patch *patch, git_diff_file *file)
117
+ {
118
+ if ((patch->diff_opts.flags & GIT_DIFF_SHOW_BINARY) != 0)
119
+ return false;
120
+
121
+ return (file->flags & GIT_DIFF_FLAG_BINARY) != 0;
122
+ }
123
+
124
+ static bool diff_patch_diffable(git_patch *patch)
125
+ {
126
+ size_t olen, nlen;
127
+
128
+ if (patch->delta->status == GIT_DELTA_UNMODIFIED)
129
+ return false;
130
+
131
+ /* if we've determined this to be binary (and we are not showing binary
132
+ * data) then we have skipped loading the map data. instead, query the
133
+ * file data itself.
134
+ */
135
+ if ((patch->delta->flags & GIT_DIFF_FLAG_BINARY) != 0 &&
136
+ (patch->diff_opts.flags & GIT_DIFF_SHOW_BINARY) == 0) {
137
+ olen = (size_t)patch->ofile.file->size;
138
+ nlen = (size_t)patch->nfile.file->size;
139
+ } else {
140
+ olen = patch->ofile.map.len;
141
+ nlen = patch->nfile.map.len;
142
+ }
143
+
144
+ /* if both sides are empty, files are identical */
145
+ if (!olen && !nlen)
146
+ return false;
147
+
148
+ /* otherwise, check the file sizes and the oid */
149
+ return (olen != nlen ||
150
+ !git_oid_equal(&patch->ofile.file->id, &patch->nfile.file->id));
151
+ }
152
+
119
153
  static int diff_patch_load(git_patch *patch, git_diff_output *output)
120
154
  {
121
155
  int error = 0;
@@ -128,7 +162,7 @@ static int diff_patch_load(git_patch *patch, git_diff_output *output)
128
162
  * binary, then there is no need to actually load the data
129
163
  */
130
164
  if ((patch->ofile.opts_flags & GIT_DIFF_SKIP_BINARY_CHECK) != 0 &&
131
- output && !output->hunk_cb && !output->data_cb)
165
+ output && !output->binary_cb && !output->hunk_cb && !output->data_cb)
132
166
  return 0;
133
167
 
134
168
  incomplete_data =
@@ -141,25 +175,29 @@ static int diff_patch_load(git_patch *patch, git_diff_output *output)
141
175
  * need 2x data size and this minimizes peak memory footprint
142
176
  */
143
177
  if (patch->ofile.src == GIT_ITERATOR_TYPE_WORKDIR) {
144
- if ((error = git_diff_file_content__load(&patch->ofile)) < 0 ||
145
- (patch->ofile.file->flags & GIT_DIFF_FLAG_BINARY) != 0)
178
+ if ((error = git_diff_file_content__load(
179
+ &patch->ofile, &patch->diff_opts)) < 0 ||
180
+ should_skip_binary(patch, patch->ofile.file))
146
181
  goto cleanup;
147
182
  }
148
183
  if (patch->nfile.src == GIT_ITERATOR_TYPE_WORKDIR) {
149
- if ((error = git_diff_file_content__load(&patch->nfile)) < 0 ||
150
- (patch->nfile.file->flags & GIT_DIFF_FLAG_BINARY) != 0)
184
+ if ((error = git_diff_file_content__load(
185
+ &patch->nfile, &patch->diff_opts)) < 0 ||
186
+ should_skip_binary(patch, patch->nfile.file))
151
187
  goto cleanup;
152
188
  }
153
189
 
154
190
  /* once workdir has been tried, load other data as needed */
155
191
  if (patch->ofile.src != GIT_ITERATOR_TYPE_WORKDIR) {
156
- if ((error = git_diff_file_content__load(&patch->ofile)) < 0 ||
157
- (patch->ofile.file->flags & GIT_DIFF_FLAG_BINARY) != 0)
192
+ if ((error = git_diff_file_content__load(
193
+ &patch->ofile, &patch->diff_opts)) < 0 ||
194
+ should_skip_binary(patch, patch->ofile.file))
158
195
  goto cleanup;
159
196
  }
160
197
  if (patch->nfile.src != GIT_ITERATOR_TYPE_WORKDIR) {
161
- if ((error = git_diff_file_content__load(&patch->nfile)) < 0 ||
162
- (patch->nfile.file->flags & GIT_DIFF_FLAG_BINARY) != 0)
198
+ if ((error = git_diff_file_content__load(
199
+ &patch->nfile, &patch->diff_opts)) < 0 ||
200
+ should_skip_binary(patch, patch->nfile.file))
163
201
  goto cleanup;
164
202
  }
165
203
 
@@ -177,14 +215,7 @@ cleanup:
177
215
  diff_patch_update_binary(patch);
178
216
 
179
217
  if (!error) {
180
- /* patch is diffable only for non-binary, modified files where
181
- * at least one side has data and the data actually changed
182
- */
183
- if ((patch->delta->flags & GIT_DIFF_FLAG_BINARY) == 0 &&
184
- patch->delta->status != GIT_DELTA_UNMODIFIED &&
185
- (patch->ofile.map.len || patch->nfile.map.len) &&
186
- (patch->ofile.map.len != patch->nfile.map.len ||
187
- !git_oid_equal(&patch->ofile.file->id, &patch->nfile.file->id)))
218
+ if (diff_patch_diffable(patch))
188
219
  patch->flags |= GIT_DIFF_PATCH_DIFFABLE;
189
220
 
190
221
  patch->flags |= GIT_DIFF_PATCH_LOADED;
@@ -207,6 +238,103 @@ static int diff_patch_invoke_file_callback(
207
238
  "git_patch");
208
239
  }
209
240
 
241
+ static int create_binary(
242
+ git_diff_binary_t *out_type,
243
+ char **out_data,
244
+ size_t *out_datalen,
245
+ size_t *out_inflatedlen,
246
+ const char *a_data,
247
+ size_t a_datalen,
248
+ const char *b_data,
249
+ size_t b_datalen)
250
+ {
251
+ git_buf deflate = GIT_BUF_INIT, delta = GIT_BUF_INIT;
252
+ unsigned long delta_data_len;
253
+ int error;
254
+
255
+ /* The git_delta function accepts unsigned long only */
256
+ if (!git__is_ulong(a_datalen) || !git__is_ulong(b_datalen))
257
+ return GIT_EBUFS;
258
+
259
+ if ((error = git_zstream_deflatebuf(&deflate, b_data, b_datalen)) < 0)
260
+ goto done;
261
+
262
+ /* The git_delta function accepts unsigned long only */
263
+ if (!git__is_ulong(deflate.size)) {
264
+ error = GIT_EBUFS;
265
+ goto done;
266
+ }
267
+
268
+ if (a_datalen && b_datalen) {
269
+ void *delta_data = git_delta(
270
+ a_data, (unsigned long)a_datalen,
271
+ b_data, (unsigned long)b_datalen,
272
+ &delta_data_len, (unsigned long)deflate.size);
273
+
274
+ if (delta_data) {
275
+ error = git_zstream_deflatebuf(
276
+ &delta, delta_data, (size_t)delta_data_len);
277
+
278
+ git__free(delta_data);
279
+
280
+ if (error < 0)
281
+ goto done;
282
+ }
283
+ }
284
+
285
+ if (delta.size && delta.size < deflate.size) {
286
+ *out_type = GIT_DIFF_BINARY_DELTA;
287
+ *out_datalen = delta.size;
288
+ *out_data = git_buf_detach(&delta);
289
+ *out_inflatedlen = delta_data_len;
290
+ } else {
291
+ *out_type = GIT_DIFF_BINARY_LITERAL;
292
+ *out_datalen = deflate.size;
293
+ *out_data = git_buf_detach(&deflate);
294
+ *out_inflatedlen = b_datalen;
295
+ }
296
+
297
+ done:
298
+ git_buf_free(&deflate);
299
+ git_buf_free(&delta);
300
+
301
+ return error;
302
+ }
303
+
304
+ static int diff_binary(git_diff_output *output, git_patch *patch)
305
+ {
306
+ git_diff_binary binary = {{0}};
307
+ const char *old_data = patch->ofile.map.data;
308
+ const char *new_data = patch->nfile.map.data;
309
+ size_t old_len = patch->ofile.map.len,
310
+ new_len = patch->nfile.map.len;
311
+ int error;
312
+
313
+ /* Create the old->new delta (as the "new" side of the patch),
314
+ * and the new->old delta (as the "old" side)
315
+ */
316
+ if ((error = create_binary(&binary.old_file.type,
317
+ (char **)&binary.old_file.data,
318
+ &binary.old_file.datalen,
319
+ &binary.old_file.inflatedlen,
320
+ new_data, new_len, old_data, old_len)) < 0 ||
321
+ (error = create_binary(&binary.new_file.type,
322
+ (char **)&binary.new_file.data,
323
+ &binary.new_file.datalen,
324
+ &binary.new_file.inflatedlen,
325
+ old_data, old_len, new_data, new_len)) < 0)
326
+ return error;
327
+
328
+ error = giterr_set_after_callback_function(
329
+ output->binary_cb(patch->delta, &binary, output->payload),
330
+ "git_patch");
331
+
332
+ git__free((char *) binary.old_file.data);
333
+ git__free((char *) binary.new_file.data);
334
+
335
+ return error;
336
+ }
337
+
210
338
  static int diff_patch_generate(git_patch *patch, git_diff_output *output)
211
339
  {
212
340
  int error = 0;
@@ -214,8 +342,8 @@ static int diff_patch_generate(git_patch *patch, git_diff_output *output)
214
342
  if ((patch->flags & GIT_DIFF_PATCH_DIFFED) != 0)
215
343
  return 0;
216
344
 
217
- /* if we are not looking at the hunks and lines, don't do the diff */
218
- if (!output->hunk_cb && !output->data_cb)
345
+ /* if we are not looking at the binary or text data, don't do the diff */
346
+ if (!output->binary_cb && !output->hunk_cb && !output->data_cb)
219
347
  return 0;
220
348
 
221
349
  if ((patch->flags & GIT_DIFF_PATCH_LOADED) == 0 &&
@@ -225,10 +353,16 @@ static int diff_patch_generate(git_patch *patch, git_diff_output *output)
225
353
  if ((patch->flags & GIT_DIFF_PATCH_DIFFABLE) == 0)
226
354
  return 0;
227
355
 
228
- if (output->diff_cb != NULL &&
229
- (error = output->diff_cb(output, patch)) < 0)
230
- patch->flags |= GIT_DIFF_PATCH_DIFFED;
356
+ if ((patch->delta->flags & GIT_DIFF_FLAG_BINARY) != 0) {
357
+ if (output->binary_cb)
358
+ error = diff_binary(output, patch);
359
+ }
360
+ else {
361
+ if (output->diff_cb)
362
+ error = output->diff_cb(output, patch);
363
+ }
231
364
 
365
+ patch->flags |= GIT_DIFF_PATCH_DIFFED;
232
366
  return error;
233
367
  }
234
368
 
@@ -245,6 +379,12 @@ static void diff_patch_free(git_patch *patch)
245
379
 
246
380
  git_pool_clear(&patch->flattened);
247
381
 
382
+ git__free((char *)patch->diff_opts.old_prefix);
383
+ git__free((char *)patch->diff_opts.new_prefix);
384
+
385
+ git__free((char *)patch->binary.old_file.data);
386
+ git__free((char *)patch->binary.new_file.data);
387
+
248
388
  if (patch->flags & GIT_DIFF_PATCH_ALLOCATED)
249
389
  git__free(patch);
250
390
  }
@@ -260,6 +400,7 @@ static int diff_required(git_diff *diff, const char *action)
260
400
  int git_diff_foreach(
261
401
  git_diff *diff,
262
402
  git_diff_file_cb file_cb,
403
+ git_diff_binary_cb binary_cb,
263
404
  git_diff_hunk_cb hunk_cb,
264
405
  git_diff_line_cb data_cb,
265
406
  void *payload)
@@ -275,7 +416,7 @@ int git_diff_foreach(
275
416
  memset(&xo, 0, sizeof(xo));
276
417
  memset(&patch, 0, sizeof(patch));
277
418
  diff_output_init(
278
- &xo.output, &diff->opts, file_cb, hunk_cb, data_cb, payload);
419
+ &xo.output, &diff->opts, file_cb, binary_cb, hunk_cb, data_cb, payload);
279
420
  git_xdiff_init(&xo, &diff->opts);
280
421
 
281
422
  git_vector_foreach(&diff->deltas, idx, patch.delta) {
@@ -284,11 +425,15 @@ int git_diff_foreach(
284
425
  if (git_diff_delta__should_skip(&diff->opts, patch.delta))
285
426
  continue;
286
427
 
428
+ if (binary_cb || hunk_cb || data_cb) {
429
+ if ((error = diff_patch_init_from_diff(&patch, diff, idx)) != 0 ||
430
+ (error = diff_patch_load(&patch, &xo.output)) != 0)
431
+ return error;
432
+ }
433
+
287
434
  if ((error = diff_patch_invoke_file_callback(&patch, &xo.output)) == 0) {
288
- if (hunk_cb || data_cb) {
289
- if ((error = diff_patch_init_from_diff(&patch, diff, idx)) == 0)
435
+ if (binary_cb || hunk_cb || data_cb)
290
436
  error = diff_patch_generate(&patch, &xo.output);
291
- }
292
437
  }
293
438
 
294
439
  git_patch_free(&patch);
@@ -350,7 +495,8 @@ static int diff_patch_from_sources(
350
495
  git_diff_file *lfile = &pd->delta.old_file, *rfile = &pd->delta.new_file;
351
496
  git_diff_file_content *ldata = &pd->patch.ofile, *rdata = &pd->patch.nfile;
352
497
 
353
- GITERR_CHECK_VERSION(opts, GIT_DIFF_OPTIONS_VERSION, "git_diff_options");
498
+ if ((error = diff_patch_normalize_options(&pd->patch.diff_opts, opts)) < 0)
499
+ return error;
354
500
 
355
501
  if (opts && (opts->flags & GIT_DIFF_REVERSE) != 0) {
356
502
  void *tmp = lfile; lfile = rfile; rfile = tmp;
@@ -419,6 +565,7 @@ static int diff_from_sources(
419
565
  git_diff_file_content_src *newsrc,
420
566
  const git_diff_options *opts,
421
567
  git_diff_file_cb file_cb,
568
+ git_diff_binary_cb binary_cb,
422
569
  git_diff_hunk_cb hunk_cb,
423
570
  git_diff_line_cb data_cb,
424
571
  void *payload)
@@ -429,7 +576,7 @@ static int diff_from_sources(
429
576
 
430
577
  memset(&xo, 0, sizeof(xo));
431
578
  diff_output_init(
432
- &xo.output, opts, file_cb, hunk_cb, data_cb, payload);
579
+ &xo.output, opts, file_cb, binary_cb, hunk_cb, data_cb, payload);
433
580
  git_xdiff_init(&xo, opts);
434
581
 
435
582
  memset(&pd, 0, sizeof(pd));
@@ -477,6 +624,7 @@ int git_diff_blobs(
477
624
  const char *new_path,
478
625
  const git_diff_options *opts,
479
626
  git_diff_file_cb file_cb,
627
+ git_diff_binary_cb binary_cb,
480
628
  git_diff_hunk_cb hunk_cb,
481
629
  git_diff_line_cb data_cb,
482
630
  void *payload)
@@ -486,7 +634,7 @@ int git_diff_blobs(
486
634
  git_diff_file_content_src nsrc =
487
635
  GIT_DIFF_FILE_CONTENT_SRC__BLOB(new_blob, new_path);
488
636
  return diff_from_sources(
489
- &osrc, &nsrc, opts, file_cb, hunk_cb, data_cb, payload);
637
+ &osrc, &nsrc, opts, file_cb, binary_cb, hunk_cb, data_cb, payload);
490
638
  }
491
639
 
492
640
  int git_patch_from_blobs(
@@ -512,6 +660,7 @@ int git_diff_blob_to_buffer(
512
660
  const char *buf_path,
513
661
  const git_diff_options *opts,
514
662
  git_diff_file_cb file_cb,
663
+ git_diff_binary_cb binary_cb,
515
664
  git_diff_hunk_cb hunk_cb,
516
665
  git_diff_line_cb data_cb,
517
666
  void *payload)
@@ -521,7 +670,7 @@ int git_diff_blob_to_buffer(
521
670
  git_diff_file_content_src nsrc =
522
671
  GIT_DIFF_FILE_CONTENT_SRC__BUF(buf, buflen, buf_path);
523
672
  return diff_from_sources(
524
- &osrc, &nsrc, opts, file_cb, hunk_cb, data_cb, payload);
673
+ &osrc, &nsrc, opts, file_cb, binary_cb, hunk_cb, data_cb, payload);
525
674
  }
526
675
 
527
676
  int git_patch_from_blob_and_buffer(
@@ -549,6 +698,7 @@ int git_diff_buffers(
549
698
  const char *new_path,
550
699
  const git_diff_options *opts,
551
700
  git_diff_file_cb file_cb,
701
+ git_diff_binary_cb binary_cb,
552
702
  git_diff_hunk_cb hunk_cb,
553
703
  git_diff_line_cb data_cb,
554
704
  void *payload)
@@ -558,7 +708,7 @@ int git_diff_buffers(
558
708
  git_diff_file_content_src nsrc =
559
709
  GIT_DIFF_FILE_CONTENT_SRC__BUF(new_buf, new_len, new_path);
560
710
  return diff_from_sources(
561
- &osrc, &nsrc, opts, file_cb, hunk_cb, data_cb, payload);
711
+ &osrc, &nsrc, opts, file_cb, binary_cb, hunk_cb, data_cb, payload);
562
712
  }
563
713
 
564
714
  int git_patch_from_buffers(
@@ -812,6 +962,7 @@ void git_patch__new_data(
812
962
  int git_patch__invoke_callbacks(
813
963
  git_patch *patch,
814
964
  git_diff_file_cb file_cb,
965
+ git_diff_binary_cb binary_cb,
815
966
  git_diff_hunk_cb hunk_cb,
816
967
  git_diff_line_cb line_cb,
817
968
  void *payload)
@@ -822,6 +973,13 @@ int git_patch__invoke_callbacks(
822
973
  if (file_cb)
823
974
  error = file_cb(patch->delta, 0, payload);
824
975
 
976
+ if ((patch->delta->flags & GIT_DIFF_FLAG_BINARY) != 0) {
977
+ if (binary_cb)
978
+ error = binary_cb(patch->delta, &patch->binary, payload);
979
+
980
+ return error;
981
+ }
982
+
825
983
  if (!hunk_cb && !line_cb)
826
984
  return error;
827
985
 
@@ -855,6 +1013,36 @@ static int diff_patch_file_cb(
855
1013
  return 0;
856
1014
  }
857
1015
 
1016
+ static int diff_patch_binary_cb(
1017
+ const git_diff_delta *delta,
1018
+ const git_diff_binary *binary,
1019
+ void *payload)
1020
+ {
1021
+ git_patch *patch = payload;
1022
+
1023
+ GIT_UNUSED(delta);
1024
+
1025
+ memcpy(&patch->binary, binary, sizeof(git_diff_binary));
1026
+
1027
+ if (binary->old_file.data) {
1028
+ patch->binary.old_file.data = git__malloc(binary->old_file.datalen);
1029
+ GITERR_CHECK_ALLOC(patch->binary.old_file.data);
1030
+
1031
+ memcpy((char *)patch->binary.old_file.data,
1032
+ binary->old_file.data, binary->old_file.datalen);
1033
+ }
1034
+
1035
+ if (binary->new_file.data) {
1036
+ patch->binary.new_file.data = git__malloc(binary->new_file.datalen);
1037
+ GITERR_CHECK_ALLOC(patch->binary.new_file.data);
1038
+
1039
+ memcpy((char *)patch->binary.new_file.data,
1040
+ binary->new_file.data, binary->new_file.datalen);
1041
+ }
1042
+
1043
+ return 0;
1044
+ }
1045
+
858
1046
  static int diff_patch_hunk_cb(
859
1047
  const git_diff_delta *delta,
860
1048
  const git_diff_hunk *hunk_,
@@ -921,6 +1109,7 @@ static void diff_output_init(
921
1109
  git_diff_output *out,
922
1110
  const git_diff_options *opts,
923
1111
  git_diff_file_cb file_cb,
1112
+ git_diff_binary_cb binary_cb,
924
1113
  git_diff_hunk_cb hunk_cb,
925
1114
  git_diff_line_cb data_cb,
926
1115
  void *payload)
@@ -930,6 +1119,7 @@ static void diff_output_init(
930
1119
  memset(out, 0, sizeof(*out));
931
1120
 
932
1121
  out->file_cb = file_cb;
1122
+ out->binary_cb = binary_cb;
933
1123
  out->hunk_cb = hunk_cb;
934
1124
  out->data_cb = data_cb;
935
1125
  out->payload = payload;
@@ -938,6 +1128,11 @@ static void diff_output_init(
938
1128
  static void diff_output_to_patch(git_diff_output *out, git_patch *patch)
939
1129
  {
940
1130
  diff_output_init(
941
- out, NULL,
942
- diff_patch_file_cb, diff_patch_hunk_cb, diff_patch_line_cb, patch);
1131
+ out,
1132
+ NULL,
1133
+ diff_patch_file_cb,
1134
+ diff_patch_binary_cb,
1135
+ diff_patch_hunk_cb,
1136
+ diff_patch_line_cb,
1137
+ patch);
943
1138
  }