rugged 0.22.2 → 0.23.0b1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (155) hide show
  1. checksums.yaml +4 -4
  2. data/ext/rugged/rugged.c +1 -2
  3. data/ext/rugged/rugged_branch_collection.c +6 -44
  4. data/ext/rugged/rugged_config.c +7 -3
  5. data/ext/rugged/rugged_diff_delta.c +1 -1
  6. data/ext/rugged/rugged_diff_line.c +1 -1
  7. data/ext/rugged/rugged_object.c +2 -2
  8. data/ext/rugged/rugged_reference_collection.c +12 -56
  9. data/ext/rugged/rugged_remote.c +4 -33
  10. data/ext/rugged/rugged_remote_collection.c +1 -1
  11. data/ext/rugged/rugged_repo.c +10 -36
  12. data/ext/rugged/rugged_settings.c +3 -3
  13. data/ext/rugged/rugged_tree.c +1 -1
  14. data/lib/rugged/version.rb +1 -1
  15. data/vendor/libgit2/CMakeLists.txt +10 -3
  16. data/vendor/libgit2/COPYING +15 -21
  17. data/vendor/libgit2/include/git2/annotated_commit.h +20 -3
  18. data/vendor/libgit2/include/git2/branch.h +20 -16
  19. data/vendor/libgit2/include/git2/checkout.h +32 -18
  20. data/vendor/libgit2/include/git2/cherrypick.h +2 -2
  21. data/vendor/libgit2/include/git2/clone.h +4 -10
  22. data/vendor/libgit2/include/git2/config.h +66 -12
  23. data/vendor/libgit2/include/git2/describe.h +3 -2
  24. data/vendor/libgit2/include/git2/diff.h +3 -3
  25. data/vendor/libgit2/include/git2/errors.h +1 -0
  26. data/vendor/libgit2/include/git2/filter.h +21 -5
  27. data/vendor/libgit2/include/git2/index.h +32 -0
  28. data/vendor/libgit2/include/git2/merge.h +20 -3
  29. data/vendor/libgit2/include/git2/oid.h +1 -1
  30. data/vendor/libgit2/include/git2/pack.h +13 -0
  31. data/vendor/libgit2/include/git2/patch.h +3 -6
  32. data/vendor/libgit2/include/git2/rebase.h +8 -12
  33. data/vendor/libgit2/include/git2/refs.h +19 -29
  34. data/vendor/libgit2/include/git2/remote.h +5 -11
  35. data/vendor/libgit2/include/git2/repository.h +44 -15
  36. data/vendor/libgit2/include/git2/reset.h +19 -10
  37. data/vendor/libgit2/include/git2/revert.h +2 -2
  38. data/vendor/libgit2/include/git2/submodule.h +3 -9
  39. data/vendor/libgit2/include/git2/sys/config.h +3 -1
  40. data/vendor/libgit2/include/git2/sys/filter.h +10 -2
  41. data/vendor/libgit2/include/git2/sys/hashsig.h +49 -22
  42. data/vendor/libgit2/include/git2/transport.h +1 -1
  43. data/vendor/libgit2/include/git2/types.h +10 -3
  44. data/vendor/libgit2/include/git2/version.h +3 -2
  45. data/vendor/libgit2/src/annotated_commit.c +28 -0
  46. data/vendor/libgit2/src/array.h +19 -8
  47. data/vendor/libgit2/src/attr.c +95 -35
  48. data/vendor/libgit2/src/attr_file.c +51 -17
  49. data/vendor/libgit2/src/attr_file.h +37 -10
  50. data/vendor/libgit2/src/attrcache.c +13 -7
  51. data/vendor/libgit2/src/attrcache.h +1 -0
  52. data/vendor/libgit2/src/blame.c +26 -2
  53. data/vendor/libgit2/src/blame_git.c +6 -2
  54. data/vendor/libgit2/src/blob.c +6 -8
  55. data/vendor/libgit2/src/branch.c +55 -43
  56. data/vendor/libgit2/src/buf_text.c +13 -6
  57. data/vendor/libgit2/src/buffer.c +110 -25
  58. data/vendor/libgit2/src/buffer.h +18 -0
  59. data/vendor/libgit2/src/checkout.c +164 -92
  60. data/vendor/libgit2/src/checkout.h +0 -7
  61. data/vendor/libgit2/src/cherrypick.c +13 -7
  62. data/vendor/libgit2/src/clone.c +23 -25
  63. data/vendor/libgit2/src/commit.c +3 -3
  64. data/vendor/libgit2/src/common.h +23 -1
  65. data/vendor/libgit2/src/config.c +137 -19
  66. data/vendor/libgit2/src/config.h +2 -2
  67. data/vendor/libgit2/src/config_cache.c +2 -1
  68. data/vendor/libgit2/src/config_file.c +39 -18
  69. data/vendor/libgit2/src/config_file.h +1 -1
  70. data/vendor/libgit2/src/crlf.c +1 -1
  71. data/vendor/libgit2/src/delta-apply.c +3 -2
  72. data/vendor/libgit2/src/delta.c +25 -6
  73. data/vendor/libgit2/src/describe.c +2 -0
  74. data/vendor/libgit2/src/diff.c +8 -5
  75. data/vendor/libgit2/src/diff_driver.c +39 -18
  76. data/vendor/libgit2/src/diff_file.c +1 -1
  77. data/vendor/libgit2/src/diff_patch.c +12 -6
  78. data/vendor/libgit2/src/diff_tform.c +21 -24
  79. data/vendor/libgit2/src/filebuf.c +14 -12
  80. data/vendor/libgit2/src/fileops.c +61 -18
  81. data/vendor/libgit2/src/fileops.h +11 -2
  82. data/vendor/libgit2/src/filter.c +351 -99
  83. data/vendor/libgit2/src/filter.h +17 -0
  84. data/vendor/libgit2/src/global.c +38 -9
  85. data/vendor/libgit2/src/hash/hash_generic.c +1 -1
  86. data/vendor/libgit2/src/hashsig.c +28 -16
  87. data/vendor/libgit2/src/ignore.c +2 -2
  88. data/vendor/libgit2/src/index.c +159 -42
  89. data/vendor/libgit2/src/index.h +29 -0
  90. data/vendor/libgit2/src/indexer.c +11 -2
  91. data/vendor/libgit2/src/integer.h +96 -0
  92. data/vendor/libgit2/src/iterator.c +5 -3
  93. data/vendor/libgit2/src/khash.h +41 -29
  94. data/vendor/libgit2/src/merge.c +48 -35
  95. data/vendor/libgit2/src/merge.h +0 -1
  96. data/vendor/libgit2/src/merge_file.c +13 -0
  97. data/vendor/libgit2/src/mwindow.c +1 -1
  98. data/vendor/libgit2/src/notes.c +1 -1
  99. data/vendor/libgit2/src/odb.c +13 -11
  100. data/vendor/libgit2/src/odb_loose.c +22 -10
  101. data/vendor/libgit2/src/odb_mempack.c +4 -2
  102. data/vendor/libgit2/src/offmap.h +3 -2
  103. data/vendor/libgit2/src/oid.c +1 -1
  104. data/vendor/libgit2/src/oidmap.h +2 -1
  105. data/vendor/libgit2/src/openssl_stream.c +6 -3
  106. data/vendor/libgit2/src/pack-objects.c +273 -12
  107. data/vendor/libgit2/src/pack-objects.h +10 -0
  108. data/vendor/libgit2/src/pack.c +17 -6
  109. data/vendor/libgit2/src/pack.h +1 -3
  110. data/vendor/libgit2/src/path.c +68 -38
  111. data/vendor/libgit2/src/pathspec.c +3 -0
  112. data/vendor/libgit2/src/pool.c +9 -8
  113. data/vendor/libgit2/src/posix.c +11 -1
  114. data/vendor/libgit2/src/push.c +15 -17
  115. data/vendor/libgit2/src/push.h +1 -6
  116. data/vendor/libgit2/src/rebase.c +77 -35
  117. data/vendor/libgit2/src/refdb_fs.c +2 -2
  118. data/vendor/libgit2/src/refs.c +107 -81
  119. data/vendor/libgit2/src/refs.h +2 -2
  120. data/vendor/libgit2/src/refspec.c +3 -0
  121. data/vendor/libgit2/src/remote.c +19 -21
  122. data/vendor/libgit2/src/repository.c +258 -67
  123. data/vendor/libgit2/src/repository.h +31 -16
  124. data/vendor/libgit2/src/reset.c +28 -12
  125. data/vendor/libgit2/src/revert.c +12 -7
  126. data/vendor/libgit2/src/revwalk.c +3 -5
  127. data/vendor/libgit2/src/revwalk.h +1 -1
  128. data/vendor/libgit2/src/sortedcache.c +5 -3
  129. data/vendor/libgit2/src/stash.c +3 -5
  130. data/vendor/libgit2/src/strmap.h +2 -1
  131. data/vendor/libgit2/src/submodule.c +5 -6
  132. data/vendor/libgit2/src/tag.c +7 -5
  133. data/vendor/libgit2/src/transaction.c +1 -1
  134. data/vendor/libgit2/src/transports/cred.c +5 -2
  135. data/vendor/libgit2/src/transports/git.c +2 -3
  136. data/vendor/libgit2/src/transports/local.c +15 -34
  137. data/vendor/libgit2/src/transports/smart.c +1 -1
  138. data/vendor/libgit2/src/transports/smart_pkt.c +58 -18
  139. data/vendor/libgit2/src/transports/smart_protocol.c +2 -2
  140. data/vendor/libgit2/src/transports/winhttp.c +2 -2
  141. data/vendor/libgit2/src/tree.c +7 -5
  142. data/vendor/libgit2/src/tsort.c +3 -1
  143. data/vendor/libgit2/src/util.c +25 -0
  144. data/vendor/libgit2/src/util.h +31 -27
  145. data/vendor/libgit2/src/vector.c +2 -7
  146. data/vendor/libgit2/src/win32/dir.c +5 -3
  147. data/vendor/libgit2/src/win32/git2.rc +8 -4
  148. data/vendor/libgit2/src/win32/mingw-compat.h +7 -0
  149. data/vendor/libgit2/src/win32/msvc-compat.h +3 -0
  150. data/vendor/libgit2/src/win32/posix.h +1 -3
  151. data/vendor/libgit2/src/win32/posix_w32.c +31 -7
  152. data/vendor/libgit2/src/win32/utf-conv.c +1 -3
  153. data/vendor/libgit2/src/zstream.c +1 -1
  154. metadata +5 -5
  155. data/vendor/libgit2/src/bswap.h +0 -97
@@ -302,7 +302,7 @@ static int diff_file_content_load_workdir_file(
302
302
 
303
303
  if ((error = git_filter_list_load(
304
304
  &fl, fc->repo, NULL, fc->file->path,
305
- GIT_FILTER_TO_ODB, GIT_FILTER_OPT_ALLOW_UNSAFE)) < 0)
305
+ GIT_FILTER_TO_ODB, GIT_FILTER_ALLOW_UNSAFE)) < 0)
306
306
  goto cleanup;
307
307
 
308
308
  /* if there are no filters, try to mmap the file */
@@ -284,11 +284,12 @@ int git_diff_foreach(
284
284
  if (git_diff_delta__should_skip(&diff->opts, patch.delta))
285
285
  continue;
286
286
 
287
- if ((error = diff_patch_init_from_diff(&patch, diff, idx)) < 0)
288
- break;
289
-
290
- if (!(error = diff_patch_invoke_file_callback(&patch, &xo.output)))
291
- error = diff_patch_generate(&patch, &xo.output);
287
+ 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)
290
+ error = diff_patch_generate(&patch, &xo.output);
291
+ }
292
+ }
292
293
 
293
294
  git_patch_free(&patch);
294
295
 
@@ -387,8 +388,13 @@ static int diff_patch_with_delta_alloc(
387
388
  diff_patch_with_delta *pd;
388
389
  size_t old_len = *old_path ? strlen(*old_path) : 0;
389
390
  size_t new_len = *new_path ? strlen(*new_path) : 0;
391
+ size_t alloc_len;
392
+
393
+ GITERR_CHECK_ALLOC_ADD(&alloc_len, sizeof(*pd), old_len);
394
+ GITERR_CHECK_ALLOC_ADD(&alloc_len, alloc_len, new_len);
395
+ GITERR_CHECK_ALLOC_ADD(&alloc_len, alloc_len, 2);
390
396
 
391
- *out = pd = git__calloc(1, sizeof(*pd) + old_len + new_len + 2);
397
+ *out = pd = git__calloc(1, alloc_len);
392
398
  GITERR_CHECK_ALLOC(pd);
393
399
 
394
400
  pd->patch.flags = GIT_DIFF_PATCH_ALLOCATED;
@@ -219,34 +219,18 @@ int git_diff_find_similar__hashsig_for_file(
219
219
  void **out, const git_diff_file *f, const char *path, void *p)
220
220
  {
221
221
  git_hashsig_option_t opt = (git_hashsig_option_t)(intptr_t)p;
222
- int error = 0;
223
222
 
224
223
  GIT_UNUSED(f);
225
- error = git_hashsig_create_fromfile((git_hashsig **)out, path, opt);
226
-
227
- if (error == GIT_EBUFS) {
228
- error = 0;
229
- giterr_clear();
230
- }
231
-
232
- return error;
224
+ return git_hashsig_create_fromfile((git_hashsig **)out, path, opt);
233
225
  }
234
226
 
235
227
  int git_diff_find_similar__hashsig_for_buf(
236
228
  void **out, const git_diff_file *f, const char *buf, size_t len, void *p)
237
229
  {
238
230
  git_hashsig_option_t opt = (git_hashsig_option_t)(intptr_t)p;
239
- int error = 0;
240
231
 
241
232
  GIT_UNUSED(f);
242
- error = git_hashsig_create((git_hashsig **)out, buf, len, opt);
243
-
244
- if (error == GIT_EBUFS) {
245
- error = 0;
246
- giterr_clear();
247
- }
248
-
249
- return error;
233
+ return git_hashsig_create((git_hashsig **)out, buf, len, opt);
250
234
  }
251
235
 
252
236
  void git_diff_find_similar__hashsig_free(void *sig, void *payload)
@@ -258,8 +242,14 @@ void git_diff_find_similar__hashsig_free(void *sig, void *payload)
258
242
  int git_diff_find_similar__calc_similarity(
259
243
  int *score, void *siga, void *sigb, void *payload)
260
244
  {
245
+ int error;
246
+
261
247
  GIT_UNUSED(payload);
262
- *score = git_hashsig_compare(siga, sigb);
248
+ error = git_hashsig_compare(siga, sigb);
249
+ if (error < 0)
250
+ return error;
251
+
252
+ *score = error;
263
253
  return 0;
264
254
  }
265
255
 
@@ -273,6 +263,7 @@ static int normalize_find_opts(
273
263
  const git_diff_find_options *given)
274
264
  {
275
265
  git_config *cfg = NULL;
266
+ git_hashsig_option_t hashsig_opts;
276
267
 
277
268
  GITERR_CHECK_VERSION(given, GIT_DIFF_FIND_OPTIONS_VERSION, "git_diff_find_options");
278
269
 
@@ -286,7 +277,7 @@ static int normalize_find_opts(
286
277
  if (!given ||
287
278
  (given->flags & GIT_DIFF_FIND_ALL) == GIT_DIFF_FIND_BY_CONFIG)
288
279
  {
289
- const char *rule =
280
+ char *rule =
290
281
  git_config__get_string_force(cfg, "diff.renames", "true");
291
282
  int boolval;
292
283
 
@@ -296,6 +287,8 @@ static int normalize_find_opts(
296
287
  opts->flags |= GIT_DIFF_FIND_RENAMES | GIT_DIFF_FIND_COPIES;
297
288
  else
298
289
  opts->flags |= GIT_DIFF_FIND_RENAMES;
290
+
291
+ git__free(rule);
299
292
  }
300
293
 
301
294
  /* some flags imply others */
@@ -354,11 +347,13 @@ static int normalize_find_opts(
354
347
  opts->metric->similarity = git_diff_find_similar__calc_similarity;
355
348
 
356
349
  if (opts->flags & GIT_DIFF_FIND_IGNORE_WHITESPACE)
357
- opts->metric->payload = (void *)GIT_HASHSIG_IGNORE_WHITESPACE;
350
+ hashsig_opts = GIT_HASHSIG_IGNORE_WHITESPACE;
358
351
  else if (opts->flags & GIT_DIFF_FIND_DONT_IGNORE_WHITESPACE)
359
- opts->metric->payload = (void *)GIT_HASHSIG_NORMAL;
352
+ hashsig_opts = GIT_HASHSIG_NORMAL;
360
353
  else
361
- opts->metric->payload = (void *)GIT_HASHSIG_SMART_WHITESPACE;
354
+ hashsig_opts = GIT_HASHSIG_SMART_WHITESPACE;
355
+ hashsig_opts |= GIT_HASHSIG_ALLOW_SMALL_FILES;
356
+ opts->metric->payload = (void *)hashsig_opts;
362
357
  }
363
358
 
364
359
  return 0;
@@ -818,6 +813,7 @@ int git_diff_find_similar(
818
813
  size_t num_deltas, num_srcs = 0, num_tgts = 0;
819
814
  size_t tried_srcs = 0, tried_tgts = 0;
820
815
  size_t num_rewrites = 0, num_updates = 0, num_bumped = 0;
816
+ size_t sigcache_size;
821
817
  void **sigcache = NULL; /* cache of similarity metric file signatures */
822
818
  diff_find_match *tgt2src = NULL;
823
819
  diff_find_match *src2tgt = NULL;
@@ -838,7 +834,8 @@ int git_diff_find_similar(
838
834
  if ((opts.flags & GIT_DIFF_FIND_ALL) == 0)
839
835
  goto cleanup;
840
836
 
841
- sigcache = git__calloc(num_deltas * 2, sizeof(void *));
837
+ GITERR_CHECK_ALLOC_MULTIPLY(&sigcache_size, num_deltas, 2);
838
+ sigcache = git__calloc(sigcache_size, sizeof(void *));
842
839
  GITERR_CHECK_ALLOC(sigcache);
843
840
 
844
841
  /* Label rename sources and targets
@@ -194,7 +194,7 @@ static int write_deflate(git_filebuf *file, void *source, size_t len)
194
194
  int git_filebuf_open(git_filebuf *file, const char *path, int flags, mode_t mode)
195
195
  {
196
196
  int compression, error = -1;
197
- size_t path_len;
197
+ size_t path_len, alloc_len;
198
198
 
199
199
  /* opening an already open buffer is a programming error;
200
200
  * assert that this never happens instead of returning
@@ -271,7 +271,8 @@ int git_filebuf_open(git_filebuf *file, const char *path, int flags, mode_t mode
271
271
  GITERR_CHECK_ALLOC(file->path_original);
272
272
 
273
273
  /* create the locking path by appending ".lock" to the original */
274
- file->path_lock = git__malloc(path_len + GIT_FILELOCK_EXTLENGTH);
274
+ GITERR_CHECK_ALLOC_ADD(&alloc_len, path_len, GIT_FILELOCK_EXTLENGTH);
275
+ file->path_lock = git__malloc(alloc_len);
275
276
  GITERR_CHECK_ALLOC(file->path_lock);
276
277
 
277
278
  memcpy(file->path_lock, file->path_original, path_len);
@@ -407,8 +408,8 @@ int git_filebuf_reserve(git_filebuf *file, void **buffer, size_t len)
407
408
  int git_filebuf_printf(git_filebuf *file, const char *format, ...)
408
409
  {
409
410
  va_list arglist;
410
- size_t space_left;
411
- int len, res;
411
+ size_t space_left, len, alloclen;
412
+ int written, res;
412
413
  char *tmp_buffer;
413
414
 
414
415
  ENSURE_BUF_OK(file);
@@ -417,15 +418,16 @@ int git_filebuf_printf(git_filebuf *file, const char *format, ...)
417
418
 
418
419
  do {
419
420
  va_start(arglist, format);
420
- len = p_vsnprintf((char *)file->buffer + file->buf_pos, space_left, format, arglist);
421
+ written = p_vsnprintf((char *)file->buffer + file->buf_pos, space_left, format, arglist);
421
422
  va_end(arglist);
422
423
 
423
- if (len < 0) {
424
+ if (written < 0) {
424
425
  file->last_error = BUFERR_MEM;
425
426
  return -1;
426
427
  }
427
428
 
428
- if ((size_t)len + 1 <= space_left) {
429
+ len = written;
430
+ if (len + 1 <= space_left) {
429
431
  file->buf_pos += len;
430
432
  return 0;
431
433
  }
@@ -435,19 +437,19 @@ int git_filebuf_printf(git_filebuf *file, const char *format, ...)
435
437
 
436
438
  space_left = file->buf_size - file->buf_pos;
437
439
 
438
- } while ((size_t)len + 1 <= space_left);
440
+ } while (len + 1 <= space_left);
439
441
 
440
- tmp_buffer = git__malloc(len + 1);
441
- if (!tmp_buffer) {
442
+ if (GIT_ADD_SIZET_OVERFLOW(&alloclen, len, 1) ||
443
+ !(tmp_buffer = git__malloc(alloclen))) {
442
444
  file->last_error = BUFERR_MEM;
443
445
  return -1;
444
446
  }
445
447
 
446
448
  va_start(arglist, format);
447
- len = p_vsnprintf(tmp_buffer, len + 1, format, arglist);
449
+ written = p_vsnprintf(tmp_buffer, len + 1, format, arglist);
448
450
  va_end(arglist);
449
451
 
450
- if (len < 0) {
452
+ if (written < 0) {
451
453
  git__free(tmp_buffer);
452
454
  file->last_error = BUFERR_MEM;
453
455
  return -1;
@@ -7,11 +7,14 @@
7
7
  #include "common.h"
8
8
  #include "fileops.h"
9
9
  #include "global.h"
10
+ #include "strmap.h"
10
11
  #include <ctype.h>
11
12
  #if GIT_WIN32
12
13
  #include "win32/findfile.h"
13
14
  #endif
14
15
 
16
+ GIT__USE_STRMAP
17
+
15
18
  int git_futils_mkpath2file(const char *file_path, const mode_t mode)
16
19
  {
17
20
  return git_futils_mkdir(
@@ -121,10 +124,17 @@ mode_t git_futils_canonical_mode(mode_t raw_mode)
121
124
  int git_futils_readbuffer_fd(git_buf *buf, git_file fd, size_t len)
122
125
  {
123
126
  ssize_t read_size = 0;
127
+ size_t alloc_len;
124
128
 
125
129
  git_buf_clear(buf);
126
130
 
127
- if (git_buf_grow(buf, len + 1) < 0)
131
+ if (!git__is_ssizet(len)) {
132
+ giterr_set(GITERR_INVALID, "Read too large.");
133
+ return -1;
134
+ }
135
+
136
+ GITERR_CHECK_ALLOC_ADD(&alloc_len, len, 1);
137
+ if (git_buf_grow(buf, alloc_len) < 0)
128
138
  return -1;
129
139
 
130
140
  /* p_read loops internally to read len bytes */
@@ -174,7 +184,7 @@ int git_futils_readbuffer_updated(
174
184
  */
175
185
  if (size && *size != (size_t)st.st_size)
176
186
  changed = true;
177
- if (mtime && *mtime != st.st_mtime)
187
+ if (mtime && *mtime != (time_t)st.st_mtime)
178
188
  changed = true;
179
189
  if (!size && !mtime)
180
190
  changed = true;
@@ -313,7 +323,7 @@ GIT_INLINE(int) validate_existing(
313
323
  }
314
324
 
315
325
  else if (!S_ISDIR(st->st_mode)) {
316
- giterr_set(GITERR_INVALID,
326
+ giterr_set(GITERR_FILESYSTEM,
317
327
  "Failed to make directory '%s': directory exists", make_path);
318
328
  return GIT_EEXISTS;
319
329
  }
@@ -321,12 +331,12 @@ GIT_INLINE(int) validate_existing(
321
331
  return 0;
322
332
  }
323
333
 
324
- int git_futils_mkdir_withperf(
334
+ int git_futils_mkdir_ext(
325
335
  const char *path,
326
336
  const char *base,
327
337
  mode_t mode,
328
338
  uint32_t flags,
329
- struct git_futils_mkdir_perfdata *perfdata)
339
+ struct git_futils_mkdir_options *opts)
330
340
  {
331
341
  int error = -1;
332
342
  git_buf make_path = GIT_BUF_INIT;
@@ -389,6 +399,7 @@ int git_futils_mkdir_withperf(
389
399
 
390
400
  /* walk down tail of path making each directory */
391
401
  for (tail = &make_path.ptr[root]; *tail; *tail = lastch) {
402
+ bool mkdir_attempted = false;
392
403
 
393
404
  /* advance tail to include next path component */
394
405
  while (*tail == '/')
@@ -401,29 +412,40 @@ int git_futils_mkdir_withperf(
401
412
  *tail = '\0';
402
413
  st.st_mode = 0;
403
414
 
415
+ if (opts->dir_map && git_strmap_exists(opts->dir_map, make_path.ptr))
416
+ continue;
417
+
404
418
  /* See what's going on with this path component */
405
- perfdata->stat_calls++;
419
+ opts->perfdata.stat_calls++;
406
420
 
421
+ retry_lstat:
407
422
  if (p_lstat(make_path.ptr, &st) < 0) {
408
- perfdata->mkdir_calls++;
409
-
410
- if (errno != ENOENT || p_mkdir(make_path.ptr, mode) < 0) {
411
- giterr_set(GITERR_OS, "Failed to make directory '%s'", make_path.ptr);
412
- error = GIT_EEXISTS;
423
+ if (mkdir_attempted || errno != ENOENT) {
424
+ giterr_set(GITERR_OS, "Cannot access component in path '%s'", make_path.ptr);
425
+ error = -1;
413
426
  goto done;
414
427
  }
415
428
 
416
429
  giterr_clear();
430
+ opts->perfdata.mkdir_calls++;
431
+ mkdir_attempted = true;
432
+ if (p_mkdir(make_path.ptr, mode) < 0) {
433
+ if (errno == EEXIST)
434
+ goto retry_lstat;
435
+ giterr_set(GITERR_OS, "Failed to make directory '%s'", make_path.ptr);
436
+ error = -1;
437
+ goto done;
438
+ }
417
439
  } else {
418
440
  /* with exclusive create, existing dir is an error */
419
441
  if ((flags & GIT_MKDIR_EXCL) != 0) {
420
- giterr_set(GITERR_INVALID, "Failed to make directory '%s': directory exists", make_path.ptr);
442
+ giterr_set(GITERR_FILESYSTEM, "Failed to make directory '%s': directory exists", make_path.ptr);
421
443
  error = GIT_EEXISTS;
422
444
  goto done;
423
445
  }
424
446
 
425
447
  if ((error = validate_existing(
426
- make_path.ptr, &st, mode, flags, perfdata)) < 0)
448
+ make_path.ptr, &st, mode, flags, &opts->perfdata)) < 0)
427
449
  goto done;
428
450
  }
429
451
 
@@ -432,7 +454,7 @@ int git_futils_mkdir_withperf(
432
454
  (lastch == '\0' && (flags & GIT_MKDIR_CHMOD) != 0)) &&
433
455
  st.st_mode != mode) {
434
456
 
435
- perfdata->chmod_calls++;
457
+ opts->perfdata.chmod_calls++;
436
458
 
437
459
  if ((error = p_chmod(make_path.ptr, mode)) < 0 &&
438
460
  lastch == '\0') {
@@ -441,6 +463,23 @@ int git_futils_mkdir_withperf(
441
463
  goto done;
442
464
  }
443
465
  }
466
+
467
+ if (opts->dir_map && opts->pool) {
468
+ char *cache_path;
469
+ size_t alloc_size;
470
+
471
+ GITERR_CHECK_ALLOC_ADD(&alloc_size, make_path.size, 1);
472
+ if (!git__is_uint32(alloc_size))
473
+ return -1;
474
+ cache_path = git_pool_malloc(opts->pool, (uint32_t)alloc_size);
475
+ GITERR_CHECK_ALLOC(cache_path);
476
+
477
+ memcpy(cache_path, make_path.ptr, make_path.size + 1);
478
+
479
+ git_strmap_insert(opts->dir_map, cache_path, cache_path, error);
480
+ if (error < 0)
481
+ goto done;
482
+ }
444
483
  }
445
484
 
446
485
  error = 0;
@@ -448,7 +487,7 @@ int git_futils_mkdir_withperf(
448
487
  /* check that full path really is a directory if requested & needed */
449
488
  if ((flags & GIT_MKDIR_VERIFY_DIR) != 0 &&
450
489
  lastch != '\0') {
451
- perfdata->stat_calls++;
490
+ opts->perfdata.stat_calls++;
452
491
 
453
492
  if (p_stat(make_path.ptr, &st) < 0 || !S_ISDIR(st.st_mode)) {
454
493
  giterr_set(GITERR_OS, "Path is not a directory '%s'",
@@ -468,8 +507,8 @@ int git_futils_mkdir(
468
507
  mode_t mode,
469
508
  uint32_t flags)
470
509
  {
471
- struct git_futils_mkdir_perfdata perfdata = {0};
472
- return git_futils_mkdir_withperf(path, base, mode, flags, &perfdata);
510
+ struct git_futils_mkdir_options options = {0};
511
+ return git_futils_mkdir_ext(path, base, mode, flags, &options);
473
512
  }
474
513
 
475
514
  int git_futils_mkdir_r(const char *path, const char *base, const mode_t mode)
@@ -691,7 +730,11 @@ static int cp_link(const char *from, const char *to, size_t link_size)
691
730
  {
692
731
  int error = 0;
693
732
  ssize_t read_len;
694
- char *link_data = git__malloc(link_size + 1);
733
+ char *link_data;
734
+ size_t alloc_size;
735
+
736
+ GITERR_CHECK_ALLOC_ADD(&alloc_size, link_size, 1);
737
+ link_data = git__malloc(alloc_size);
695
738
  GITERR_CHECK_ALLOC(link_data);
696
739
 
697
740
  read_len = p_readlink(from, link_data, link_size);
@@ -11,6 +11,8 @@
11
11
  #include "map.h"
12
12
  #include "posix.h"
13
13
  #include "path.h"
14
+ #include "pool.h"
15
+ #include "strmap.h"
14
16
 
15
17
  /**
16
18
  * Filebuffer methods
@@ -95,6 +97,13 @@ struct git_futils_mkdir_perfdata
95
97
  size_t chmod_calls;
96
98
  };
97
99
 
100
+ struct git_futils_mkdir_options
101
+ {
102
+ git_strmap *dir_map;
103
+ git_pool *pool;
104
+ struct git_futils_mkdir_perfdata perfdata;
105
+ };
106
+
98
107
  /**
99
108
  * Create a directory or entire path.
100
109
  *
@@ -106,10 +115,10 @@ struct git_futils_mkdir_perfdata
106
115
  * @param base Root for relative path. These directories will never be made.
107
116
  * @param mode The mode to use for created directories.
108
117
  * @param flags Combination of the mkdir flags above.
109
- * @param perfdata Performance data, use `git_futils_mkdir` if you don't want this data.
118
+ * @param opts Extended options, use `git_futils_mkdir` if you are not interested.
110
119
  * @return 0 on success, else error code
111
120
  */
112
- extern int git_futils_mkdir_withperf(const char *path, const char *base, mode_t mode, uint32_t flags, struct git_futils_mkdir_perfdata *perfdata);
121
+ extern int git_futils_mkdir_ext(const char *path, const char *base, mode_t mode, uint32_t flags, struct git_futils_mkdir_options *opts);
113
122
 
114
123
  /**
115
124
  * Create a directory or entire path. Similar to `git_futils_mkdir_withperf`
@@ -23,7 +23,7 @@ struct git_filter_source {
23
23
  git_oid oid; /* zero if unknown (which is likely) */
24
24
  uint16_t filemode; /* zero if unknown */
25
25
  git_filter_mode_t mode;
26
- uint32_t options;
26
+ uint32_t flags;
27
27
  };
28
28
 
29
29
  typedef struct {
@@ -34,6 +34,7 @@ typedef struct {
34
34
  struct git_filter_list {
35
35
  git_array_t(git_filter_entry) filters;
36
36
  git_filter_source source;
37
+ git_buf *temp_buf;
37
38
  char path[GIT_FLEX_ARRAY];
38
39
  };
39
40
 
@@ -228,7 +229,7 @@ int git_filter_register(
228
229
  const char *name, git_filter *filter, int priority)
229
230
  {
230
231
  git_filter_def *fdef;
231
- size_t nattr = 0, nmatch = 0;
232
+ size_t nattr = 0, nmatch = 0, alloc_len;
232
233
  git_buf attrs = GIT_BUF_INIT;
233
234
 
234
235
  assert(name && filter);
@@ -245,8 +246,11 @@ int git_filter_register(
245
246
  if (filter_def_scan_attrs(&attrs, &nattr, &nmatch, filter->attributes) < 0)
246
247
  return -1;
247
248
 
248
- fdef = git__calloc(
249
- sizeof(git_filter_def) + 2 * nattr * sizeof(char *), 1);
249
+ GITERR_CHECK_ALLOC_MULTIPLY(&alloc_len, nattr, 2);
250
+ GITERR_CHECK_ALLOC_MULTIPLY(&alloc_len, alloc_len, sizeof(char *));
251
+ GITERR_CHECK_ALLOC_ADD(&alloc_len, alloc_len, sizeof(git_filter_def));
252
+
253
+ fdef = git__calloc(1, alloc_len);
250
254
  GITERR_CHECK_ALLOC(fdef);
251
255
 
252
256
  fdef->filter_name = git__strdup(name);
@@ -368,18 +372,21 @@ git_filter_mode_t git_filter_source_mode(const git_filter_source *src)
368
372
  return src->mode;
369
373
  }
370
374
 
371
- uint32_t git_filter_source_options(const git_filter_source *src)
375
+ uint32_t git_filter_source_flags(const git_filter_source *src)
372
376
  {
373
- return src->options;
377
+ return src->flags;
374
378
  }
375
379
 
376
380
  static int filter_list_new(
377
381
  git_filter_list **out, const git_filter_source *src)
378
382
  {
379
383
  git_filter_list *fl = NULL;
380
- size_t pathlen = src->path ? strlen(src->path) : 0;
384
+ size_t pathlen = src->path ? strlen(src->path) : 0, alloclen;
385
+
386
+ GITERR_CHECK_ALLOC_ADD(&alloclen, sizeof(git_filter_list), pathlen);
387
+ GITERR_CHECK_ALLOC_ADD(&alloclen, alloclen, 1);
381
388
 
382
- fl = git__calloc(1, sizeof(git_filter_list) + pathlen + 1);
389
+ fl = git__calloc(1, alloclen);
383
390
  GITERR_CHECK_ALLOC(fl);
384
391
 
385
392
  if (src->path)
@@ -387,22 +394,26 @@ static int filter_list_new(
387
394
  fl->source.repo = src->repo;
388
395
  fl->source.path = fl->path;
389
396
  fl->source.mode = src->mode;
390
- fl->source.options = src->options;
397
+ fl->source.flags = src->flags;
391
398
 
392
399
  *out = fl;
393
400
  return 0;
394
401
  }
395
402
 
396
403
  static int filter_list_check_attributes(
397
- const char ***out, git_filter_def *fdef, const git_filter_source *src)
404
+ const char ***out,
405
+ git_repository *repo,
406
+ git_attr_session *attr_session,
407
+ git_filter_def *fdef,
408
+ const git_filter_source *src)
398
409
  {
399
410
  int error;
400
411
  size_t i;
401
412
  const char **strs = git__calloc(fdef->nattrs, sizeof(const char *));
402
413
  GITERR_CHECK_ALLOC(strs);
403
414
 
404
- error = git_attr_get_many(
405
- strs, src->repo, 0, src->path, fdef->nattrs, fdef->attrs);
415
+ error = git_attr_get_many_with_session(
416
+ strs, repo, attr_session, 0, src->path, fdef->nattrs, fdef->attrs);
406
417
 
407
418
  /* if no values were found but no matches are needed, it's okay! */
408
419
  if (error == GIT_ENOTFOUND && !fdef->nmatches) {
@@ -438,23 +449,23 @@ int git_filter_list_new(
438
449
  git_filter_list **out,
439
450
  git_repository *repo,
440
451
  git_filter_mode_t mode,
441
- uint32_t options)
452
+ uint32_t flags)
442
453
  {
443
454
  git_filter_source src = { 0 };
444
455
  src.repo = repo;
445
456
  src.path = NULL;
446
457
  src.mode = mode;
447
- src.options = options;
458
+ src.flags = flags;
448
459
  return filter_list_new(out, &src);
449
460
  }
450
461
 
451
- int git_filter_list_load(
462
+ int git_filter_list__load_ext(
452
463
  git_filter_list **filters,
453
464
  git_repository *repo,
454
465
  git_blob *blob, /* can be NULL */
455
466
  const char *path,
456
467
  git_filter_mode_t mode,
457
- uint32_t options)
468
+ git_filter_options *filter_opts)
458
469
  {
459
470
  int error = 0;
460
471
  git_filter_list *fl = NULL;
@@ -469,7 +480,8 @@ int git_filter_list_load(
469
480
  src.repo = repo;
470
481
  src.path = path;
471
482
  src.mode = mode;
472
- src.options = options;
483
+ src.flags = filter_opts->flags;
484
+
473
485
  if (blob)
474
486
  git_oid_cpy(&src.oid, git_blob_id(blob));
475
487
 
@@ -481,7 +493,9 @@ int git_filter_list_load(
481
493
  continue;
482
494
 
483
495
  if (fdef->nattrs > 0) {
484
- error = filter_list_check_attributes(&values, fdef, &src);
496
+ error = filter_list_check_attributes(
497
+ &values, repo, filter_opts->attr_session, fdef, &src);
498
+
485
499
  if (error == GIT_ENOTFOUND) {
486
500
  error = 0;
487
501
  continue;
@@ -503,8 +517,12 @@ int git_filter_list_load(
503
517
  else if (error < 0)
504
518
  break;
505
519
  else {
506
- if (!fl && (error = filter_list_new(&fl, &src)) < 0)
507
- return error;
520
+ if (!fl) {
521
+ if ((error = filter_list_new(&fl, &src)) < 0)
522
+ return error;
523
+
524
+ fl->temp_buf = filter_opts->temp_buf;
525
+ }
508
526
 
509
527
  fe = git_array_alloc(fl->filters);
510
528
  GITERR_CHECK_ALLOC(fe);
@@ -523,6 +541,22 @@ int git_filter_list_load(
523
541
  return error;
524
542
  }
525
543
 
544
+ int git_filter_list_load(
545
+ git_filter_list **filters,
546
+ git_repository *repo,
547
+ git_blob *blob, /* can be NULL */
548
+ const char *path,
549
+ git_filter_mode_t mode,
550
+ uint32_t flags)
551
+ {
552
+ git_filter_options filter_opts = GIT_FILTER_OPTIONS_INIT;
553
+
554
+ filter_opts.flags = flags;
555
+
556
+ return git_filter_list__load_ext(
557
+ filters, repo, blob, path, mode, &filter_opts);
558
+ }
559
+
526
560
  void git_filter_list_free(git_filter_list *fl)
527
561
  {
528
562
  uint32_t i;
@@ -575,84 +609,72 @@ size_t git_filter_list_length(const git_filter_list *fl)
575
609
  return fl ? git_array_size(fl->filters) : 0;
576
610
  }
577
611
 
578
- static int filter_list_out_buffer_from_raw(
579
- git_buf *out, const void *ptr, size_t size)
612
+ struct buf_stream {
613
+ git_writestream parent;
614
+ git_buf *target;
615
+ bool complete;
616
+ };
617
+
618
+ static int buf_stream_write(
619
+ git_writestream *s, const char *buffer, size_t len)
580
620
  {
581
- if (git_buf_is_allocated(out))
582
- git_buf_free(out);
621
+ struct buf_stream *buf_stream = (struct buf_stream *)s;
622
+ assert(buf_stream);
583
623
 
584
- if (!size) {
585
- git_buf_init(out, 0);
586
- } else {
587
- out->ptr = (char *)ptr;
588
- out->asize = 0;
589
- out->size = size;
590
- }
624
+ assert(buf_stream->complete == 0);
591
625
 
592
- return 0;
626
+ return git_buf_put(buf_stream->target, buffer, len);
593
627
  }
594
628
 
595
- int git_filter_list_apply_to_data(
596
- git_buf *tgt, git_filter_list *fl, git_buf *src)
629
+ static int buf_stream_close(git_writestream *s)
597
630
  {
598
- int error = 0;
599
- uint32_t i;
600
- git_buf *dbuffer[2], local = GIT_BUF_INIT;
601
- unsigned int si = 0;
631
+ struct buf_stream *buf_stream = (struct buf_stream *)s;
632
+ assert(buf_stream);
602
633
 
603
- git_buf_sanitize(tgt);
604
- git_buf_sanitize(src);
634
+ assert(buf_stream->complete == 0);
635
+ buf_stream->complete = 1;
605
636
 
606
- if (!fl)
607
- return filter_list_out_buffer_from_raw(tgt, src->ptr, src->size);
637
+ return 0;
638
+ }
608
639
 
609
- dbuffer[0] = src;
610
- dbuffer[1] = tgt;
640
+ static void buf_stream_free(git_writestream *s)
641
+ {
642
+ GIT_UNUSED(s);
643
+ }
611
644
 
612
- /* if `src` buffer is reallocable, then use it, otherwise copy it */
613
- if (!git_buf_is_allocated(src)) {
614
- if (git_buf_set(&local, src->ptr, src->size) < 0)
615
- return -1;
616
- dbuffer[0] = &local;
617
- }
645
+ static void buf_stream_init(struct buf_stream *writer, git_buf *target)
646
+ {
647
+ memset(writer, 0, sizeof(struct buf_stream));
618
648
 
619
- for (i = 0; i < git_array_size(fl->filters); ++i) {
620
- unsigned int di = 1 - si;
621
- uint32_t fidx = (fl->source.mode == GIT_FILTER_TO_WORKTREE) ?
622
- i : git_array_size(fl->filters) - 1 - i;
623
- git_filter_entry *fe = git_array_get(fl->filters, fidx);
624
-
625
- dbuffer[di]->size = 0;
626
-
627
- /* Apply the filter from dbuffer[src] to the other buffer;
628
- * if the filtering is canceled by the user mid-filter,
629
- * we skip to the next filter without changing the source
630
- * of the double buffering (so that the text goes through
631
- * cleanly).
632
- */
649
+ writer->parent.write = buf_stream_write;
650
+ writer->parent.close = buf_stream_close;
651
+ writer->parent.free = buf_stream_free;
652
+ writer->target = target;
633
653
 
634
- error = fe->filter->apply(
635
- fe->filter, &fe->payload, dbuffer[di], dbuffer[si], &fl->source);
654
+ git_buf_clear(target);
655
+ }
636
656
 
637
- if (error == GIT_PASSTHROUGH) {
638
- /* PASSTHROUGH means filter decided not to process the buffer */
639
- error = 0;
640
- } else if (!error) {
641
- git_buf_sanitize(dbuffer[di]); /* force NUL termination */
642
- si = di; /* swap buffers */
643
- } else {
644
- tgt->size = 0;
645
- goto cleanup;
646
- }
657
+ int git_filter_list_apply_to_data(
658
+ git_buf *tgt, git_filter_list *filters, git_buf *src)
659
+ {
660
+ struct buf_stream writer;
661
+ int error;
662
+
663
+ git_buf_sanitize(tgt);
664
+ git_buf_sanitize(src);
665
+
666
+ if (!filters) {
667
+ git_buf_attach_notowned(tgt, src->ptr, src->size);
668
+ return 0;
647
669
  }
648
670
 
649
- /* Ensure that the output ends up in dbuffer[1] (i.e. the dest) */
650
- if (si != 1)
651
- git_buf_swap(dbuffer[0], dbuffer[1]);
671
+ buf_stream_init(&writer, tgt);
652
672
 
653
- cleanup:
654
- git_buf_free(&local); /* don't leak if we allocated locally */
673
+ if ((error = git_filter_list_stream_data(filters, src,
674
+ (git_writestream *)&writer)) < 0)
675
+ return error;
655
676
 
677
+ assert(writer.complete);
656
678
  return error;
657
679
  }
658
680
 
@@ -662,28 +684,21 @@ int git_filter_list_apply_to_file(
662
684
  git_repository *repo,
663
685
  const char *path)
664
686
  {
687
+ struct buf_stream writer;
665
688
  int error;
666
- const char *base = repo ? git_repository_workdir(repo) : NULL;
667
- git_buf abspath = GIT_BUF_INIT, raw = GIT_BUF_INIT;
668
689
 
669
- if (!(error = git_path_join_unrooted(&abspath, path, base, NULL)) &&
670
- !(error = git_futils_readbuffer(&raw, abspath.ptr)))
671
- {
672
- error = git_filter_list_apply_to_data(out, filters, &raw);
690
+ buf_stream_init(&writer, out);
673
691
 
674
- git_buf_free(&raw);
675
- }
692
+ if ((error = git_filter_list_stream_file(
693
+ filters, repo, path, (git_writestream *)&writer)) < 0)
694
+ return error;
676
695
 
677
- git_buf_free(&abspath);
696
+ assert(writer.complete);
678
697
  return error;
679
698
  }
680
699
 
681
- int git_filter_list_apply_to_blob(
682
- git_buf *out,
683
- git_filter_list *filters,
684
- git_blob *blob)
700
+ static int buf_from_blob(git_buf *out, git_blob *blob)
685
701
  {
686
- git_buf in = GIT_BUF_INIT;
687
702
  git_off_t rawsize = git_blob_rawsize(blob);
688
703
 
689
704
  if (!git__is_sizet(rawsize)) {
@@ -691,12 +706,249 @@ int git_filter_list_apply_to_blob(
691
706
  return -1;
692
707
  }
693
708
 
694
- in.ptr = (char *)git_blob_rawcontent(blob);
695
- in.asize = 0;
696
- in.size = (size_t)rawsize;
709
+ git_buf_attach_notowned(out, git_blob_rawcontent(blob), (size_t)rawsize);
710
+ return 0;
711
+ }
712
+
713
+ int git_filter_list_apply_to_blob(
714
+ git_buf *out,
715
+ git_filter_list *filters,
716
+ git_blob *blob)
717
+ {
718
+ struct buf_stream writer;
719
+ int error;
720
+
721
+ buf_stream_init(&writer, out);
722
+
723
+ if ((error = git_filter_list_stream_blob(
724
+ filters, blob, (git_writestream *)&writer)) < 0)
725
+ return error;
726
+
727
+ assert(writer.complete);
728
+ return error;
729
+ }
730
+
731
+ struct proxy_stream {
732
+ git_writestream parent;
733
+ git_filter *filter;
734
+ const git_filter_source *source;
735
+ void **payload;
736
+ git_buf input;
737
+ git_buf temp_buf;
738
+ git_buf *output;
739
+ git_writestream *target;
740
+ };
741
+
742
+ static int proxy_stream_write(
743
+ git_writestream *s, const char *buffer, size_t len)
744
+ {
745
+ struct proxy_stream *proxy_stream = (struct proxy_stream *)s;
746
+ assert(proxy_stream);
747
+
748
+ return git_buf_put(&proxy_stream->input, buffer, len);
749
+ }
750
+
751
+ static int proxy_stream_close(git_writestream *s)
752
+ {
753
+ struct proxy_stream *proxy_stream = (struct proxy_stream *)s;
754
+ git_buf *writebuf;
755
+ int error;
756
+
757
+ assert(proxy_stream);
758
+
759
+ error = proxy_stream->filter->apply(
760
+ proxy_stream->filter,
761
+ proxy_stream->payload,
762
+ proxy_stream->output,
763
+ &proxy_stream->input,
764
+ proxy_stream->source);
765
+
766
+ if (error == GIT_PASSTHROUGH) {
767
+ writebuf = &proxy_stream->input;
768
+ } else if (error == 0) {
769
+ git_buf_sanitize(proxy_stream->output);
770
+ writebuf = proxy_stream->output;
771
+ } else {
772
+ return error;
773
+ }
774
+
775
+ if ((error = proxy_stream->target->write(
776
+ proxy_stream->target, writebuf->ptr, writebuf->size)) == 0)
777
+ error = proxy_stream->target->close(proxy_stream->target);
778
+
779
+ return error;
780
+ }
781
+
782
+ static void proxy_stream_free(git_writestream *s)
783
+ {
784
+ struct proxy_stream *proxy_stream = (struct proxy_stream *)s;
785
+ assert(proxy_stream);
786
+
787
+ git_buf_free(&proxy_stream->input);
788
+ git_buf_free(&proxy_stream->temp_buf);
789
+ git__free(proxy_stream);
790
+ }
791
+
792
+ static int proxy_stream_init(
793
+ git_writestream **out,
794
+ git_filter *filter,
795
+ git_buf *temp_buf,
796
+ void **payload,
797
+ const git_filter_source *source,
798
+ git_writestream *target)
799
+ {
800
+ struct proxy_stream *proxy_stream = git__calloc(1, sizeof(struct proxy_stream));
801
+ GITERR_CHECK_ALLOC(proxy_stream);
802
+
803
+ proxy_stream->parent.write = proxy_stream_write;
804
+ proxy_stream->parent.close = proxy_stream_close;
805
+ proxy_stream->parent.free = proxy_stream_free;
806
+ proxy_stream->filter = filter;
807
+ proxy_stream->payload = payload;
808
+ proxy_stream->source = source;
809
+ proxy_stream->target = target;
810
+ proxy_stream->output = temp_buf ? temp_buf : &proxy_stream->temp_buf;
811
+
812
+ *out = (git_writestream *)proxy_stream;
813
+ return 0;
814
+ }
815
+
816
+ static int stream_list_init(
817
+ git_writestream **out,
818
+ git_vector *streams,
819
+ git_filter_list *filters,
820
+ git_writestream *target)
821
+ {
822
+ git_writestream *last_stream = target;
823
+ size_t i;
824
+ int error = 0;
825
+
826
+ *out = NULL;
827
+
828
+ if (!filters) {
829
+ *out = target;
830
+ return 0;
831
+ }
832
+
833
+ /* Create filters last to first to get the chaining direction */
834
+ for (i = 0; i < git_array_size(filters->filters); ++i) {
835
+ size_t filter_idx = (filters->source.mode == GIT_FILTER_TO_WORKTREE) ?
836
+ git_array_size(filters->filters) - 1 - i : i;
837
+ git_filter_entry *fe = git_array_get(filters->filters, filter_idx);
838
+ git_writestream *filter_stream;
839
+
840
+ assert(fe->filter->stream || fe->filter->apply);
841
+
842
+ /* If necessary, create a stream that proxies the traditional
843
+ * application.
844
+ */
845
+ if (fe->filter->stream)
846
+ error = fe->filter->stream(&filter_stream, fe->filter,
847
+ &fe->payload, &filters->source, last_stream);
848
+ else
849
+ /* Create a stream that proxies the one-shot apply */
850
+ error = proxy_stream_init(&filter_stream, fe->filter,
851
+ filters->temp_buf, &fe->payload, &filters->source,
852
+ last_stream);
853
+
854
+ if (error < 0)
855
+ return error;
856
+
857
+ git_vector_insert(streams, filter_stream);
858
+ last_stream = filter_stream;
859
+ }
860
+
861
+ *out = last_stream;
862
+ return 0;
863
+ }
864
+
865
+ void stream_list_free(git_vector *streams)
866
+ {
867
+ git_writestream *stream;
868
+ size_t i;
869
+
870
+ git_vector_foreach(streams, i, stream)
871
+ stream->free(stream);
872
+ git_vector_free(streams);
873
+ }
874
+
875
+ #define STREAM_BUFSIZE 10240
876
+
877
+ int git_filter_list_stream_file(
878
+ git_filter_list *filters,
879
+ git_repository *repo,
880
+ const char *path,
881
+ git_writestream *target)
882
+ {
883
+ char buf[STREAM_BUFSIZE];
884
+ git_buf abspath = GIT_BUF_INIT;
885
+ const char *base = repo ? git_repository_workdir(repo) : NULL;
886
+ git_vector filter_streams = GIT_VECTOR_INIT;
887
+ git_writestream *stream_start;
888
+ ssize_t readlen;
889
+ int fd, error;
890
+
891
+ if ((error = stream_list_init(
892
+ &stream_start, &filter_streams, filters, target)) < 0 ||
893
+ (error = git_path_join_unrooted(&abspath, path, base, NULL)) < 0)
894
+ goto done;
895
+
896
+ if ((fd = git_futils_open_ro(abspath.ptr)) < 0) {
897
+ error = fd;
898
+ goto done;
899
+ }
900
+
901
+ while ((readlen = p_read(fd, buf, STREAM_BUFSIZE)) > 0) {
902
+ if ((error = stream_start->write(stream_start, buf, readlen)) < 0)
903
+ goto done;
904
+ }
905
+
906
+ if (!readlen)
907
+ error = stream_start->close(stream_start);
908
+ else if (readlen < 0)
909
+ error = readlen;
910
+
911
+ p_close(fd);
912
+
913
+ done:
914
+ stream_list_free(&filter_streams);
915
+ git_buf_free(&abspath);
916
+ return error;
917
+ }
918
+
919
+ int git_filter_list_stream_data(
920
+ git_filter_list *filters,
921
+ git_buf *data,
922
+ git_writestream *target)
923
+ {
924
+ git_vector filter_streams = GIT_VECTOR_INIT;
925
+ git_writestream *stream_start;
926
+ int error = 0;
927
+
928
+ git_buf_sanitize(data);
929
+
930
+ if ((error = stream_list_init(
931
+ &stream_start, &filter_streams, filters, target)) == 0 &&
932
+ (error =
933
+ stream_start->write(stream_start, data->ptr, data->size)) == 0)
934
+ error = stream_start->close(stream_start);
935
+
936
+ stream_list_free(&filter_streams);
937
+ return error;
938
+ }
939
+
940
+ int git_filter_list_stream_blob(
941
+ git_filter_list *filters,
942
+ git_blob *blob,
943
+ git_writestream *target)
944
+ {
945
+ git_buf in = GIT_BUF_INIT;
946
+
947
+ if (buf_from_blob(&in, blob) < 0)
948
+ return -1;
697
949
 
698
950
  if (filters)
699
951
  git_oid_cpy(&filters->source.oid, git_blob_id(blob));
700
952
 
701
- return git_filter_list_apply_to_data(out, filters, &in);
953
+ return git_filter_list_stream_data(filters, &in, target);
702
954
  }