rugged 0.18.0.gh.de28323 → 0.19.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (283) hide show
  1. data/README.md +9 -4
  2. data/Rakefile +1 -1
  3. data/ext/rugged/extconf.rb +10 -0
  4. data/ext/rugged/rugged.c +153 -86
  5. data/ext/rugged/rugged.h +44 -33
  6. data/ext/rugged/rugged_blob.c +288 -60
  7. data/ext/rugged/rugged_branch.c +82 -57
  8. data/ext/rugged/rugged_commit.c +83 -86
  9. data/ext/rugged/rugged_config.c +68 -68
  10. data/ext/rugged/rugged_diff.c +509 -0
  11. data/ext/rugged/rugged_diff_delta.c +94 -0
  12. data/ext/rugged/rugged_diff_hunk.c +100 -0
  13. data/ext/rugged/rugged_diff_line.c +79 -0
  14. data/ext/rugged/rugged_diff_patch.c +169 -0
  15. data/ext/rugged/rugged_index.c +539 -8
  16. data/ext/rugged/rugged_note.c +74 -80
  17. data/ext/rugged/rugged_object.c +63 -8
  18. data/ext/rugged/rugged_reference.c +231 -145
  19. data/ext/rugged/rugged_remote.c +509 -53
  20. data/ext/rugged/rugged_repo.c +572 -236
  21. data/ext/rugged/rugged_revwalk.c +59 -36
  22. data/ext/rugged/rugged_settings.c +7 -9
  23. data/ext/rugged/rugged_signature.c +7 -11
  24. data/ext/rugged/rugged_tag.c +93 -39
  25. data/ext/rugged/rugged_tree.c +321 -58
  26. data/lib/rugged.rb +1 -0
  27. data/lib/rugged/commit.rb +16 -1
  28. data/lib/rugged/console.rb +9 -0
  29. data/lib/rugged/diff.rb +19 -0
  30. data/lib/rugged/diff/delta.rb +54 -0
  31. data/lib/rugged/diff/hunk.rb +23 -0
  32. data/lib/rugged/diff/line.rb +29 -0
  33. data/lib/rugged/diff/patch.rb +28 -0
  34. data/lib/rugged/repository.rb +36 -39
  35. data/lib/rugged/version.rb +1 -1
  36. data/test/blob_test.rb +308 -1
  37. data/test/branch_test.rb +7 -0
  38. data/test/commit_test.rb +7 -10
  39. data/test/coverage/cover.rb +9 -1
  40. data/test/diff_test.rb +777 -0
  41. data/test/fixtures/archive.tar.gz +0 -0
  42. data/test/fixtures/attr/attr0 +1 -0
  43. data/test/fixtures/attr/attr1 +29 -0
  44. data/test/fixtures/attr/attr2 +21 -0
  45. data/test/fixtures/attr/attr3 +4 -0
  46. data/test/fixtures/attr/binfile +1 -0
  47. data/test/fixtures/attr/dir/file +0 -0
  48. data/test/fixtures/attr/file +1 -0
  49. data/test/fixtures/attr/gitattributes +29 -0
  50. data/test/fixtures/attr/gitignore +2 -0
  51. data/test/fixtures/attr/ign +1 -0
  52. data/test/fixtures/attr/macro_bad +1 -0
  53. data/test/fixtures/attr/macro_test +1 -0
  54. data/test/fixtures/attr/root_test1 +1 -0
  55. data/test/fixtures/attr/root_test2 +6 -0
  56. data/test/fixtures/attr/root_test3 +19 -0
  57. data/test/fixtures/attr/root_test4.txt +14 -0
  58. data/test/fixtures/attr/sub/abc +37 -0
  59. data/test/fixtures/attr/sub/dir/file +0 -0
  60. data/test/fixtures/attr/sub/file +1 -0
  61. data/test/fixtures/attr/sub/ign/file +1 -0
  62. data/test/fixtures/attr/sub/ign/sub/file +1 -0
  63. data/test/fixtures/attr/sub/sub/dir +0 -0
  64. data/test/fixtures/attr/sub/sub/file +1 -0
  65. data/test/fixtures/attr/sub/sub/subsub.txt +1 -0
  66. data/test/fixtures/attr/sub/subdir_test1 +2 -0
  67. data/test/fixtures/attr/sub/subdir_test2.txt +1 -0
  68. data/test/fixtures/diff/another.txt +38 -0
  69. data/test/fixtures/diff/readme.txt +36 -0
  70. data/test/fixtures/mergedrepo/conflicts-one.txt +5 -0
  71. data/test/fixtures/mergedrepo/conflicts-two.txt +5 -0
  72. data/test/fixtures/mergedrepo/one.txt +10 -0
  73. data/test/fixtures/mergedrepo/two.txt +12 -0
  74. data/test/fixtures/status/current_file +1 -0
  75. data/test/fixtures/status/ignored_file +1 -0
  76. data/test/fixtures/status/modified_file +2 -0
  77. data/test/fixtures/status/new_file +1 -0
  78. data/test/fixtures/status/staged_changes +2 -0
  79. data/test/fixtures/status/staged_changes_modified_file +3 -0
  80. data/test/fixtures/status/staged_delete_modified_file +1 -0
  81. data/test/fixtures/status/staged_new_file +1 -0
  82. data/test/fixtures/status/staged_new_file_modified_file +2 -0
  83. data/test/fixtures/status/subdir.txt +2 -0
  84. data/test/fixtures/status/subdir/current_file +1 -0
  85. data/test/fixtures/status/subdir/modified_file +2 -0
  86. data/test/fixtures/status/subdir/new_file +1 -0
  87. data/test/fixtures/status//350/277/231 +1 -0
  88. data/test/fixtures/testrepo.git/config +5 -0
  89. data/test/fixtures/testrepo.git/objects/77/71329dfa3002caf8c61a0ceb62a31d09023f37 +0 -0
  90. data/test/fixtures/text_file.md +464 -0
  91. data/test/fixtures/unsymlinked.git/HEAD +1 -0
  92. data/test/fixtures/unsymlinked.git/config +6 -0
  93. data/test/fixtures/unsymlinked.git/description +1 -0
  94. data/test/fixtures/unsymlinked.git/info/exclude +2 -0
  95. data/test/fixtures/unsymlinked.git/objects/08/8b64704e0d6b8bd061dea879418cb5442a3fbf +0 -0
  96. data/test/fixtures/unsymlinked.git/objects/13/a5e939bca25940c069fd2169d993dba328e30b +0 -0
  97. data/test/fixtures/unsymlinked.git/objects/19/bf568e59e3a0b363cafb4106226e62d4a4c41c +0 -0
  98. data/test/fixtures/unsymlinked.git/objects/58/1fadd35b4cf320d102a152f918729011604773 +0 -0
  99. data/test/fixtures/unsymlinked.git/objects/5c/87b6791e8b13da658a14d1ef7e09b5dc3bac8c +0 -0
  100. data/test/fixtures/unsymlinked.git/objects/6f/e5f5398af85fb3de8a6aba0339b6d3bfa26a27 +0 -0
  101. data/test/fixtures/unsymlinked.git/objects/7f/ccd75616ec188b8f1b23d67506a334cc34a49d +0 -0
  102. data/test/fixtures/unsymlinked.git/objects/80/6999882bf91d24241e4077906b9017605eb1f3 +0 -0
  103. data/test/fixtures/unsymlinked.git/objects/83/7d176303c5005505ec1e4a30231c40930c0230 +0 -0
  104. data/test/fixtures/unsymlinked.git/objects/a8/595ccca04f40818ae0155c8f9c77a230e597b6 +2 -0
  105. data/test/fixtures/unsymlinked.git/objects/cf/8f1cf5cce859c438d6cc067284cb5e161206e7 +0 -0
  106. data/test/fixtures/unsymlinked.git/objects/d5/278d05c8607ec420bfee4cf219fbc0eeebfd6a +0 -0
  107. data/test/fixtures/unsymlinked.git/objects/f4/e16fb76536591a41454194058d048d8e4dd2e9 +0 -0
  108. data/test/fixtures/unsymlinked.git/objects/f9/e65619d93fdf2673882e0a261c5e93b1a84006 +0 -0
  109. data/test/fixtures/unsymlinked.git/refs/heads/exe-file +1 -0
  110. data/test/fixtures/unsymlinked.git/refs/heads/master +1 -0
  111. data/test/fixtures/unsymlinked.git/refs/heads/reg-file +1 -0
  112. data/test/index_test.rb +120 -0
  113. data/test/reference_test.rb +38 -3
  114. data/test/remote_test.rb +224 -3
  115. data/test/repo_reset_test.rb +2 -0
  116. data/test/repo_test.rb +147 -10
  117. data/test/test_helper.rb +5 -2
  118. data/vendor/libgit2/include/git2/attr.h +3 -3
  119. data/vendor/libgit2/include/git2/blob.h +11 -17
  120. data/vendor/libgit2/include/git2/branch.h +3 -2
  121. data/vendor/libgit2/include/git2/checkout.h +7 -0
  122. data/vendor/libgit2/include/git2/clone.h +3 -0
  123. data/vendor/libgit2/include/git2/commit.h +61 -66
  124. data/vendor/libgit2/include/git2/common.h +73 -42
  125. data/vendor/libgit2/include/git2/config.h +57 -71
  126. data/vendor/libgit2/include/git2/cred_helpers.h +2 -2
  127. data/vendor/libgit2/include/git2/diff.h +179 -30
  128. data/vendor/libgit2/include/git2/errors.h +3 -3
  129. data/vendor/libgit2/include/git2/index.h +225 -146
  130. data/vendor/libgit2/include/git2/indexer.h +2 -22
  131. data/vendor/libgit2/include/git2/inttypes.h +9 -9
  132. data/vendor/libgit2/include/git2/merge.h +123 -5
  133. data/vendor/libgit2/include/git2/odb.h +59 -38
  134. data/vendor/libgit2/include/git2/odb_backend.h +45 -104
  135. data/vendor/libgit2/include/git2/oid.h +30 -19
  136. data/vendor/libgit2/include/git2/pack.h +21 -3
  137. data/vendor/libgit2/include/git2/refdb.h +0 -35
  138. data/vendor/libgit2/include/git2/refs.h +93 -31
  139. data/vendor/libgit2/include/git2/refspec.h +17 -0
  140. data/vendor/libgit2/include/git2/remote.h +60 -20
  141. data/vendor/libgit2/include/git2/repository.h +48 -70
  142. data/vendor/libgit2/include/git2/reset.h +3 -3
  143. data/vendor/libgit2/include/git2/revparse.h +22 -0
  144. data/vendor/libgit2/include/git2/stash.h +1 -1
  145. data/vendor/libgit2/include/git2/status.h +131 -56
  146. data/vendor/libgit2/include/git2/strarray.h +2 -2
  147. data/vendor/libgit2/include/git2/submodule.h +16 -16
  148. data/vendor/libgit2/include/git2/sys/commit.h +46 -0
  149. data/vendor/libgit2/include/git2/sys/config.h +71 -0
  150. data/vendor/libgit2/include/git2/sys/index.h +179 -0
  151. data/vendor/libgit2/include/git2/sys/odb_backend.h +86 -0
  152. data/vendor/libgit2/include/git2/sys/refdb_backend.h +158 -0
  153. data/vendor/libgit2/include/git2/sys/refs.h +38 -0
  154. data/vendor/libgit2/include/git2/sys/repository.h +106 -0
  155. data/vendor/libgit2/include/git2/tag.h +44 -18
  156. data/vendor/libgit2/include/git2/trace.h +1 -2
  157. data/vendor/libgit2/include/git2/transport.h +74 -0
  158. data/vendor/libgit2/include/git2/tree.h +12 -22
  159. data/vendor/libgit2/include/git2/types.h +33 -0
  160. data/vendor/libgit2/include/git2/version.h +2 -2
  161. data/vendor/libgit2/src/array.h +66 -0
  162. data/vendor/libgit2/src/attr.c +26 -13
  163. data/vendor/libgit2/src/attr_file.c +3 -2
  164. data/vendor/libgit2/src/attr_file.h +3 -3
  165. data/vendor/libgit2/src/attrcache.h +4 -4
  166. data/vendor/libgit2/src/blob.c +13 -9
  167. data/vendor/libgit2/src/blob.h +2 -2
  168. data/vendor/libgit2/src/branch.c +67 -49
  169. data/vendor/libgit2/src/cache.c +224 -54
  170. data/vendor/libgit2/src/cache.h +33 -20
  171. data/vendor/libgit2/src/checkout.c +145 -85
  172. data/vendor/libgit2/src/clone.c +62 -50
  173. data/vendor/libgit2/src/commit.c +74 -40
  174. data/vendor/libgit2/src/commit.h +2 -3
  175. data/vendor/libgit2/src/commit_list.c +14 -8
  176. data/vendor/libgit2/src/config.c +119 -36
  177. data/vendor/libgit2/src/config.h +3 -0
  178. data/vendor/libgit2/src/config_cache.c +24 -7
  179. data/vendor/libgit2/src/config_file.c +9 -6
  180. data/vendor/libgit2/src/crlf.c +4 -2
  181. data/vendor/libgit2/src/date.c +3 -3
  182. data/vendor/libgit2/src/delta.c +1 -1
  183. data/vendor/libgit2/src/diff.c +681 -303
  184. data/vendor/libgit2/src/diff.h +34 -2
  185. data/vendor/libgit2/src/diff_driver.c +405 -0
  186. data/vendor/libgit2/src/diff_driver.h +49 -0
  187. data/vendor/libgit2/src/diff_file.c +447 -0
  188. data/vendor/libgit2/src/diff_file.h +58 -0
  189. data/vendor/libgit2/src/diff_patch.c +995 -0
  190. data/vendor/libgit2/src/diff_patch.h +46 -0
  191. data/vendor/libgit2/src/diff_print.c +430 -0
  192. data/vendor/libgit2/src/diff_tform.c +464 -203
  193. data/vendor/libgit2/src/diff_xdiff.c +166 -0
  194. data/vendor/libgit2/src/diff_xdiff.h +28 -0
  195. data/vendor/libgit2/src/fetch.c +11 -4
  196. data/vendor/libgit2/src/fileops.c +85 -61
  197. data/vendor/libgit2/src/fileops.h +4 -0
  198. data/vendor/libgit2/src/global.c +10 -2
  199. data/vendor/libgit2/src/global.h +0 -8
  200. data/vendor/libgit2/src/hash/hash_generic.h +3 -3
  201. data/vendor/libgit2/src/hash/hash_win32.h +4 -4
  202. data/vendor/libgit2/src/hashsig.c +0 -1
  203. data/vendor/libgit2/src/ignore.c +68 -28
  204. data/vendor/libgit2/src/ignore.h +10 -1
  205. data/vendor/libgit2/src/index.c +666 -84
  206. data/vendor/libgit2/src/index.h +6 -0
  207. data/vendor/libgit2/src/indexer.c +10 -28
  208. data/vendor/libgit2/src/iterator.c +427 -283
  209. data/vendor/libgit2/src/iterator.h +58 -4
  210. data/vendor/libgit2/src/merge.c +1892 -32
  211. data/vendor/libgit2/src/merge.h +132 -5
  212. data/vendor/libgit2/src/merge_file.c +174 -0
  213. data/vendor/libgit2/src/merge_file.h +71 -0
  214. data/vendor/libgit2/src/mwindow.c +1 -1
  215. data/vendor/libgit2/src/notes.c +45 -48
  216. data/vendor/libgit2/src/object.c +89 -127
  217. data/vendor/libgit2/src/object.h +0 -1
  218. data/vendor/libgit2/src/object_api.c +129 -0
  219. data/vendor/libgit2/src/odb.c +156 -59
  220. data/vendor/libgit2/src/odb.h +5 -2
  221. data/vendor/libgit2/src/odb_loose.c +31 -17
  222. data/vendor/libgit2/src/odb_pack.c +39 -43
  223. data/vendor/libgit2/src/oid.c +62 -27
  224. data/vendor/libgit2/src/oid.h +33 -0
  225. data/vendor/libgit2/src/oidmap.h +4 -6
  226. data/vendor/libgit2/src/pack-objects.c +54 -22
  227. data/vendor/libgit2/src/pack.c +98 -56
  228. data/vendor/libgit2/src/pack.h +3 -1
  229. data/vendor/libgit2/src/pathspec.c +26 -1
  230. data/vendor/libgit2/src/pathspec.h +14 -0
  231. data/vendor/libgit2/src/pool.c +5 -0
  232. data/vendor/libgit2/src/posix.c +2 -2
  233. data/vendor/libgit2/src/posix.h +3 -0
  234. data/vendor/libgit2/src/push.c +13 -10
  235. data/vendor/libgit2/src/refdb.c +82 -62
  236. data/vendor/libgit2/src/refdb.h +16 -16
  237. data/vendor/libgit2/src/refdb_fs.c +386 -133
  238. data/vendor/libgit2/src/reflog.c +3 -1
  239. data/vendor/libgit2/src/refs.c +247 -221
  240. data/vendor/libgit2/src/refs.h +2 -1
  241. data/vendor/libgit2/src/refspec.c +18 -1
  242. data/vendor/libgit2/src/refspec.h +3 -1
  243. data/vendor/libgit2/src/remote.c +434 -253
  244. data/vendor/libgit2/src/remote.h +5 -3
  245. data/vendor/libgit2/src/repository.c +197 -111
  246. data/vendor/libgit2/src/repository.h +26 -5
  247. data/vendor/libgit2/src/reset.c +1 -1
  248. data/vendor/libgit2/src/revparse.c +84 -79
  249. data/vendor/libgit2/src/revwalk.c +1 -1
  250. data/vendor/libgit2/src/signature.c +22 -10
  251. data/vendor/libgit2/src/stash.c +5 -2
  252. data/vendor/libgit2/src/status.c +311 -107
  253. data/vendor/libgit2/src/status.h +23 -0
  254. data/vendor/libgit2/src/submodule.c +21 -13
  255. data/vendor/libgit2/src/tag.c +42 -31
  256. data/vendor/libgit2/src/tag.h +2 -3
  257. data/vendor/libgit2/src/thread-utils.h +105 -3
  258. data/vendor/libgit2/src/trace.c +1 -2
  259. data/vendor/libgit2/src/trace.h +3 -3
  260. data/vendor/libgit2/src/transport.c +18 -6
  261. data/vendor/libgit2/src/transports/cred.c +103 -1
  262. data/vendor/libgit2/src/transports/local.c +19 -9
  263. data/vendor/libgit2/src/transports/smart_protocol.c +32 -12
  264. data/vendor/libgit2/src/transports/ssh.c +519 -0
  265. data/vendor/libgit2/src/transports/winhttp.c +3 -1
  266. data/vendor/libgit2/src/tree.c +26 -28
  267. data/vendor/libgit2/src/tree.h +3 -3
  268. data/vendor/libgit2/src/unix/posix.h +2 -0
  269. data/vendor/libgit2/src/util.c +43 -6
  270. data/vendor/libgit2/src/util.h +40 -12
  271. data/vendor/libgit2/src/vector.c +3 -5
  272. data/vendor/libgit2/src/vector.h +9 -0
  273. data/vendor/libgit2/src/win32/dir.c +1 -1
  274. data/vendor/libgit2/src/win32/error.c +2 -0
  275. data/vendor/libgit2/src/win32/findfile.c +3 -6
  276. data/vendor/libgit2/src/win32/posix_w32.c +85 -59
  277. data/vendor/libgit2/src/win32/pthread.c +16 -8
  278. data/vendor/libgit2/src/win32/pthread.h +7 -4
  279. metadata +407 -306
  280. data/test/coverage/HEAD.json +0 -1
  281. data/vendor/libgit2/include/git2/refdb_backend.h +0 -109
  282. data/vendor/libgit2/src/diff_output.c +0 -1819
  283. data/vendor/libgit2/src/diff_output.h +0 -93
@@ -22,6 +22,9 @@ extern int git_futils_readbuffer_updated(
22
22
  git_buf *obj, const char *path, time_t *mtime, size_t *size, int *updated);
23
23
  extern int git_futils_readbuffer_fd(git_buf *obj, git_file fd, size_t len);
24
24
 
25
+ extern int git_futils_writebuffer(
26
+ const git_buf *buf, const char *path, int open_flags, mode_t mode);
27
+
25
28
  /**
26
29
  * File utils
27
30
  *
@@ -223,6 +226,7 @@ extern git_off_t git_futils_filesize(git_file fd);
223
226
  #define GIT_MODE_PERMS_MASK 0777
224
227
  #define GIT_CANONICAL_PERMS(MODE) (((MODE) & 0100) ? 0755 : 0644)
225
228
  #define GIT_MODE_TYPE(MODE) ((MODE) & ~GIT_MODE_PERMS_MASK)
229
+ #define GIT_MODE_ISBLOB(MODE) (GIT_MODE_TYPE(MODE) == GIT_MODE_TYPE(GIT_FILEMODE_BLOB))
226
230
 
227
231
  /**
228
232
  * Convert a mode_t from the OS to a legal git mode_t value.
@@ -61,7 +61,8 @@ int git_threads_init(void)
61
61
  return 0;
62
62
 
63
63
  _tls_index = TlsAlloc();
64
- git_mutex_init(&git__mwindow_mutex);
64
+ if (git_mutex_init(&git__mwindow_mutex))
65
+ return -1;
65
66
 
66
67
  /* Initialize any other subsystems that have global state */
67
68
  if ((error = git_hash_global_init()) >= 0)
@@ -121,7 +122,8 @@ int git_threads_init(void)
121
122
  if (_tls_init)
122
123
  return 0;
123
124
 
124
- git_mutex_init(&git__mwindow_mutex);
125
+ if (git_mutex_init(&git__mwindow_mutex))
126
+ return -1;
125
127
  pthread_key_create(&_tls_key, &cb__free_status);
126
128
 
127
129
  /* Initialize any other subsystems that have global state */
@@ -135,6 +137,12 @@ int git_threads_init(void)
135
137
 
136
138
  void git_threads_shutdown(void)
137
139
  {
140
+ if (_tls_init) {
141
+ void *ptr = pthread_getspecific(_tls_key);
142
+ pthread_setspecific(_tls_key, NULL);
143
+ git__free(ptr);
144
+ }
145
+
138
146
  pthread_key_delete(_tls_key);
139
147
  _tls_init = 0;
140
148
  git_mutex_free(&git__mwindow_mutex);
@@ -10,14 +10,6 @@
10
10
  #include "mwindow.h"
11
11
  #include "hash.h"
12
12
 
13
- #if defined(GIT_THREADS) && defined(_MSC_VER)
14
- # define GIT_MEMORY_BARRIER MemoryBarrier()
15
- #elif defined(GIT_THREADS)
16
- # define GIT_MEMORY_BARRIER __sync_synchronize()
17
- #else
18
- # define GIT_MEMORY_BARRIER /* noop */
19
- #endif
20
-
21
13
  typedef struct {
22
14
  git_error *last_error;
23
15
  git_error error_t;
@@ -11,9 +11,9 @@
11
11
  #include "hash.h"
12
12
 
13
13
  struct git_hash_ctx {
14
- unsigned long long size;
15
- unsigned int H[5];
16
- unsigned int W[16];
14
+ unsigned long long size;
15
+ unsigned int H[5];
16
+ unsigned int W[16];
17
17
  };
18
18
 
19
19
  #define git_hash_global_init() 0
@@ -48,10 +48,10 @@ struct hash_cryptoapi_prov {
48
48
 
49
49
  /* Function declarations for CNG */
50
50
  typedef NTSTATUS (WINAPI *hash_win32_cng_open_algorithm_provider_fn)(
51
- HANDLE /* BCRYPT_ALG_HANDLE */ *phAlgorithm,
52
- LPCWSTR pszAlgId,
53
- LPCWSTR pszImplementation,
54
- DWORD dwFlags);
51
+ HANDLE /* BCRYPT_ALG_HANDLE */ *phAlgorithm,
52
+ LPCWSTR pszAlgId,
53
+ LPCWSTR pszImplementation,
54
+ DWORD dwFlags);
55
55
 
56
56
  typedef NTSTATUS (WINAPI *hash_win32_cng_get_property_fn)(
57
57
  HANDLE /* BCRYPT_HANDLE */ hObject,
@@ -365,4 +365,3 @@ int git_hashsig_compare(const git_hashsig *a, const git_hashsig *b)
365
365
  return (hashsig_heap_compare(&a->mins, &b->mins) +
366
366
  hashsig_heap_compare(&a->maxs, &b->maxs)) / 2;
367
367
  }
368
-
@@ -15,24 +15,14 @@ static int parse_ignore_file(
15
15
  git_attr_fnmatch *match = NULL;
16
16
  const char *scan = NULL;
17
17
  char *context = NULL;
18
- bool ignore_case = false;
19
- git_config *cfg = NULL;
20
- int val;
21
-
22
- /* Prefer to have the caller pass in a git_ignores as the parsedata object.
23
- * If they did not, then we can (much more slowly) find the value of
24
- * ignore_case by using the repository object. */
25
- if (parsedata != NULL) {
26
- ignore_case = ((git_ignores *)parsedata)->ignore_case;
27
- } else {
28
- if ((error = git_repository_config(&cfg, repo)) < 0)
29
- return error;
30
-
31
- if (git_config_get_bool(&val, cfg, "core.ignorecase") == 0)
32
- ignore_case = (val != 0);
18
+ int ignore_case = false;
33
19
 
34
- git_config_free(cfg);
35
- }
20
+ /* Prefer to have the caller pass in a git_ignores as the parsedata
21
+ * object. If they did not, then look up the value of ignore_case */
22
+ if (parsedata != NULL)
23
+ ignore_case = ((git_ignores *)parsedata)->ignore_case;
24
+ else if (git_repository__cvar(&ignore_case, repo, GIT_CVAR_IGNORECASE) < 0)
25
+ return error;
36
26
 
37
27
  if (ignores->key && git__suffixcmp(ignores->key, "/" GIT_IGNORE_FILE) == 0) {
38
28
  context = ignores->key + 2;
@@ -109,8 +99,6 @@ int git_ignore__for_path(
109
99
  {
110
100
  int error = 0;
111
101
  const char *workdir = git_repository_workdir(repo);
112
- git_config *cfg = NULL;
113
- int val;
114
102
 
115
103
  assert(ignores);
116
104
 
@@ -118,17 +106,11 @@ int git_ignore__for_path(
118
106
  git_buf_init(&ignores->dir, 0);
119
107
  ignores->ign_internal = NULL;
120
108
 
121
- /* Set the ignore_case flag appropriately */
122
- if ((error = git_repository_config(&cfg, repo)) < 0)
109
+ /* Read the ignore_case flag */
110
+ if ((error = git_repository__cvar(
111
+ &ignores->ignore_case, repo, GIT_CVAR_IGNORECASE)) < 0)
123
112
  goto cleanup;
124
113
 
125
- if (git_config_get_bool(&val, cfg, "core.ignorecase") == 0)
126
- ignores->ignore_case = (val != 0);
127
- else
128
- ignores->ignore_case = 0;
129
-
130
- git_config_free(cfg);
131
-
132
114
  if ((error = git_vector_init(&ignores->ign_path, 8, NULL)) < 0 ||
133
115
  (error = git_vector_init(&ignores->ign_global, 2, NULL)) < 0 ||
134
116
  (error = git_attr_cache__init(repo)) < 0)
@@ -358,3 +340,61 @@ cleanup:
358
340
  return error;
359
341
  }
360
342
 
343
+
344
+ int git_ignore__check_pathspec_for_exact_ignores(
345
+ git_repository *repo,
346
+ git_vector *vspec,
347
+ bool no_fnmatch)
348
+ {
349
+ int error = 0;
350
+ size_t i;
351
+ git_attr_fnmatch *match;
352
+ int ignored;
353
+ git_buf path = GIT_BUF_INIT;
354
+ const char *wd, *filename;
355
+ git_index *idx;
356
+
357
+ if ((error = git_repository__ensure_not_bare(
358
+ repo, "validate pathspec")) < 0 ||
359
+ (error = git_repository_index(&idx, repo)) < 0)
360
+ return error;
361
+
362
+ wd = git_repository_workdir(repo);
363
+
364
+ git_vector_foreach(vspec, i, match) {
365
+ /* skip wildcard matches (if they are being used) */
366
+ if ((match->flags & GIT_ATTR_FNMATCH_HASWILD) != 0 &&
367
+ !no_fnmatch)
368
+ continue;
369
+
370
+ filename = match->pattern;
371
+
372
+ /* if file is already in the index, it's fine */
373
+ if (git_index_get_bypath(idx, filename, 0) != NULL)
374
+ continue;
375
+
376
+ if ((error = git_buf_joinpath(&path, wd, filename)) < 0)
377
+ break;
378
+
379
+ /* is there a file on disk that matches this exactly? */
380
+ if (!git_path_isfile(path.ptr))
381
+ continue;
382
+
383
+ /* is that file ignored? */
384
+ if ((error = git_ignore_path_is_ignored(&ignored, repo, filename)) < 0)
385
+ break;
386
+
387
+ if (ignored) {
388
+ giterr_set(GITERR_INVALID, "pathspec contains ignored file '%s'",
389
+ filename);
390
+ error = GIT_EINVALIDSPEC;
391
+ break;
392
+ }
393
+ }
394
+
395
+ git_index_free(idx);
396
+ git_buf_free(&path);
397
+
398
+ return error;
399
+ }
400
+
@@ -28,7 +28,7 @@ typedef struct {
28
28
  git_attr_file *ign_internal;
29
29
  git_vector ign_path;
30
30
  git_vector ign_global;
31
- unsigned int ignore_case:1;
31
+ int ignore_case;
32
32
  } git_ignores;
33
33
 
34
34
  extern int git_ignore__for_path(git_repository *repo, const char *path, git_ignores *ign);
@@ -41,4 +41,13 @@ extern void git_ignore__free(git_ignores *ign);
41
41
 
42
42
  extern int git_ignore__lookup(git_ignores *ign, const char *path, int *ignored);
43
43
 
44
+ /* command line Git sometimes generates an error message if given a
45
+ * pathspec that contains an exact match to an ignored file (provided
46
+ * --force isn't also given). This makes it easy to check it that has
47
+ * happened. Returns GIT_EINVALIDSPEC if the pathspec contains ignored
48
+ * exact matches (that are not already present in the index).
49
+ */
50
+ extern int git_ignore__check_pathspec_for_exact_ignores(
51
+ git_repository *repo, git_vector *pathspec, bool no_fnmatch);
52
+
44
53
  #endif
@@ -15,10 +15,13 @@
15
15
  #include "hash.h"
16
16
  #include "iterator.h"
17
17
  #include "pathspec.h"
18
+ #include "ignore.h"
19
+
18
20
  #include "git2/odb.h"
19
21
  #include "git2/oid.h"
20
22
  #include "git2/blob.h"
21
23
  #include "git2/config.h"
24
+ #include "git2/sys/index.h"
22
25
 
23
26
  #define entry_size(type,len) ((offsetof(type, path) + (len) + 8) & ~7)
24
27
  #define short_entry_size(len) entry_size(struct entry_short, len)
@@ -35,6 +38,7 @@ static const unsigned int INDEX_VERSION_NUMBER_EXT = 3;
35
38
  static const unsigned int INDEX_HEADER_SIG = 0x44495243;
36
39
  static const char INDEX_EXT_TREECACHE_SIG[] = {'T', 'R', 'E', 'E'};
37
40
  static const char INDEX_EXT_UNMERGED_SIG[] = {'R', 'E', 'U', 'C'};
41
+ static const char INDEX_EXT_CONFLICT_NAME_SIG[] = {'N', 'A', 'M', 'E'};
38
42
 
39
43
  #define INDEX_OWNER(idx) ((git_repository *)(GIT_REFCOUNT_OWNER(idx)))
40
44
 
@@ -102,11 +106,6 @@ static int index_find(size_t *at_pos, git_index *index, const char *path, int st
102
106
  static void index_entry_free(git_index_entry *entry);
103
107
  static void index_entry_reuc_free(git_index_reuc_entry *reuc);
104
108
 
105
- GIT_INLINE(int) index_entry_stage(const git_index_entry *entry)
106
- {
107
- return (entry->flags & GIT_IDXENTRY_STAGEMASK) >> GIT_IDXENTRY_STAGESHIFT;
108
- }
109
-
110
109
  static int index_srch(const void *key, const void *array_member)
111
110
  {
112
111
  const struct entry_srch_key *srch_key = key;
@@ -116,7 +115,7 @@ static int index_srch(const void *key, const void *array_member)
116
115
  ret = strcmp(srch_key->path, entry->path);
117
116
 
118
117
  if (ret == 0)
119
- ret = srch_key->stage - index_entry_stage(entry);
118
+ ret = srch_key->stage - GIT_IDXENTRY_STAGE(entry);
120
119
 
121
120
  return ret;
122
121
  }
@@ -130,7 +129,7 @@ static int index_isrch(const void *key, const void *array_member)
130
129
  ret = strcasecmp(srch_key->path, entry->path);
131
130
 
132
131
  if (ret == 0)
133
- ret = srch_key->stage - index_entry_stage(entry);
132
+ ret = srch_key->stage - GIT_IDXENTRY_STAGE(entry);
134
133
 
135
134
  return ret;
136
135
  }
@@ -168,7 +167,7 @@ static int index_cmp(const void *a, const void *b)
168
167
  diff = strcmp(entry_a->path, entry_b->path);
169
168
 
170
169
  if (diff == 0)
171
- diff = (index_entry_stage(entry_a) - index_entry_stage(entry_b));
170
+ diff = (GIT_IDXENTRY_STAGE(entry_a) - GIT_IDXENTRY_STAGE(entry_b));
172
171
 
173
172
  return diff;
174
173
  }
@@ -182,11 +181,56 @@ static int index_icmp(const void *a, const void *b)
182
181
  diff = strcasecmp(entry_a->path, entry_b->path);
183
182
 
184
183
  if (diff == 0)
185
- diff = (index_entry_stage(entry_a) - index_entry_stage(entry_b));
184
+ diff = (GIT_IDXENTRY_STAGE(entry_a) - GIT_IDXENTRY_STAGE(entry_b));
186
185
 
187
186
  return diff;
188
187
  }
189
188
 
189
+ static int conflict_name_cmp(const void *a, const void *b)
190
+ {
191
+ const git_index_name_entry *name_a = a;
192
+ const git_index_name_entry *name_b = b;
193
+
194
+ if (name_a->ancestor && !name_b->ancestor)
195
+ return 1;
196
+
197
+ if (!name_a->ancestor && name_b->ancestor)
198
+ return -1;
199
+
200
+ if (name_a->ancestor)
201
+ return strcmp(name_a->ancestor, name_b->ancestor);
202
+
203
+ if (!name_a->ours || !name_b->ours)
204
+ return 0;
205
+
206
+ return strcmp(name_a->ours, name_b->ours);
207
+ }
208
+
209
+ /**
210
+ * TODO: enable this when resolving case insensitive conflicts
211
+ */
212
+ #if 0
213
+ static int conflict_name_icmp(const void *a, const void *b)
214
+ {
215
+ const git_index_name_entry *name_a = a;
216
+ const git_index_name_entry *name_b = b;
217
+
218
+ if (name_a->ancestor && !name_b->ancestor)
219
+ return 1;
220
+
221
+ if (!name_a->ancestor && name_b->ancestor)
222
+ return -1;
223
+
224
+ if (name_a->ancestor)
225
+ return strcasecmp(name_a->ancestor, name_b->ancestor);
226
+
227
+ if (!name_a->ours || !name_b->ours)
228
+ return 0;
229
+
230
+ return strcasecmp(name_a->ours, name_b->ours);
231
+ }
232
+ #endif
233
+
190
234
  static int reuc_srch(const void *key, const void *array_member)
191
235
  {
192
236
  const git_index_reuc_entry *reuc = array_member;
@@ -246,16 +290,16 @@ void git_index__set_ignore_case(git_index *index, bool ignore_case)
246
290
  {
247
291
  index->ignore_case = ignore_case;
248
292
 
249
- index->entries._cmp = ignore_case ? index_icmp : index_cmp;
250
293
  index->entries_cmp_path = ignore_case ? index_icmp_path : index_cmp_path;
251
294
  index->entries_search = ignore_case ? index_isrch : index_srch;
252
295
  index->entries_search_path = ignore_case ? index_isrch_path : index_srch_path;
253
- index->entries.sorted = 0;
296
+
297
+ git_vector_set_cmp(&index->entries, ignore_case ? index_icmp : index_cmp);
254
298
  git_vector_sort(&index->entries);
255
299
 
256
- index->reuc._cmp = ignore_case ? reuc_icmp : reuc_cmp;
257
300
  index->reuc_search = ignore_case ? reuc_isrch : reuc_srch;
258
- index->reuc.sorted = 0;
301
+
302
+ git_vector_set_cmp(&index->reuc, ignore_case ? reuc_icmp : reuc_cmp);
259
303
  git_vector_sort(&index->reuc);
260
304
  }
261
305
 
@@ -278,6 +322,7 @@ int git_index_open(git_index **index_out, const char *index_path)
278
322
  }
279
323
 
280
324
  if (git_vector_init(&index->entries, 32, index_cmp) < 0 ||
325
+ git_vector_init(&index->names, 32, conflict_name_cmp) < 0 ||
281
326
  git_vector_init(&index->reuc, 32, reuc_cmp) < 0)
282
327
  return -1;
283
328
 
@@ -301,9 +346,12 @@ static void index_free(git_index *index)
301
346
  {
302
347
  git_index_clear(index);
303
348
  git_vector_free(&index->entries);
349
+ git_vector_free(&index->names);
304
350
  git_vector_free(&index->reuc);
305
351
 
306
352
  git__free(index->index_file_path);
353
+
354
+ git__memzero(index, sizeof(*index));
307
355
  git__free(index);
308
356
  }
309
357
 
@@ -315,22 +363,27 @@ void git_index_free(git_index *index)
315
363
  GIT_REFCOUNT_DEC(index, index_free);
316
364
  }
317
365
 
318
- void git_index_clear(git_index *index)
366
+ static void index_entries_free(git_vector *entries)
319
367
  {
320
368
  size_t i;
321
369
 
322
- assert(index);
323
-
324
- for (i = 0; i < index->entries.length; ++i) {
325
- git_index_entry *e;
326
- e = git_vector_get(&index->entries, i);
370
+ for (i = 0; i < entries->length; ++i) {
371
+ git_index_entry *e = git_vector_get(entries, i);
327
372
  git__free(e->path);
328
373
  git__free(e);
329
374
  }
330
- git_vector_clear(&index->entries);
331
375
 
376
+ git_vector_clear(entries);
377
+ }
378
+
379
+ void git_index_clear(git_index *index)
380
+ {
381
+ assert(index);
382
+
383
+ index_entries_free(&index->entries);
332
384
  git_index_reuc_clear(index);
333
-
385
+ git_index_name_clear(index);
386
+
334
387
  git_futils_filestamp_set(&index->stamp, NULL);
335
388
 
336
389
  git_tree_cache_free(index->tree);
@@ -352,19 +405,18 @@ int git_index_set_caps(git_index *index, unsigned int caps)
352
405
  old_ignore_case = index->ignore_case;
353
406
 
354
407
  if (caps == GIT_INDEXCAP_FROM_OWNER) {
355
- git_config *cfg;
408
+ git_repository *repo = INDEX_OWNER(index);
356
409
  int val;
357
410
 
358
- if (INDEX_OWNER(index) == NULL ||
359
- git_repository_config__weakptr(&cfg, INDEX_OWNER(index)) < 0)
360
- return create_index_error(-1,
361
- "Cannot get repository config to set index caps");
411
+ if (!repo)
412
+ return create_index_error(
413
+ -1, "Cannot access repository to set index caps");
362
414
 
363
- if (git_config_get_bool(&val, cfg, "core.ignorecase") == 0)
415
+ if (!git_repository__cvar(&val, repo, GIT_CVAR_IGNORECASE))
364
416
  index->ignore_case = (val != 0);
365
- if (git_config_get_bool(&val, cfg, "core.filemode") == 0)
417
+ if (!git_repository__cvar(&val, repo, GIT_CVAR_FILEMODE))
366
418
  index->distrust_filemode = (val == 0);
367
- if (git_config_get_bool(&val, cfg, "core.symlinks") == 0)
419
+ if (!git_repository__cvar(&val, repo, GIT_CVAR_SYMLINKS))
368
420
  index->no_symlinks = (val == 0);
369
421
  }
370
422
  else {
@@ -497,8 +549,10 @@ const git_index_entry *git_index_get_bypath(
497
549
 
498
550
  git_vector_sort(&index->entries);
499
551
 
500
- if (index_find(&pos, index, path, stage) < 0)
552
+ if (index_find(&pos, index, path, stage) < 0) {
553
+ giterr_set(GITERR_INDEX, "Index does not contain %s", path);
501
554
  return NULL;
555
+ }
502
556
 
503
557
  return git_index_get_byindex(index, pos);
504
558
  }
@@ -586,8 +640,9 @@ static int index_entry_init(git_index_entry **entry_out, git_index *index, const
586
640
 
587
641
  static int index_entry_reuc_init(git_index_reuc_entry **reuc_out,
588
642
  const char *path,
589
- int ancestor_mode, git_oid *ancestor_oid,
590
- int our_mode, git_oid *our_oid, int their_mode, git_oid *their_oid)
643
+ int ancestor_mode, const git_oid *ancestor_oid,
644
+ int our_mode, const git_oid *our_oid,
645
+ int their_mode, const git_oid *their_oid)
591
646
  {
592
647
  git_index_reuc_entry *reuc = NULL;
593
648
 
@@ -668,7 +723,7 @@ static int index_insert(git_index *index, git_index_entry *entry, int replace)
668
723
  entry->flags |= GIT_IDXENTRY_NAMEMASK;
669
724
 
670
725
  /* look if an entry with this path already exists */
671
- if (!index_find(&position, index, entry->path, index_entry_stage(entry))) {
726
+ if (!index_find(&position, index, entry->path, GIT_IDXENTRY_STAGE(entry))) {
672
727
  existing = (git_index_entry **)&index->entries.contents[position];
673
728
 
674
729
  /* update filemode to existing values if stat is not trusted */
@@ -681,8 +736,9 @@ static int index_insert(git_index *index, git_index_entry *entry, int replace)
681
736
  if (!replace || !existing)
682
737
  return git_vector_insert(&index->entries, entry);
683
738
 
684
- /* exists, replace it */
685
- git__free((*existing)->path);
739
+ /* exists, replace it (preserving name from existing entry) */
740
+ git__free(entry->path);
741
+ entry->path = (*existing)->path;
686
742
  git__free(*existing);
687
743
  *existing = entry;
688
744
 
@@ -691,9 +747,9 @@ static int index_insert(git_index *index, git_index_entry *entry, int replace)
691
747
 
692
748
  static int index_conflict_to_reuc(git_index *index, const char *path)
693
749
  {
694
- git_index_entry *conflict_entries[3];
750
+ const git_index_entry *conflict_entries[3];
695
751
  int ancestor_mode, our_mode, their_mode;
696
- git_oid *ancestor_oid, *our_oid, *their_oid;
752
+ git_oid const *ancestor_oid, *our_oid, *their_oid;
697
753
  int ret;
698
754
 
699
755
  if ((ret = git_index_conflict_get(&conflict_entries[0],
@@ -779,8 +835,11 @@ int git_index_remove(git_index *index, const char *path, int stage)
779
835
 
780
836
  git_vector_sort(&index->entries);
781
837
 
782
- if (index_find(&position, index, path, stage) < 0)
838
+ if (index_find(&position, index, path, stage) < 0) {
839
+ giterr_set(GITERR_INDEX, "Index does not contain %s at stage %d",
840
+ path, stage);
783
841
  return GIT_ENOTFOUND;
842
+ }
784
843
 
785
844
  entry = git_vector_get(&index->entries, position);
786
845
  if (entry != NULL)
@@ -813,7 +872,7 @@ int git_index_remove_directory(git_index *index, const char *dir, int stage)
813
872
  if (!entry || git__prefixcmp(entry->path, pfx.ptr) != 0)
814
873
  break;
815
874
 
816
- if (index_entry_stage(entry) != stage) {
875
+ if (GIT_IDXENTRY_STAGE(entry) != stage) {
817
876
  ++pos;
818
877
  continue;
819
878
  }
@@ -927,53 +986,80 @@ on_error:
927
986
  return ret;
928
987
  }
929
988
 
930
- int git_index_conflict_get(git_index_entry **ancestor_out,
931
- git_index_entry **our_out,
932
- git_index_entry **their_out,
933
- git_index *index, const char *path)
989
+ static int index_conflict__get_byindex(
990
+ const git_index_entry **ancestor_out,
991
+ const git_index_entry **our_out,
992
+ const git_index_entry **their_out,
993
+ git_index *index,
994
+ size_t n)
934
995
  {
935
- size_t pos, posmax;
936
- int stage;
937
- git_index_entry *conflict_entry;
938
- int error = GIT_ENOTFOUND;
996
+ const git_index_entry *conflict_entry;
997
+ const char *path = NULL;
998
+ size_t count;
999
+ int stage, len = 0;
939
1000
 
940
- assert(ancestor_out && our_out && their_out && index && path);
1001
+ assert(ancestor_out && our_out && their_out && index);
941
1002
 
942
1003
  *ancestor_out = NULL;
943
1004
  *our_out = NULL;
944
1005
  *their_out = NULL;
945
1006
 
946
- if (git_index_find(&pos, index, path) < 0)
947
- return GIT_ENOTFOUND;
1007
+ for (count = git_index_entrycount(index); n < count; ++n) {
1008
+ conflict_entry = git_vector_get(&index->entries, n);
948
1009
 
949
- for (posmax = git_index_entrycount(index); pos < posmax; ++pos) {
950
-
951
- conflict_entry = git_vector_get(&index->entries, pos);
952
-
953
- if (index->entries_cmp_path(conflict_entry->path, path) != 0)
1010
+ if (path && index->entries_cmp_path(conflict_entry->path, path) != 0)
954
1011
  break;
955
1012
 
956
- stage = index_entry_stage(conflict_entry);
1013
+ stage = GIT_IDXENTRY_STAGE(conflict_entry);
1014
+ path = conflict_entry->path;
957
1015
 
958
1016
  switch (stage) {
959
1017
  case 3:
960
1018
  *their_out = conflict_entry;
961
- error = 0;
1019
+ len++;
962
1020
  break;
963
1021
  case 2:
964
1022
  *our_out = conflict_entry;
965
- error = 0;
1023
+ len++;
966
1024
  break;
967
1025
  case 1:
968
1026
  *ancestor_out = conflict_entry;
969
- error = 0;
1027
+ len++;
970
1028
  break;
971
1029
  default:
972
1030
  break;
973
1031
  };
974
1032
  }
975
1033
 
976
- return error;
1034
+ return len;
1035
+ }
1036
+
1037
+ int git_index_conflict_get(
1038
+ const git_index_entry **ancestor_out,
1039
+ const git_index_entry **our_out,
1040
+ const git_index_entry **their_out,
1041
+ git_index *index,
1042
+ const char *path)
1043
+ {
1044
+ size_t pos;
1045
+ int len = 0;
1046
+
1047
+ assert(ancestor_out && our_out && their_out && index && path);
1048
+
1049
+ *ancestor_out = NULL;
1050
+ *our_out = NULL;
1051
+ *their_out = NULL;
1052
+
1053
+ if (git_index_find(&pos, index, path) < 0)
1054
+ return GIT_ENOTFOUND;
1055
+
1056
+ if ((len = index_conflict__get_byindex(
1057
+ ancestor_out, our_out, their_out, index, pos)) < 0)
1058
+ return len;
1059
+ else if (len == 0)
1060
+ return GIT_ENOTFOUND;
1061
+
1062
+ return 0;
977
1063
  }
978
1064
 
979
1065
  int git_index_conflict_remove(git_index *index, const char *path)
@@ -995,7 +1081,7 @@ int git_index_conflict_remove(git_index *index, const char *path)
995
1081
  if (index->entries_cmp_path(conflict_entry->path, path) != 0)
996
1082
  break;
997
1083
 
998
- if (index_entry_stage(conflict_entry) == 0) {
1084
+ if (GIT_IDXENTRY_STAGE(conflict_entry) == 0) {
999
1085
  pos++;
1000
1086
  continue;
1001
1087
  }
@@ -1014,7 +1100,7 @@ static int index_conflicts_match(const git_vector *v, size_t idx)
1014
1100
  {
1015
1101
  git_index_entry *entry = git_vector_get(v, idx);
1016
1102
 
1017
- if (index_entry_stage(entry) > 0) {
1103
+ if (GIT_IDXENTRY_STAGE(entry) > 0) {
1018
1104
  index_entry_free(entry);
1019
1105
  return 1;
1020
1106
  }
@@ -1036,20 +1122,151 @@ int git_index_has_conflicts(const git_index *index)
1036
1122
  assert(index);
1037
1123
 
1038
1124
  git_vector_foreach(&index->entries, i, entry) {
1039
- if (index_entry_stage(entry) > 0)
1125
+ if (GIT_IDXENTRY_STAGE(entry) > 0)
1040
1126
  return 1;
1041
1127
  }
1042
1128
 
1043
1129
  return 0;
1044
1130
  }
1045
1131
 
1132
+ int git_index_conflict_iterator_new(
1133
+ git_index_conflict_iterator **iterator_out,
1134
+ git_index *index)
1135
+ {
1136
+ git_index_conflict_iterator *it = NULL;
1137
+
1138
+ assert(iterator_out && index);
1139
+
1140
+ it = git__calloc(1, sizeof(git_index_conflict_iterator));
1141
+ GITERR_CHECK_ALLOC(it);
1142
+
1143
+ it->index = index;
1144
+
1145
+ *iterator_out = it;
1146
+ return 0;
1147
+ }
1148
+
1149
+ int git_index_conflict_next(
1150
+ const git_index_entry **ancestor_out,
1151
+ const git_index_entry **our_out,
1152
+ const git_index_entry **their_out,
1153
+ git_index_conflict_iterator *iterator)
1154
+ {
1155
+ const git_index_entry *entry;
1156
+ int len;
1157
+
1158
+ assert(ancestor_out && our_out && their_out && iterator);
1159
+
1160
+ *ancestor_out = NULL;
1161
+ *our_out = NULL;
1162
+ *their_out = NULL;
1163
+
1164
+ while (iterator->cur < iterator->index->entries.length) {
1165
+ entry = git_index_get_byindex(iterator->index, iterator->cur);
1166
+
1167
+ if (git_index_entry_stage(entry) > 0) {
1168
+ if ((len = index_conflict__get_byindex(
1169
+ ancestor_out,
1170
+ our_out,
1171
+ their_out,
1172
+ iterator->index,
1173
+ iterator->cur)) < 0)
1174
+ return len;
1175
+
1176
+ iterator->cur += len;
1177
+ return 0;
1178
+ }
1179
+
1180
+ iterator->cur++;
1181
+ }
1182
+
1183
+ return GIT_ITEROVER;
1184
+ }
1185
+
1186
+ void git_index_conflict_iterator_free(git_index_conflict_iterator *iterator)
1187
+ {
1188
+ if (iterator == NULL)
1189
+ return;
1190
+
1191
+ git__free(iterator);
1192
+ }
1193
+
1194
+ unsigned int git_index_name_entrycount(git_index *index)
1195
+ {
1196
+ assert(index);
1197
+ return (unsigned int)index->names.length;
1198
+ }
1199
+
1200
+ const git_index_name_entry *git_index_name_get_byindex(
1201
+ git_index *index, size_t n)
1202
+ {
1203
+ assert(index);
1204
+
1205
+ git_vector_sort(&index->names);
1206
+ return git_vector_get(&index->names, n);
1207
+ }
1208
+
1209
+ int git_index_name_add(git_index *index,
1210
+ const char *ancestor, const char *ours, const char *theirs)
1211
+ {
1212
+ git_index_name_entry *conflict_name;
1213
+
1214
+ assert ((ancestor && ours) || (ancestor && theirs) || (ours && theirs));
1215
+
1216
+ conflict_name = git__calloc(1, sizeof(git_index_name_entry));
1217
+ GITERR_CHECK_ALLOC(conflict_name);
1218
+
1219
+ if (ancestor) {
1220
+ conflict_name->ancestor = git__strdup(ancestor);
1221
+ GITERR_CHECK_ALLOC(conflict_name->ancestor);
1222
+ }
1223
+
1224
+ if (ours) {
1225
+ conflict_name->ours = git__strdup(ours);
1226
+ GITERR_CHECK_ALLOC(conflict_name->ours);
1227
+ }
1228
+
1229
+ if (theirs) {
1230
+ conflict_name->theirs = git__strdup(theirs);
1231
+ GITERR_CHECK_ALLOC(conflict_name->theirs);
1232
+ }
1233
+
1234
+ return git_vector_insert(&index->names, conflict_name);
1235
+ }
1236
+
1237
+ void git_index_name_clear(git_index *index)
1238
+ {
1239
+ size_t i;
1240
+ git_index_name_entry *conflict_name;
1241
+
1242
+ assert(index);
1243
+
1244
+ git_vector_foreach(&index->names, i, conflict_name) {
1245
+ if (conflict_name->ancestor)
1246
+ git__free(conflict_name->ancestor);
1247
+
1248
+ if (conflict_name->ours)
1249
+ git__free(conflict_name->ours);
1250
+
1251
+ if (conflict_name->theirs)
1252
+ git__free(conflict_name->theirs);
1253
+
1254
+ git__free(conflict_name);
1255
+ }
1256
+
1257
+ git_vector_clear(&index->names);
1258
+ }
1259
+
1046
1260
  unsigned int git_index_reuc_entrycount(git_index *index)
1047
1261
  {
1048
1262
  assert(index);
1049
1263
  return (unsigned int)index->reuc.length;
1050
1264
  }
1051
1265
 
1052
- static int index_reuc_insert(git_index *index, git_index_reuc_entry *reuc, int replace)
1266
+ static int index_reuc_insert(
1267
+ git_index *index,
1268
+ git_index_reuc_entry *reuc,
1269
+ int replace)
1053
1270
  {
1054
1271
  git_index_reuc_entry **existing = NULL;
1055
1272
  size_t position;
@@ -1071,9 +1288,9 @@ static int index_reuc_insert(git_index *index, git_index_reuc_entry *reuc, int r
1071
1288
  }
1072
1289
 
1073
1290
  int git_index_reuc_add(git_index *index, const char *path,
1074
- int ancestor_mode, git_oid *ancestor_oid,
1075
- int our_mode, git_oid *our_oid,
1076
- int their_mode, git_oid *their_oid)
1291
+ int ancestor_mode, const git_oid *ancestor_oid,
1292
+ int our_mode, const git_oid *our_oid,
1293
+ int their_mode, const git_oid *their_oid)
1077
1294
  {
1078
1295
  git_index_reuc_entry *reuc = NULL;
1079
1296
  int error = 0;
@@ -1164,8 +1381,9 @@ static int read_reuc(git_index *index, const char *buffer, size_t size)
1164
1381
  size_t len;
1165
1382
  int i;
1166
1383
 
1167
- /* This gets called multiple times, the vector might already be initialized */
1168
- if (index->reuc._alloc_size == 0 && git_vector_init(&index->reuc, 16, reuc_cmp) < 0)
1384
+ /* If called multiple times, the vector might already be initialized */
1385
+ if (index->reuc._alloc_size == 0 &&
1386
+ git_vector_init(&index->reuc, 16, reuc_cmp) < 0)
1169
1387
  return -1;
1170
1388
 
1171
1389
  while (size) {
@@ -1175,12 +1393,9 @@ static int read_reuc(git_index *index, const char *buffer, size_t size)
1175
1393
  if (size <= len)
1176
1394
  return index_error_invalid("reading reuc entries");
1177
1395
 
1178
- lost = git__malloc(sizeof(git_index_reuc_entry));
1396
+ lost = git__calloc(1, sizeof(git_index_reuc_entry));
1179
1397
  GITERR_CHECK_ALLOC(lost);
1180
1398
 
1181
- if (git_vector_insert(&index->reuc, lost) < 0)
1182
- return -1;
1183
-
1184
1399
  /* read NUL-terminated pathname for entry */
1185
1400
  lost->path = git__strdup(buffer);
1186
1401
  GITERR_CHECK_ALLOC(lost->path);
@@ -1218,6 +1433,10 @@ static int read_reuc(git_index *index, const char *buffer, size_t size)
1218
1433
  size -= 20;
1219
1434
  buffer += 20;
1220
1435
  }
1436
+
1437
+ /* entry was read successfully - insert into reuc vector */
1438
+ if (git_vector_insert(&index->reuc, lost) < 0)
1439
+ return -1;
1221
1440
  }
1222
1441
 
1223
1442
  /* entries are guaranteed to be sorted on-disk */
@@ -1226,6 +1445,52 @@ static int read_reuc(git_index *index, const char *buffer, size_t size)
1226
1445
  return 0;
1227
1446
  }
1228
1447
 
1448
+
1449
+ static int read_conflict_names(git_index *index, const char *buffer, size_t size)
1450
+ {
1451
+ size_t len;
1452
+
1453
+ /* This gets called multiple times, the vector might already be initialized */
1454
+ if (index->names._alloc_size == 0 &&
1455
+ git_vector_init(&index->names, 16, conflict_name_cmp) < 0)
1456
+ return -1;
1457
+
1458
+ #define read_conflict_name(ptr) \
1459
+ len = strlen(buffer) + 1; \
1460
+ if (size < len) \
1461
+ return index_error_invalid("reading conflict name entries"); \
1462
+ \
1463
+ if (len == 1) \
1464
+ ptr = NULL; \
1465
+ else { \
1466
+ ptr = git__malloc(len); \
1467
+ GITERR_CHECK_ALLOC(ptr); \
1468
+ memcpy(ptr, buffer, len); \
1469
+ } \
1470
+ \
1471
+ buffer += len; \
1472
+ size -= len;
1473
+
1474
+ while (size) {
1475
+ git_index_name_entry *conflict_name = git__calloc(1, sizeof(git_index_name_entry));
1476
+ GITERR_CHECK_ALLOC(conflict_name);
1477
+
1478
+ read_conflict_name(conflict_name->ancestor);
1479
+ read_conflict_name(conflict_name->ours);
1480
+ read_conflict_name(conflict_name->theirs);
1481
+
1482
+ if (git_vector_insert(&index->names, conflict_name) < 0)
1483
+ return -1;
1484
+ }
1485
+
1486
+ #undef read_conflict_name
1487
+
1488
+ /* entries are guaranteed to be sorted on-disk */
1489
+ index->names.sorted = 1;
1490
+
1491
+ return 0;
1492
+ }
1493
+
1229
1494
  static size_t read_entry(git_index_entry *dest, const void *buffer, size_t buffer_size)
1230
1495
  {
1231
1496
  size_t path_length, entry_size;
@@ -1318,7 +1583,8 @@ static size_t read_extension(git_index *index, const char *buffer, size_t buffer
1318
1583
 
1319
1584
  total_size = dest.extension_size + sizeof(struct index_extension);
1320
1585
 
1321
- if (buffer_size - total_size < INDEX_FOOTER_SIZE)
1586
+ if (buffer_size < total_size ||
1587
+ buffer_size - total_size < INDEX_FOOTER_SIZE)
1322
1588
  return 0;
1323
1589
 
1324
1590
  /* optional extension */
@@ -1330,6 +1596,9 @@ static size_t read_extension(git_index *index, const char *buffer, size_t buffer
1330
1596
  } else if (memcmp(dest.signature, INDEX_EXT_UNMERGED_SIG, 4) == 0) {
1331
1597
  if (read_reuc(index, buffer + 8, dest.extension_size) < 0)
1332
1598
  return 0;
1599
+ } else if (memcmp(dest.signature, INDEX_EXT_CONFLICT_NAME_SIG, 4) == 0) {
1600
+ if (read_conflict_names(index, buffer + 8, dest.extension_size) < 0)
1601
+ return 0;
1333
1602
  }
1334
1603
  /* else, unsupported extension. We cannot parse this, but we can skip
1335
1604
  * it by returning `total_size */
@@ -1345,7 +1614,7 @@ static size_t read_extension(git_index *index, const char *buffer, size_t buffer
1345
1614
  static int parse_index(git_index *index, const char *buffer, size_t buffer_size)
1346
1615
  {
1347
1616
  unsigned int i;
1348
- struct index_header header;
1617
+ struct index_header header = { 0 };
1349
1618
  git_oid checksum_calculated, checksum_expected;
1350
1619
 
1351
1620
  #define seek_forward(_increase) { \
@@ -1401,7 +1670,7 @@ static int parse_index(git_index *index, const char *buffer, size_t buffer_size)
1401
1670
 
1402
1671
  /* see if we have read any bytes from the extension */
1403
1672
  if (extension_size == 0)
1404
- return index_error_invalid("extension size is zero");
1673
+ return index_error_invalid("extension is truncated");
1405
1674
 
1406
1675
  seek_forward(extension_size);
1407
1676
  }
@@ -1412,7 +1681,7 @@ static int parse_index(git_index *index, const char *buffer, size_t buffer_size)
1412
1681
  /* 160-bit SHA-1 over the content of the index file before this checksum. */
1413
1682
  git_oid_fromraw(&checksum_expected, (const unsigned char *)buffer);
1414
1683
 
1415
- if (git_oid_cmp(&checksum_calculated, &checksum_expected) != 0)
1684
+ if (git_oid__cmp(&checksum_calculated, &checksum_expected) != 0)
1416
1685
  return index_error_invalid("calculated checksum does not match expected");
1417
1686
 
1418
1687
  #undef seek_forward
@@ -1543,6 +1812,61 @@ static int write_extension(git_filebuf *file, struct index_extension *header, gi
1543
1812
  return error;
1544
1813
  }
1545
1814
 
1815
+ static int create_name_extension_data(git_buf *name_buf, git_index_name_entry *conflict_name)
1816
+ {
1817
+ int error = 0;
1818
+
1819
+ if (conflict_name->ancestor == NULL)
1820
+ error = git_buf_put(name_buf, "\0", 1);
1821
+ else
1822
+ error = git_buf_put(name_buf, conflict_name->ancestor, strlen(conflict_name->ancestor) + 1);
1823
+
1824
+ if (error != 0)
1825
+ goto on_error;
1826
+
1827
+ if (conflict_name->ours == NULL)
1828
+ error = git_buf_put(name_buf, "\0", 1);
1829
+ else
1830
+ error = git_buf_put(name_buf, conflict_name->ours, strlen(conflict_name->ours) + 1);
1831
+
1832
+ if (error != 0)
1833
+ goto on_error;
1834
+
1835
+ if (conflict_name->theirs == NULL)
1836
+ error = git_buf_put(name_buf, "\0", 1);
1837
+ else
1838
+ error = git_buf_put(name_buf, conflict_name->theirs, strlen(conflict_name->theirs) + 1);
1839
+
1840
+ on_error:
1841
+ return error;
1842
+ }
1843
+
1844
+ static int write_name_extension(git_index *index, git_filebuf *file)
1845
+ {
1846
+ git_buf name_buf = GIT_BUF_INIT;
1847
+ git_vector *out = &index->names;
1848
+ git_index_name_entry *conflict_name;
1849
+ struct index_extension extension;
1850
+ size_t i;
1851
+ int error = 0;
1852
+
1853
+ git_vector_foreach(out, i, conflict_name) {
1854
+ if ((error = create_name_extension_data(&name_buf, conflict_name)) < 0)
1855
+ goto done;
1856
+ }
1857
+
1858
+ memset(&extension, 0x0, sizeof(struct index_extension));
1859
+ memcpy(&extension.signature, INDEX_EXT_CONFLICT_NAME_SIG, 4);
1860
+ extension.extension_size = (uint32_t)name_buf.size;
1861
+
1862
+ error = write_extension(file, &extension, &name_buf);
1863
+
1864
+ git_buf_free(&name_buf);
1865
+
1866
+ done:
1867
+ return error;
1868
+ }
1869
+
1546
1870
  static int create_reuc_extension_data(git_buf *reuc_buf, git_index_reuc_entry *reuc)
1547
1871
  {
1548
1872
  int i;
@@ -1613,6 +1937,10 @@ static int write_index(git_index *index, git_filebuf *file)
1613
1937
 
1614
1938
  /* TODO: write tree cache extension */
1615
1939
 
1940
+ /* write the rename conflict extension */
1941
+ if (index->names.length > 0 && write_name_extension(index, file) < 0)
1942
+ return -1;
1943
+
1616
1944
  /* write the reuc extension */
1617
1945
  if (index->reuc.length > 0 && write_reuc_extension(index, file) < 0)
1618
1946
  return -1;
@@ -1626,18 +1954,19 @@ static int write_index(git_index *index, git_filebuf *file)
1626
1954
 
1627
1955
  int git_index_entry_stage(const git_index_entry *entry)
1628
1956
  {
1629
- return index_entry_stage(entry);
1957
+ return GIT_IDXENTRY_STAGE(entry);
1630
1958
  }
1631
1959
 
1632
1960
  typedef struct read_tree_data {
1633
1961
  git_index *index;
1634
- git_transfer_progress *stats;
1962
+ git_vector *old_entries;
1635
1963
  } read_tree_data;
1636
1964
 
1637
- static int read_tree_cb(const char *root, const git_tree_entry *tentry, void *data)
1965
+ static int read_tree_cb(
1966
+ const char *root, const git_tree_entry *tentry, void *payload)
1638
1967
  {
1639
- git_index *index = (git_index *)data;
1640
- git_index_entry *entry = NULL;
1968
+ read_tree_data *data = payload;
1969
+ git_index_entry *entry = NULL, *old_entry;
1641
1970
  git_buf path = GIT_BUF_INIT;
1642
1971
 
1643
1972
  if (git_tree_entry__is_tree(tentry))
@@ -1652,6 +1981,25 @@ static int read_tree_cb(const char *root, const git_tree_entry *tentry, void *da
1652
1981
  entry->mode = tentry->attr;
1653
1982
  entry->oid = tentry->oid;
1654
1983
 
1984
+ /* look for corresponding old entry and copy data to new entry */
1985
+ if (data->old_entries) {
1986
+ size_t pos;
1987
+ struct entry_srch_key skey;
1988
+
1989
+ skey.path = path.ptr;
1990
+ skey.stage = 0;
1991
+
1992
+ if (!git_vector_bsearch2(
1993
+ &pos, data->old_entries, data->index->entries_search, &skey) &&
1994
+ (old_entry = git_vector_get(data->old_entries, pos)) != NULL &&
1995
+ entry->mode == old_entry->mode &&
1996
+ git_oid_equal(&entry->oid, &old_entry->oid))
1997
+ {
1998
+ memcpy(entry, old_entry, sizeof(*entry));
1999
+ entry->flags_extended = 0;
2000
+ }
2001
+ }
2002
+
1655
2003
  if (path.size < GIT_IDXENTRY_NAMEMASK)
1656
2004
  entry->flags = path.size & GIT_IDXENTRY_NAMEMASK;
1657
2005
  else
@@ -1660,7 +2008,7 @@ static int read_tree_cb(const char *root, const git_tree_entry *tentry, void *da
1660
2008
  entry->path = git_buf_detach(&path);
1661
2009
  git_buf_free(&path);
1662
2010
 
1663
- if (git_vector_insert(&index->entries, entry) < 0) {
2011
+ if (git_vector_insert(&data->index->entries, entry) < 0) {
1664
2012
  index_entry_free(entry);
1665
2013
  return -1;
1666
2014
  }
@@ -1670,12 +2018,246 @@ static int read_tree_cb(const char *root, const git_tree_entry *tentry, void *da
1670
2018
 
1671
2019
  int git_index_read_tree(git_index *index, const git_tree *tree)
1672
2020
  {
2021
+ int error = 0;
2022
+ git_vector entries = GIT_VECTOR_INIT;
2023
+ read_tree_data data;
2024
+
2025
+ git_vector_sort(&index->entries);
2026
+
2027
+ git_vector_set_cmp(&entries, index->entries._cmp);
2028
+ git_vector_swap(&entries, &index->entries);
2029
+
1673
2030
  git_index_clear(index);
1674
2031
 
1675
- return git_tree_walk(tree, GIT_TREEWALK_POST, read_tree_cb, index);
2032
+ data.index = index;
2033
+ data.old_entries = &entries;
2034
+
2035
+ error = git_tree_walk(tree, GIT_TREEWALK_POST, read_tree_cb, &data);
2036
+
2037
+ index_entries_free(&entries);
2038
+ git_vector_free(&entries);
2039
+
2040
+ git_vector_sort(&index->entries);
2041
+
2042
+ return error;
1676
2043
  }
1677
2044
 
1678
2045
  git_repository *git_index_owner(const git_index *index)
1679
2046
  {
1680
2047
  return INDEX_OWNER(index);
1681
2048
  }
2049
+
2050
+ int git_index_add_all(
2051
+ git_index *index,
2052
+ const git_strarray *paths,
2053
+ unsigned int flags,
2054
+ git_index_matched_path_cb cb,
2055
+ void *payload)
2056
+ {
2057
+ int error;
2058
+ git_repository *repo;
2059
+ git_iterator *wditer = NULL;
2060
+ const git_index_entry *wd = NULL;
2061
+ git_index_entry *entry;
2062
+ git_pathspec_context ps;
2063
+ const char *match;
2064
+ size_t existing;
2065
+ bool no_fnmatch = (flags & GIT_INDEX_ADD_DISABLE_PATHSPEC_MATCH) != 0;
2066
+ int ignorecase;
2067
+ git_oid blobid;
2068
+
2069
+ assert(index);
2070
+
2071
+ if (INDEX_OWNER(index) == NULL)
2072
+ return create_index_error(-1,
2073
+ "Could not add paths to index. "
2074
+ "Index is not backed up by an existing repository.");
2075
+
2076
+ repo = INDEX_OWNER(index);
2077
+ if ((error = git_repository__ensure_not_bare(repo, "index add all")) < 0)
2078
+ return error;
2079
+
2080
+ if (git_repository__cvar(&ignorecase, repo, GIT_CVAR_IGNORECASE) < 0)
2081
+ return -1;
2082
+
2083
+ if ((error = git_pathspec_context_init(&ps, paths)) < 0)
2084
+ return error;
2085
+
2086
+ /* optionally check that pathspec doesn't mention any ignored files */
2087
+ if ((flags & GIT_INDEX_ADD_CHECK_PATHSPEC) != 0 &&
2088
+ (flags & GIT_INDEX_ADD_FORCE) == 0 &&
2089
+ (error = git_ignore__check_pathspec_for_exact_ignores(
2090
+ repo, &ps.pathspec, no_fnmatch)) < 0)
2091
+ goto cleanup;
2092
+
2093
+ if ((error = git_iterator_for_workdir(
2094
+ &wditer, repo, 0, ps.prefix, ps.prefix)) < 0)
2095
+ goto cleanup;
2096
+
2097
+ while (!(error = git_iterator_advance(&wd, wditer))) {
2098
+
2099
+ /* check if path actually matches */
2100
+ if (!git_pathspec_match_path(
2101
+ &ps.pathspec, wd->path, no_fnmatch, ignorecase, &match))
2102
+ continue;
2103
+
2104
+ /* skip ignored items that are not already in the index */
2105
+ if ((flags & GIT_INDEX_ADD_FORCE) == 0 &&
2106
+ git_iterator_current_is_ignored(wditer) &&
2107
+ index_find(&existing, index, wd->path, 0) < 0)
2108
+ continue;
2109
+
2110
+ /* issue notification callback if requested */
2111
+ if (cb && (error = cb(wd->path, match, payload)) != 0) {
2112
+ if (error > 0) /* return > 0 means skip this one */
2113
+ continue;
2114
+ if (error < 0) { /* return < 0 means abort */
2115
+ giterr_clear();
2116
+ error = GIT_EUSER;
2117
+ break;
2118
+ }
2119
+ }
2120
+
2121
+ /* TODO: Should we check if the file on disk is already an exact
2122
+ * match to the file in the index and skip this work if it is?
2123
+ */
2124
+
2125
+ /* write the blob to disk and get the oid */
2126
+ if ((error = git_blob_create_fromworkdir(&blobid, repo, wd->path)) < 0)
2127
+ break;
2128
+
2129
+ /* make the new entry to insert */
2130
+ if ((entry = index_entry_dup(wd)) == NULL) {
2131
+ error = -1;
2132
+ break;
2133
+ }
2134
+ entry->oid = blobid;
2135
+
2136
+ /* add working directory item to index */
2137
+ if ((error = index_insert(index, entry, 1)) < 0) {
2138
+ index_entry_free(entry);
2139
+ break;
2140
+ }
2141
+
2142
+ git_tree_cache_invalidate_path(index->tree, wd->path);
2143
+
2144
+ /* add implies conflict resolved, move conflict entries to REUC */
2145
+ if ((error = index_conflict_to_reuc(index, wd->path)) < 0) {
2146
+ if (error != GIT_ENOTFOUND)
2147
+ break;
2148
+ giterr_clear();
2149
+ }
2150
+ }
2151
+
2152
+ if (error == GIT_ITEROVER)
2153
+ error = 0;
2154
+
2155
+ cleanup:
2156
+ git_iterator_free(wditer);
2157
+ git_pathspec_context_free(&ps);
2158
+
2159
+ return error;
2160
+ }
2161
+
2162
+ enum {
2163
+ INDEX_ACTION_NONE = 0,
2164
+ INDEX_ACTION_UPDATE = 1,
2165
+ INDEX_ACTION_REMOVE = 2,
2166
+ };
2167
+
2168
+ static int index_apply_to_all(
2169
+ git_index *index,
2170
+ int action,
2171
+ const git_strarray *paths,
2172
+ git_index_matched_path_cb cb,
2173
+ void *payload)
2174
+ {
2175
+ int error = 0;
2176
+ size_t i;
2177
+ git_pathspec_context ps;
2178
+ const char *match;
2179
+ git_buf path = GIT_BUF_INIT;
2180
+
2181
+ assert(index);
2182
+
2183
+ if ((error = git_pathspec_context_init(&ps, paths)) < 0)
2184
+ return error;
2185
+
2186
+ git_vector_sort(&index->entries);
2187
+
2188
+ for (i = 0; !error && i < index->entries.length; ++i) {
2189
+ git_index_entry *entry = git_vector_get(&index->entries, i);
2190
+
2191
+ /* check if path actually matches */
2192
+ if (!git_pathspec_match_path(
2193
+ &ps.pathspec, entry->path, false, index->ignore_case, &match))
2194
+ continue;
2195
+
2196
+ /* issue notification callback if requested */
2197
+ if (cb && (error = cb(entry->path, match, payload)) != 0) {
2198
+ if (error > 0) { /* return > 0 means skip this one */
2199
+ error = 0;
2200
+ continue;
2201
+ }
2202
+ if (error < 0) { /* return < 0 means abort */
2203
+ giterr_clear();
2204
+ error = GIT_EUSER;
2205
+ break;
2206
+ }
2207
+ }
2208
+
2209
+ /* index manipulation may alter entry, so don't depend on it */
2210
+ if ((error = git_buf_sets(&path, entry->path)) < 0)
2211
+ break;
2212
+
2213
+ switch (action) {
2214
+ case INDEX_ACTION_NONE:
2215
+ break;
2216
+ case INDEX_ACTION_UPDATE:
2217
+ error = git_index_add_bypath(index, path.ptr);
2218
+
2219
+ if (error == GIT_ENOTFOUND) {
2220
+ giterr_clear();
2221
+
2222
+ error = git_index_remove_bypath(index, path.ptr);
2223
+
2224
+ if (!error) /* back up foreach if we removed this */
2225
+ i--;
2226
+ }
2227
+ break;
2228
+ case INDEX_ACTION_REMOVE:
2229
+ if (!(error = git_index_remove_bypath(index, path.ptr)))
2230
+ i--; /* back up foreach if we removed this */
2231
+ break;
2232
+ default:
2233
+ giterr_set(GITERR_INVALID, "Unknown index action %d", action);
2234
+ error = -1;
2235
+ break;
2236
+ }
2237
+ }
2238
+
2239
+ git_buf_free(&path);
2240
+ git_pathspec_context_free(&ps);
2241
+
2242
+ return error;
2243
+ }
2244
+
2245
+ int git_index_remove_all(
2246
+ git_index *index,
2247
+ const git_strarray *pathspec,
2248
+ git_index_matched_path_cb cb,
2249
+ void *payload)
2250
+ {
2251
+ return index_apply_to_all(
2252
+ index, INDEX_ACTION_REMOVE, pathspec, cb, payload);
2253
+ }
2254
+
2255
+ int git_index_update_all(
2256
+ git_index *index,
2257
+ const git_strarray *pathspec,
2258
+ git_index_matched_path_cb cb,
2259
+ void *payload)
2260
+ {
2261
+ return index_apply_to_all(
2262
+ index, INDEX_ACTION_UPDATE, pathspec, cb, payload);
2263
+ }