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
@@ -150,6 +150,15 @@ static int checkout_notify(
150
150
  }
151
151
  }
152
152
 
153
+ GIT_INLINE(bool) is_workdir_base_or_new(
154
+ const git_oid *workdir_id,
155
+ const git_diff_file *baseitem,
156
+ const git_diff_file *newitem)
157
+ {
158
+ return (git_oid__cmp(&baseitem->id, workdir_id) == 0 ||
159
+ git_oid__cmp(&newitem->id, workdir_id) == 0);
160
+ }
161
+
153
162
  static bool checkout_is_workdir_modified(
154
163
  checkout_data *data,
155
164
  const git_diff_file *baseitem,
@@ -171,7 +180,7 @@ static bool checkout_is_workdir_modified(
171
180
  return true;
172
181
  }
173
182
 
174
- if (git_submodule_status(&sm_status, sm) < 0 ||
183
+ if (git_submodule_status(&sm_status, data->repo, wditem->path, GIT_SUBMODULE_IGNORE_UNSPECIFIED) < 0 ||
175
184
  GIT_SUBMODULE_STATUS_IS_WD_DIRTY(sm_status))
176
185
  rval = true;
177
186
  else if ((sm_oid = git_submodule_wd_id(sm)) == NULL)
@@ -193,8 +202,7 @@ static bool checkout_is_workdir_modified(
193
202
  if (wditem->mtime.seconds == ie->mtime.seconds &&
194
203
  wditem->mtime.nanoseconds == ie->mtime.nanoseconds &&
195
204
  wditem->file_size == ie->file_size)
196
- return (git_oid__cmp(&baseitem->id, &ie->id) != 0 &&
197
- git_oid_cmp(&newitem->id, &ie->id) != 0);
205
+ return !is_workdir_base_or_new(&ie->id, baseitem, newitem);
198
206
  }
199
207
 
200
208
  /* depending on where base is coming from, we may or may not know
@@ -203,10 +211,13 @@ static bool checkout_is_workdir_modified(
203
211
  if (baseitem->size && wditem->file_size != baseitem->size)
204
212
  return true;
205
213
 
206
- if (git_diff__oid_for_entry(&oid, data->diff, wditem, NULL) < 0)
214
+ if (git_diff__oid_for_entry(&oid, data->diff, wditem, wditem->mode, NULL) < 0)
207
215
  return false;
208
216
 
209
- return (git_oid__cmp(&baseitem->id, &oid) != 0);
217
+ /* Allow the checkout if the workdir is not modified *or* if the checkout
218
+ * target's contents are already in the working directory.
219
+ */
220
+ return !is_workdir_base_or_new(&oid, baseitem, newitem);
210
221
  }
211
222
 
212
223
  #define CHECKOUT_ACTION_IF(FLAG,YES,NO) \
@@ -1292,7 +1303,7 @@ static int checkout_get_actions(
1292
1303
  (int)counts[CHECKOUT_ACTION__CONFLICT],
1293
1304
  counts[CHECKOUT_ACTION__CONFLICT] == 1 ?
1294
1305
  "conflict prevents" : "conflicts prevent");
1295
- error = GIT_EMERGECONFLICT;
1306
+ error = GIT_ECONFLICT;
1296
1307
  goto fail;
1297
1308
  }
1298
1309
 
@@ -1849,11 +1860,6 @@ static int checkout_create_submodules(
1849
1860
  git_diff_delta *delta;
1850
1861
  size_t i;
1851
1862
 
1852
- /* initial reload of submodules if .gitmodules was changed */
1853
- if (data->reload_submodules &&
1854
- (error = git_submodule_reload_all(data->repo, 1)) < 0)
1855
- return error;
1856
-
1857
1863
  git_vector_foreach(&data->diff->deltas, i, delta) {
1858
1864
  if (actions[i] & CHECKOUT_ACTION__DEFER_REMOVE) {
1859
1865
  /* this has a blocker directory that should only be removed iff
@@ -1874,8 +1880,7 @@ static int checkout_create_submodules(
1874
1880
  }
1875
1881
  }
1876
1882
 
1877
- /* final reload once submodules have been updated */
1878
- return git_submodule_reload_all(data->repo, 1);
1883
+ return 0;
1879
1884
  }
1880
1885
 
1881
1886
  static int checkout_lookup_head_tree(git_tree **out, git_repository *repo)
@@ -2062,7 +2067,7 @@ static int checkout_write_merge(
2062
2067
 
2063
2068
  if (result.path == NULL || result.mode == 0) {
2064
2069
  giterr_set(GITERR_CHECKOUT, "Could not merge contents of file");
2065
- error = GIT_EMERGECONFLICT;
2070
+ error = GIT_ECONFLICT;
2066
2071
  goto done;
2067
2072
  }
2068
2073
 
@@ -2357,7 +2362,7 @@ static int checkout_data_init(
2357
2362
  /* cannot checkout if unresolved conflicts exist */
2358
2363
  if ((data->opts.checkout_strategy & GIT_CHECKOUT_FORCE) == 0 &&
2359
2364
  git_index_has_conflicts(data->index)) {
2360
- error = GIT_EMERGECONFLICT;
2365
+ error = GIT_ECONFLICT;
2361
2366
  giterr_set(GITERR_CHECKOUT,
2362
2367
  "unresolved conflicts exist in the index");
2363
2368
  goto cleanup;
@@ -2397,7 +2402,7 @@ static int checkout_data_init(
2397
2402
  &data->can_symlink, repo, GIT_CVAR_SYMLINKS)) < 0)
2398
2403
  goto cleanup;
2399
2404
 
2400
- if (!data->opts.baseline) {
2405
+ if (!data->opts.baseline && !data->opts.baseline_index) {
2401
2406
  data->opts_free_baseline = true;
2402
2407
 
2403
2408
  error = checkout_lookup_head_tree(&data->opts.baseline, repo);
@@ -2501,12 +2506,21 @@ int git_checkout_iterator(
2501
2506
  (error = git_iterator_for_workdir_ext(
2502
2507
  &workdir, data.repo, data.opts.target_directory, index, NULL,
2503
2508
  iterflags | GIT_ITERATOR_DONT_AUTOEXPAND,
2504
- data.pfx, data.pfx)) < 0 ||
2505
- (error = git_iterator_for_tree(
2506
- &baseline, data.opts.baseline,
2507
- iterflags, data.pfx, data.pfx)) < 0)
2509
+ data.pfx, data.pfx)) < 0)
2508
2510
  goto cleanup;
2509
2511
 
2512
+ if (data.opts.baseline_index) {
2513
+ if ((error = git_iterator_for_index(
2514
+ &baseline, data.opts.baseline_index,
2515
+ iterflags, data.pfx, data.pfx)) < 0)
2516
+ goto cleanup;
2517
+ } else {
2518
+ if ((error = git_iterator_for_tree(
2519
+ &baseline, data.opts.baseline,
2520
+ iterflags, data.pfx, data.pfx)) < 0)
2521
+ goto cleanup;
2522
+ }
2523
+
2510
2524
  /* Should not have case insensitivity mismatch */
2511
2525
  assert(git_iterator_ignore_case(workdir) == git_iterator_ignore_case(baseline));
2512
2526
 
@@ -24,7 +24,7 @@
24
24
  #include "repository.h"
25
25
  #include "odb.h"
26
26
 
27
- static int clone_local_into(git_repository *repo, git_remote *remote, const git_checkout_options *co_opts, const char *branch, int link);
27
+ static int clone_local_into(git_repository *repo, git_remote *remote, const git_fetch_options *fetch_opts, const git_checkout_options *co_opts, const char *branch, int link);
28
28
 
29
29
  static int create_branch(
30
30
  git_reference **branch,
@@ -242,13 +242,9 @@ static int default_remote_create(
242
242
  const char *url,
243
243
  void *payload)
244
244
  {
245
- int error;
246
- git_remote_callbacks *callbacks = payload;
247
-
248
- if ((error = git_remote_create(out, repo, name, url)) < 0)
249
- return error;
245
+ GIT_UNUSED(payload);
250
246
 
251
- return git_remote_set_callbacks(*out, callbacks);
247
+ return git_remote_create(out, repo, name, url);
252
248
  }
253
249
 
254
250
  /*
@@ -277,15 +273,12 @@ static int create_and_configure_origin(
277
273
 
278
274
  if (!remote_create) {
279
275
  remote_create = default_remote_create;
280
- payload = (void *)&options->remote_callbacks;
276
+ payload = NULL;
281
277
  }
282
278
 
283
279
  if ((error = remote_create(&origin, repo, "origin", url, payload)) < 0)
284
280
  goto on_error;
285
281
 
286
- if ((error = git_remote_save(origin)) < 0)
287
- goto on_error;
288
-
289
282
  *out = origin;
290
283
  return 0;
291
284
 
@@ -328,12 +321,12 @@ static int checkout_branch(git_repository *repo, git_remote *remote, const git_c
328
321
  return error;
329
322
  }
330
323
 
331
- static int clone_into(git_repository *repo, git_remote *_remote, const git_checkout_options *co_opts, const char *branch)
324
+ static int clone_into(git_repository *repo, git_remote *_remote, const git_fetch_options *opts, const git_checkout_options *co_opts, const char *branch)
332
325
  {
333
326
  int error;
334
327
  git_buf reflog_message = GIT_BUF_INIT;
328
+ git_fetch_options fetch_opts;
335
329
  git_remote *remote;
336
- const git_remote_callbacks *callbacks;
337
330
 
338
331
  assert(repo && _remote);
339
332
 
@@ -345,18 +338,12 @@ static int clone_into(git_repository *repo, git_remote *_remote, const git_check
345
338
  if ((error = git_remote_dup(&remote, _remote)) < 0)
346
339
  return error;
347
340
 
348
- callbacks = git_remote_get_callbacks(_remote);
349
- if (!giterr__check_version(callbacks, 1, "git_remote_callbacks") &&
350
- (error = git_remote_set_callbacks(remote, callbacks)) < 0)
351
- goto cleanup;
352
-
353
- if ((error = git_remote_add_fetch(remote, "refs/tags/*:refs/tags/*")) < 0)
354
- goto cleanup;
355
-
356
- git_remote_set_update_fetchhead(remote, 0);
341
+ memcpy(&fetch_opts, opts, sizeof(git_fetch_options));
342
+ fetch_opts.update_fetchhead = 0;
343
+ fetch_opts.download_tags = GIT_REMOTE_DOWNLOAD_TAGS_ALL;
357
344
  git_buf_printf(&reflog_message, "clone: from %s", git_remote_url(remote));
358
345
 
359
- if ((error = git_remote_fetch(remote, NULL, git_buf_cstr(&reflog_message))) != 0)
346
+ if ((error = git_remote_fetch(remote, NULL, &fetch_opts, git_buf_cstr(&reflog_message))) != 0)
360
347
  goto cleanup;
361
348
 
362
349
  error = checkout_branch(repo, remote, co_opts, branch, git_buf_cstr(&reflog_message));
@@ -439,11 +426,11 @@ int git_clone(
439
426
 
440
427
  if (clone_local == 1)
441
428
  error = clone_local_into(
442
- repo, origin, &options.checkout_opts,
429
+ repo, origin, &options.fetch_opts, &options.checkout_opts,
443
430
  options.checkout_branch, link);
444
431
  else if (clone_local == 0)
445
432
  error = clone_into(
446
- repo, origin, &options.checkout_opts,
433
+ repo, origin, &options.fetch_opts, &options.checkout_opts,
447
434
  options.checkout_branch);
448
435
  else
449
436
  error = -1;
@@ -506,7 +493,7 @@ static bool can_link(const char *src, const char *dst, int link)
506
493
  #endif
507
494
  }
508
495
 
509
- static int clone_local_into(git_repository *repo, git_remote *remote, const git_checkout_options *co_opts, const char *branch, int link)
496
+ static int clone_local_into(git_repository *repo, git_remote *remote, const git_fetch_options *fetch_opts, const git_checkout_options *co_opts, const char *branch, int link)
510
497
  {
511
498
  int error, flags;
512
499
  git_repository *src;
@@ -545,13 +532,26 @@ static int clone_local_into(git_repository *repo, git_remote *remote, const git_
545
532
  if (can_link(git_repository_path(src), git_repository_path(repo), link))
546
533
  flags |= GIT_CPDIR_LINK_FILES;
547
534
 
548
- if ((error = git_futils_cp_r(git_buf_cstr(&src_odb), git_buf_cstr(&dst_odb),
549
- flags, GIT_OBJECT_DIR_MODE)) < 0)
535
+ error = git_futils_cp_r(git_buf_cstr(&src_odb), git_buf_cstr(&dst_odb),
536
+ flags, GIT_OBJECT_DIR_MODE);
537
+
538
+ /*
539
+ * can_link() doesn't catch all variations, so if we hit an
540
+ * error and did want to link, let's try again without trying
541
+ * to link.
542
+ */
543
+ if (error < 0 && link) {
544
+ flags &= ~GIT_CPDIR_LINK_FILES;
545
+ error = git_futils_cp_r(git_buf_cstr(&src_odb), git_buf_cstr(&dst_odb),
546
+ flags, GIT_OBJECT_DIR_MODE);
547
+ }
548
+
549
+ if (error < 0)
550
550
  goto cleanup;
551
551
 
552
552
  git_buf_printf(&reflog_message, "clone: from %s", git_remote_url(remote));
553
553
 
554
- if ((error = git_remote_fetch(remote, NULL, git_buf_cstr(&reflog_message))) != 0)
554
+ if ((error = git_remote_fetch(remote, NULL, fetch_opts, git_buf_cstr(&reflog_message))) != 0)
555
555
  goto cleanup;
556
556
 
557
557
  error = checkout_branch(repo, remote, co_opts, branch, git_buf_cstr(&reflog_message));
@@ -309,6 +309,7 @@ int git_commit__parse(void *_commit, git_odb_object *odb_obj)
309
309
  const char *buffer_end = buffer_start + git_odb_object_size(odb_obj);
310
310
  git_oid parent_id;
311
311
  size_t header_len;
312
+ git_signature dummy_sig;
312
313
 
313
314
  buffer = buffer_start;
314
315
 
@@ -337,6 +338,15 @@ int git_commit__parse(void *_commit, git_odb_object *odb_obj)
337
338
  if (git_signature__parse(commit->author, &buffer, buffer_end, "author ", '\n') < 0)
338
339
  return -1;
339
340
 
341
+ /* Some tools create multiple author fields, ignore the extra ones */
342
+ while ((size_t)(buffer_end - buffer) >= strlen("author ") && !git__prefixcmp(buffer, "author ")) {
343
+ if (git_signature__parse(&dummy_sig, &buffer, buffer_end, "author ", '\n') < 0)
344
+ return -1;
345
+
346
+ git__free(dummy_sig.name);
347
+ git__free(dummy_sig.email);
348
+ }
349
+
340
350
  /* Always parse the committer; we need the commit time */
341
351
  commit->committer = git__malloc(sizeof(git_signature));
342
352
  GITERR_CHECK_ALLOC(commit->committer);
@@ -508,3 +518,58 @@ int git_commit_nth_gen_ancestor(
508
518
  *ancestor = parent;
509
519
  return 0;
510
520
  }
521
+
522
+ int git_commit_header_field(git_buf *out, const git_commit *commit, const char *field)
523
+ {
524
+ const char *buf = commit->raw_header;
525
+ const char *h, *eol;
526
+
527
+ git_buf_sanitize(out);
528
+ while ((h = strchr(buf, '\n')) && h[1] != '\0' && h[1] != '\n') {
529
+ h++;
530
+ if (git__prefixcmp(h, field)) {
531
+ buf = h;
532
+ continue;
533
+ }
534
+
535
+ h += strlen(field);
536
+ eol = strchr(h, '\n');
537
+ if (h[0] != ' ') {
538
+ buf = h;
539
+ continue;
540
+ }
541
+ if (!eol)
542
+ goto malformed;
543
+
544
+ h++; /* skip the SP */
545
+
546
+ git_buf_put(out, h, eol - h);
547
+ if (git_buf_oom(out))
548
+ goto oom;
549
+
550
+ /* If the next line starts with SP, it's multi-line, we must continue */
551
+ while (eol[1] == ' ') {
552
+ git_buf_putc(out, '\n');
553
+ h = eol + 2;
554
+ eol = strchr(h, '\n');
555
+ if (!eol)
556
+ goto malformed;
557
+
558
+ git_buf_put(out, h, eol - h);
559
+ }
560
+
561
+ if (git_buf_oom(out))
562
+ goto oom;
563
+
564
+ return 0;
565
+ }
566
+
567
+ return GIT_ENOTFOUND;
568
+
569
+ malformed:
570
+ giterr_set(GITERR_OBJECT, "malformed header");
571
+ return -1;
572
+ oom:
573
+ giterr_set_oom();
574
+ return -1;
575
+ }
@@ -68,6 +68,11 @@
68
68
 
69
69
  #include <regex.h>
70
70
 
71
+ #define DEFAULT_BUFSIZE 65536
72
+ #define FILEIO_BUFSIZE DEFAULT_BUFSIZE
73
+ #define FILTERIO_BUFSIZE DEFAULT_BUFSIZE
74
+ #define NETIO_BUFSIZE DEFAULT_BUFSIZE
75
+
71
76
  /**
72
77
  * Check a pointer allocation result, returning -1 if it failed.
73
78
  */
@@ -1194,6 +1194,26 @@ fail_parse:
1194
1194
  return -1;
1195
1195
  }
1196
1196
 
1197
+ int git_config_lookup_map_enum(git_cvar_t *type_out, const char **str_out,
1198
+ const git_cvar_map *maps, size_t map_n, int enum_val)
1199
+ {
1200
+ size_t i;
1201
+
1202
+ for (i = 0; i < map_n; i++) {
1203
+ const git_cvar_map *m = &maps[i];
1204
+
1205
+ if (m->map_value != enum_val)
1206
+ continue;
1207
+
1208
+ *type_out = m->cvar_type;
1209
+ *str_out = m->str_match;
1210
+ return 0;
1211
+ }
1212
+
1213
+ giterr_set(GITERR_CONFIG, "invalid enum value");
1214
+ return GIT_ENOTFOUND;
1215
+ }
1216
+
1197
1217
  int git_config_parse_bool(int *out, const char *value)
1198
1218
  {
1199
1219
  if (git__parse_bool(out, value) == 0)
@@ -82,4 +82,10 @@ extern int git_config__get_int_force(
82
82
  extern int git_config__cvar(
83
83
  int *out, git_config *config, git_cvar_cached cvar);
84
84
 
85
+ /**
86
+ * The opposite of git_config_lookup_map_value, we take an enum value
87
+ * and map it to the string or bool value on the config.
88
+ */
89
+ int git_config_lookup_map_enum(git_cvar_t *type_out, const char **str_out,
90
+ const git_cvar_map *maps, size_t map_n, int enum_val);
85
91
  #endif
@@ -156,7 +156,7 @@ int git_config_file_normalize_section(char *start, char *end)
156
156
  if (end && scan >= end)
157
157
  break;
158
158
  if (isalnum(*scan))
159
- *scan = (char)tolower(*scan);
159
+ *scan = (char)git__tolower(*scan);
160
160
  else if (*scan != '-' || scan == start)
161
161
  return GIT_EINVALIDSPEC;
162
162
  }
@@ -1083,7 +1083,7 @@ static int parse_section_header(struct reader *reader, char **section_out)
1083
1083
  goto fail_parse;
1084
1084
  }
1085
1085
 
1086
- name[name_length++] = (char) tolower(c);
1086
+ name[name_length++] = (char)git__tolower(c);
1087
1087
 
1088
1088
  } while ((c = line[pos++]) != ']');
1089
1089
 
@@ -193,28 +193,29 @@ static const char *line_ending(struct crlf_attrs *ca)
193
193
  case GIT_CRLF_CRLF:
194
194
  return "\r\n";
195
195
 
196
+ case GIT_CRLF_GUESS:
197
+ if (ca->auto_crlf == GIT_AUTO_CRLF_FALSE)
198
+ return "\n";
199
+ break;
200
+
196
201
  case GIT_CRLF_AUTO:
197
202
  case GIT_CRLF_TEXT:
198
- case GIT_CRLF_GUESS:
199
203
  break;
200
204
 
201
205
  default:
202
206
  goto line_ending_error;
203
207
  }
204
208
 
205
- switch (ca->eol) {
206
- case GIT_EOL_UNSET:
207
- return GIT_EOL_NATIVE == GIT_EOL_CRLF ? "\r\n" : "\n";
208
-
209
- case GIT_EOL_CRLF:
209
+ if (ca->auto_crlf == GIT_AUTO_CRLF_TRUE)
210
210
  return "\r\n";
211
-
212
- case GIT_EOL_LF:
211
+ else if (ca->auto_crlf == GIT_AUTO_CRLF_INPUT)
213
212
  return "\n";
214
-
215
- default:
216
- goto line_ending_error;
217
- }
213
+ else if (ca->eol == GIT_EOL_UNSET)
214
+ return GIT_EOL_NATIVE == GIT_EOL_CRLF ? "\r\n" : "\n";
215
+ else if (ca->eol == GIT_EOL_LF)
216
+ return "\n";
217
+ else if (ca->eol == GIT_EOL_CRLF)
218
+ return "\r\n";
218
219
 
219
220
  line_ending_error:
220
221
  giterr_set(GITERR_INVALID, "Invalid input to line ending filter");
@@ -224,16 +225,14 @@ line_ending_error:
224
225
  static int crlf_apply_to_workdir(
225
226
  struct crlf_attrs *ca, git_buf *to, const git_buf *from)
226
227
  {
228
+ git_buf_text_stats stats;
227
229
  const char *workdir_ending = NULL;
230
+ bool is_binary;
228
231
 
229
232
  /* Empty file? Nothing to do. */
230
233
  if (git_buf_len(from) == 0)
231
234
  return 0;
232
235
 
233
- /* Don't filter binary files */
234
- if (git_buf_text_is_binary(from))
235
- return GIT_PASSTHROUGH;
236
-
237
236
  /* Determine proper line ending */
238
237
  workdir_ending = line_ending(ca);
239
238
  if (!workdir_ending)
@@ -243,6 +242,29 @@ static int crlf_apply_to_workdir(
243
242
  if (strcmp(workdir_ending, "\r\n") != 0)
244
243
  return GIT_PASSTHROUGH;
245
244
 
245
+ /* If there are no LFs, or all LFs are part of a CRLF, nothing to do */
246
+ is_binary = git_buf_text_gather_stats(&stats, from, false);
247
+
248
+ if (stats.lf == 0 || stats.lf == stats.crlf)
249
+ return GIT_PASSTHROUGH;
250
+
251
+ if (ca->crlf_action == GIT_CRLF_AUTO ||
252
+ ca->crlf_action == GIT_CRLF_GUESS) {
253
+
254
+ /* If we have any existing CR or CRLF line endings, do nothing */
255
+ if (ca->crlf_action == GIT_CRLF_GUESS &&
256
+ stats.cr > 0 && stats.crlf > 0)
257
+ return GIT_PASSTHROUGH;
258
+
259
+ /* If we have bare CR characters, do nothing */
260
+ if (stats.cr != stats.crlf)
261
+ return GIT_PASSTHROUGH;
262
+
263
+ /* Don't filter binary files */
264
+ if (is_binary)
265
+ return GIT_PASSTHROUGH;
266
+ }
267
+
246
268
  return git_buf_text_lf_to_crlf(to, from);
247
269
  }
248
270
 
@@ -278,7 +300,7 @@ static int crlf_check(
278
300
  return GIT_PASSTHROUGH;
279
301
 
280
302
  if (ca.crlf_action == GIT_CRLF_GUESS ||
281
- (ca.crlf_action == GIT_CRLF_AUTO &&
303
+ ((ca.crlf_action == GIT_CRLF_AUTO || ca.crlf_action == GIT_CRLF_TEXT) &&
282
304
  git_filter_source_mode(src) == GIT_FILTER_SMUDGE)) {
283
305
 
284
306
  error = git_repository__cvar(