rugged 0.19.0 → 0.28.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (668) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +1 -1
  3. data/README.md +184 -33
  4. data/ext/rugged/extconf.rb +111 -28
  5. data/ext/rugged/rugged.c +327 -89
  6. data/ext/rugged/rugged.h +64 -28
  7. data/ext/rugged/rugged_allocator.c +89 -0
  8. data/ext/rugged/rugged_backend.c +17 -0
  9. data/ext/rugged/rugged_blame.c +278 -0
  10. data/ext/rugged/rugged_blob.c +301 -75
  11. data/ext/rugged/rugged_branch.c +92 -242
  12. data/ext/rugged/rugged_branch_collection.c +388 -0
  13. data/ext/rugged/rugged_commit.c +575 -79
  14. data/ext/rugged/rugged_config.c +129 -36
  15. data/ext/rugged/rugged_cred.c +131 -0
  16. data/ext/rugged/rugged_diff.c +291 -122
  17. data/ext/rugged/rugged_diff_delta.c +16 -22
  18. data/ext/rugged/rugged_diff_hunk.c +35 -51
  19. data/ext/rugged/rugged_diff_line.c +23 -36
  20. data/ext/rugged/rugged_index.c +289 -152
  21. data/ext/rugged/rugged_note.c +50 -60
  22. data/ext/rugged/rugged_object.c +13 -30
  23. data/ext/rugged/rugged_patch.c +400 -0
  24. data/ext/rugged/rugged_rebase.c +397 -0
  25. data/ext/rugged/rugged_reference.c +76 -346
  26. data/ext/rugged/rugged_reference_collection.c +423 -0
  27. data/ext/rugged/rugged_remote.c +438 -461
  28. data/ext/rugged/rugged_remote_collection.c +435 -0
  29. data/ext/rugged/rugged_repo.c +1548 -365
  30. data/ext/rugged/rugged_revwalk.c +378 -99
  31. data/ext/rugged/rugged_settings.c +86 -23
  32. data/ext/rugged/rugged_signature.c +47 -37
  33. data/ext/rugged/rugged_submodule.c +835 -0
  34. data/ext/rugged/rugged_submodule_collection.c +366 -0
  35. data/ext/rugged/rugged_tag.c +88 -210
  36. data/ext/rugged/rugged_tag_collection.c +326 -0
  37. data/ext/rugged/rugged_tree.c +460 -217
  38. data/lib/rugged/attributes.rb +46 -0
  39. data/lib/rugged/blob.rb +33 -0
  40. data/lib/rugged/branch.rb +12 -16
  41. data/lib/rugged/commit.rb +9 -0
  42. data/lib/rugged/console.rb +5 -0
  43. data/lib/rugged/credentials.rb +48 -0
  44. data/lib/rugged/diff/delta.rb +6 -2
  45. data/lib/rugged/diff/hunk.rb +9 -9
  46. data/lib/rugged/diff/line.rb +28 -5
  47. data/lib/rugged/diff.rb +7 -1
  48. data/lib/rugged/index.rb +120 -0
  49. data/lib/rugged/object.rb +5 -0
  50. data/lib/rugged/patch.rb +41 -0
  51. data/lib/rugged/reference.rb +6 -3
  52. data/lib/rugged/remote.rb +5 -9
  53. data/lib/rugged/repository.rb +126 -14
  54. data/lib/rugged/submodule_collection.rb +53 -0
  55. data/lib/rugged/tag.rb +45 -16
  56. data/lib/rugged/tree.rb +163 -1
  57. data/lib/rugged/version.rb +6 -1
  58. data/lib/rugged/walker.rb +5 -0
  59. data/lib/rugged.rb +16 -1
  60. data/vendor/libgit2/AUTHORS +77 -0
  61. data/vendor/libgit2/CMakeLists.txt +317 -0
  62. data/vendor/libgit2/COPYING +993 -0
  63. data/vendor/libgit2/cmake/Modules/AddCFlagIfSupported.cmake +30 -0
  64. data/vendor/libgit2/cmake/Modules/CheckPrototypeDefinition.c.in +29 -0
  65. data/vendor/libgit2/cmake/Modules/CheckPrototypeDefinition.cmake +96 -0
  66. data/vendor/libgit2/cmake/Modules/EnableWarnings.cmake +11 -0
  67. data/vendor/libgit2/cmake/Modules/FindCoreFoundation.cmake +26 -0
  68. data/vendor/libgit2/cmake/Modules/FindGSSAPI.cmake +324 -0
  69. data/vendor/libgit2/cmake/Modules/FindHTTP_Parser.cmake +39 -0
  70. data/vendor/libgit2/cmake/Modules/FindIconv.cmake +45 -0
  71. data/vendor/libgit2/cmake/Modules/FindPkgLibraries.cmake +28 -0
  72. data/vendor/libgit2/cmake/Modules/FindSecurity.cmake +28 -0
  73. data/vendor/libgit2/cmake/Modules/FindStatNsec.cmake +20 -0
  74. data/vendor/libgit2/cmake/Modules/FindmbedTLS.cmake +93 -0
  75. data/vendor/libgit2/cmake/Modules/IdeSplitSources.cmake +22 -0
  76. data/vendor/libgit2/deps/http-parser/CMakeLists.txt +5 -0
  77. data/vendor/libgit2/deps/http-parser/COPYING +23 -0
  78. data/vendor/libgit2/deps/http-parser/http_parser.c +5 -2
  79. data/vendor/libgit2/deps/http-parser/http_parser.h +2 -0
  80. data/vendor/libgit2/deps/regex/CMakeLists.txt +2 -0
  81. data/vendor/libgit2/deps/regex/COPYING +502 -0
  82. data/vendor/libgit2/deps/regex/regex.c +10 -3
  83. data/vendor/libgit2/deps/winhttp/CMakeLists.txt +26 -0
  84. data/vendor/libgit2/deps/winhttp/COPYING.GPL +993 -0
  85. data/vendor/libgit2/deps/winhttp/COPYING.LGPL +502 -0
  86. data/vendor/libgit2/deps/winhttp/urlmon.h +45 -0
  87. data/vendor/libgit2/deps/winhttp/winhttp.def +29 -0
  88. data/vendor/libgit2/deps/winhttp/winhttp.h +594 -0
  89. data/vendor/libgit2/deps/winhttp/winhttp64.def +29 -0
  90. data/vendor/libgit2/deps/zlib/CMakeLists.txt +5 -0
  91. data/vendor/libgit2/deps/zlib/COPYING +27 -0
  92. data/vendor/libgit2/deps/zlib/adler32.c +51 -34
  93. data/vendor/libgit2/deps/zlib/crc32.c +61 -61
  94. data/vendor/libgit2/deps/zlib/crc32.h +1 -1
  95. data/vendor/libgit2/deps/zlib/deflate.c +681 -352
  96. data/vendor/libgit2/deps/zlib/deflate.h +25 -18
  97. data/vendor/libgit2/deps/zlib/gzguts.h +218 -0
  98. data/vendor/libgit2/deps/zlib/infback.c +640 -0
  99. data/vendor/libgit2/deps/zlib/inffast.c +36 -53
  100. data/vendor/libgit2/deps/zlib/inffixed.h +3 -3
  101. data/vendor/libgit2/deps/zlib/inflate.c +167 -86
  102. data/vendor/libgit2/deps/zlib/inflate.h +7 -4
  103. data/vendor/libgit2/deps/zlib/inftrees.c +24 -50
  104. data/vendor/libgit2/deps/zlib/trees.c +55 -96
  105. data/vendor/libgit2/deps/zlib/zconf.h +499 -19
  106. data/vendor/libgit2/deps/zlib/zlib.h +526 -227
  107. data/vendor/libgit2/deps/zlib/zutil.c +39 -32
  108. data/vendor/libgit2/deps/zlib/zutil.h +75 -78
  109. data/vendor/libgit2/include/git2/annotated_commit.h +125 -0
  110. data/vendor/libgit2/include/git2/apply.h +129 -0
  111. data/vendor/libgit2/include/git2/attr.h +36 -21
  112. data/vendor/libgit2/include/git2/blame.h +229 -0
  113. data/vendor/libgit2/include/git2/blob.h +81 -44
  114. data/vendor/libgit2/include/git2/branch.h +81 -42
  115. data/vendor/libgit2/include/git2/buffer.h +128 -0
  116. data/vendor/libgit2/include/git2/checkout.h +141 -67
  117. data/vendor/libgit2/include/git2/cherrypick.h +92 -0
  118. data/vendor/libgit2/include/git2/clone.h +157 -58
  119. data/vendor/libgit2/include/git2/commit.h +231 -12
  120. data/vendor/libgit2/include/git2/common.h +216 -30
  121. data/vendor/libgit2/include/git2/config.h +274 -48
  122. data/vendor/libgit2/include/git2/cred_helpers.h +4 -4
  123. data/vendor/libgit2/include/git2/deprecated.h +253 -0
  124. data/vendor/libgit2/include/git2/describe.h +189 -0
  125. data/vendor/libgit2/include/git2/diff.h +985 -575
  126. data/vendor/libgit2/include/git2/errors.h +93 -52
  127. data/vendor/libgit2/include/git2/filter.h +217 -0
  128. data/vendor/libgit2/include/git2/global.h +44 -0
  129. data/vendor/libgit2/include/git2/graph.h +17 -0
  130. data/vendor/libgit2/include/git2/ignore.h +2 -2
  131. data/vendor/libgit2/include/git2/index.h +269 -94
  132. data/vendor/libgit2/include/git2/indexer.h +44 -12
  133. data/vendor/libgit2/include/git2/mailmap.h +115 -0
  134. data/vendor/libgit2/include/git2/merge.h +501 -64
  135. data/vendor/libgit2/include/git2/message.h +52 -17
  136. data/vendor/libgit2/include/git2/net.h +11 -5
  137. data/vendor/libgit2/include/git2/notes.h +120 -16
  138. data/vendor/libgit2/include/git2/object.h +62 -23
  139. data/vendor/libgit2/include/git2/odb.h +140 -24
  140. data/vendor/libgit2/include/git2/odb_backend.h +56 -12
  141. data/vendor/libgit2/include/git2/oid.h +17 -18
  142. data/vendor/libgit2/include/git2/oidarray.h +40 -0
  143. data/vendor/libgit2/include/git2/pack.h +86 -7
  144. data/vendor/libgit2/include/git2/patch.h +274 -0
  145. data/vendor/libgit2/include/git2/pathspec.h +280 -0
  146. data/vendor/libgit2/include/git2/proxy.h +96 -0
  147. data/vendor/libgit2/include/git2/rebase.h +323 -0
  148. data/vendor/libgit2/include/git2/reflog.h +12 -9
  149. data/vendor/libgit2/include/git2/refs.h +241 -46
  150. data/vendor/libgit2/include/git2/refspec.h +20 -4
  151. data/vendor/libgit2/include/git2/remote.h +636 -209
  152. data/vendor/libgit2/include/git2/repository.h +267 -57
  153. data/vendor/libgit2/include/git2/reset.h +36 -6
  154. data/vendor/libgit2/include/git2/revert.h +91 -0
  155. data/vendor/libgit2/include/git2/revparse.h +27 -16
  156. data/vendor/libgit2/include/git2/revwalk.h +78 -35
  157. data/vendor/libgit2/include/git2/signature.h +32 -5
  158. data/vendor/libgit2/include/git2/stash.h +160 -21
  159. data/vendor/libgit2/include/git2/status.h +92 -30
  160. data/vendor/libgit2/include/git2/submodule.h +226 -133
  161. data/vendor/libgit2/include/git2/sys/alloc.h +101 -0
  162. data/vendor/libgit2/include/git2/sys/commit.h +38 -4
  163. data/vendor/libgit2/include/git2/sys/config.h +68 -9
  164. data/vendor/libgit2/include/git2/sys/diff.h +94 -0
  165. data/vendor/libgit2/include/git2/sys/filter.h +332 -0
  166. data/vendor/libgit2/include/git2/sys/hashsig.h +106 -0
  167. data/vendor/libgit2/include/git2/sys/index.h +6 -5
  168. data/vendor/libgit2/include/git2/sys/mempack.h +86 -0
  169. data/vendor/libgit2/include/git2/sys/merge.h +182 -0
  170. data/vendor/libgit2/include/git2/sys/odb_backend.h +66 -28
  171. data/vendor/libgit2/include/git2/sys/openssl.h +38 -0
  172. data/vendor/libgit2/include/git2/sys/path.h +64 -0
  173. data/vendor/libgit2/include/git2/sys/refdb_backend.h +79 -19
  174. data/vendor/libgit2/include/git2/sys/reflog.h +21 -0
  175. data/vendor/libgit2/include/git2/sys/refs.h +13 -2
  176. data/vendor/libgit2/include/git2/sys/repository.h +64 -1
  177. data/vendor/libgit2/include/git2/sys/stream.h +138 -0
  178. data/vendor/libgit2/include/git2/sys/time.h +31 -0
  179. data/vendor/libgit2/include/git2/sys/transport.h +439 -0
  180. data/vendor/libgit2/include/git2/tag.h +11 -2
  181. data/vendor/libgit2/include/git2/trace.h +1 -1
  182. data/vendor/libgit2/include/git2/transaction.h +121 -0
  183. data/vendor/libgit2/include/git2/transport.h +261 -292
  184. data/vendor/libgit2/include/git2/tree.h +111 -21
  185. data/vendor/libgit2/include/git2/types.h +244 -32
  186. data/vendor/libgit2/include/git2/version.h +5 -2
  187. data/vendor/libgit2/include/git2/worktree.h +255 -0
  188. data/vendor/libgit2/include/git2.h +50 -40
  189. data/vendor/libgit2/libgit2.pc.in +13 -0
  190. data/vendor/libgit2/src/CMakeLists.txt +525 -0
  191. data/vendor/libgit2/src/alloc.c +55 -0
  192. data/vendor/libgit2/src/alloc.h +40 -0
  193. data/vendor/libgit2/src/annotated_commit.c +228 -0
  194. data/vendor/libgit2/src/annotated_commit.h +52 -0
  195. data/vendor/libgit2/src/apply.c +855 -0
  196. data/vendor/libgit2/src/apply.h +25 -0
  197. data/vendor/libgit2/src/array.h +74 -16
  198. data/vendor/libgit2/src/attr.c +239 -408
  199. data/vendor/libgit2/src/attr.h +3 -33
  200. data/vendor/libgit2/src/attr_file.c +424 -156
  201. data/vendor/libgit2/src/attr_file.h +95 -23
  202. data/vendor/libgit2/src/attrcache.c +469 -0
  203. data/vendor/libgit2/src/attrcache.h +37 -5
  204. data/vendor/libgit2/src/bitvec.h +75 -0
  205. data/vendor/libgit2/src/blame.c +532 -0
  206. data/vendor/libgit2/src/blame.h +95 -0
  207. data/vendor/libgit2/src/blame_git.c +668 -0
  208. data/vendor/libgit2/src/blame_git.h +22 -0
  209. data/vendor/libgit2/src/blob.c +233 -129
  210. data/vendor/libgit2/src/blob.h +29 -1
  211. data/vendor/libgit2/src/branch.c +295 -197
  212. data/vendor/libgit2/src/branch.h +2 -0
  213. data/vendor/libgit2/src/buf_text.c +52 -27
  214. data/vendor/libgit2/src/buf_text.h +7 -7
  215. data/vendor/libgit2/src/buffer.c +609 -52
  216. data/vendor/libgit2/src/buffer.h +68 -23
  217. data/vendor/libgit2/src/cache.c +48 -51
  218. data/vendor/libgit2/src/cache.h +6 -4
  219. data/vendor/libgit2/src/cc-compat.h +35 -7
  220. data/vendor/libgit2/src/checkout.c +1827 -483
  221. data/vendor/libgit2/src/checkout.h +4 -1
  222. data/vendor/libgit2/src/cherrypick.c +230 -0
  223. data/vendor/libgit2/src/clone.c +338 -258
  224. data/vendor/libgit2/src/{compress.h → clone.h} +5 -5
  225. data/vendor/libgit2/src/commit.c +711 -124
  226. data/vendor/libgit2/src/commit.h +10 -3
  227. data/vendor/libgit2/src/commit_list.c +21 -14
  228. data/vendor/libgit2/src/commit_list.h +9 -3
  229. data/vendor/libgit2/src/common.h +153 -13
  230. data/vendor/libgit2/src/config.c +871 -242
  231. data/vendor/libgit2/src/config.h +58 -14
  232. data/vendor/libgit2/src/config_backend.h +84 -0
  233. data/vendor/libgit2/src/config_cache.c +44 -18
  234. data/vendor/libgit2/src/config_entries.c +259 -0
  235. data/vendor/libgit2/src/config_entries.h +23 -0
  236. data/vendor/libgit2/src/config_file.c +837 -1113
  237. data/vendor/libgit2/src/config_mem.c +224 -0
  238. data/vendor/libgit2/src/config_parse.c +558 -0
  239. data/vendor/libgit2/src/config_parse.h +64 -0
  240. data/vendor/libgit2/src/crlf.c +290 -195
  241. data/vendor/libgit2/src/date.c +35 -7
  242. data/vendor/libgit2/src/delta.c +275 -71
  243. data/vendor/libgit2/src/delta.h +80 -58
  244. data/vendor/libgit2/src/describe.c +893 -0
  245. data/vendor/libgit2/src/diff.c +330 -1128
  246. data/vendor/libgit2/src/diff.h +25 -67
  247. data/vendor/libgit2/src/diff_driver.c +225 -109
  248. data/vendor/libgit2/src/diff_driver.h +5 -2
  249. data/vendor/libgit2/src/diff_file.c +128 -103
  250. data/vendor/libgit2/src/diff_file.h +17 -12
  251. data/vendor/libgit2/src/diff_generate.c +1622 -0
  252. data/vendor/libgit2/src/diff_generate.h +128 -0
  253. data/vendor/libgit2/src/diff_parse.c +108 -0
  254. data/vendor/libgit2/src/diff_parse.h +20 -0
  255. data/vendor/libgit2/src/diff_print.c +578 -218
  256. data/vendor/libgit2/src/diff_stats.c +362 -0
  257. data/vendor/libgit2/src/diff_tform.c +429 -257
  258. data/vendor/libgit2/src/diff_tform.h +25 -0
  259. data/vendor/libgit2/src/diff_xdiff.c +143 -46
  260. data/vendor/libgit2/src/diff_xdiff.h +12 -5
  261. data/vendor/libgit2/src/errors.c +150 -34
  262. data/vendor/libgit2/src/features.h.in +37 -0
  263. data/vendor/libgit2/src/fetch.c +69 -46
  264. data/vendor/libgit2/src/fetch.h +6 -12
  265. data/vendor/libgit2/src/fetchhead.c +40 -33
  266. data/vendor/libgit2/src/fetchhead.h +5 -4
  267. data/vendor/libgit2/src/filebuf.c +163 -61
  268. data/vendor/libgit2/src/filebuf.h +13 -7
  269. data/vendor/libgit2/src/fileops.c +549 -407
  270. data/vendor/libgit2/src/fileops.h +97 -106
  271. data/vendor/libgit2/src/filter.c +989 -46
  272. data/vendor/libgit2/src/filter.h +21 -70
  273. data/vendor/libgit2/src/fnmatch.c +67 -11
  274. data/vendor/libgit2/src/fnmatch.h +27 -7
  275. data/vendor/libgit2/src/global.c +257 -63
  276. data/vendor/libgit2/src/global.h +19 -0
  277. data/vendor/libgit2/src/graph.c +39 -23
  278. data/vendor/libgit2/src/hash/hash_collisiondetect.h +51 -0
  279. data/vendor/libgit2/src/hash/hash_common_crypto.h +61 -0
  280. data/vendor/libgit2/src/hash/hash_generic.c +3 -3
  281. data/vendor/libgit2/src/hash/hash_generic.h +10 -5
  282. data/vendor/libgit2/src/hash/hash_mbedtls.c +38 -0
  283. data/vendor/libgit2/src/hash/hash_mbedtls.h +24 -0
  284. data/vendor/libgit2/src/hash/hash_openssl.h +26 -8
  285. data/vendor/libgit2/src/hash/hash_win32.c +71 -43
  286. data/vendor/libgit2/src/hash/hash_win32.h +4 -3
  287. data/vendor/libgit2/src/hash/sha1dc/sha1.c +1900 -0
  288. data/vendor/libgit2/src/hash/sha1dc/sha1.h +110 -0
  289. data/vendor/libgit2/src/hash/sha1dc/ubc_check.c +372 -0
  290. data/vendor/libgit2/src/hash/sha1dc/ubc_check.h +52 -0
  291. data/vendor/libgit2/src/hash.c +0 -1
  292. data/vendor/libgit2/src/hash.h +13 -6
  293. data/vendor/libgit2/src/hashsig.c +121 -126
  294. data/vendor/libgit2/src/ident.c +129 -0
  295. data/vendor/libgit2/src/idxmap.c +153 -0
  296. data/vendor/libgit2/src/idxmap.h +41 -0
  297. data/vendor/libgit2/src/ignore.c +362 -123
  298. data/vendor/libgit2/src/ignore.h +16 -4
  299. data/vendor/libgit2/src/index.c +2131 -692
  300. data/vendor/libgit2/src/index.h +138 -6
  301. data/vendor/libgit2/src/indexer.c +866 -266
  302. data/vendor/libgit2/src/indexer.h +16 -0
  303. data/vendor/libgit2/src/integer.h +106 -0
  304. data/vendor/libgit2/src/iterator.c +1888 -967
  305. data/vendor/libgit2/src/iterator.h +130 -67
  306. data/vendor/libgit2/src/khash.h +43 -29
  307. data/vendor/libgit2/src/mailmap.c +485 -0
  308. data/vendor/libgit2/src/mailmap.h +35 -0
  309. data/vendor/libgit2/src/map.h +1 -1
  310. data/vendor/libgit2/src/merge.c +1679 -479
  311. data/vendor/libgit2/src/merge.h +89 -22
  312. data/vendor/libgit2/src/merge_driver.c +426 -0
  313. data/vendor/libgit2/src/merge_driver.h +62 -0
  314. data/vendor/libgit2/src/merge_file.c +238 -101
  315. data/vendor/libgit2/src/message.c +4 -28
  316. data/vendor/libgit2/src/message.h +3 -1
  317. data/vendor/libgit2/src/mwindow.c +123 -15
  318. data/vendor/libgit2/src/mwindow.h +10 -1
  319. data/vendor/libgit2/src/netops.c +178 -499
  320. data/vendor/libgit2/src/netops.h +51 -27
  321. data/vendor/libgit2/src/notes.c +251 -94
  322. data/vendor/libgit2/src/notes.h +5 -2
  323. data/vendor/libgit2/src/object.c +253 -67
  324. data/vendor/libgit2/src/object.h +40 -2
  325. data/vendor/libgit2/src/object_api.c +30 -11
  326. data/vendor/libgit2/src/odb.c +765 -201
  327. data/vendor/libgit2/src/odb.h +40 -8
  328. data/vendor/libgit2/src/odb_loose.c +560 -346
  329. data/vendor/libgit2/src/odb_mempack.c +185 -0
  330. data/vendor/libgit2/src/odb_pack.c +117 -73
  331. data/vendor/libgit2/src/offmap.c +113 -0
  332. data/vendor/libgit2/src/offmap.h +32 -42
  333. data/vendor/libgit2/src/oid.c +45 -25
  334. data/vendor/libgit2/src/oid.h +26 -8
  335. data/vendor/libgit2/src/oidarray.c +34 -0
  336. data/vendor/libgit2/src/oidarray.h +20 -0
  337. data/vendor/libgit2/src/oidmap.c +125 -0
  338. data/vendor/libgit2/src/oidmap.h +30 -17
  339. data/vendor/libgit2/src/pack-objects.c +688 -265
  340. data/vendor/libgit2/src/pack-objects.h +27 -13
  341. data/vendor/libgit2/src/pack.c +418 -202
  342. data/vendor/libgit2/src/pack.h +25 -16
  343. data/vendor/libgit2/src/parse.c +124 -0
  344. data/vendor/libgit2/src/parse.h +61 -0
  345. data/vendor/libgit2/src/patch.c +223 -0
  346. data/vendor/libgit2/src/patch.h +68 -0
  347. data/vendor/libgit2/src/patch_generate.c +901 -0
  348. data/vendor/libgit2/src/patch_generate.h +69 -0
  349. data/vendor/libgit2/src/patch_parse.c +1136 -0
  350. data/vendor/libgit2/src/patch_parse.h +51 -0
  351. data/vendor/libgit2/src/path.c +1247 -241
  352. data/vendor/libgit2/src/path.h +353 -57
  353. data/vendor/libgit2/src/pathspec.c +586 -58
  354. data/vendor/libgit2/src/pathspec.h +37 -15
  355. data/vendor/libgit2/src/pool.c +134 -221
  356. data/vendor/libgit2/src/pool.h +38 -50
  357. data/vendor/libgit2/src/posix.c +76 -10
  358. data/vendor/libgit2/src/posix.h +74 -32
  359. data/vendor/libgit2/src/pqueue.c +79 -117
  360. data/vendor/libgit2/src/pqueue.h +38 -82
  361. data/vendor/libgit2/src/proxy.c +39 -0
  362. data/vendor/libgit2/src/proxy.h +17 -0
  363. data/vendor/libgit2/src/push.c +178 -279
  364. data/vendor/libgit2/src/push.h +93 -4
  365. data/vendor/libgit2/src/reader.c +265 -0
  366. data/vendor/libgit2/src/reader.h +107 -0
  367. data/vendor/libgit2/src/rebase.c +1364 -0
  368. data/vendor/libgit2/src/refdb.c +74 -19
  369. data/vendor/libgit2/src/refdb.h +16 -3
  370. data/vendor/libgit2/src/refdb_fs.c +1472 -603
  371. data/vendor/libgit2/src/refdb_fs.h +4 -0
  372. data/vendor/libgit2/src/reflog.c +40 -330
  373. data/vendor/libgit2/src/reflog.h +8 -2
  374. data/vendor/libgit2/src/refs.c +641 -225
  375. data/vendor/libgit2/src/refs.h +53 -6
  376. data/vendor/libgit2/src/refspec.c +175 -62
  377. data/vendor/libgit2/src/refspec.h +10 -25
  378. data/vendor/libgit2/src/remote.c +1741 -723
  379. data/vendor/libgit2/src/remote.h +17 -5
  380. data/vendor/libgit2/src/repository.c +1505 -421
  381. data/vendor/libgit2/src/repository.h +95 -15
  382. data/vendor/libgit2/src/reset.c +63 -26
  383. data/vendor/libgit2/src/revert.c +232 -0
  384. data/vendor/libgit2/src/revparse.c +94 -80
  385. data/vendor/libgit2/src/revwalk.c +427 -194
  386. data/vendor/libgit2/src/revwalk.h +14 -5
  387. data/vendor/libgit2/src/settings.c +290 -0
  388. data/vendor/libgit2/src/sha1_lookup.c +16 -159
  389. data/vendor/libgit2/src/sha1_lookup.h +5 -4
  390. data/vendor/libgit2/src/signature.c +138 -26
  391. data/vendor/libgit2/src/signature.h +5 -0
  392. data/vendor/libgit2/src/sortedcache.c +395 -0
  393. data/vendor/libgit2/src/sortedcache.h +180 -0
  394. data/vendor/libgit2/src/stash.c +629 -168
  395. data/vendor/libgit2/src/status.c +125 -75
  396. data/vendor/libgit2/src/status.h +4 -2
  397. data/vendor/libgit2/src/stdalloc.c +120 -0
  398. data/vendor/libgit2/src/stdalloc.h +17 -0
  399. data/vendor/libgit2/src/stream.h +86 -0
  400. data/vendor/libgit2/src/streams/mbedtls.c +483 -0
  401. data/vendor/libgit2/src/streams/mbedtls.h +23 -0
  402. data/vendor/libgit2/src/streams/openssl.c +789 -0
  403. data/vendor/libgit2/src/streams/openssl.h +23 -0
  404. data/vendor/libgit2/src/streams/registry.c +118 -0
  405. data/vendor/libgit2/src/streams/registry.h +19 -0
  406. data/vendor/libgit2/src/streams/socket.c +235 -0
  407. data/vendor/libgit2/src/streams/socket.h +23 -0
  408. data/vendor/libgit2/src/streams/stransport.c +323 -0
  409. data/vendor/libgit2/src/streams/stransport.h +21 -0
  410. data/vendor/libgit2/src/streams/tls.c +73 -0
  411. data/vendor/libgit2/src/streams/tls.h +31 -0
  412. data/vendor/libgit2/src/strmap.c +147 -0
  413. data/vendor/libgit2/src/strmap.h +46 -51
  414. data/vendor/libgit2/src/strnlen.h +24 -0
  415. data/vendor/libgit2/src/submodule.c +1633 -877
  416. data/vendor/libgit2/src/submodule.h +83 -21
  417. data/vendor/libgit2/src/sysdir.c +355 -0
  418. data/vendor/libgit2/src/sysdir.h +119 -0
  419. data/vendor/libgit2/src/tag.c +87 -62
  420. data/vendor/libgit2/src/tag.h +4 -1
  421. data/vendor/libgit2/src/thread-utils.c +3 -0
  422. data/vendor/libgit2/src/thread-utils.h +71 -35
  423. data/vendor/libgit2/src/trace.c +4 -4
  424. data/vendor/libgit2/src/trace.h +11 -3
  425. data/vendor/libgit2/src/trailer.c +416 -0
  426. data/vendor/libgit2/src/transaction.c +382 -0
  427. data/vendor/libgit2/src/transaction.h +14 -0
  428. data/vendor/libgit2/src/transport.c +133 -67
  429. data/vendor/libgit2/src/transports/auth.c +75 -0
  430. data/vendor/libgit2/src/transports/auth.h +64 -0
  431. data/vendor/libgit2/src/transports/auth_negotiate.c +277 -0
  432. data/vendor/libgit2/src/transports/auth_negotiate.h +27 -0
  433. data/vendor/libgit2/src/transports/cred.c +296 -68
  434. data/vendor/libgit2/src/transports/cred.h +16 -0
  435. data/vendor/libgit2/src/transports/cred_helpers.c +4 -0
  436. data/vendor/libgit2/src/transports/git.c +108 -90
  437. data/vendor/libgit2/src/transports/http.c +803 -258
  438. data/vendor/libgit2/src/transports/http.h +25 -0
  439. data/vendor/libgit2/src/transports/local.c +265 -169
  440. data/vendor/libgit2/src/transports/smart.c +255 -45
  441. data/vendor/libgit2/src/transports/smart.h +42 -22
  442. data/vendor/libgit2/src/transports/smart_pkt.c +250 -159
  443. data/vendor/libgit2/src/transports/smart_protocol.c +414 -196
  444. data/vendor/libgit2/src/transports/ssh.c +645 -236
  445. data/vendor/libgit2/src/transports/ssh.h +14 -0
  446. data/vendor/libgit2/src/transports/winhttp.c +809 -353
  447. data/vendor/libgit2/src/tree-cache.c +138 -52
  448. data/vendor/libgit2/src/tree-cache.h +14 -7
  449. data/vendor/libgit2/src/tree.c +620 -259
  450. data/vendor/libgit2/src/tree.h +12 -19
  451. data/vendor/libgit2/src/tsort.c +3 -2
  452. data/vendor/libgit2/src/unix/map.c +25 -7
  453. data/vendor/libgit2/src/unix/posix.h +77 -12
  454. data/vendor/libgit2/src/unix/pthread.h +56 -0
  455. data/vendor/libgit2/src/unix/realpath.c +12 -8
  456. data/vendor/libgit2/src/userdiff.h +208 -0
  457. data/vendor/libgit2/src/util.c +349 -165
  458. data/vendor/libgit2/src/util.h +167 -85
  459. data/vendor/libgit2/src/varint.c +43 -0
  460. data/vendor/libgit2/src/varint.h +17 -0
  461. data/vendor/libgit2/src/vector.c +156 -33
  462. data/vendor/libgit2/src/vector.h +41 -5
  463. data/vendor/libgit2/src/win32/dir.c +22 -42
  464. data/vendor/libgit2/src/win32/dir.h +7 -5
  465. data/vendor/libgit2/src/win32/error.c +6 -32
  466. data/vendor/libgit2/src/win32/error.h +4 -2
  467. data/vendor/libgit2/src/win32/findfile.c +62 -69
  468. data/vendor/libgit2/src/win32/findfile.h +5 -13
  469. data/vendor/libgit2/src/win32/git2.rc +44 -0
  470. data/vendor/libgit2/src/win32/map.c +39 -11
  471. data/vendor/libgit2/src/win32/mingw-compat.h +10 -11
  472. data/vendor/libgit2/src/win32/msvc-compat.h +10 -33
  473. data/vendor/libgit2/src/win32/path_w32.c +476 -0
  474. data/vendor/libgit2/src/win32/path_w32.h +104 -0
  475. data/vendor/libgit2/src/win32/posix.h +35 -30
  476. data/vendor/libgit2/src/win32/posix_w32.c +659 -327
  477. data/vendor/libgit2/src/win32/precompiled.h +7 -2
  478. data/vendor/libgit2/src/win32/reparse.h +57 -0
  479. data/vendor/libgit2/src/win32/thread.c +258 -0
  480. data/vendor/libgit2/src/win32/thread.h +64 -0
  481. data/vendor/libgit2/src/win32/utf-conv.c +127 -62
  482. data/vendor/libgit2/src/win32/utf-conv.h +47 -6
  483. data/vendor/libgit2/src/win32/version.h +21 -4
  484. data/vendor/libgit2/src/win32/w32_buffer.c +54 -0
  485. data/vendor/libgit2/src/win32/w32_buffer.h +20 -0
  486. data/vendor/libgit2/src/win32/w32_crtdbg_stacktrace.c +438 -0
  487. data/vendor/libgit2/src/win32/w32_crtdbg_stacktrace.h +129 -0
  488. data/vendor/libgit2/src/win32/w32_stack.c +193 -0
  489. data/vendor/libgit2/src/win32/w32_stack.h +140 -0
  490. data/vendor/libgit2/src/win32/w32_util.c +95 -0
  491. data/vendor/libgit2/src/win32/w32_util.h +170 -0
  492. data/vendor/libgit2/src/win32/win32-compat.h +52 -0
  493. data/vendor/libgit2/src/worktree.c +578 -0
  494. data/vendor/libgit2/src/worktree.h +39 -0
  495. data/vendor/libgit2/src/xdiff/xdiff.h +33 -18
  496. data/vendor/libgit2/src/xdiff/xdiffi.c +578 -88
  497. data/vendor/libgit2/src/xdiff/xdiffi.h +3 -2
  498. data/vendor/libgit2/src/xdiff/xemit.c +106 -45
  499. data/vendor/libgit2/src/xdiff/xemit.h +3 -3
  500. data/vendor/libgit2/src/xdiff/xhistogram.c +5 -4
  501. data/vendor/libgit2/src/xdiff/xinclude.h +3 -2
  502. data/vendor/libgit2/src/xdiff/xmacros.h +2 -2
  503. data/vendor/libgit2/src/xdiff/xmerge.c +167 -48
  504. data/vendor/libgit2/src/xdiff/xpatience.c +42 -10
  505. data/vendor/libgit2/src/xdiff/xprepare.c +14 -14
  506. data/vendor/libgit2/src/xdiff/xprepare.h +2 -2
  507. data/vendor/libgit2/src/xdiff/xtypes.h +2 -2
  508. data/vendor/libgit2/src/xdiff/xutils.c +60 -56
  509. data/vendor/libgit2/src/xdiff/xutils.h +3 -5
  510. data/vendor/libgit2/src/zstream.c +205 -0
  511. data/vendor/libgit2/src/zstream.h +53 -0
  512. metadata +281 -233
  513. data/Rakefile +0 -61
  514. data/ext/rugged/rugged_diff_patch.c +0 -169
  515. data/lib/rugged/diff/patch.rb +0 -28
  516. data/test/blob_test.rb +0 -341
  517. data/test/branch_test.rb +0 -199
  518. data/test/commit_test.rb +0 -104
  519. data/test/config_test.rb +0 -45
  520. data/test/coverage/cover.rb +0 -133
  521. data/test/diff_test.rb +0 -777
  522. data/test/errors_test.rb +0 -34
  523. data/test/fixtures/alternate/objects/14/6ae76773c91e3b1d00cf7a338ec55ae58297e2 +0 -0
  524. data/test/fixtures/alternate/objects/14/9c32d47e99d0a3572ff1e70a2e0051bbf347a9 +0 -0
  525. data/test/fixtures/alternate/objects/14/fb3108588f9421bf764041e5e3ac305eb6277f +0 -0
  526. data/test/fixtures/archive.tar.gz +0 -0
  527. data/test/fixtures/attr/attr0 +0 -1
  528. data/test/fixtures/attr/attr1 +0 -29
  529. data/test/fixtures/attr/attr2 +0 -21
  530. data/test/fixtures/attr/attr3 +0 -4
  531. data/test/fixtures/attr/binfile +0 -1
  532. data/test/fixtures/attr/dir/file +0 -0
  533. data/test/fixtures/attr/file +0 -1
  534. data/test/fixtures/attr/gitattributes +0 -29
  535. data/test/fixtures/attr/gitignore +0 -2
  536. data/test/fixtures/attr/ign +0 -1
  537. data/test/fixtures/attr/macro_bad +0 -1
  538. data/test/fixtures/attr/macro_test +0 -1
  539. data/test/fixtures/attr/root_test1 +0 -1
  540. data/test/fixtures/attr/root_test2 +0 -6
  541. data/test/fixtures/attr/root_test3 +0 -19
  542. data/test/fixtures/attr/root_test4.txt +0 -14
  543. data/test/fixtures/attr/sub/abc +0 -37
  544. data/test/fixtures/attr/sub/dir/file +0 -0
  545. data/test/fixtures/attr/sub/file +0 -1
  546. data/test/fixtures/attr/sub/ign/file +0 -1
  547. data/test/fixtures/attr/sub/ign/sub/file +0 -1
  548. data/test/fixtures/attr/sub/sub/dir +0 -0
  549. data/test/fixtures/attr/sub/sub/file +0 -1
  550. data/test/fixtures/attr/sub/sub/subsub.txt +0 -1
  551. data/test/fixtures/attr/sub/subdir_test1 +0 -2
  552. data/test/fixtures/attr/sub/subdir_test2.txt +0 -1
  553. data/test/fixtures/diff/another.txt +0 -38
  554. data/test/fixtures/diff/readme.txt +0 -36
  555. data/test/fixtures/mergedrepo/conflicts-one.txt +0 -5
  556. data/test/fixtures/mergedrepo/conflicts-two.txt +0 -5
  557. data/test/fixtures/mergedrepo/one.txt +0 -10
  558. data/test/fixtures/mergedrepo/two.txt +0 -12
  559. data/test/fixtures/status/current_file +0 -1
  560. data/test/fixtures/status/ignored_file +0 -1
  561. data/test/fixtures/status/modified_file +0 -2
  562. data/test/fixtures/status/new_file +0 -1
  563. data/test/fixtures/status/staged_changes +0 -2
  564. data/test/fixtures/status/staged_changes_modified_file +0 -3
  565. data/test/fixtures/status/staged_delete_modified_file +0 -1
  566. data/test/fixtures/status/staged_new_file +0 -1
  567. data/test/fixtures/status/staged_new_file_modified_file +0 -2
  568. data/test/fixtures/status/subdir/current_file +0 -1
  569. data/test/fixtures/status/subdir/modified_file +0 -2
  570. data/test/fixtures/status/subdir/new_file +0 -1
  571. data/test/fixtures/status/subdir.txt +0 -2
  572. data/test/fixtures/status//350/277/231 +0 -1
  573. data/test/fixtures/testrepo.git/HEAD +0 -1
  574. data/test/fixtures/testrepo.git/config +0 -13
  575. data/test/fixtures/testrepo.git/description +0 -1
  576. data/test/fixtures/testrepo.git/index +0 -0
  577. data/test/fixtures/testrepo.git/info/exclude +0 -6
  578. data/test/fixtures/testrepo.git/logs/HEAD +0 -3
  579. data/test/fixtures/testrepo.git/logs/refs/heads/master +0 -3
  580. data/test/fixtures/testrepo.git/logs/refs/notes/commits +0 -1
  581. data/test/fixtures/testrepo.git/objects/0c/37a5391bbff43c37f0d0371823a5509eed5b1d +0 -0
  582. data/test/fixtures/testrepo.git/objects/13/85f264afb75a56a5bec74243be9b367ba4ca08 +0 -0
  583. data/test/fixtures/testrepo.git/objects/18/1037049a54a1eb5fab404658a3a250b44335d7 +0 -0
  584. data/test/fixtures/testrepo.git/objects/18/10dff58d8a660512d4832e740f692884338ccd +0 -0
  585. data/test/fixtures/testrepo.git/objects/2d/2eff63372b08adf0a9eb84109ccf7d19e2f3a2 +0 -0
  586. data/test/fixtures/testrepo.git/objects/36/060c58702ed4c2a40832c51758d5344201d89a +0 -2
  587. data/test/fixtures/testrepo.git/objects/44/1034f860c1d5d90e4188d11ae0d325176869a8 +0 -1
  588. data/test/fixtures/testrepo.git/objects/45/b983be36b73c0788dc9cbcb76cbb80fc7bb057 +0 -0
  589. data/test/fixtures/testrepo.git/objects/4a/202b346bb0fb0db7eff3cffeb3c70babbd2045 +0 -2
  590. data/test/fixtures/testrepo.git/objects/5b/5b025afb0b4c913b4c338a42934a3863bf3644 +0 -2
  591. data/test/fixtures/testrepo.git/objects/60/d415052a33de2150bf68757f6461df4f563ae4 +0 -0
  592. data/test/fixtures/testrepo.git/objects/61/9f9935957e010c419cb9d15621916ddfcc0b96 +0 -0
  593. data/test/fixtures/testrepo.git/objects/68/8a8f4ef7496901d15322972f96e212a9e466cc +0 -1
  594. data/test/fixtures/testrepo.git/objects/75/057dd4114e74cca1d750d0aee1647c903cb60a +0 -0
  595. data/test/fixtures/testrepo.git/objects/77/71329dfa3002caf8c61a0ceb62a31d09023f37 +0 -0
  596. data/test/fixtures/testrepo.git/objects/81/4889a078c031f61ed08ab5fa863aea9314344d +0 -0
  597. data/test/fixtures/testrepo.git/objects/84/96071c1b46c854b31185ea97743be6a8774479 +0 -0
  598. data/test/fixtures/testrepo.git/objects/94/eca2de348d5f672faf56b0decafa5937e3235e +0 -0
  599. data/test/fixtures/testrepo.git/objects/9b/7384fe1676186192842f5d3e129457b62db9e3 +0 -0
  600. data/test/fixtures/testrepo.git/objects/9f/d738e8f7967c078dceed8190330fc8648ee56a +0 -3
  601. data/test/fixtures/testrepo.git/objects/a4/a7dce85cf63874e984719f4fdd239f5145052f +0 -2
  602. data/test/fixtures/testrepo.git/objects/a7/1586c1dfe8a71c6cbf6c129f404c5642ff31bd +0 -0
  603. data/test/fixtures/testrepo.git/objects/a8/233120f6ad708f843d861ce2b7228ec4e3dec6 +0 -0
  604. data/test/fixtures/testrepo.git/objects/b7/4713326bc972cc15751ed504dca6f6f3b91f7a +0 -3
  605. data/test/fixtures/testrepo.git/objects/be/3563ae3f795b2b4353bcce3a527ad0a4f7f644 +0 -3
  606. data/test/fixtures/testrepo.git/objects/c4/7800c7266a2be04c571c04d5a6614691ea99bd +0 -3
  607. data/test/fixtures/testrepo.git/objects/c4/dc1555e4d4fa0e0c9c3fc46734c7c35b3ce90b +0 -0
  608. data/test/fixtures/testrepo.git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 +0 -0
  609. data/test/fixtures/testrepo.git/objects/f6/0079018b664e4e79329a7ef9559c8d9e0378d1 +0 -0
  610. data/test/fixtures/testrepo.git/objects/fa/49b077972391ad58037050f2a75f74e3671e92 +0 -0
  611. data/test/fixtures/testrepo.git/objects/fd/093bff70906175335656e6ce6ae05783708765 +0 -0
  612. data/test/fixtures/testrepo.git/objects/pack/pack-d7c6adf9f61318f041845b01440d09aa7a91e1b5.idx +0 -0
  613. data/test/fixtures/testrepo.git/objects/pack/pack-d7c6adf9f61318f041845b01440d09aa7a91e1b5.pack +0 -0
  614. data/test/fixtures/testrepo.git/packed-refs +0 -2
  615. data/test/fixtures/testrepo.git/refs/heads/master +0 -1
  616. data/test/fixtures/testrepo.git/refs/notes/commits +0 -1
  617. data/test/fixtures/testrepo.git/refs/tags/v0.9 +0 -1
  618. data/test/fixtures/testrepo.git/refs/tags/v1.0 +0 -1
  619. data/test/fixtures/text_file.md +0 -464
  620. data/test/fixtures/unsymlinked.git/HEAD +0 -1
  621. data/test/fixtures/unsymlinked.git/config +0 -6
  622. data/test/fixtures/unsymlinked.git/description +0 -1
  623. data/test/fixtures/unsymlinked.git/info/exclude +0 -2
  624. data/test/fixtures/unsymlinked.git/objects/08/8b64704e0d6b8bd061dea879418cb5442a3fbf +0 -0
  625. data/test/fixtures/unsymlinked.git/objects/13/a5e939bca25940c069fd2169d993dba328e30b +0 -0
  626. data/test/fixtures/unsymlinked.git/objects/19/bf568e59e3a0b363cafb4106226e62d4a4c41c +0 -0
  627. data/test/fixtures/unsymlinked.git/objects/58/1fadd35b4cf320d102a152f918729011604773 +0 -0
  628. data/test/fixtures/unsymlinked.git/objects/5c/87b6791e8b13da658a14d1ef7e09b5dc3bac8c +0 -0
  629. data/test/fixtures/unsymlinked.git/objects/6f/e5f5398af85fb3de8a6aba0339b6d3bfa26a27 +0 -0
  630. data/test/fixtures/unsymlinked.git/objects/7f/ccd75616ec188b8f1b23d67506a334cc34a49d +0 -0
  631. data/test/fixtures/unsymlinked.git/objects/80/6999882bf91d24241e4077906b9017605eb1f3 +0 -0
  632. data/test/fixtures/unsymlinked.git/objects/83/7d176303c5005505ec1e4a30231c40930c0230 +0 -0
  633. data/test/fixtures/unsymlinked.git/objects/a8/595ccca04f40818ae0155c8f9c77a230e597b6 +0 -2
  634. data/test/fixtures/unsymlinked.git/objects/cf/8f1cf5cce859c438d6cc067284cb5e161206e7 +0 -0
  635. data/test/fixtures/unsymlinked.git/objects/d5/278d05c8607ec420bfee4cf219fbc0eeebfd6a +0 -0
  636. data/test/fixtures/unsymlinked.git/objects/f4/e16fb76536591a41454194058d048d8e4dd2e9 +0 -0
  637. data/test/fixtures/unsymlinked.git/objects/f9/e65619d93fdf2673882e0a261c5e93b1a84006 +0 -0
  638. data/test/fixtures/unsymlinked.git/refs/heads/exe-file +0 -1
  639. data/test/fixtures/unsymlinked.git/refs/heads/master +0 -1
  640. data/test/fixtures/unsymlinked.git/refs/heads/reg-file +0 -1
  641. data/test/index_test.rb +0 -333
  642. data/test/lib_test.rb +0 -127
  643. data/test/note_test.rb +0 -158
  644. data/test/object_test.rb +0 -43
  645. data/test/reference_test.rb +0 -207
  646. data/test/remote_test.rb +0 -324
  647. data/test/repo_pack_test.rb +0 -24
  648. data/test/repo_reset_test.rb +0 -82
  649. data/test/repo_test.rb +0 -402
  650. data/test/tag_test.rb +0 -68
  651. data/test/test_helper.rb +0 -92
  652. data/test/tree_test.rb +0 -91
  653. data/test/walker_test.rb +0 -88
  654. data/vendor/libgit2/Makefile.embed +0 -42
  655. data/vendor/libgit2/include/git2/push.h +0 -131
  656. data/vendor/libgit2/include/git2/threads.h +0 -50
  657. data/vendor/libgit2/src/amiga/map.c +0 -48
  658. data/vendor/libgit2/src/bswap.h +0 -97
  659. data/vendor/libgit2/src/compress.c +0 -53
  660. data/vendor/libgit2/src/config_file.h +0 -60
  661. data/vendor/libgit2/src/delta-apply.c +0 -134
  662. data/vendor/libgit2/src/delta-apply.h +0 -50
  663. data/vendor/libgit2/src/diff_patch.c +0 -995
  664. data/vendor/libgit2/src/diff_patch.h +0 -46
  665. data/vendor/libgit2/src/hashsig.h +0 -72
  666. data/vendor/libgit2/src/merge_file.h +0 -71
  667. data/vendor/libgit2/src/win32/pthread.c +0 -144
  668. data/vendor/libgit2/src/win32/pthread.h +0 -50
@@ -5,17 +5,21 @@
5
5
  * a Linking Exception. For full terms see the included COPYING file.
6
6
  */
7
7
 
8
+ #include "index.h"
9
+
8
10
  #include <stddef.h>
9
11
 
10
- #include "common.h"
11
12
  #include "repository.h"
12
- #include "index.h"
13
13
  #include "tree.h"
14
14
  #include "tree-cache.h"
15
15
  #include "hash.h"
16
16
  #include "iterator.h"
17
17
  #include "pathspec.h"
18
18
  #include "ignore.h"
19
+ #include "blob.h"
20
+ #include "idxmap.h"
21
+ #include "diff.h"
22
+ #include "varint.h"
19
23
 
20
24
  #include "git2/odb.h"
21
25
  #include "git2/oid.h"
@@ -23,17 +27,43 @@
23
27
  #include "git2/config.h"
24
28
  #include "git2/sys/index.h"
25
29
 
26
- #define entry_size(type,len) ((offsetof(type, path) + (len) + 8) & ~7)
27
- #define short_entry_size(len) entry_size(struct entry_short, len)
28
- #define long_entry_size(len) entry_size(struct entry_long, len)
30
+ #define INSERT_IN_MAP_EX(idx, map, e, err) do { \
31
+ if ((idx)->ignore_case) \
32
+ git_idxmap_icase_insert((git_idxmap_icase *) (map), (e), (e), (err)); \
33
+ else \
34
+ git_idxmap_insert((map), (e), (e), (err)); \
35
+ } while (0)
36
+
37
+ #define INSERT_IN_MAP(idx, e, err) INSERT_IN_MAP_EX(idx, (idx)->entries_map, e, err)
38
+
39
+ #define LOOKUP_IN_MAP(p, idx, k) do { \
40
+ if ((idx)->ignore_case) \
41
+ (p) = git_idxmap_icase_lookup_index((git_idxmap_icase *) index->entries_map, (k)); \
42
+ else \
43
+ (p) = git_idxmap_lookup_index(index->entries_map, (k)); \
44
+ } while (0)
45
+
46
+ #define DELETE_IN_MAP(idx, e) do { \
47
+ if ((idx)->ignore_case) \
48
+ git_idxmap_icase_delete((git_idxmap_icase *) (idx)->entries_map, (e)); \
49
+ else \
50
+ git_idxmap_delete((idx)->entries_map, (e)); \
51
+ } while (0)
52
+
53
+ static int index_apply_to_wd_diff(git_index *index, int action, const git_strarray *paths,
54
+ unsigned int flags,
55
+ git_index_matched_path_cb cb, void *payload);
29
56
 
30
57
  #define minimal_entry_size (offsetof(struct entry_short, path))
31
58
 
32
59
  static const size_t INDEX_FOOTER_SIZE = GIT_OID_RAWSZ;
33
60
  static const size_t INDEX_HEADER_SIZE = 12;
34
61
 
35
- static const unsigned int INDEX_VERSION_NUMBER = 2;
62
+ static const unsigned int INDEX_VERSION_NUMBER_DEFAULT = 2;
63
+ static const unsigned int INDEX_VERSION_NUMBER_LB = 2;
36
64
  static const unsigned int INDEX_VERSION_NUMBER_EXT = 3;
65
+ static const unsigned int INDEX_VERSION_NUMBER_COMP = 4;
66
+ static const unsigned int INDEX_VERSION_NUMBER_UB = 4;
37
67
 
38
68
  static const unsigned int INDEX_HEADER_SIG = 0x44495243;
39
69
  static const char INDEX_EXT_TREECACHE_SIG[] = {'T', 'R', 'E', 'E'};
@@ -89,76 +119,101 @@ struct entry_long {
89
119
 
90
120
  struct entry_srch_key {
91
121
  const char *path;
122
+ size_t pathlen;
92
123
  int stage;
93
124
  };
94
125
 
126
+ struct entry_internal {
127
+ git_index_entry entry;
128
+ size_t pathlen;
129
+ char path[GIT_FLEX_ARRAY];
130
+ };
131
+
132
+ struct reuc_entry_internal {
133
+ git_index_reuc_entry entry;
134
+ size_t pathlen;
135
+ char path[GIT_FLEX_ARRAY];
136
+ };
137
+
138
+ bool git_index__enforce_unsaved_safety = false;
139
+
95
140
  /* local declarations */
96
- static size_t read_extension(git_index *index, const char *buffer, size_t buffer_size);
97
- static size_t read_entry(git_index_entry *dest, const void *buffer, size_t buffer_size);
141
+ static int read_extension(size_t *read_len, git_index *index, const char *buffer, size_t buffer_size);
98
142
  static int read_header(struct index_header *dest, const void *buffer);
99
143
 
100
144
  static int parse_index(git_index *index, const char *buffer, size_t buffer_size);
101
145
  static bool is_index_extended(git_index *index);
102
- static int write_index(git_index *index, git_filebuf *file);
103
-
104
- static int index_find(size_t *at_pos, git_index *index, const char *path, int stage);
146
+ static int write_index(git_oid *checksum, git_index *index, git_filebuf *file);
105
147
 
106
148
  static void index_entry_free(git_index_entry *entry);
107
149
  static void index_entry_reuc_free(git_index_reuc_entry *reuc);
108
150
 
109
- static int index_srch(const void *key, const void *array_member)
151
+ int git_index_entry_srch(const void *key, const void *array_member)
110
152
  {
111
153
  const struct entry_srch_key *srch_key = key;
112
- const git_index_entry *entry = array_member;
113
- int ret;
114
-
115
- ret = strcmp(srch_key->path, entry->path);
154
+ const struct entry_internal *entry = array_member;
155
+ int cmp;
156
+ size_t len1, len2, len;
157
+
158
+ len1 = srch_key->pathlen;
159
+ len2 = entry->pathlen;
160
+ len = len1 < len2 ? len1 : len2;
161
+
162
+ cmp = memcmp(srch_key->path, entry->path, len);
163
+ if (cmp)
164
+ return cmp;
165
+ if (len1 < len2)
166
+ return -1;
167
+ if (len1 > len2)
168
+ return 1;
116
169
 
117
- if (ret == 0)
118
- ret = srch_key->stage - GIT_IDXENTRY_STAGE(entry);
170
+ if (srch_key->stage != GIT_INDEX_STAGE_ANY)
171
+ return srch_key->stage - GIT_INDEX_ENTRY_STAGE(&entry->entry);
119
172
 
120
- return ret;
173
+ return 0;
121
174
  }
122
175
 
123
- static int index_isrch(const void *key, const void *array_member)
176
+ int git_index_entry_isrch(const void *key, const void *array_member)
124
177
  {
125
178
  const struct entry_srch_key *srch_key = key;
126
- const git_index_entry *entry = array_member;
127
- int ret;
179
+ const struct entry_internal *entry = array_member;
180
+ int cmp;
181
+ size_t len1, len2, len;
128
182
 
129
- ret = strcasecmp(srch_key->path, entry->path);
183
+ len1 = srch_key->pathlen;
184
+ len2 = entry->pathlen;
185
+ len = len1 < len2 ? len1 : len2;
130
186
 
131
- if (ret == 0)
132
- ret = srch_key->stage - GIT_IDXENTRY_STAGE(entry);
187
+ cmp = strncasecmp(srch_key->path, entry->path, len);
133
188
 
134
- return ret;
135
- }
189
+ if (cmp)
190
+ return cmp;
191
+ if (len1 < len2)
192
+ return -1;
193
+ if (len1 > len2)
194
+ return 1;
136
195
 
137
- static int index_cmp_path(const void *a, const void *b)
138
- {
139
- return strcmp((const char *)a, (const char *)b);
140
- }
196
+ if (srch_key->stage != GIT_INDEX_STAGE_ANY)
197
+ return srch_key->stage - GIT_INDEX_ENTRY_STAGE(&entry->entry);
141
198
 
142
- static int index_icmp_path(const void *a, const void *b)
143
- {
144
- return strcasecmp((const char *)a, (const char *)b);
199
+ return 0;
145
200
  }
146
201
 
147
- static int index_srch_path(const void *path, const void *array_member)
202
+ static int index_entry_srch_path(const void *path, const void *array_member)
148
203
  {
149
204
  const git_index_entry *entry = array_member;
150
205
 
151
206
  return strcmp((const char *)path, entry->path);
152
207
  }
153
208
 
154
- static int index_isrch_path(const void *path, const void *array_member)
209
+ static int index_entry_isrch_path(const void *path, const void *array_member)
155
210
  {
156
211
  const git_index_entry *entry = array_member;
157
212
 
158
213
  return strcasecmp((const char *)path, entry->path);
159
214
  }
160
215
 
161
- static int index_cmp(const void *a, const void *b)
216
+ int git_index_entry_cmp(const void *a, const void *b)
162
217
  {
163
218
  int diff;
164
219
  const git_index_entry *entry_a = a;
@@ -167,12 +222,12 @@ static int index_cmp(const void *a, const void *b)
167
222
  diff = strcmp(entry_a->path, entry_b->path);
168
223
 
169
224
  if (diff == 0)
170
- diff = (GIT_IDXENTRY_STAGE(entry_a) - GIT_IDXENTRY_STAGE(entry_b));
225
+ diff = (GIT_INDEX_ENTRY_STAGE(entry_a) - GIT_INDEX_ENTRY_STAGE(entry_b));
171
226
 
172
227
  return diff;
173
228
  }
174
229
 
175
- static int index_icmp(const void *a, const void *b)
230
+ int git_index_entry_icmp(const void *a, const void *b)
176
231
  {
177
232
  int diff;
178
233
  const git_index_entry *entry_a = a;
@@ -181,7 +236,7 @@ static int index_icmp(const void *a, const void *b)
181
236
  diff = strcasecmp(entry_a->path, entry_b->path);
182
237
 
183
238
  if (diff == 0)
184
- diff = (GIT_IDXENTRY_STAGE(entry_a) - GIT_IDXENTRY_STAGE(entry_b));
239
+ diff = (GIT_INDEX_ENTRY_STAGE(entry_a) - GIT_INDEX_ENTRY_STAGE(entry_b));
185
240
 
186
241
  return diff;
187
242
  }
@@ -261,7 +316,21 @@ static int reuc_icmp(const void *a, const void *b)
261
316
  return strcasecmp(info_a->path, info_b->path);
262
317
  }
263
318
 
264
- static unsigned int index_create_mode(unsigned int mode)
319
+ static void index_entry_reuc_free(git_index_reuc_entry *reuc)
320
+ {
321
+ git__free(reuc);
322
+ }
323
+
324
+ static void index_entry_free(git_index_entry *entry)
325
+ {
326
+ if (!entry)
327
+ return;
328
+
329
+ memset(&entry->id, 0, sizeof(entry->id));
330
+ git__free(entry);
331
+ }
332
+
333
+ unsigned int git_index__create_mode(unsigned int mode)
265
334
  {
266
335
  if (S_ISLNK(mode))
267
336
  return S_IFLNK;
@@ -269,7 +338,7 @@ static unsigned int index_create_mode(unsigned int mode)
269
338
  if (S_ISDIR(mode) || (mode & S_IFMT) == (S_IFLNK | S_IFDIR))
270
339
  return (S_IFLNK | S_IFDIR);
271
340
 
272
- return S_IFREG | ((mode & 0100) ? 0755 : 0644);
341
+ return S_IFREG | GIT_PERMS_CANONICAL(mode);
273
342
  }
274
343
 
275
344
  static unsigned int index_merge_mode(
@@ -281,24 +350,52 @@ static unsigned int index_merge_mode(
281
350
 
282
351
  if (index->distrust_filemode && S_ISREG(mode))
283
352
  return (existing && S_ISREG(existing->mode)) ?
284
- existing->mode : index_create_mode(0666);
353
+ existing->mode : git_index__create_mode(0666);
354
+
355
+ return git_index__create_mode(mode);
356
+ }
357
+
358
+ GIT_INLINE(int) index_find_in_entries(
359
+ size_t *out, git_vector *entries, git_vector_cmp entry_srch,
360
+ const char *path, size_t path_len, int stage)
361
+ {
362
+ struct entry_srch_key srch_key;
363
+ srch_key.path = path;
364
+ srch_key.pathlen = !path_len ? strlen(path) : path_len;
365
+ srch_key.stage = stage;
366
+ return git_vector_bsearch2(out, entries, entry_srch, &srch_key);
367
+ }
285
368
 
286
- return index_create_mode(mode);
369
+ GIT_INLINE(int) index_find(
370
+ size_t *out, git_index *index,
371
+ const char *path, size_t path_len, int stage)
372
+ {
373
+ git_vector_sort(&index->entries);
374
+
375
+ return index_find_in_entries(
376
+ out, &index->entries, index->entries_search, path, path_len, stage);
287
377
  }
288
378
 
289
379
  void git_index__set_ignore_case(git_index *index, bool ignore_case)
290
380
  {
291
381
  index->ignore_case = ignore_case;
292
382
 
293
- index->entries_cmp_path = ignore_case ? index_icmp_path : index_cmp_path;
294
- index->entries_search = ignore_case ? index_isrch : index_srch;
295
- index->entries_search_path = ignore_case ? index_isrch_path : index_srch_path;
383
+ if (ignore_case) {
384
+ index->entries_cmp_path = git__strcasecmp_cb;
385
+ index->entries_search = git_index_entry_isrch;
386
+ index->entries_search_path = index_entry_isrch_path;
387
+ index->reuc_search = reuc_isrch;
388
+ } else {
389
+ index->entries_cmp_path = git__strcmp_cb;
390
+ index->entries_search = git_index_entry_srch;
391
+ index->entries_search_path = index_entry_srch_path;
392
+ index->reuc_search = reuc_srch;
393
+ }
296
394
 
297
- git_vector_set_cmp(&index->entries, ignore_case ? index_icmp : index_cmp);
395
+ git_vector_set_cmp(&index->entries,
396
+ ignore_case ? git_index_entry_icmp : git_index_entry_cmp);
298
397
  git_vector_sort(&index->entries);
299
398
 
300
- index->reuc_search = ignore_case ? reuc_isrch : reuc_srch;
301
-
302
399
  git_vector_set_cmp(&index->reuc, ignore_case ? reuc_icmp : reuc_cmp);
303
400
  git_vector_sort(&index->reuc);
304
401
  }
@@ -306,35 +403,50 @@ void git_index__set_ignore_case(git_index *index, bool ignore_case)
306
403
  int git_index_open(git_index **index_out, const char *index_path)
307
404
  {
308
405
  git_index *index;
406
+ int error = -1;
309
407
 
310
408
  assert(index_out);
311
409
 
312
410
  index = git__calloc(1, sizeof(git_index));
313
- GITERR_CHECK_ALLOC(index);
411
+ GIT_ERROR_CHECK_ALLOC(index);
412
+
413
+ git_pool_init(&index->tree_pool, 1);
314
414
 
315
415
  if (index_path != NULL) {
316
416
  index->index_file_path = git__strdup(index_path);
317
- GITERR_CHECK_ALLOC(index->index_file_path);
417
+ if (!index->index_file_path)
418
+ goto fail;
318
419
 
319
420
  /* Check if index file is stored on disk already */
320
421
  if (git_path_exists(index->index_file_path) == true)
321
422
  index->on_disk = 1;
322
423
  }
323
424
 
324
- if (git_vector_init(&index->entries, 32, index_cmp) < 0 ||
325
- git_vector_init(&index->names, 32, conflict_name_cmp) < 0 ||
326
- git_vector_init(&index->reuc, 32, reuc_cmp) < 0)
327
- return -1;
425
+ if (git_vector_init(&index->entries, 32, git_index_entry_cmp) < 0 ||
426
+ git_idxmap_alloc(&index->entries_map) < 0 ||
427
+ git_vector_init(&index->names, 8, conflict_name_cmp) < 0 ||
428
+ git_vector_init(&index->reuc, 8, reuc_cmp) < 0 ||
429
+ git_vector_init(&index->deleted, 8, git_index_entry_cmp) < 0)
430
+ goto fail;
328
431
 
329
- index->entries_cmp_path = index_cmp_path;
330
- index->entries_search = index_srch;
331
- index->entries_search_path = index_srch_path;
432
+ index->entries_cmp_path = git__strcmp_cb;
433
+ index->entries_search = git_index_entry_srch;
434
+ index->entries_search_path = index_entry_srch_path;
332
435
  index->reuc_search = reuc_srch;
436
+ index->version = INDEX_VERSION_NUMBER_DEFAULT;
437
+
438
+ if (index_path != NULL && (error = git_index_read(index, true)) < 0)
439
+ goto fail;
333
440
 
334
441
  *index_out = index;
335
442
  GIT_REFCOUNT_INC(index);
336
443
 
337
- return (index_path != NULL) ? git_index_read(index) : 0;
444
+ return 0;
445
+
446
+ fail:
447
+ git_pool_clear(&index->tree_pool);
448
+ git_index_free(index);
449
+ return error;
338
450
  }
339
451
 
340
452
  int git_index_new(git_index **out)
@@ -344,10 +456,17 @@ int git_index_new(git_index **out)
344
456
 
345
457
  static void index_free(git_index *index)
346
458
  {
459
+ /* index iterators increment the refcount of the index, so if we
460
+ * get here then there should be no outstanding iterators.
461
+ */
462
+ assert(!git_atomic_get(&index->readers));
463
+
347
464
  git_index_clear(index);
465
+ git_idxmap_free(index->entries_map);
348
466
  git_vector_free(&index->entries);
349
467
  git_vector_free(&index->names);
350
468
  git_vector_free(&index->reuc);
469
+ git_vector_free(&index->deleted);
351
470
 
352
471
  git__free(index->index_file_path);
353
472
 
@@ -363,54 +482,93 @@ void git_index_free(git_index *index)
363
482
  GIT_REFCOUNT_DEC(index, index_free);
364
483
  }
365
484
 
366
- static void index_entries_free(git_vector *entries)
485
+ /* call with locked index */
486
+ static void index_free_deleted(git_index *index)
367
487
  {
488
+ int readers = (int)git_atomic_get(&index->readers);
368
489
  size_t i;
369
490
 
370
- for (i = 0; i < entries->length; ++i) {
371
- git_index_entry *e = git_vector_get(entries, i);
372
- git__free(e->path);
373
- git__free(e);
491
+ if (readers > 0 || !index->deleted.length)
492
+ return;
493
+
494
+ for (i = 0; i < index->deleted.length; ++i) {
495
+ git_index_entry *ie = git__swap(index->deleted.contents[i], NULL);
496
+ index_entry_free(ie);
374
497
  }
375
498
 
376
- git_vector_clear(entries);
499
+ git_vector_clear(&index->deleted);
377
500
  }
378
501
 
379
- void git_index_clear(git_index *index)
502
+ /* call with locked index */
503
+ static int index_remove_entry(git_index *index, size_t pos)
380
504
  {
505
+ int error = 0;
506
+ git_index_entry *entry = git_vector_get(&index->entries, pos);
507
+
508
+ if (entry != NULL) {
509
+ git_tree_cache_invalidate_path(index->tree, entry->path);
510
+ DELETE_IN_MAP(index, entry);
511
+ }
512
+
513
+ error = git_vector_remove(&index->entries, pos);
514
+
515
+ if (!error) {
516
+ if (git_atomic_get(&index->readers) > 0) {
517
+ error = git_vector_insert(&index->deleted, entry);
518
+ } else {
519
+ index_entry_free(entry);
520
+ }
521
+
522
+ index->dirty = 1;
523
+ }
524
+
525
+ return error;
526
+ }
527
+
528
+ int git_index_clear(git_index *index)
529
+ {
530
+ int error = 0;
531
+
381
532
  assert(index);
382
533
 
383
- index_entries_free(&index->entries);
534
+ index->dirty = 1;
535
+ index->tree = NULL;
536
+ git_pool_clear(&index->tree_pool);
537
+
538
+ git_idxmap_clear(index->entries_map);
539
+ while (!error && index->entries.length > 0)
540
+ error = index_remove_entry(index, index->entries.length - 1);
541
+ index_free_deleted(index);
542
+
384
543
  git_index_reuc_clear(index);
385
544
  git_index_name_clear(index);
386
545
 
387
546
  git_futils_filestamp_set(&index->stamp, NULL);
388
547
 
389
- git_tree_cache_free(index->tree);
390
- index->tree = NULL;
548
+ return error;
391
549
  }
392
550
 
393
551
  static int create_index_error(int error, const char *msg)
394
552
  {
395
- giterr_set(GITERR_INDEX, msg);
553
+ git_error_set_str(GIT_ERROR_INDEX, msg);
396
554
  return error;
397
555
  }
398
556
 
399
- int git_index_set_caps(git_index *index, unsigned int caps)
557
+ int git_index_set_caps(git_index *index, int caps)
400
558
  {
401
- int old_ignore_case;
559
+ unsigned int old_ignore_case;
402
560
 
403
561
  assert(index);
404
562
 
405
563
  old_ignore_case = index->ignore_case;
406
564
 
407
- if (caps == GIT_INDEXCAP_FROM_OWNER) {
565
+ if (caps == GIT_INDEX_CAPABILITY_FROM_OWNER) {
408
566
  git_repository *repo = INDEX_OWNER(index);
409
567
  int val;
410
568
 
411
569
  if (!repo)
412
570
  return create_index_error(
413
- -1, "Cannot access repository to set index caps");
571
+ -1, "cannot access repository to set index caps");
414
572
 
415
573
  if (!git_repository__cvar(&val, repo, GIT_CVAR_IGNORECASE))
416
574
  index->ignore_case = (val != 0);
@@ -420,91 +578,240 @@ int git_index_set_caps(git_index *index, unsigned int caps)
420
578
  index->no_symlinks = (val == 0);
421
579
  }
422
580
  else {
423
- index->ignore_case = ((caps & GIT_INDEXCAP_IGNORE_CASE) != 0);
424
- index->distrust_filemode = ((caps & GIT_INDEXCAP_NO_FILEMODE) != 0);
425
- index->no_symlinks = ((caps & GIT_INDEXCAP_NO_SYMLINKS) != 0);
581
+ index->ignore_case = ((caps & GIT_INDEX_CAPABILITY_IGNORE_CASE) != 0);
582
+ index->distrust_filemode = ((caps & GIT_INDEX_CAPABILITY_NO_FILEMODE) != 0);
583
+ index->no_symlinks = ((caps & GIT_INDEX_CAPABILITY_NO_SYMLINKS) != 0);
426
584
  }
427
585
 
428
586
  if (old_ignore_case != index->ignore_case) {
429
- git_index__set_ignore_case(index, index->ignore_case);
587
+ git_index__set_ignore_case(index, (bool)index->ignore_case);
430
588
  }
431
589
 
432
590
  return 0;
433
591
  }
434
592
 
435
- unsigned int git_index_caps(const git_index *index)
593
+ int git_index_caps(const git_index *index)
594
+ {
595
+ return ((index->ignore_case ? GIT_INDEX_CAPABILITY_IGNORE_CASE : 0) |
596
+ (index->distrust_filemode ? GIT_INDEX_CAPABILITY_NO_FILEMODE : 0) |
597
+ (index->no_symlinks ? GIT_INDEX_CAPABILITY_NO_SYMLINKS : 0));
598
+ }
599
+
600
+ const git_oid *git_index_checksum(git_index *index)
601
+ {
602
+ return &index->checksum;
603
+ }
604
+
605
+ /**
606
+ * Returns 1 for changed, 0 for not changed and <0 for errors
607
+ */
608
+ static int compare_checksum(git_index *index)
436
609
  {
437
- return ((index->ignore_case ? GIT_INDEXCAP_IGNORE_CASE : 0) |
438
- (index->distrust_filemode ? GIT_INDEXCAP_NO_FILEMODE : 0) |
439
- (index->no_symlinks ? GIT_INDEXCAP_NO_SYMLINKS : 0));
610
+ int fd;
611
+ ssize_t bytes_read;
612
+ git_oid checksum = {{ 0 }};
613
+
614
+ if ((fd = p_open(index->index_file_path, O_RDONLY)) < 0)
615
+ return fd;
616
+
617
+ if (p_lseek(fd, -20, SEEK_END) < 0) {
618
+ p_close(fd);
619
+ git_error_set(GIT_ERROR_OS, "failed to seek to end of file");
620
+ return -1;
621
+ }
622
+
623
+ bytes_read = p_read(fd, &checksum, GIT_OID_RAWSZ);
624
+ p_close(fd);
625
+
626
+ if (bytes_read < 0)
627
+ return -1;
628
+
629
+ return !!git_oid_cmp(&checksum, &index->checksum);
440
630
  }
441
631
 
442
- int git_index_read(git_index *index)
632
+ int git_index_read(git_index *index, int force)
443
633
  {
444
634
  int error = 0, updated;
445
635
  git_buf buffer = GIT_BUF_INIT;
446
- git_futils_filestamp stamp = {0};
636
+ git_futils_filestamp stamp = index->stamp;
447
637
 
448
638
  if (!index->index_file_path)
449
639
  return create_index_error(-1,
450
- "Failed to read index: The index is in-memory only");
640
+ "failed to read index: The index is in-memory only");
641
+
642
+ index->on_disk = git_path_exists(index->index_file_path);
643
+
644
+ if (!index->on_disk) {
645
+ if (force && (error = git_index_clear(index)) < 0)
646
+ return error;
451
647
 
452
- if (!index->on_disk || git_path_exists(index->index_file_path) == false) {
453
- git_index_clear(index);
454
- index->on_disk = 0;
648
+ index->dirty = 0;
455
649
  return 0;
456
650
  }
457
651
 
458
- updated = git_futils_filestamp_check(&stamp, index->index_file_path);
459
- if (updated <= 0)
652
+ if ((updated = git_futils_filestamp_check(&stamp, index->index_file_path) < 0) ||
653
+ ((updated = compare_checksum(index)) < 0)) {
654
+ git_error_set(
655
+ GIT_ERROR_INDEX,
656
+ "failed to read index: '%s' no longer exists",
657
+ index->index_file_path);
460
658
  return updated;
659
+ }
660
+
661
+ if (!updated && !force)
662
+ return 0;
461
663
 
462
664
  error = git_futils_readbuffer(&buffer, index->index_file_path);
463
665
  if (error < 0)
464
666
  return error;
465
667
 
466
- git_index_clear(index);
467
- error = parse_index(index, buffer.ptr, buffer.size);
668
+ index->tree = NULL;
669
+ git_pool_clear(&index->tree_pool);
670
+
671
+ error = git_index_clear(index);
468
672
 
469
673
  if (!error)
674
+ error = parse_index(index, buffer.ptr, buffer.size);
675
+
676
+ if (!error) {
470
677
  git_futils_filestamp_set(&index->stamp, &stamp);
678
+ index->dirty = 0;
679
+ }
471
680
 
472
- git_buf_free(&buffer);
681
+ git_buf_dispose(&buffer);
473
682
  return error;
474
683
  }
475
684
 
476
- int git_index_write(git_index *index)
685
+ int git_index_read_safely(git_index *index)
686
+ {
687
+ if (git_index__enforce_unsaved_safety && index->dirty) {
688
+ git_error_set(GIT_ERROR_INDEX,
689
+ "the index has unsaved changes that would be overwritten by this operation");
690
+ return GIT_EINDEXDIRTY;
691
+ }
692
+
693
+ return git_index_read(index, false);
694
+ }
695
+
696
+ int git_index__changed_relative_to(
697
+ git_index *index, const git_oid *checksum)
698
+ {
699
+ /* attempt to update index (ignoring errors) */
700
+ if (git_index_read(index, false) < 0)
701
+ git_error_clear();
702
+
703
+ return !!git_oid_cmp(&index->checksum, checksum);
704
+ }
705
+
706
+ static bool is_racy_entry(git_index *index, const git_index_entry *entry)
707
+ {
708
+ /* Git special-cases submodules in the check */
709
+ if (S_ISGITLINK(entry->mode))
710
+ return false;
711
+
712
+ return git_index_entry_newer_than_index(entry, index);
713
+ }
714
+
715
+ /*
716
+ * Force the next diff to take a look at those entries which have the
717
+ * same timestamp as the current index.
718
+ */
719
+ static int truncate_racily_clean(git_index *index)
477
720
  {
478
- git_filebuf file = GIT_FILEBUF_INIT;
721
+ size_t i;
479
722
  int error;
723
+ git_index_entry *entry;
724
+ git_diff_options diff_opts = GIT_DIFF_OPTIONS_INIT;
725
+ git_diff *diff = NULL;
726
+ git_vector paths = GIT_VECTOR_INIT;
727
+ git_diff_delta *delta;
480
728
 
481
- if (!index->index_file_path)
482
- return create_index_error(-1,
483
- "Failed to read index: The index is in-memory only");
729
+ /* Nothing to do if there's no repo to talk about */
730
+ if (!INDEX_OWNER(index))
731
+ return 0;
484
732
 
485
- git_vector_sort(&index->entries);
486
- git_vector_sort(&index->reuc);
733
+ /* If there's no workdir, we can't know where to even check */
734
+ if (!git_repository_workdir(INDEX_OWNER(index)))
735
+ return 0;
487
736
 
488
- if ((error = git_filebuf_open(
489
- &file, index->index_file_path, GIT_FILEBUF_HASH_CONTENTS)) < 0)
490
- return error;
737
+ diff_opts.flags |= GIT_DIFF_INCLUDE_TYPECHANGE | GIT_DIFF_IGNORE_SUBMODULES | GIT_DIFF_DISABLE_PATHSPEC_MATCH;
738
+ git_vector_foreach(&index->entries, i, entry) {
739
+ if ((entry->flags_extended & GIT_INDEX_ENTRY_UPTODATE) == 0 &&
740
+ is_racy_entry(index, entry))
741
+ git_vector_insert(&paths, (char *)entry->path);
742
+ }
743
+
744
+ if (paths.length == 0)
745
+ goto done;
491
746
 
492
- if ((error = write_index(index, &file)) < 0) {
493
- git_filebuf_cleanup(&file);
747
+ diff_opts.pathspec.count = paths.length;
748
+ diff_opts.pathspec.strings = (char **)paths.contents;
749
+
750
+ if ((error = git_diff_index_to_workdir(&diff, INDEX_OWNER(index), index, &diff_opts)) < 0)
494
751
  return error;
752
+
753
+ git_vector_foreach(&diff->deltas, i, delta) {
754
+ entry = (git_index_entry *)git_index_get_bypath(index, delta->old_file.path, 0);
755
+
756
+ /* Ensure that we have a stage 0 for this file (ie, it's not a
757
+ * conflict), otherwise smudging it is quite pointless.
758
+ */
759
+ if (entry) {
760
+ entry->file_size = 0;
761
+ index->dirty = 1;
762
+ }
495
763
  }
496
764
 
497
- if ((error = git_filebuf_commit(&file, GIT_INDEX_FILE_MODE)) < 0)
498
- return error;
765
+ done:
766
+ git_diff_free(diff);
767
+ git_vector_free(&paths);
768
+ return 0;
769
+ }
499
770
 
500
- error = git_futils_filestamp_check(&index->stamp, index->index_file_path);
501
- if (error < 0)
502
- return error;
771
+ unsigned git_index_version(git_index *index)
772
+ {
773
+ assert(index);
774
+
775
+ return index->version;
776
+ }
777
+
778
+ int git_index_set_version(git_index *index, unsigned int version)
779
+ {
780
+ assert(index);
781
+
782
+ if (version < INDEX_VERSION_NUMBER_LB ||
783
+ version > INDEX_VERSION_NUMBER_UB) {
784
+ git_error_set(GIT_ERROR_INDEX, "invalid version number");
785
+ return -1;
786
+ }
787
+
788
+ index->version = version;
503
789
 
504
- index->on_disk = 1;
505
790
  return 0;
506
791
  }
507
792
 
793
+ int git_index_write(git_index *index)
794
+ {
795
+ git_indexwriter writer = GIT_INDEXWRITER_INIT;
796
+ int error;
797
+
798
+ truncate_racily_clean(index);
799
+
800
+ if ((error = git_indexwriter_init(&writer, index)) == 0 &&
801
+ (error = git_indexwriter_commit(&writer)) == 0)
802
+ index->dirty = 0;
803
+
804
+ git_indexwriter_cleanup(&writer);
805
+
806
+ return error;
807
+ }
808
+
809
+ const char * git_index_path(const git_index *index)
810
+ {
811
+ assert(index);
812
+ return index->index_file_path;
813
+ }
814
+
508
815
  int git_index_write_tree(git_oid *oid, git_index *index)
509
816
  {
510
817
  git_repository *repo;
@@ -515,12 +822,13 @@ int git_index_write_tree(git_oid *oid, git_index *index)
515
822
 
516
823
  if (repo == NULL)
517
824
  return create_index_error(-1, "Failed to write tree. "
518
- "The index file is not backed up by an existing repository");
825
+ "the index file is not backed up by an existing repository");
519
826
 
520
827
  return git_tree__write_index(oid, index, repo);
521
828
  }
522
829
 
523
- int git_index_write_tree_to(git_oid *oid, git_index *index, git_repository *repo)
830
+ int git_index_write_tree_to(
831
+ git_oid *oid, git_index *index, git_repository *repo)
524
832
  {
525
833
  assert(oid && index && repo);
526
834
  return git_tree__write_index(oid, index, repo);
@@ -543,99 +851,172 @@ const git_index_entry *git_index_get_byindex(
543
851
  const git_index_entry *git_index_get_bypath(
544
852
  git_index *index, const char *path, int stage)
545
853
  {
854
+ git_index_entry key = {{ 0 }};
546
855
  size_t pos;
547
856
 
548
857
  assert(index);
549
858
 
550
- git_vector_sort(&index->entries);
859
+ key.path = path;
860
+ GIT_INDEX_ENTRY_STAGE_SET(&key, stage);
551
861
 
552
- if (index_find(&pos, index, path, stage) < 0) {
553
- giterr_set(GITERR_INDEX, "Index does not contain %s", path);
554
- return NULL;
555
- }
862
+ LOOKUP_IN_MAP(pos, index, &key);
863
+
864
+ if (git_idxmap_valid_index(index->entries_map, pos))
865
+ return git_idxmap_value_at(index->entries_map, pos);
556
866
 
557
- return git_index_get_byindex(index, pos);
867
+ git_error_set(GIT_ERROR_INDEX, "index does not contain '%s'", path);
868
+ return NULL;
558
869
  }
559
870
 
560
- void git_index_entry__init_from_stat(git_index_entry *entry, struct stat *st)
871
+ void git_index_entry__init_from_stat(
872
+ git_index_entry *entry, struct stat *st, bool trust_mode)
561
873
  {
562
- entry->ctime.seconds = (git_time_t)st->st_ctime;
563
- entry->mtime.seconds = (git_time_t)st->st_mtime;
564
- /* entry->mtime.nanoseconds = st->st_mtimensec; */
565
- /* entry->ctime.nanoseconds = st->st_ctimensec; */
874
+ entry->ctime.seconds = (int32_t)st->st_ctime;
875
+ entry->mtime.seconds = (int32_t)st->st_mtime;
876
+ #if defined(GIT_USE_NSEC)
877
+ entry->mtime.nanoseconds = st->st_mtime_nsec;
878
+ entry->ctime.nanoseconds = st->st_ctime_nsec;
879
+ #endif
566
880
  entry->dev = st->st_rdev;
567
881
  entry->ino = st->st_ino;
568
- entry->mode = index_create_mode(st->st_mode);
882
+ entry->mode = (!trust_mode && S_ISREG(st->st_mode)) ?
883
+ git_index__create_mode(0666) : git_index__create_mode(st->st_mode);
569
884
  entry->uid = st->st_uid;
570
885
  entry->gid = st->st_gid;
571
- entry->file_size = st->st_size;
886
+ entry->file_size = (uint32_t)st->st_size;
572
887
  }
573
888
 
574
- int git_index_entry__cmp(const void *a, const void *b)
889
+ static void index_entry_adjust_namemask(
890
+ git_index_entry *entry,
891
+ size_t path_length)
575
892
  {
576
- const git_index_entry *entry_a = a;
577
- const git_index_entry *entry_b = b;
893
+ entry->flags &= ~GIT_INDEX_ENTRY_NAMEMASK;
578
894
 
579
- return strcmp(entry_a->path, entry_b->path);
895
+ if (path_length < GIT_INDEX_ENTRY_NAMEMASK)
896
+ entry->flags |= path_length & GIT_INDEX_ENTRY_NAMEMASK;
897
+ else
898
+ entry->flags |= GIT_INDEX_ENTRY_NAMEMASK;
580
899
  }
581
900
 
582
- int git_index_entry__cmp_icase(const void *a, const void *b)
901
+ /* When `from_workdir` is true, we will validate the paths to avoid placing
902
+ * paths that are invalid for the working directory on the current filesystem
903
+ * (eg, on Windows, we will disallow `GIT~1`, `AUX`, `COM1`, etc). This
904
+ * function will *always* prevent `.git` and directory traversal `../` from
905
+ * being added to the index.
906
+ */
907
+ static int index_entry_create(
908
+ git_index_entry **out,
909
+ git_repository *repo,
910
+ const char *path,
911
+ struct stat *st,
912
+ bool from_workdir)
583
913
  {
584
- const git_index_entry *entry_a = a;
585
- const git_index_entry *entry_b = b;
914
+ size_t pathlen = strlen(path), alloclen;
915
+ struct entry_internal *entry;
916
+ unsigned int path_valid_flags = GIT_PATH_REJECT_INDEX_DEFAULTS;
917
+ uint16_t mode = 0;
918
+
919
+ /* always reject placing `.git` in the index and directory traversal.
920
+ * when requested, disallow platform-specific filenames and upgrade to
921
+ * the platform-specific `.git` tests (eg, `git~1`, etc).
922
+ */
923
+ if (from_workdir)
924
+ path_valid_flags |= GIT_PATH_REJECT_WORKDIR_DEFAULTS;
925
+ if (st)
926
+ mode = st->st_mode;
586
927
 
587
- return strcasecmp(entry_a->path, entry_b->path);
928
+ if (!git_path_isvalid(repo, path, mode, path_valid_flags)) {
929
+ git_error_set(GIT_ERROR_INDEX, "invalid path: '%s'", path);
930
+ return -1;
931
+ }
932
+
933
+ GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, sizeof(struct entry_internal), pathlen);
934
+ GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, alloclen, 1);
935
+ entry = git__calloc(1, alloclen);
936
+ GIT_ERROR_CHECK_ALLOC(entry);
937
+
938
+ entry->pathlen = pathlen;
939
+ memcpy(entry->path, path, pathlen);
940
+ entry->entry.path = entry->path;
941
+
942
+ *out = (git_index_entry *)entry;
943
+ return 0;
588
944
  }
589
945
 
590
- static int index_entry_init(git_index_entry **entry_out, git_index *index, const char *rel_path)
946
+ static int index_entry_init(
947
+ git_index_entry **entry_out,
948
+ git_index *index,
949
+ const char *rel_path)
591
950
  {
951
+ int error = 0;
592
952
  git_index_entry *entry = NULL;
953
+ git_buf path = GIT_BUF_INIT;
593
954
  struct stat st;
594
955
  git_oid oid;
595
- const char *workdir;
596
- git_buf full_path = GIT_BUF_INIT;
597
- int error;
956
+ git_repository *repo;
598
957
 
599
958
  if (INDEX_OWNER(index) == NULL)
600
959
  return create_index_error(-1,
601
- "Could not initialize index entry. "
960
+ "could not initialize index entry. "
602
961
  "Index is not backed up by an existing repository.");
603
962
 
604
- workdir = git_repository_workdir(INDEX_OWNER(index));
963
+ /*
964
+ * FIXME: this is duplicated with the work in
965
+ * git_blob__create_from_paths. It should accept an optional stat
966
+ * structure so we can pass in the one we have to do here.
967
+ */
968
+ repo = INDEX_OWNER(index);
969
+ if (git_repository__ensure_not_bare(repo, "create blob from file") < 0)
970
+ return GIT_EBAREREPO;
971
+
972
+ if (git_buf_joinpath(&path, git_repository_workdir(repo), rel_path) < 0)
973
+ return -1;
605
974
 
606
- if (!workdir)
607
- return create_index_error(GIT_EBAREREPO,
608
- "Could not initialize index entry. Repository is bare");
975
+ error = git_path_lstat(path.ptr, &st);
976
+ git_buf_dispose(&path);
609
977
 
610
- if ((error = git_buf_joinpath(&full_path, workdir, rel_path)) < 0)
978
+ if (error < 0)
611
979
  return error;
612
980
 
613
- if ((error = git_path_lstat(full_path.ptr, &st)) < 0) {
614
- git_buf_free(&full_path);
981
+ if (index_entry_create(&entry, INDEX_OWNER(index), rel_path, &st, true) < 0)
982
+ return -1;
983
+
984
+ /* write the blob to disk and get the oid and stat info */
985
+ error = git_blob__create_from_paths(
986
+ &oid, &st, INDEX_OWNER(index), NULL, rel_path, 0, true);
987
+
988
+ if (error < 0) {
989
+ index_entry_free(entry);
615
990
  return error;
616
991
  }
617
992
 
618
- git_buf_free(&full_path); /* done with full path */
993
+ entry->id = oid;
994
+ git_index_entry__init_from_stat(entry, &st, !index->distrust_filemode);
619
995
 
620
- /* There is no need to validate the rel_path here, since it will be
621
- * immediately validated by the call to git_blob_create_fromfile.
622
- */
996
+ *entry_out = (git_index_entry *)entry;
997
+ return 0;
998
+ }
623
999
 
624
- /* write the blob to disk and get the oid */
625
- if ((error = git_blob_create_fromworkdir(&oid, INDEX_OWNER(index), rel_path)) < 0)
626
- return error;
1000
+ static git_index_reuc_entry *reuc_entry_alloc(const char *path)
1001
+ {
1002
+ size_t pathlen = strlen(path),
1003
+ structlen = sizeof(struct reuc_entry_internal),
1004
+ alloclen;
1005
+ struct reuc_entry_internal *entry;
627
1006
 
628
- entry = git__calloc(1, sizeof(git_index_entry));
629
- GITERR_CHECK_ALLOC(entry);
1007
+ if (GIT_ADD_SIZET_OVERFLOW(&alloclen, structlen, pathlen) ||
1008
+ GIT_ADD_SIZET_OVERFLOW(&alloclen, alloclen, 1))
1009
+ return NULL;
630
1010
 
631
- git_index_entry__init_from_stat(entry, &st);
1011
+ entry = git__calloc(1, alloclen);
1012
+ if (!entry)
1013
+ return NULL;
632
1014
 
633
- entry->oid = oid;
634
- entry->path = git__strdup(rel_path);
635
- GITERR_CHECK_ALLOC(entry->path);
1015
+ entry->pathlen = pathlen;
1016
+ memcpy(entry->path, path, pathlen);
1017
+ entry->entry.path = entry->path;
636
1018
 
637
- *entry_out = entry;
638
- return 0;
1019
+ return (git_index_reuc_entry *)entry;
639
1020
  }
640
1021
 
641
1022
  static int index_entry_reuc_init(git_index_reuc_entry **reuc_out,
@@ -648,103 +1029,392 @@ static int index_entry_reuc_init(git_index_reuc_entry **reuc_out,
648
1029
 
649
1030
  assert(reuc_out && path);
650
1031
 
651
- *reuc_out = NULL;
652
-
653
- reuc = git__calloc(1, sizeof(git_index_reuc_entry));
654
- GITERR_CHECK_ALLOC(reuc);
655
-
656
- reuc->path = git__strdup(path);
657
- if (reuc->path == NULL)
658
- return -1;
1032
+ *reuc_out = reuc = reuc_entry_alloc(path);
1033
+ GIT_ERROR_CHECK_ALLOC(reuc);
659
1034
 
660
- if ((reuc->mode[0] = ancestor_mode) > 0)
1035
+ if ((reuc->mode[0] = ancestor_mode) > 0) {
1036
+ assert(ancestor_oid);
661
1037
  git_oid_cpy(&reuc->oid[0], ancestor_oid);
1038
+ }
662
1039
 
663
- if ((reuc->mode[1] = our_mode) > 0)
1040
+ if ((reuc->mode[1] = our_mode) > 0) {
1041
+ assert(our_oid);
664
1042
  git_oid_cpy(&reuc->oid[1], our_oid);
1043
+ }
665
1044
 
666
- if ((reuc->mode[2] = their_mode) > 0)
1045
+ if ((reuc->mode[2] = their_mode) > 0) {
1046
+ assert(their_oid);
667
1047
  git_oid_cpy(&reuc->oid[2], their_oid);
1048
+ }
668
1049
 
669
- *reuc_out = reuc;
670
1050
  return 0;
671
1051
  }
672
1052
 
673
- static void index_entry_reuc_free(git_index_reuc_entry *reuc)
1053
+ static void index_entry_cpy(
1054
+ git_index_entry *tgt,
1055
+ const git_index_entry *src)
674
1056
  {
675
- if (!reuc)
676
- return;
677
-
678
- git__free(reuc->path);
679
- git__free(reuc);
1057
+ const char *tgt_path = tgt->path;
1058
+ memcpy(tgt, src, sizeof(*tgt));
1059
+ tgt->path = tgt_path;
680
1060
  }
681
1061
 
682
- static git_index_entry *index_entry_dup(const git_index_entry *source_entry)
1062
+ static int index_entry_dup(
1063
+ git_index_entry **out,
1064
+ git_index *index,
1065
+ const git_index_entry *src)
683
1066
  {
684
- git_index_entry *entry;
685
-
686
- entry = git__malloc(sizeof(git_index_entry));
687
- if (!entry)
688
- return NULL;
689
-
690
- memcpy(entry, source_entry, sizeof(git_index_entry));
691
-
692
- /* duplicate the path string so we own it */
693
- entry->path = git__strdup(entry->path);
694
- if (!entry->path)
695
- return NULL;
1067
+ if (index_entry_create(out, INDEX_OWNER(index), src->path, NULL, false) < 0)
1068
+ return -1;
696
1069
 
697
- return entry;
1070
+ index_entry_cpy(*out, src);
1071
+ return 0;
698
1072
  }
699
1073
 
700
- static void index_entry_free(git_index_entry *entry)
1074
+ static void index_entry_cpy_nocache(
1075
+ git_index_entry *tgt,
1076
+ const git_index_entry *src)
701
1077
  {
702
- if (!entry)
703
- return;
704
- git__free(entry->path);
705
- git__free(entry);
1078
+ git_oid_cpy(&tgt->id, &src->id);
1079
+ tgt->mode = src->mode;
1080
+ tgt->flags = src->flags;
1081
+ tgt->flags_extended = (src->flags_extended & GIT_INDEX_ENTRY_EXTENDED_FLAGS);
706
1082
  }
707
1083
 
708
- static int index_insert(git_index *index, git_index_entry *entry, int replace)
1084
+ static int index_entry_dup_nocache(
1085
+ git_index_entry **out,
1086
+ git_index *index,
1087
+ const git_index_entry *src)
709
1088
  {
710
- size_t path_length, position;
711
- git_index_entry **existing = NULL;
712
-
713
- assert(index && entry && entry->path != NULL);
714
-
715
- /* make sure that the path length flag is correct */
716
- path_length = strlen(entry->path);
717
-
718
- entry->flags &= ~GIT_IDXENTRY_NAMEMASK;
1089
+ if (index_entry_create(out, INDEX_OWNER(index), src->path, NULL, false) < 0)
1090
+ return -1;
719
1091
 
720
- if (path_length < GIT_IDXENTRY_NAMEMASK)
721
- entry->flags |= path_length & GIT_IDXENTRY_NAMEMASK;
722
- else
723
- entry->flags |= GIT_IDXENTRY_NAMEMASK;
1092
+ index_entry_cpy_nocache(*out, src);
1093
+ return 0;
1094
+ }
724
1095
 
725
- /* look if an entry with this path already exists */
726
- if (!index_find(&position, index, entry->path, GIT_IDXENTRY_STAGE(entry))) {
727
- existing = (git_index_entry **)&index->entries.contents[position];
1096
+ static int has_file_name(git_index *index,
1097
+ const git_index_entry *entry, size_t pos, int ok_to_replace)
1098
+ {
1099
+ size_t len = strlen(entry->path);
1100
+ int stage = GIT_INDEX_ENTRY_STAGE(entry);
1101
+ const char *name = entry->path;
728
1102
 
729
- /* update filemode to existing values if stat is not trusted */
730
- entry->mode = index_merge_mode(index, *existing, entry->mode);
731
- }
1103
+ while (pos < index->entries.length) {
1104
+ struct entry_internal *p = index->entries.contents[pos++];
732
1105
 
733
- /* if replacing is not requested or no existing entry exists, just
734
- * insert entry at the end; the index is no longer sorted
1106
+ if (len >= p->pathlen)
1107
+ break;
1108
+ if (memcmp(name, p->path, len))
1109
+ break;
1110
+ if (GIT_INDEX_ENTRY_STAGE(&p->entry) != stage)
1111
+ continue;
1112
+ if (p->path[len] != '/')
1113
+ continue;
1114
+ if (!ok_to_replace)
1115
+ return -1;
1116
+
1117
+ if (index_remove_entry(index, --pos) < 0)
1118
+ break;
1119
+ }
1120
+ return 0;
1121
+ }
1122
+
1123
+ /*
1124
+ * Do we have another file with a pathname that is a proper
1125
+ * subset of the name we're trying to add?
1126
+ */
1127
+ static int has_dir_name(git_index *index,
1128
+ const git_index_entry *entry, int ok_to_replace)
1129
+ {
1130
+ int stage = GIT_INDEX_ENTRY_STAGE(entry);
1131
+ const char *name = entry->path;
1132
+ const char *slash = name + strlen(name);
1133
+
1134
+ for (;;) {
1135
+ size_t len, pos;
1136
+
1137
+ for (;;) {
1138
+ if (*--slash == '/')
1139
+ break;
1140
+ if (slash <= entry->path)
1141
+ return 0;
1142
+ }
1143
+ len = slash - name;
1144
+
1145
+ if (!index_find(&pos, index, name, len, stage)) {
1146
+ if (!ok_to_replace)
1147
+ return -1;
1148
+
1149
+ if (index_remove_entry(index, pos) < 0)
1150
+ break;
1151
+ continue;
1152
+ }
1153
+
1154
+ /*
1155
+ * Trivial optimization: if we find an entry that
1156
+ * already matches the sub-directory, then we know
1157
+ * we're ok, and we can exit.
1158
+ */
1159
+ for (; pos < index->entries.length; ++pos) {
1160
+ struct entry_internal *p = index->entries.contents[pos];
1161
+
1162
+ if (p->pathlen <= len ||
1163
+ p->path[len] != '/' ||
1164
+ memcmp(p->path, name, len))
1165
+ break; /* not our subdirectory */
1166
+
1167
+ if (GIT_INDEX_ENTRY_STAGE(&p->entry) == stage)
1168
+ return 0;
1169
+ }
1170
+ }
1171
+
1172
+ return 0;
1173
+ }
1174
+
1175
+ static int check_file_directory_collision(git_index *index,
1176
+ git_index_entry *entry, size_t pos, int ok_to_replace)
1177
+ {
1178
+ if (has_file_name(index, entry, pos, ok_to_replace) < 0 ||
1179
+ has_dir_name(index, entry, ok_to_replace) < 0) {
1180
+ git_error_set(GIT_ERROR_INDEX,
1181
+ "'%s' appears as both a file and a directory", entry->path);
1182
+ return -1;
1183
+ }
1184
+
1185
+ return 0;
1186
+ }
1187
+
1188
+ static int canonicalize_directory_path(
1189
+ git_index *index,
1190
+ git_index_entry *entry,
1191
+ git_index_entry *existing)
1192
+ {
1193
+ const git_index_entry *match, *best = NULL;
1194
+ char *search, *sep;
1195
+ size_t pos, search_len, best_len;
1196
+
1197
+ if (!index->ignore_case)
1198
+ return 0;
1199
+
1200
+ /* item already exists in the index, simply re-use the existing case */
1201
+ if (existing) {
1202
+ memcpy((char *)entry->path, existing->path, strlen(existing->path));
1203
+ return 0;
1204
+ }
1205
+
1206
+ /* nothing to do */
1207
+ if (strchr(entry->path, '/') == NULL)
1208
+ return 0;
1209
+
1210
+ if ((search = git__strdup(entry->path)) == NULL)
1211
+ return -1;
1212
+
1213
+ /* starting at the parent directory and descending to the root, find the
1214
+ * common parent directory.
735
1215
  */
736
- if (!replace || !existing)
737
- return git_vector_insert(&index->entries, entry);
1216
+ while (!best && (sep = strrchr(search, '/'))) {
1217
+ sep[1] = '\0';
1218
+
1219
+ search_len = strlen(search);
738
1220
 
739
- /* exists, replace it (preserving name from existing entry) */
740
- git__free(entry->path);
741
- entry->path = (*existing)->path;
742
- git__free(*existing);
743
- *existing = entry;
1221
+ git_vector_bsearch2(
1222
+ &pos, &index->entries, index->entries_search_path, search);
1223
+
1224
+ while ((match = git_vector_get(&index->entries, pos))) {
1225
+ if (GIT_INDEX_ENTRY_STAGE(match) != 0) {
1226
+ /* conflicts do not contribute to canonical paths */
1227
+ } else if (strncmp(search, match->path, search_len) == 0) {
1228
+ /* prefer an exact match to the input filename */
1229
+ best = match;
1230
+ best_len = search_len;
1231
+ break;
1232
+ } else if (strncasecmp(search, match->path, search_len) == 0) {
1233
+ /* continue walking, there may be a path with an exact
1234
+ * (case sensitive) match later in the index, but use this
1235
+ * as the best match until that happens.
1236
+ */
1237
+ if (!best) {
1238
+ best = match;
1239
+ best_len = search_len;
1240
+ }
1241
+ } else {
1242
+ break;
1243
+ }
1244
+
1245
+ pos++;
1246
+ }
744
1247
 
1248
+ sep[0] = '\0';
1249
+ }
1250
+
1251
+ if (best)
1252
+ memcpy((char *)entry->path, best->path, best_len);
1253
+
1254
+ git__free(search);
745
1255
  return 0;
746
1256
  }
747
1257
 
1258
+ static int index_no_dups(void **old, void *new)
1259
+ {
1260
+ const git_index_entry *entry = new;
1261
+ GIT_UNUSED(old);
1262
+ git_error_set(GIT_ERROR_INDEX, "'%s' appears multiple times at stage %d",
1263
+ entry->path, GIT_INDEX_ENTRY_STAGE(entry));
1264
+ return GIT_EEXISTS;
1265
+ }
1266
+
1267
+ static void index_existing_and_best(
1268
+ git_index_entry **existing,
1269
+ size_t *existing_position,
1270
+ git_index_entry **best,
1271
+ git_index *index,
1272
+ const git_index_entry *entry)
1273
+ {
1274
+ git_index_entry *e;
1275
+ size_t pos;
1276
+ int error;
1277
+
1278
+ error = index_find(&pos,
1279
+ index, entry->path, 0, GIT_INDEX_ENTRY_STAGE(entry));
1280
+
1281
+ if (error == 0) {
1282
+ *existing = index->entries.contents[pos];
1283
+ *existing_position = pos;
1284
+ *best = index->entries.contents[pos];
1285
+ return;
1286
+ }
1287
+
1288
+ *existing = NULL;
1289
+ *existing_position = 0;
1290
+ *best = NULL;
1291
+
1292
+ if (GIT_INDEX_ENTRY_STAGE(entry) == 0) {
1293
+ for (; pos < index->entries.length; pos++) {
1294
+ int (*strcomp)(const char *a, const char *b) =
1295
+ index->ignore_case ? git__strcasecmp : git__strcmp;
1296
+
1297
+ e = index->entries.contents[pos];
1298
+
1299
+ if (strcomp(entry->path, e->path) != 0)
1300
+ break;
1301
+
1302
+ if (GIT_INDEX_ENTRY_STAGE(e) == GIT_INDEX_STAGE_ANCESTOR) {
1303
+ *best = e;
1304
+ continue;
1305
+ } else {
1306
+ *best = e;
1307
+ break;
1308
+ }
1309
+ }
1310
+ }
1311
+ }
1312
+
1313
+ /* index_insert takes ownership of the new entry - if it can't insert
1314
+ * it, then it will return an error **and also free the entry**. When
1315
+ * it replaces an existing entry, it will update the entry_ptr with the
1316
+ * actual entry in the index (and free the passed in one).
1317
+ *
1318
+ * trust_path is whether we use the given path, or whether (on case
1319
+ * insensitive systems only) we try to canonicalize the given path to
1320
+ * be within an existing directory.
1321
+ *
1322
+ * trust_mode is whether we trust the mode in entry_ptr.
1323
+ *
1324
+ * trust_id is whether we trust the id or it should be validated.
1325
+ */
1326
+ static int index_insert(
1327
+ git_index *index,
1328
+ git_index_entry **entry_ptr,
1329
+ int replace,
1330
+ bool trust_path,
1331
+ bool trust_mode,
1332
+ bool trust_id)
1333
+ {
1334
+ git_index_entry *existing, *best, *entry;
1335
+ size_t path_length, position;
1336
+ int error;
1337
+
1338
+ assert(index && entry_ptr);
1339
+
1340
+ entry = *entry_ptr;
1341
+
1342
+ /* Make sure that the path length flag is correct */
1343
+ path_length = ((struct entry_internal *)entry)->pathlen;
1344
+ index_entry_adjust_namemask(entry, path_length);
1345
+
1346
+ /* This entry is now up-to-date and should not be checked for raciness */
1347
+ entry->flags_extended |= GIT_INDEX_ENTRY_UPTODATE;
1348
+
1349
+ git_vector_sort(&index->entries);
1350
+
1351
+ /*
1352
+ * Look if an entry with this path already exists, either staged, or (if
1353
+ * this entry is a regular staged item) as the "ours" side of a conflict.
1354
+ */
1355
+ index_existing_and_best(&existing, &position, &best, index, entry);
1356
+
1357
+ /* Update the file mode */
1358
+ entry->mode = trust_mode ?
1359
+ git_index__create_mode(entry->mode) :
1360
+ index_merge_mode(index, best, entry->mode);
1361
+
1362
+ /* Canonicalize the directory name */
1363
+ if (!trust_path && (error = canonicalize_directory_path(index, entry, best)) < 0)
1364
+ goto out;
1365
+
1366
+ /* Ensure that the given id exists (unless it's a submodule) */
1367
+ if (!trust_id && INDEX_OWNER(index) &&
1368
+ (entry->mode & GIT_FILEMODE_COMMIT) != GIT_FILEMODE_COMMIT) {
1369
+
1370
+ if (!git_object__is_valid(INDEX_OWNER(index), &entry->id,
1371
+ git_object__type_from_filemode(entry->mode))) {
1372
+ error = -1;
1373
+ goto out;
1374
+ }
1375
+ }
1376
+
1377
+ /* Look for tree / blob name collisions, removing conflicts if requested */
1378
+ if ((error = check_file_directory_collision(index, entry, position, replace)) < 0)
1379
+ goto out;
1380
+
1381
+ /*
1382
+ * If we are replacing an existing item, overwrite the existing entry
1383
+ * and return it in place of the passed in one.
1384
+ */
1385
+ if (existing) {
1386
+ if (replace) {
1387
+ index_entry_cpy(existing, entry);
1388
+
1389
+ if (trust_path)
1390
+ memcpy((char *)existing->path, entry->path, strlen(entry->path));
1391
+ }
1392
+
1393
+ index_entry_free(entry);
1394
+ *entry_ptr = existing;
1395
+ } else {
1396
+ /*
1397
+ * If replace is not requested or no existing entry exists, insert
1398
+ * at the sorted position. (Since we re-sort after each insert to
1399
+ * check for dups, this is actually cheaper in the long run.)
1400
+ */
1401
+ if ((error = git_vector_insert_sorted(&index->entries, entry, index_no_dups)) < 0)
1402
+ goto out;
1403
+
1404
+ INSERT_IN_MAP(index, entry, &error);
1405
+ }
1406
+
1407
+ index->dirty = 1;
1408
+
1409
+ out:
1410
+ if (error < 0) {
1411
+ index_entry_free(*entry_ptr);
1412
+ *entry_ptr = NULL;
1413
+ }
1414
+
1415
+ return error;
1416
+ }
1417
+
748
1418
  static int index_conflict_to_reuc(git_index *index, const char *path)
749
1419
  {
750
1420
  const git_index_entry *conflict_entries[3];
@@ -760,9 +1430,9 @@ static int index_conflict_to_reuc(git_index *index, const char *path)
760
1430
  our_mode = conflict_entries[1] == NULL ? 0 : conflict_entries[1]->mode;
761
1431
  their_mode = conflict_entries[2] == NULL ? 0 : conflict_entries[2]->mode;
762
1432
 
763
- ancestor_oid = conflict_entries[0] == NULL ? NULL : &conflict_entries[0]->oid;
764
- our_oid = conflict_entries[1] == NULL ? NULL : &conflict_entries[1]->oid;
765
- their_oid = conflict_entries[2] == NULL ? NULL : &conflict_entries[2]->oid;
1433
+ ancestor_oid = conflict_entries[0] == NULL ? NULL : &conflict_entries[0]->id;
1434
+ our_oid = conflict_entries[1] == NULL ? NULL : &conflict_entries[1]->id;
1435
+ their_oid = conflict_entries[2] == NULL ? NULL : &conflict_entries[2]->id;
766
1436
 
767
1437
  if ((ret = git_index_reuc_add(index, path, ancestor_mode, ancestor_oid,
768
1438
  our_mode, our_oid, their_mode, their_oid)) >= 0)
@@ -771,6 +1441,101 @@ static int index_conflict_to_reuc(git_index *index, const char *path)
771
1441
  return ret;
772
1442
  }
773
1443
 
1444
+ GIT_INLINE(bool) is_file_or_link(const int filemode)
1445
+ {
1446
+ return (filemode == GIT_FILEMODE_BLOB ||
1447
+ filemode == GIT_FILEMODE_BLOB_EXECUTABLE ||
1448
+ filemode == GIT_FILEMODE_LINK);
1449
+ }
1450
+
1451
+ GIT_INLINE(bool) valid_filemode(const int filemode)
1452
+ {
1453
+ return (is_file_or_link(filemode) || filemode == GIT_FILEMODE_COMMIT);
1454
+ }
1455
+
1456
+ int git_index_add_frombuffer(
1457
+ git_index *index, const git_index_entry *source_entry,
1458
+ const void *buffer, size_t len)
1459
+ {
1460
+ git_index_entry *entry = NULL;
1461
+ int error = 0;
1462
+ git_oid id;
1463
+
1464
+ assert(index && source_entry->path);
1465
+
1466
+ if (INDEX_OWNER(index) == NULL)
1467
+ return create_index_error(-1,
1468
+ "could not initialize index entry. "
1469
+ "Index is not backed up by an existing repository.");
1470
+
1471
+ if (!is_file_or_link(source_entry->mode)) {
1472
+ git_error_set(GIT_ERROR_INDEX, "invalid filemode");
1473
+ return -1;
1474
+ }
1475
+
1476
+ if (index_entry_dup(&entry, index, source_entry) < 0)
1477
+ return -1;
1478
+
1479
+ error = git_blob_create_frombuffer(&id, INDEX_OWNER(index), buffer, len);
1480
+ if (error < 0) {
1481
+ index_entry_free(entry);
1482
+ return error;
1483
+ }
1484
+
1485
+ git_oid_cpy(&entry->id, &id);
1486
+ entry->file_size = len;
1487
+
1488
+ if ((error = index_insert(index, &entry, 1, true, true, true)) < 0)
1489
+ return error;
1490
+
1491
+ /* Adding implies conflict was resolved, move conflict entries to REUC */
1492
+ if ((error = index_conflict_to_reuc(index, entry->path)) < 0 && error != GIT_ENOTFOUND)
1493
+ return error;
1494
+
1495
+ git_tree_cache_invalidate_path(index->tree, entry->path);
1496
+ return 0;
1497
+ }
1498
+
1499
+ static int add_repo_as_submodule(git_index_entry **out, git_index *index, const char *path)
1500
+ {
1501
+ git_repository *sub;
1502
+ git_buf abspath = GIT_BUF_INIT;
1503
+ git_repository *repo = INDEX_OWNER(index);
1504
+ git_reference *head;
1505
+ git_index_entry *entry;
1506
+ struct stat st;
1507
+ int error;
1508
+
1509
+ if ((error = git_buf_joinpath(&abspath, git_repository_workdir(repo), path)) < 0)
1510
+ return error;
1511
+
1512
+ if ((error = p_stat(abspath.ptr, &st)) < 0) {
1513
+ git_error_set(GIT_ERROR_OS, "failed to stat repository dir");
1514
+ return -1;
1515
+ }
1516
+
1517
+ if (index_entry_create(&entry, INDEX_OWNER(index), path, &st, true) < 0)
1518
+ return -1;
1519
+
1520
+ git_index_entry__init_from_stat(entry, &st, !index->distrust_filemode);
1521
+
1522
+ if ((error = git_repository_open(&sub, abspath.ptr)) < 0)
1523
+ return error;
1524
+
1525
+ if ((error = git_repository_head(&head, sub)) < 0)
1526
+ return error;
1527
+
1528
+ git_oid_cpy(&entry->id, git_reference_target(head));
1529
+ entry->mode = GIT_FILEMODE_COMMIT;
1530
+
1531
+ git_reference_free(head);
1532
+ git_repository_free(sub);
1533
+ git_buf_dispose(&abspath);
1534
+
1535
+ *out = entry;
1536
+ return 0;
1537
+ }
1538
+
774
1539
  int git_index_add_bypath(git_index *index, const char *path)
775
1540
  {
776
1541
  git_index_entry *entry = NULL;
@@ -778,20 +1543,50 @@ int git_index_add_bypath(git_index *index, const char *path)
778
1543
 
779
1544
  assert(index && path);
780
1545
 
781
- if ((ret = index_entry_init(&entry, index, path)) < 0 ||
782
- (ret = index_insert(index, entry, 1)) < 0)
783
- goto on_error;
1546
+ if ((ret = index_entry_init(&entry, index, path)) == 0)
1547
+ ret = index_insert(index, &entry, 1, false, false, true);
1548
+
1549
+ /* If we were given a directory, let's see if it's a submodule */
1550
+ if (ret < 0 && ret != GIT_EDIRECTORY)
1551
+ return ret;
1552
+
1553
+ if (ret == GIT_EDIRECTORY) {
1554
+ git_submodule *sm;
1555
+ git_error_state err;
1556
+
1557
+ git_error_state_capture(&err, ret);
1558
+
1559
+ ret = git_submodule_lookup(&sm, INDEX_OWNER(index), path);
1560
+ if (ret == GIT_ENOTFOUND)
1561
+ return git_error_state_restore(&err);
1562
+
1563
+ git_error_state_free(&err);
1564
+
1565
+ /*
1566
+ * EEXISTS means that there is a repository at that path, but it's not known
1567
+ * as a submodule. We add its HEAD as an entry and don't register it.
1568
+ */
1569
+ if (ret == GIT_EEXISTS) {
1570
+ if ((ret = add_repo_as_submodule(&entry, index, path)) < 0)
1571
+ return ret;
1572
+
1573
+ if ((ret = index_insert(index, &entry, 1, false, false, true)) < 0)
1574
+ return ret;
1575
+ } else if (ret < 0) {
1576
+ return ret;
1577
+ } else {
1578
+ ret = git_submodule_add_to_index(sm, false);
1579
+ git_submodule_free(sm);
1580
+ return ret;
1581
+ }
1582
+ }
784
1583
 
785
1584
  /* Adding implies conflict was resolved, move conflict entries to REUC */
786
1585
  if ((ret = index_conflict_to_reuc(index, path)) < 0 && ret != GIT_ENOTFOUND)
787
- goto on_error;
1586
+ return ret;
788
1587
 
789
1588
  git_tree_cache_invalidate_path(index->tree, entry->path);
790
1589
  return 0;
791
-
792
- on_error:
793
- index_entry_free(entry);
794
- return ret;
795
1590
  }
796
1591
 
797
1592
  int git_index_remove_bypath(git_index *index, const char *path)
@@ -806,22 +1601,68 @@ int git_index_remove_bypath(git_index *index, const char *path)
806
1601
  ret != GIT_ENOTFOUND))
807
1602
  return ret;
808
1603
 
1604
+ if (ret == GIT_ENOTFOUND)
1605
+ git_error_clear();
1606
+
809
1607
  return 0;
810
1608
  }
811
1609
 
1610
+ int git_index__fill(git_index *index, const git_vector *source_entries)
1611
+ {
1612
+ const git_index_entry *source_entry = NULL;
1613
+ size_t i;
1614
+ int ret = 0;
1615
+
1616
+ assert(index);
1617
+
1618
+ if (!source_entries->length)
1619
+ return 0;
1620
+
1621
+ git_vector_size_hint(&index->entries, source_entries->length);
1622
+ git_idxmap_resize(index->entries_map, (size_t)(source_entries->length * 1.3));
1623
+
1624
+ git_vector_foreach(source_entries, i, source_entry) {
1625
+ git_index_entry *entry = NULL;
1626
+
1627
+ if ((ret = index_entry_dup(&entry, index, source_entry)) < 0)
1628
+ break;
1629
+
1630
+ index_entry_adjust_namemask(entry, ((struct entry_internal *)entry)->pathlen);
1631
+ entry->flags_extended |= GIT_INDEX_ENTRY_UPTODATE;
1632
+ entry->mode = git_index__create_mode(entry->mode);
1633
+
1634
+ if ((ret = git_vector_insert(&index->entries, entry)) < 0)
1635
+ break;
1636
+
1637
+ INSERT_IN_MAP(index, entry, &ret);
1638
+ if (ret < 0)
1639
+ break;
1640
+
1641
+ index->dirty = 1;
1642
+ }
1643
+
1644
+ if (!ret)
1645
+ git_vector_sort(&index->entries);
1646
+
1647
+ return ret;
1648
+ }
1649
+
1650
+
812
1651
  int git_index_add(git_index *index, const git_index_entry *source_entry)
813
1652
  {
814
1653
  git_index_entry *entry = NULL;
815
1654
  int ret;
816
1655
 
817
- entry = index_entry_dup(source_entry);
818
- if (entry == NULL)
1656
+ assert(index && source_entry && source_entry->path);
1657
+
1658
+ if (!valid_filemode(source_entry->mode)) {
1659
+ git_error_set(GIT_ERROR_INDEX, "invalid entry mode");
819
1660
  return -1;
1661
+ }
820
1662
 
821
- if ((ret = index_insert(index, entry, 1)) < 0) {
822
- index_entry_free(entry);
1663
+ if ((ret = index_entry_dup(&entry, index, source_entry)) < 0 ||
1664
+ (ret = index_insert(index, &entry, 1, true, true, false)) < 0)
823
1665
  return ret;
824
- }
825
1666
 
826
1667
  git_tree_cache_invalidate_path(index->tree, entry->path);
827
1668
  return 0;
@@ -829,26 +1670,22 @@ int git_index_add(git_index *index, const git_index_entry *source_entry)
829
1670
 
830
1671
  int git_index_remove(git_index *index, const char *path, int stage)
831
1672
  {
832
- size_t position;
833
1673
  int error;
834
- git_index_entry *entry;
835
-
836
- git_vector_sort(&index->entries);
1674
+ size_t position;
1675
+ git_index_entry remove_key = {{ 0 }};
837
1676
 
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);
841
- return GIT_ENOTFOUND;
842
- }
1677
+ remove_key.path = path;
1678
+ GIT_INDEX_ENTRY_STAGE_SET(&remove_key, stage);
843
1679
 
844
- entry = git_vector_get(&index->entries, position);
845
- if (entry != NULL)
846
- git_tree_cache_invalidate_path(index->tree, entry->path);
1680
+ DELETE_IN_MAP(index, &remove_key);
847
1681
 
848
- error = git_vector_remove(&index->entries, position);
849
-
850
- if (!error)
851
- index_entry_free(entry);
1682
+ if (index_find(&position, index, path, 0, stage) < 0) {
1683
+ git_error_set(
1684
+ GIT_ERROR_INDEX, "index does not contain %s at stage %d", path, stage);
1685
+ error = GIT_ENOTFOUND;
1686
+ } else {
1687
+ error = index_remove_entry(index, position);
1688
+ }
852
1689
 
853
1690
  return error;
854
1691
  }
@@ -860,47 +1697,52 @@ int git_index_remove_directory(git_index *index, const char *dir, int stage)
860
1697
  size_t pos;
861
1698
  git_index_entry *entry;
862
1699
 
863
- if (git_buf_sets(&pfx, dir) < 0 || git_path_to_dir(&pfx) < 0)
864
- return -1;
1700
+ if (!(error = git_buf_sets(&pfx, dir)) &&
1701
+ !(error = git_path_to_dir(&pfx)))
1702
+ index_find(&pos, index, pfx.ptr, pfx.size, GIT_INDEX_STAGE_ANY);
865
1703
 
866
- git_vector_sort(&index->entries);
867
-
868
- pos = git_index__prefix_position(index, pfx.ptr);
869
-
870
- while (1) {
1704
+ while (!error) {
871
1705
  entry = git_vector_get(&index->entries, pos);
872
1706
  if (!entry || git__prefixcmp(entry->path, pfx.ptr) != 0)
873
1707
  break;
874
1708
 
875
- if (GIT_IDXENTRY_STAGE(entry) != stage) {
1709
+ if (GIT_INDEX_ENTRY_STAGE(entry) != stage) {
876
1710
  ++pos;
877
1711
  continue;
878
1712
  }
879
1713
 
880
- git_tree_cache_invalidate_path(index->tree, entry->path);
881
-
882
- if ((error = git_vector_remove(&index->entries, pos)) < 0)
883
- break;
884
- index_entry_free(entry);
1714
+ error = index_remove_entry(index, pos);
885
1715
 
886
- /* removed entry at 'pos' so we don't need to increment it */
1716
+ /* removed entry at 'pos' so we don't need to increment */
887
1717
  }
888
1718
 
889
- git_buf_free(&pfx);
1719
+ git_buf_dispose(&pfx);
890
1720
 
891
1721
  return error;
892
1722
  }
893
1723
 
894
- static int index_find(size_t *at_pos, git_index *index, const char *path, int stage)
1724
+ int git_index_find_prefix(size_t *at_pos, git_index *index, const char *prefix)
895
1725
  {
896
- struct entry_srch_key srch_key;
1726
+ int error = 0;
1727
+ size_t pos;
1728
+ const git_index_entry *entry;
897
1729
 
898
- assert(path);
1730
+ index_find(&pos, index, prefix, strlen(prefix), GIT_INDEX_STAGE_ANY);
1731
+ entry = git_vector_get(&index->entries, pos);
1732
+ if (!entry || git__prefixcmp(entry->path, prefix) != 0)
1733
+ error = GIT_ENOTFOUND;
899
1734
 
900
- srch_key.path = path;
901
- srch_key.stage = stage;
1735
+ if (!error && at_pos)
1736
+ *at_pos = pos;
902
1737
 
903
- return git_vector_bsearch2(at_pos, &index->entries, index->entries_search, &srch_key);
1738
+ return error;
1739
+ }
1740
+
1741
+ int git_index__find_pos(
1742
+ size_t *out, git_index *index, const char *path, size_t path_len, int stage)
1743
+ {
1744
+ assert(index && path);
1745
+ return index_find(out, index, path, path_len, stage);
904
1746
  }
905
1747
 
906
1748
  int git_index_find(size_t *at_pos, git_index *index, const char *path)
@@ -909,21 +1751,20 @@ int git_index_find(size_t *at_pos, git_index *index, const char *path)
909
1751
 
910
1752
  assert(index && path);
911
1753
 
912
- if (git_vector_bsearch2(&pos, &index->entries, index->entries_search_path, path) < 0) {
913
- giterr_set(GITERR_INDEX, "Index does not contain %s", path);
1754
+ if (git_vector_bsearch2(
1755
+ &pos, &index->entries, index->entries_search_path, path) < 0) {
1756
+ git_error_set(GIT_ERROR_INDEX, "index does not contain %s", path);
914
1757
  return GIT_ENOTFOUND;
915
1758
  }
916
1759
 
917
1760
  /* Since our binary search only looked at path, we may be in the
918
1761
  * middle of a list of stages.
919
1762
  */
920
- while (pos > 0) {
921
- const git_index_entry *prev = git_vector_get(&index->entries, pos-1);
1763
+ for (; pos > 0; --pos) {
1764
+ const git_index_entry *prev = git_vector_get(&index->entries, pos - 1);
922
1765
 
923
1766
  if (index->entries_cmp_path(prev->path, path) != 0)
924
1767
  break;
925
-
926
- --pos;
927
1768
  }
928
1769
 
929
1770
  if (at_pos)
@@ -932,21 +1773,6 @@ int git_index_find(size_t *at_pos, git_index *index, const char *path)
932
1773
  return 0;
933
1774
  }
934
1775
 
935
- size_t git_index__prefix_position(git_index *index, const char *path)
936
- {
937
- struct entry_srch_key srch_key;
938
- size_t pos;
939
-
940
- srch_key.path = path;
941
- srch_key.stage = 0;
942
-
943
- git_vector_sort(&index->entries);
944
- git_vector_bsearch2(
945
- &pos, &index->entries, index->entries_search, &srch_key);
946
-
947
- return pos;
948
- }
949
-
950
1776
  int git_index_conflict_add(git_index *index,
951
1777
  const git_index_entry *ancestor_entry,
952
1778
  const git_index_entry *our_entry,
@@ -958,21 +1784,50 @@ int git_index_conflict_add(git_index *index,
958
1784
 
959
1785
  assert (index);
960
1786
 
961
- if ((ancestor_entry != NULL && (entries[0] = index_entry_dup(ancestor_entry)) == NULL) ||
962
- (our_entry != NULL && (entries[1] = index_entry_dup(our_entry)) == NULL) ||
963
- (their_entry != NULL && (entries[2] = index_entry_dup(their_entry)) == NULL))
964
- return -1;
1787
+ if ((ancestor_entry &&
1788
+ (ret = index_entry_dup(&entries[0], index, ancestor_entry)) < 0) ||
1789
+ (our_entry &&
1790
+ (ret = index_entry_dup(&entries[1], index, our_entry)) < 0) ||
1791
+ (their_entry &&
1792
+ (ret = index_entry_dup(&entries[2], index, their_entry)) < 0))
1793
+ goto on_error;
965
1794
 
1795
+ /* Validate entries */
1796
+ for (i = 0; i < 3; i++) {
1797
+ if (entries[i] && !valid_filemode(entries[i]->mode)) {
1798
+ git_error_set(GIT_ERROR_INDEX, "invalid filemode for stage %d entry",
1799
+ i + 1);
1800
+ ret = -1;
1801
+ goto on_error;
1802
+ }
1803
+ }
1804
+
1805
+ /* Remove existing index entries for each path */
1806
+ for (i = 0; i < 3; i++) {
1807
+ if (entries[i] == NULL)
1808
+ continue;
1809
+
1810
+ if ((ret = git_index_remove(index, entries[i]->path, 0)) != 0) {
1811
+ if (ret != GIT_ENOTFOUND)
1812
+ goto on_error;
1813
+
1814
+ git_error_clear();
1815
+ ret = 0;
1816
+ }
1817
+ }
1818
+
1819
+ /* Add the conflict entries */
966
1820
  for (i = 0; i < 3; i++) {
967
1821
  if (entries[i] == NULL)
968
1822
  continue;
969
1823
 
970
1824
  /* Make sure stage is correct */
971
- entries[i]->flags = (entries[i]->flags & ~GIT_IDXENTRY_STAGEMASK) |
972
- ((i+1) << GIT_IDXENTRY_STAGESHIFT);
1825
+ GIT_INDEX_ENTRY_STAGE_SET(entries[i], i + 1);
973
1826
 
974
- if ((ret = index_insert(index, entries[i], 1)) < 0)
1827
+ if ((ret = index_insert(index, &entries[i], 1, true, true, false)) < 0)
975
1828
  goto on_error;
1829
+
1830
+ entries[i] = NULL; /* don't free if later entry fails */
976
1831
  }
977
1832
 
978
1833
  return 0;
@@ -1010,7 +1865,7 @@ static int index_conflict__get_byindex(
1010
1865
  if (path && index->entries_cmp_path(conflict_entry->path, path) != 0)
1011
1866
  break;
1012
1867
 
1013
- stage = GIT_IDXENTRY_STAGE(conflict_entry);
1868
+ stage = GIT_INDEX_ENTRY_STAGE(conflict_entry);
1014
1869
  path = conflict_entry->path;
1015
1870
 
1016
1871
  switch (stage) {
@@ -1062,56 +1917,43 @@ int git_index_conflict_get(
1062
1917
  return 0;
1063
1918
  }
1064
1919
 
1065
- int git_index_conflict_remove(git_index *index, const char *path)
1920
+ static int index_conflict_remove(git_index *index, const char *path)
1066
1921
  {
1067
- size_t pos, posmax;
1922
+ size_t pos = 0;
1068
1923
  git_index_entry *conflict_entry;
1069
1924
  int error = 0;
1070
1925
 
1071
- assert(index && path);
1072
-
1073
- if (git_index_find(&pos, index, path) < 0)
1926
+ if (path != NULL && git_index_find(&pos, index, path) < 0)
1074
1927
  return GIT_ENOTFOUND;
1075
1928
 
1076
- posmax = git_index_entrycount(index);
1929
+ while ((conflict_entry = git_vector_get(&index->entries, pos)) != NULL) {
1077
1930
 
1078
- while (pos < posmax) {
1079
- conflict_entry = git_vector_get(&index->entries, pos);
1080
-
1081
- if (index->entries_cmp_path(conflict_entry->path, path) != 0)
1931
+ if (path != NULL &&
1932
+ index->entries_cmp_path(conflict_entry->path, path) != 0)
1082
1933
  break;
1083
1934
 
1084
- if (GIT_IDXENTRY_STAGE(conflict_entry) == 0) {
1935
+ if (GIT_INDEX_ENTRY_STAGE(conflict_entry) == 0) {
1085
1936
  pos++;
1086
1937
  continue;
1087
1938
  }
1088
1939
 
1089
- if ((error = git_vector_remove(&index->entries, pos)) < 0)
1090
- return error;
1091
-
1092
- index_entry_free(conflict_entry);
1093
- posmax--;
1940
+ if ((error = index_remove_entry(index, pos)) < 0)
1941
+ break;
1094
1942
  }
1095
1943
 
1096
- return 0;
1944
+ return error;
1097
1945
  }
1098
1946
 
1099
- static int index_conflicts_match(const git_vector *v, size_t idx)
1947
+ int git_index_conflict_remove(git_index *index, const char *path)
1100
1948
  {
1101
- git_index_entry *entry = git_vector_get(v, idx);
1102
-
1103
- if (GIT_IDXENTRY_STAGE(entry) > 0) {
1104
- index_entry_free(entry);
1105
- return 1;
1106
- }
1107
-
1108
- return 0;
1949
+ assert(index && path);
1950
+ return index_conflict_remove(index, path);
1109
1951
  }
1110
1952
 
1111
- void git_index_conflict_cleanup(git_index *index)
1953
+ int git_index_conflict_cleanup(git_index *index)
1112
1954
  {
1113
1955
  assert(index);
1114
- git_vector_remove_matching(&index->entries, index_conflicts_match);
1956
+ return index_conflict_remove(index, NULL);
1115
1957
  }
1116
1958
 
1117
1959
  int git_index_has_conflicts(const git_index *index)
@@ -1122,13 +1964,58 @@ int git_index_has_conflicts(const git_index *index)
1122
1964
  assert(index);
1123
1965
 
1124
1966
  git_vector_foreach(&index->entries, i, entry) {
1125
- if (GIT_IDXENTRY_STAGE(entry) > 0)
1967
+ if (GIT_INDEX_ENTRY_STAGE(entry) > 0)
1126
1968
  return 1;
1127
1969
  }
1128
1970
 
1129
1971
  return 0;
1130
1972
  }
1131
1973
 
1974
+ int git_index_iterator_new(
1975
+ git_index_iterator **iterator_out,
1976
+ git_index *index)
1977
+ {
1978
+ git_index_iterator *it;
1979
+ int error;
1980
+
1981
+ assert(iterator_out && index);
1982
+
1983
+ it = git__calloc(1, sizeof(git_index_iterator));
1984
+ GIT_ERROR_CHECK_ALLOC(it);
1985
+
1986
+ if ((error = git_index_snapshot_new(&it->snap, index)) < 0) {
1987
+ git__free(it);
1988
+ return error;
1989
+ }
1990
+
1991
+ it->index = index;
1992
+
1993
+ *iterator_out = it;
1994
+ return 0;
1995
+ }
1996
+
1997
+ int git_index_iterator_next(
1998
+ const git_index_entry **out,
1999
+ git_index_iterator *it)
2000
+ {
2001
+ assert(out && it);
2002
+
2003
+ if (it->cur >= git_vector_length(&it->snap))
2004
+ return GIT_ITEROVER;
2005
+
2006
+ *out = (git_index_entry *)git_vector_get(&it->snap, it->cur++);
2007
+ return 0;
2008
+ }
2009
+
2010
+ void git_index_iterator_free(git_index_iterator *it)
2011
+ {
2012
+ if (it == NULL)
2013
+ return;
2014
+
2015
+ git_index_snapshot_release(&it->snap, it->index);
2016
+ git__free(it);
2017
+ }
2018
+
1132
2019
  int git_index_conflict_iterator_new(
1133
2020
  git_index_conflict_iterator **iterator_out,
1134
2021
  git_index *index)
@@ -1138,7 +2025,7 @@ int git_index_conflict_iterator_new(
1138
2025
  assert(iterator_out && index);
1139
2026
 
1140
2027
  it = git__calloc(1, sizeof(git_index_conflict_iterator));
1141
- GITERR_CHECK_ALLOC(it);
2028
+ GIT_ERROR_CHECK_ALLOC(it);
1142
2029
 
1143
2030
  it->index = index;
1144
2031
 
@@ -1164,7 +2051,7 @@ int git_index_conflict_next(
1164
2051
  while (iterator->cur < iterator->index->entries.length) {
1165
2052
  entry = git_index_get_byindex(iterator->index, iterator->cur);
1166
2053
 
1167
- if (git_index_entry_stage(entry) > 0) {
2054
+ if (git_index_entry_is_conflict(entry)) {
1168
2055
  if ((len = index_conflict__get_byindex(
1169
2056
  ancestor_out,
1170
2057
  our_out,
@@ -1191,10 +2078,10 @@ void git_index_conflict_iterator_free(git_index_conflict_iterator *iterator)
1191
2078
  git__free(iterator);
1192
2079
  }
1193
2080
 
1194
- unsigned int git_index_name_entrycount(git_index *index)
2081
+ size_t git_index_name_entrycount(git_index *index)
1195
2082
  {
1196
2083
  assert(index);
1197
- return (unsigned int)index->names.length;
2084
+ return index->names.length;
1198
2085
  }
1199
2086
 
1200
2087
  const git_index_name_entry *git_index_name_get_byindex(
@@ -1206,32 +2093,37 @@ const git_index_name_entry *git_index_name_get_byindex(
1206
2093
  return git_vector_get(&index->names, n);
1207
2094
  }
1208
2095
 
2096
+ static void index_name_entry_free(git_index_name_entry *ne)
2097
+ {
2098
+ if (!ne)
2099
+ return;
2100
+ git__free(ne->ancestor);
2101
+ git__free(ne->ours);
2102
+ git__free(ne->theirs);
2103
+ git__free(ne);
2104
+ }
2105
+
1209
2106
  int git_index_name_add(git_index *index,
1210
2107
  const char *ancestor, const char *ours, const char *theirs)
1211
2108
  {
1212
2109
  git_index_name_entry *conflict_name;
1213
2110
 
1214
- assert ((ancestor && ours) || (ancestor && theirs) || (ours && theirs));
2111
+ assert((ancestor && ours) || (ancestor && theirs) || (ours && theirs));
1215
2112
 
1216
2113
  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
- }
2114
+ GIT_ERROR_CHECK_ALLOC(conflict_name);
1228
2115
 
1229
- if (theirs) {
1230
- conflict_name->theirs = git__strdup(theirs);
1231
- GITERR_CHECK_ALLOC(conflict_name->theirs);
2116
+ if ((ancestor && !(conflict_name->ancestor = git__strdup(ancestor))) ||
2117
+ (ours && !(conflict_name->ours = git__strdup(ours))) ||
2118
+ (theirs && !(conflict_name->theirs = git__strdup(theirs))) ||
2119
+ git_vector_insert(&index->names, conflict_name) < 0)
2120
+ {
2121
+ index_name_entry_free(conflict_name);
2122
+ return -1;
1232
2123
  }
1233
2124
 
1234
- return git_vector_insert(&index->names, conflict_name);
2125
+ index->dirty = 1;
2126
+ return 0;
1235
2127
  }
1236
2128
 
1237
2129
  void git_index_name_clear(git_index *index)
@@ -1241,50 +2133,40 @@ void git_index_name_clear(git_index *index)
1241
2133
 
1242
2134
  assert(index);
1243
2135
 
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
- }
2136
+ git_vector_foreach(&index->names, i, conflict_name)
2137
+ index_name_entry_free(conflict_name);
1256
2138
 
1257
2139
  git_vector_clear(&index->names);
2140
+
2141
+ index->dirty = 1;
1258
2142
  }
1259
2143
 
1260
- unsigned int git_index_reuc_entrycount(git_index *index)
2144
+ size_t git_index_reuc_entrycount(git_index *index)
1261
2145
  {
1262
2146
  assert(index);
1263
- return (unsigned int)index->reuc.length;
2147
+ return index->reuc.length;
2148
+ }
2149
+
2150
+ static int index_reuc_on_dup(void **old, void *new)
2151
+ {
2152
+ index_entry_reuc_free(*old);
2153
+ *old = new;
2154
+ return GIT_EEXISTS;
1264
2155
  }
1265
2156
 
1266
2157
  static int index_reuc_insert(
1267
2158
  git_index *index,
1268
- git_index_reuc_entry *reuc,
1269
- int replace)
2159
+ git_index_reuc_entry *reuc)
1270
2160
  {
1271
- git_index_reuc_entry **existing = NULL;
1272
- size_t position;
2161
+ int res;
1273
2162
 
1274
2163
  assert(index && reuc && reuc->path != NULL);
2164
+ assert(git_vector_is_sorted(&index->reuc));
1275
2165
 
1276
- if (!git_index_reuc_find(&position, index, reuc->path))
1277
- existing = (git_index_reuc_entry **)&index->reuc.contents[position];
1278
-
1279
- if (!replace || !existing)
1280
- return git_vector_insert(&index->reuc, reuc);
2166
+ res = git_vector_insert_sorted(&index->reuc, reuc, &index_reuc_on_dup);
2167
+ index->dirty = 1;
1281
2168
 
1282
- /* exists, replace it */
1283
- git__free((*existing)->path);
1284
- git__free(*existing);
1285
- *existing = reuc;
1286
-
1287
- return 0;
2169
+ return res == GIT_EEXISTS ? 0 : res;
1288
2170
  }
1289
2171
 
1290
2172
  int git_index_reuc_add(git_index *index, const char *path,
@@ -1297,15 +2179,13 @@ int git_index_reuc_add(git_index *index, const char *path,
1297
2179
 
1298
2180
  assert(index && path);
1299
2181
 
1300
- if ((error = index_entry_reuc_init(&reuc, path, ancestor_mode, ancestor_oid, our_mode, our_oid, their_mode, their_oid)) < 0 ||
1301
- (error = index_reuc_insert(index, reuc, 1)) < 0)
1302
- {
2182
+ if ((error = index_entry_reuc_init(&reuc, path, ancestor_mode,
2183
+ ancestor_oid, our_mode, our_oid, their_mode, their_oid)) < 0 ||
2184
+ (error = index_reuc_insert(index, reuc)) < 0)
1303
2185
  index_entry_reuc_free(reuc);
1304
- return error;
1305
- }
1306
2186
 
1307
2187
  return error;
1308
- }
2188
+ }
1309
2189
 
1310
2190
  int git_index_reuc_find(size_t *at_pos, git_index *index, const char *path)
1311
2191
  {
@@ -1321,7 +2201,7 @@ const git_index_reuc_entry *git_index_reuc_get_bypath(
1321
2201
  if (!index->reuc.length)
1322
2202
  return NULL;
1323
2203
 
1324
- git_vector_sort(&index->reuc);
2204
+ assert(git_vector_is_sorted(&index->reuc));
1325
2205
 
1326
2206
  if (git_index_reuc_find(&pos, index, path) < 0)
1327
2207
  return NULL;
@@ -1333,8 +2213,8 @@ const git_index_reuc_entry *git_index_reuc_get_byindex(
1333
2213
  git_index *index, size_t n)
1334
2214
  {
1335
2215
  assert(index);
2216
+ assert(git_vector_is_sorted(&index->reuc));
1336
2217
 
1337
- git_vector_sort(&index->reuc);
1338
2218
  return git_vector_get(&index->reuc, n);
1339
2219
  }
1340
2220
 
@@ -1343,7 +2223,7 @@ int git_index_reuc_remove(git_index *index, size_t position)
1343
2223
  int error;
1344
2224
  git_index_reuc_entry *reuc;
1345
2225
 
1346
- git_vector_sort(&index->reuc);
2226
+ assert(git_vector_is_sorted(&index->reuc));
1347
2227
 
1348
2228
  reuc = git_vector_get(&index->reuc, position);
1349
2229
  error = git_vector_remove(&index->reuc, position);
@@ -1351,27 +2231,27 @@ int git_index_reuc_remove(git_index *index, size_t position)
1351
2231
  if (!error)
1352
2232
  index_entry_reuc_free(reuc);
1353
2233
 
2234
+ index->dirty = 1;
1354
2235
  return error;
1355
2236
  }
1356
2237
 
1357
2238
  void git_index_reuc_clear(git_index *index)
1358
2239
  {
1359
2240
  size_t i;
1360
- git_index_reuc_entry *reuc;
1361
2241
 
1362
2242
  assert(index);
1363
2243
 
1364
- git_vector_foreach(&index->reuc, i, reuc) {
1365
- git__free(reuc->path);
1366
- git__free(reuc);
1367
- }
2244
+ for (i = 0; i < index->reuc.length; ++i)
2245
+ index_entry_reuc_free(git__swap(index->reuc.contents[i], NULL));
1368
2246
 
1369
2247
  git_vector_clear(&index->reuc);
2248
+
2249
+ index->dirty = 1;
1370
2250
  }
1371
2251
 
1372
2252
  static int index_error_invalid(const char *message)
1373
2253
  {
1374
- giterr_set(GITERR_INDEX, "Invalid data in index - %s", message);
2254
+ git_error_set(GIT_ERROR_INDEX, "invalid data in index - %s", message);
1375
2255
  return -1;
1376
2256
  }
1377
2257
 
@@ -1389,34 +2269,34 @@ static int read_reuc(git_index *index, const char *buffer, size_t size)
1389
2269
  while (size) {
1390
2270
  git_index_reuc_entry *lost;
1391
2271
 
1392
- len = strlen(buffer) + 1;
2272
+ len = p_strnlen(buffer, size) + 1;
1393
2273
  if (size <= len)
1394
2274
  return index_error_invalid("reading reuc entries");
1395
2275
 
1396
- lost = git__calloc(1, sizeof(git_index_reuc_entry));
1397
- GITERR_CHECK_ALLOC(lost);
1398
-
1399
- /* read NUL-terminated pathname for entry */
1400
- lost->path = git__strdup(buffer);
1401
- GITERR_CHECK_ALLOC(lost->path);
2276
+ lost = reuc_entry_alloc(buffer);
2277
+ GIT_ERROR_CHECK_ALLOC(lost);
1402
2278
 
1403
2279
  size -= len;
1404
2280
  buffer += len;
1405
2281
 
1406
2282
  /* read 3 ASCII octal numbers for stage entries */
1407
2283
  for (i = 0; i < 3; i++) {
1408
- int tmp;
2284
+ int64_t tmp;
1409
2285
 
1410
- if (git__strtol32(&tmp, buffer, &endptr, 8) < 0 ||
2286
+ if (git__strntol64(&tmp, buffer, size, &endptr, 8) < 0 ||
1411
2287
  !endptr || endptr == buffer || *endptr ||
1412
- (unsigned)tmp > UINT_MAX)
2288
+ tmp < 0 || tmp > UINT32_MAX) {
2289
+ index_entry_reuc_free(lost);
1413
2290
  return index_error_invalid("reading reuc entry stage");
2291
+ }
1414
2292
 
1415
- lost->mode[i] = tmp;
2293
+ lost->mode[i] = (uint32_t)tmp;
1416
2294
 
1417
2295
  len = (endptr + 1) - buffer;
1418
- if (size <= len)
2296
+ if (size <= len) {
2297
+ index_entry_reuc_free(lost);
1419
2298
  return index_error_invalid("reading reuc entry stage");
2299
+ }
1420
2300
 
1421
2301
  size -= len;
1422
2302
  buffer += len;
@@ -1426,8 +2306,10 @@ static int read_reuc(git_index *index, const char *buffer, size_t size)
1426
2306
  for (i = 0; i < 3; i++) {
1427
2307
  if (!lost->mode[i])
1428
2308
  continue;
1429
- if (size < 20)
2309
+ if (size < 20) {
2310
+ index_entry_reuc_free(lost);
1430
2311
  return index_error_invalid("reading reuc entry oid");
2312
+ }
1431
2313
 
1432
2314
  git_oid_fromraw(&lost->oid[i], (const unsigned char *) buffer);
1433
2315
  size -= 20;
@@ -1440,7 +2322,7 @@ static int read_reuc(git_index *index, const char *buffer, size_t size)
1440
2322
  }
1441
2323
 
1442
2324
  /* entries are guaranteed to be sorted on-disk */
1443
- index->reuc.sorted = 1;
2325
+ git_vector_set_sorted(&index->reuc, true);
1444
2326
 
1445
2327
  return 0;
1446
2328
  }
@@ -1456,15 +2338,16 @@ static int read_conflict_names(git_index *index, const char *buffer, size_t size
1456
2338
  return -1;
1457
2339
 
1458
2340
  #define read_conflict_name(ptr) \
1459
- len = strlen(buffer) + 1; \
1460
- if (size < len) \
1461
- return index_error_invalid("reading conflict name entries"); \
1462
- \
2341
+ len = p_strnlen(buffer, size) + 1; \
2342
+ if (size < len) { \
2343
+ index_error_invalid("reading conflict name entries"); \
2344
+ goto out_err; \
2345
+ } \
1463
2346
  if (len == 1) \
1464
2347
  ptr = NULL; \
1465
2348
  else { \
1466
2349
  ptr = git__malloc(len); \
1467
- GITERR_CHECK_ALLOC(ptr); \
2350
+ GIT_ERROR_CHECK_ALLOC(ptr); \
1468
2351
  memcpy(ptr, buffer, len); \
1469
2352
  } \
1470
2353
  \
@@ -1473,84 +2356,157 @@ static int read_conflict_names(git_index *index, const char *buffer, size_t size
1473
2356
 
1474
2357
  while (size) {
1475
2358
  git_index_name_entry *conflict_name = git__calloc(1, sizeof(git_index_name_entry));
1476
- GITERR_CHECK_ALLOC(conflict_name);
2359
+ GIT_ERROR_CHECK_ALLOC(conflict_name);
1477
2360
 
1478
2361
  read_conflict_name(conflict_name->ancestor);
1479
2362
  read_conflict_name(conflict_name->ours);
1480
2363
  read_conflict_name(conflict_name->theirs);
1481
2364
 
1482
2365
  if (git_vector_insert(&index->names, conflict_name) < 0)
1483
- return -1;
2366
+ goto out_err;
2367
+
2368
+ continue;
2369
+
2370
+ out_err:
2371
+ git__free(conflict_name->ancestor);
2372
+ git__free(conflict_name->ours);
2373
+ git__free(conflict_name->theirs);
2374
+ git__free(conflict_name);
2375
+ return -1;
1484
2376
  }
1485
2377
 
1486
2378
  #undef read_conflict_name
1487
2379
 
1488
2380
  /* entries are guaranteed to be sorted on-disk */
1489
- index->names.sorted = 1;
2381
+ git_vector_set_sorted(&index->names, true);
1490
2382
 
1491
2383
  return 0;
1492
2384
  }
1493
2385
 
1494
- static size_t read_entry(git_index_entry *dest, const void *buffer, size_t buffer_size)
2386
+ static size_t index_entry_size(size_t path_len, size_t varint_len, uint32_t flags)
2387
+ {
2388
+ if (varint_len) {
2389
+ if (flags & GIT_INDEX_ENTRY_EXTENDED)
2390
+ return offsetof(struct entry_long, path) + path_len + 1 + varint_len;
2391
+ else
2392
+ return offsetof(struct entry_short, path) + path_len + 1 + varint_len;
2393
+ } else {
2394
+ #define entry_size(type,len) ((offsetof(type, path) + (len) + 8) & ~7)
2395
+ if (flags & GIT_INDEX_ENTRY_EXTENDED)
2396
+ return entry_size(struct entry_long, path_len);
2397
+ else
2398
+ return entry_size(struct entry_short, path_len);
2399
+ #undef entry_size
2400
+ }
2401
+ }
2402
+
2403
+ static int read_entry(
2404
+ git_index_entry **out,
2405
+ size_t *out_size,
2406
+ git_index *index,
2407
+ const void *buffer,
2408
+ size_t buffer_size,
2409
+ const char *last)
1495
2410
  {
1496
2411
  size_t path_length, entry_size;
1497
- uint16_t flags_raw;
1498
2412
  const char *path_ptr;
1499
- const struct entry_short *source = buffer;
2413
+ struct entry_short source;
2414
+ git_index_entry entry = {{0}};
2415
+ bool compressed = index->version >= INDEX_VERSION_NUMBER_COMP;
2416
+ char *tmp_path = NULL;
1500
2417
 
1501
2418
  if (INDEX_FOOTER_SIZE + minimal_entry_size > buffer_size)
1502
- return 0;
2419
+ return -1;
1503
2420
 
1504
- memset(dest, 0x0, sizeof(git_index_entry));
1505
-
1506
- dest->ctime.seconds = (git_time_t)ntohl(source->ctime.seconds);
1507
- dest->ctime.nanoseconds = ntohl(source->ctime.nanoseconds);
1508
- dest->mtime.seconds = (git_time_t)ntohl(source->mtime.seconds);
1509
- dest->mtime.nanoseconds = ntohl(source->mtime.nanoseconds);
1510
- dest->dev = ntohl(source->dev);
1511
- dest->ino = ntohl(source->ino);
1512
- dest->mode = ntohl(source->mode);
1513
- dest->uid = ntohl(source->uid);
1514
- dest->gid = ntohl(source->gid);
1515
- dest->file_size = ntohl(source->file_size);
1516
- git_oid_cpy(&dest->oid, &source->oid);
1517
- dest->flags = ntohs(source->flags);
1518
-
1519
- if (dest->flags & GIT_IDXENTRY_EXTENDED) {
1520
- const struct entry_long *source_l = (const struct entry_long *)source;
1521
- path_ptr = source_l->path;
1522
-
1523
- flags_raw = ntohs(source_l->flags_extended);
1524
- memcpy(&dest->flags_extended, &flags_raw, 2);
2421
+ /* buffer is not guaranteed to be aligned */
2422
+ memcpy(&source, buffer, sizeof(struct entry_short));
2423
+
2424
+ entry.ctime.seconds = (git_time_t)ntohl(source.ctime.seconds);
2425
+ entry.ctime.nanoseconds = ntohl(source.ctime.nanoseconds);
2426
+ entry.mtime.seconds = (git_time_t)ntohl(source.mtime.seconds);
2427
+ entry.mtime.nanoseconds = ntohl(source.mtime.nanoseconds);
2428
+ entry.dev = ntohl(source.dev);
2429
+ entry.ino = ntohl(source.ino);
2430
+ entry.mode = ntohl(source.mode);
2431
+ entry.uid = ntohl(source.uid);
2432
+ entry.gid = ntohl(source.gid);
2433
+ entry.file_size = ntohl(source.file_size);
2434
+ git_oid_cpy(&entry.id, &source.oid);
2435
+ entry.flags = ntohs(source.flags);
2436
+
2437
+ if (entry.flags & GIT_INDEX_ENTRY_EXTENDED) {
2438
+ uint16_t flags_raw;
2439
+ size_t flags_offset;
2440
+
2441
+ flags_offset = offsetof(struct entry_long, flags_extended);
2442
+ memcpy(&flags_raw, (const char *) buffer + flags_offset,
2443
+ sizeof(flags_raw));
2444
+ flags_raw = ntohs(flags_raw);
2445
+
2446
+ memcpy(&entry.flags_extended, &flags_raw, sizeof(flags_raw));
2447
+ path_ptr = (const char *) buffer + offsetof(struct entry_long, path);
1525
2448
  } else
1526
- path_ptr = source->path;
2449
+ path_ptr = (const char *) buffer + offsetof(struct entry_short, path);
1527
2450
 
1528
- path_length = dest->flags & GIT_IDXENTRY_NAMEMASK;
2451
+ if (!compressed) {
2452
+ path_length = entry.flags & GIT_INDEX_ENTRY_NAMEMASK;
1529
2453
 
1530
- /* if this is a very long string, we must find its
1531
- * real length without overflowing */
1532
- if (path_length == 0xFFF) {
1533
- const char *path_end;
2454
+ /* if this is a very long string, we must find its
2455
+ * real length without overflowing */
2456
+ if (path_length == 0xFFF) {
2457
+ const char *path_end;
1534
2458
 
1535
- path_end = memchr(path_ptr, '\0', buffer_size);
1536
- if (path_end == NULL)
1537
- return 0;
2459
+ path_end = memchr(path_ptr, '\0', buffer_size);
2460
+ if (path_end == NULL)
2461
+ return -1;
2462
+
2463
+ path_length = path_end - path_ptr;
2464
+ }
2465
+
2466
+ entry_size = index_entry_size(path_length, 0, entry.flags);
2467
+ entry.path = (char *)path_ptr;
2468
+ } else {
2469
+ size_t varint_len, last_len, prefix_len, suffix_len, path_len;
2470
+ uintmax_t strip_len;
2471
+
2472
+ strip_len = git_decode_varint((const unsigned char *)path_ptr, &varint_len);
2473
+ last_len = strlen(last);
2474
+
2475
+ if (varint_len == 0 || last_len < strip_len)
2476
+ return index_error_invalid("incorrect prefix length");
2477
+
2478
+ prefix_len = last_len - (size_t)strip_len;
2479
+ suffix_len = strlen(path_ptr + varint_len);
2480
+
2481
+ GIT_ERROR_CHECK_ALLOC_ADD(&path_len, prefix_len, suffix_len);
2482
+ GIT_ERROR_CHECK_ALLOC_ADD(&path_len, path_len, 1);
2483
+
2484
+ if (path_len > GIT_PATH_MAX)
2485
+ return index_error_invalid("unreasonable path length");
1538
2486
 
1539
- path_length = path_end - path_ptr;
2487
+ tmp_path = git__malloc(path_len);
2488
+ GIT_ERROR_CHECK_ALLOC(tmp_path);
2489
+
2490
+ memcpy(tmp_path, last, prefix_len);
2491
+ memcpy(tmp_path + prefix_len, path_ptr + varint_len, suffix_len + 1);
2492
+ entry_size = index_entry_size(suffix_len, varint_len, entry.flags);
2493
+ entry.path = tmp_path;
1540
2494
  }
1541
2495
 
1542
- if (dest->flags & GIT_IDXENTRY_EXTENDED)
1543
- entry_size = long_entry_size(path_length);
1544
- else
1545
- entry_size = short_entry_size(path_length);
2496
+ if (entry_size == 0)
2497
+ return -1;
1546
2498
 
1547
2499
  if (INDEX_FOOTER_SIZE + entry_size > buffer_size)
1548
- return 0;
2500
+ return -1;
1549
2501
 
1550
- dest->path = git__strdup(path_ptr);
1551
- assert(dest->path);
2502
+ if (index_entry_dup(out, index, &entry) < 0) {
2503
+ git__free(tmp_path);
2504
+ return -1;
2505
+ }
1552
2506
 
1553
- return entry_size;
2507
+ git__free(tmp_path);
2508
+ *out_size = entry_size;
2509
+ return 0;
1554
2510
  }
1555
2511
 
1556
2512
  static int read_header(struct index_header *dest, const void *buffer)
@@ -1562,64 +2518,72 @@ static int read_header(struct index_header *dest, const void *buffer)
1562
2518
  return index_error_invalid("incorrect header signature");
1563
2519
 
1564
2520
  dest->version = ntohl(source->version);
1565
- if (dest->version != INDEX_VERSION_NUMBER_EXT &&
1566
- dest->version != INDEX_VERSION_NUMBER)
2521
+ if (dest->version < INDEX_VERSION_NUMBER_LB ||
2522
+ dest->version > INDEX_VERSION_NUMBER_UB)
1567
2523
  return index_error_invalid("incorrect header version");
1568
2524
 
1569
2525
  dest->entry_count = ntohl(source->entry_count);
1570
2526
  return 0;
1571
2527
  }
1572
2528
 
1573
- static size_t read_extension(git_index *index, const char *buffer, size_t buffer_size)
2529
+ static int read_extension(size_t *read_len, git_index *index, const char *buffer, size_t buffer_size)
1574
2530
  {
1575
- const struct index_extension *source;
1576
2531
  struct index_extension dest;
1577
2532
  size_t total_size;
1578
2533
 
1579
- source = (const struct index_extension *)(buffer);
1580
-
1581
- memcpy(dest.signature, source->signature, 4);
1582
- dest.extension_size = ntohl(source->extension_size);
2534
+ /* buffer is not guaranteed to be aligned */
2535
+ memcpy(&dest, buffer, sizeof(struct index_extension));
2536
+ dest.extension_size = ntohl(dest.extension_size);
1583
2537
 
1584
2538
  total_size = dest.extension_size + sizeof(struct index_extension);
1585
2539
 
1586
- if (buffer_size < total_size ||
1587
- buffer_size - total_size < INDEX_FOOTER_SIZE)
1588
- return 0;
2540
+ if (dest.extension_size > total_size ||
2541
+ buffer_size < total_size ||
2542
+ buffer_size - total_size < INDEX_FOOTER_SIZE) {
2543
+ index_error_invalid("extension is truncated");
2544
+ return -1;
2545
+ }
1589
2546
 
1590
2547
  /* optional extension */
1591
2548
  if (dest.signature[0] >= 'A' && dest.signature[0] <= 'Z') {
1592
2549
  /* tree cache */
1593
2550
  if (memcmp(dest.signature, INDEX_EXT_TREECACHE_SIG, 4) == 0) {
1594
- if (git_tree_cache_read(&index->tree, buffer + 8, dest.extension_size) < 0)
1595
- return 0;
2551
+ if (git_tree_cache_read(&index->tree, buffer + 8, dest.extension_size, &index->tree_pool) < 0)
2552
+ return -1;
1596
2553
  } else if (memcmp(dest.signature, INDEX_EXT_UNMERGED_SIG, 4) == 0) {
1597
2554
  if (read_reuc(index, buffer + 8, dest.extension_size) < 0)
1598
- return 0;
2555
+ return -1;
1599
2556
  } else if (memcmp(dest.signature, INDEX_EXT_CONFLICT_NAME_SIG, 4) == 0) {
1600
2557
  if (read_conflict_names(index, buffer + 8, dest.extension_size) < 0)
1601
- return 0;
2558
+ return -1;
1602
2559
  }
1603
2560
  /* else, unsupported extension. We cannot parse this, but we can skip
1604
2561
  * it by returning `total_size */
1605
2562
  } else {
1606
2563
  /* we cannot handle non-ignorable extensions;
1607
2564
  * in fact they aren't even defined in the standard */
1608
- return 0;
2565
+ git_error_set(GIT_ERROR_INDEX, "unsupported mandatory extension: '%.4s'", dest.signature);
2566
+ return -1;
1609
2567
  }
1610
2568
 
1611
- return total_size;
2569
+ *read_len = total_size;
2570
+
2571
+ return 0;
1612
2572
  }
1613
2573
 
1614
2574
  static int parse_index(git_index *index, const char *buffer, size_t buffer_size)
1615
2575
  {
2576
+ int error = 0;
1616
2577
  unsigned int i;
1617
2578
  struct index_header header = { 0 };
1618
2579
  git_oid checksum_calculated, checksum_expected;
2580
+ const char *last = NULL;
2581
+ const char *empty = "";
1619
2582
 
1620
2583
  #define seek_forward(_increase) { \
1621
- if (_increase >= buffer_size) \
1622
- return index_error_invalid("ran out of data while parsing"); \
2584
+ if (_increase >= buffer_size) { \
2585
+ error = index_error_invalid("ran out of data while parsing"); \
2586
+ goto done; } \
1623
2587
  buffer += _increase; \
1624
2588
  buffer_size -= _increase;\
1625
2589
  }
@@ -1632,65 +2596,95 @@ static int parse_index(git_index *index, const char *buffer, size_t buffer_size)
1632
2596
  git_hash_buf(&checksum_calculated, buffer, buffer_size - INDEX_FOOTER_SIZE);
1633
2597
 
1634
2598
  /* Parse header */
1635
- if (read_header(&header, buffer) < 0)
1636
- return -1;
2599
+ if ((error = read_header(&header, buffer)) < 0)
2600
+ return error;
2601
+
2602
+ index->version = header.version;
2603
+ if (index->version >= INDEX_VERSION_NUMBER_COMP)
2604
+ last = empty;
1637
2605
 
1638
2606
  seek_forward(INDEX_HEADER_SIZE);
1639
2607
 
1640
- git_vector_clear(&index->entries);
2608
+ assert(!index->entries.length);
2609
+
2610
+ if (index->ignore_case)
2611
+ git_idxmap_icase_resize((git_idxmap_icase *) index->entries_map, header.entry_count);
2612
+ else
2613
+ git_idxmap_resize(index->entries_map, header.entry_count);
1641
2614
 
1642
2615
  /* Parse all the entries */
1643
2616
  for (i = 0; i < header.entry_count && buffer_size > INDEX_FOOTER_SIZE; ++i) {
2617
+ git_index_entry *entry = NULL;
1644
2618
  size_t entry_size;
1645
- git_index_entry *entry;
1646
2619
 
1647
- entry = git__malloc(sizeof(git_index_entry));
1648
- GITERR_CHECK_ALLOC(entry);
2620
+ if ((error = read_entry(&entry, &entry_size, index, buffer, buffer_size, last)) < 0) {
2621
+ error = index_error_invalid("invalid entry");
2622
+ goto done;
2623
+ }
2624
+
2625
+ if ((error = git_vector_insert(&index->entries, entry)) < 0) {
2626
+ index_entry_free(entry);
2627
+ goto done;
2628
+ }
1649
2629
 
1650
- entry_size = read_entry(entry, buffer, buffer_size);
2630
+ INSERT_IN_MAP(index, entry, &error);
1651
2631
 
1652
- /* 0 bytes read means an object corruption */
1653
- if (entry_size == 0)
1654
- return index_error_invalid("invalid entry");
2632
+ if (error < 0) {
2633
+ index_entry_free(entry);
2634
+ goto done;
2635
+ }
2636
+ error = 0;
1655
2637
 
1656
- if (git_vector_insert(&index->entries, entry) < 0)
1657
- return -1;
2638
+ if (index->version >= INDEX_VERSION_NUMBER_COMP)
2639
+ last = entry->path;
1658
2640
 
1659
2641
  seek_forward(entry_size);
1660
2642
  }
1661
2643
 
1662
- if (i != header.entry_count)
1663
- return index_error_invalid("header entries changed while parsing");
2644
+ if (i != header.entry_count) {
2645
+ error = index_error_invalid("header entries changed while parsing");
2646
+ goto done;
2647
+ }
1664
2648
 
1665
2649
  /* There's still space for some extensions! */
1666
2650
  while (buffer_size > INDEX_FOOTER_SIZE) {
1667
2651
  size_t extension_size;
1668
2652
 
1669
- extension_size = read_extension(index, buffer, buffer_size);
1670
-
1671
- /* see if we have read any bytes from the extension */
1672
- if (extension_size == 0)
1673
- return index_error_invalid("extension is truncated");
2653
+ if ((error = read_extension(&extension_size, index, buffer, buffer_size)) < 0) {
2654
+ goto done;
2655
+ }
1674
2656
 
1675
2657
  seek_forward(extension_size);
1676
2658
  }
1677
2659
 
1678
- if (buffer_size != INDEX_FOOTER_SIZE)
1679
- return index_error_invalid("buffer size does not match index footer size");
2660
+ if (buffer_size != INDEX_FOOTER_SIZE) {
2661
+ error = index_error_invalid(
2662
+ "buffer size does not match index footer size");
2663
+ goto done;
2664
+ }
1680
2665
 
1681
2666
  /* 160-bit SHA-1 over the content of the index file before this checksum. */
1682
2667
  git_oid_fromraw(&checksum_expected, (const unsigned char *)buffer);
1683
2668
 
1684
- if (git_oid__cmp(&checksum_calculated, &checksum_expected) != 0)
1685
- return index_error_invalid("calculated checksum does not match expected");
2669
+ if (git_oid__cmp(&checksum_calculated, &checksum_expected) != 0) {
2670
+ error = index_error_invalid(
2671
+ "calculated checksum does not match expected");
2672
+ goto done;
2673
+ }
2674
+
2675
+ git_oid_cpy(&index->checksum, &checksum_calculated);
1686
2676
 
1687
2677
  #undef seek_forward
1688
2678
 
1689
- /* Entries are stored case-sensitively on disk. */
1690
- index->entries.sorted = !index->ignore_case;
2679
+ /* Entries are stored case-sensitively on disk, so re-sort now if
2680
+ * in-memory index is supposed to be case-insensitive
2681
+ */
2682
+ git_vector_set_sorted(&index->entries, !index->ignore_case);
1691
2683
  git_vector_sort(&index->entries);
1692
2684
 
1693
- return 0;
2685
+ index->dirty = 0;
2686
+ done:
2687
+ return error;
1694
2688
  }
1695
2689
 
1696
2690
  static bool is_index_extended(git_index *index)
@@ -1701,36 +2695,48 @@ static bool is_index_extended(git_index *index)
1701
2695
  extended = 0;
1702
2696
 
1703
2697
  git_vector_foreach(&index->entries, i, entry) {
1704
- entry->flags &= ~GIT_IDXENTRY_EXTENDED;
1705
- if (entry->flags_extended & GIT_IDXENTRY_EXTENDED_FLAGS) {
2698
+ entry->flags &= ~GIT_INDEX_ENTRY_EXTENDED;
2699
+ if (entry->flags_extended & GIT_INDEX_ENTRY_EXTENDED_FLAGS) {
1706
2700
  extended++;
1707
- entry->flags |= GIT_IDXENTRY_EXTENDED;
2701
+ entry->flags |= GIT_INDEX_ENTRY_EXTENDED;
1708
2702
  }
1709
2703
  }
1710
2704
 
1711
2705
  return (extended > 0);
1712
2706
  }
1713
2707
 
1714
- static int write_disk_entry(git_filebuf *file, git_index_entry *entry)
2708
+ static int write_disk_entry(git_filebuf *file, git_index_entry *entry, const char *last)
1715
2709
  {
1716
2710
  void *mem = NULL;
1717
- struct entry_short *ondisk;
2711
+ struct entry_short ondisk;
1718
2712
  size_t path_len, disk_size;
2713
+ int varint_len = 0;
1719
2714
  char *path;
2715
+ const char *path_start = entry->path;
2716
+ size_t same_len = 0;
1720
2717
 
1721
- path_len = strlen(entry->path);
2718
+ path_len = ((struct entry_internal *)entry)->pathlen;
1722
2719
 
1723
- if (entry->flags & GIT_IDXENTRY_EXTENDED)
1724
- disk_size = long_entry_size(path_len);
1725
- else
1726
- disk_size = short_entry_size(path_len);
2720
+ if (last) {
2721
+ const char *last_c = last;
2722
+
2723
+ while (*path_start == *last_c) {
2724
+ if (!*path_start || !*last_c)
2725
+ break;
2726
+ ++path_start;
2727
+ ++last_c;
2728
+ ++same_len;
2729
+ }
2730
+ path_len -= same_len;
2731
+ varint_len = git_encode_varint(NULL, 0, same_len);
2732
+ }
2733
+
2734
+ disk_size = index_entry_size(path_len, varint_len, entry->flags);
1727
2735
 
1728
2736
  if (git_filebuf_reserve(file, &mem, disk_size) < 0)
1729
2737
  return -1;
1730
2738
 
1731
- ondisk = (struct entry_short *)mem;
1732
-
1733
- memset(ondisk, 0x0, disk_size);
2739
+ memset(mem, 0x0, disk_size);
1734
2740
 
1735
2741
  /**
1736
2742
  * Yes, we have to truncate.
@@ -1742,31 +2748,57 @@ static int write_disk_entry(git_filebuf *file, git_index_entry *entry)
1742
2748
  *
1743
2749
  * In 2038 I will be either too dead or too rich to care about this
1744
2750
  */
1745
- ondisk->ctime.seconds = htonl((uint32_t)entry->ctime.seconds);
1746
- ondisk->mtime.seconds = htonl((uint32_t)entry->mtime.seconds);
1747
- ondisk->ctime.nanoseconds = htonl(entry->ctime.nanoseconds);
1748
- ondisk->mtime.nanoseconds = htonl(entry->mtime.nanoseconds);
1749
- ondisk->dev = htonl(entry->dev);
1750
- ondisk->ino = htonl(entry->ino);
1751
- ondisk->mode = htonl(entry->mode);
1752
- ondisk->uid = htonl(entry->uid);
1753
- ondisk->gid = htonl(entry->gid);
1754
- ondisk->file_size = htonl((uint32_t)entry->file_size);
1755
-
1756
- git_oid_cpy(&ondisk->oid, &entry->oid);
1757
-
1758
- ondisk->flags = htons(entry->flags);
1759
-
1760
- if (entry->flags & GIT_IDXENTRY_EXTENDED) {
1761
- struct entry_long *ondisk_ext;
1762
- ondisk_ext = (struct entry_long *)ondisk;
1763
- ondisk_ext->flags_extended = htons(entry->flags_extended);
1764
- path = ondisk_ext->path;
2751
+ ondisk.ctime.seconds = htonl((uint32_t)entry->ctime.seconds);
2752
+ ondisk.mtime.seconds = htonl((uint32_t)entry->mtime.seconds);
2753
+ ondisk.ctime.nanoseconds = htonl(entry->ctime.nanoseconds);
2754
+ ondisk.mtime.nanoseconds = htonl(entry->mtime.nanoseconds);
2755
+ ondisk.dev = htonl(entry->dev);
2756
+ ondisk.ino = htonl(entry->ino);
2757
+ ondisk.mode = htonl(entry->mode);
2758
+ ondisk.uid = htonl(entry->uid);
2759
+ ondisk.gid = htonl(entry->gid);
2760
+ ondisk.file_size = htonl((uint32_t)entry->file_size);
2761
+
2762
+ git_oid_cpy(&ondisk.oid, &entry->id);
2763
+
2764
+ ondisk.flags = htons(entry->flags);
2765
+
2766
+ if (entry->flags & GIT_INDEX_ENTRY_EXTENDED) {
2767
+ struct entry_long ondisk_ext;
2768
+ memcpy(&ondisk_ext, &ondisk, sizeof(struct entry_short));
2769
+ ondisk_ext.flags_extended = htons(entry->flags_extended &
2770
+ GIT_INDEX_ENTRY_EXTENDED_FLAGS);
2771
+ memcpy(mem, &ondisk_ext, offsetof(struct entry_long, path));
2772
+ path = ((struct entry_long*)mem)->path;
2773
+ disk_size -= offsetof(struct entry_long, path);
2774
+ } else {
2775
+ memcpy(mem, &ondisk, offsetof(struct entry_short, path));
2776
+ path = ((struct entry_short*)mem)->path;
2777
+ disk_size -= offsetof(struct entry_short, path);
1765
2778
  }
1766
- else
1767
- path = ondisk->path;
1768
2779
 
1769
- memcpy(path, entry->path, path_len);
2780
+ if (last) {
2781
+ varint_len = git_encode_varint((unsigned char *) path,
2782
+ disk_size, same_len);
2783
+ assert(varint_len > 0);
2784
+ path += varint_len;
2785
+ disk_size -= varint_len;
2786
+
2787
+ /*
2788
+ * If using path compression, we are not allowed
2789
+ * to have additional trailing NULs.
2790
+ */
2791
+ assert(disk_size == path_len + 1);
2792
+ } else {
2793
+ /*
2794
+ * If no path compression is used, we do have
2795
+ * NULs as padding. As such, simply assert that
2796
+ * we have enough space left to write the path.
2797
+ */
2798
+ assert(disk_size > path_len);
2799
+ }
2800
+
2801
+ memcpy(path, path_start, path_len + 1);
1770
2802
 
1771
2803
  return 0;
1772
2804
  }
@@ -1775,21 +2807,29 @@ static int write_entries(git_index *index, git_filebuf *file)
1775
2807
  {
1776
2808
  int error = 0;
1777
2809
  size_t i;
1778
- git_vector case_sorted;
2810
+ git_vector case_sorted, *entries;
1779
2811
  git_index_entry *entry;
1780
- git_vector *out = &index->entries;
2812
+ const char *last = NULL;
1781
2813
 
1782
2814
  /* If index->entries is sorted case-insensitively, then we need
1783
2815
  * to re-sort it case-sensitively before writing */
1784
2816
  if (index->ignore_case) {
1785
- git_vector_dup(&case_sorted, &index->entries, index_cmp);
2817
+ git_vector_dup(&case_sorted, &index->entries, git_index_entry_cmp);
1786
2818
  git_vector_sort(&case_sorted);
1787
- out = &case_sorted;
2819
+ entries = &case_sorted;
2820
+ } else {
2821
+ entries = &index->entries;
1788
2822
  }
1789
2823
 
1790
- git_vector_foreach(out, i, entry)
1791
- if ((error = write_disk_entry(file, entry)) < 0)
2824
+ if (index->version >= INDEX_VERSION_NUMBER_COMP)
2825
+ last = "";
2826
+
2827
+ git_vector_foreach(entries, i, entry) {
2828
+ if ((error = write_disk_entry(file, entry, last)) < 0)
1792
2829
  break;
2830
+ if (index->version >= INDEX_VERSION_NUMBER_COMP)
2831
+ last = entry->path;
2832
+ }
1793
2833
 
1794
2834
  if (index->ignore_case)
1795
2835
  git_vector_free(&case_sorted);
@@ -1800,16 +2840,13 @@ static int write_entries(git_index *index, git_filebuf *file)
1800
2840
  static int write_extension(git_filebuf *file, struct index_extension *header, git_buf *data)
1801
2841
  {
1802
2842
  struct index_extension ondisk;
1803
- int error = 0;
1804
2843
 
1805
2844
  memset(&ondisk, 0x0, sizeof(struct index_extension));
1806
2845
  memcpy(&ondisk, header, 4);
1807
2846
  ondisk.extension_size = htonl(header->extension_size);
1808
2847
 
1809
- if ((error = git_filebuf_write(file, &ondisk, sizeof(struct index_extension))) == 0)
1810
- error = git_filebuf_write(file, data->ptr, data->size);
1811
-
1812
- return error;
2848
+ git_filebuf_write(file, &ondisk, sizeof(struct index_extension));
2849
+ return git_filebuf_write(file, data->ptr, data->size);
1813
2850
  }
1814
2851
 
1815
2852
  static int create_name_extension_data(git_buf *name_buf, git_index_name_entry *conflict_name)
@@ -1861,7 +2898,7 @@ static int write_name_extension(git_index *index, git_filebuf *file)
1861
2898
 
1862
2899
  error = write_extension(file, &extension, &name_buf);
1863
2900
 
1864
- git_buf_free(&name_buf);
2901
+ git_buf_dispose(&name_buf);
1865
2902
 
1866
2903
  done:
1867
2904
  return error;
@@ -1909,24 +2946,62 @@ static int write_reuc_extension(git_index *index, git_filebuf *file)
1909
2946
 
1910
2947
  error = write_extension(file, &extension, &reuc_buf);
1911
2948
 
1912
- git_buf_free(&reuc_buf);
2949
+ git_buf_dispose(&reuc_buf);
1913
2950
 
1914
2951
  done:
1915
2952
  return error;
1916
2953
  }
1917
2954
 
1918
- static int write_index(git_index *index, git_filebuf *file)
2955
+ static int write_tree_extension(git_index *index, git_filebuf *file)
2956
+ {
2957
+ struct index_extension extension;
2958
+ git_buf buf = GIT_BUF_INIT;
2959
+ int error;
2960
+
2961
+ if (index->tree == NULL)
2962
+ return 0;
2963
+
2964
+ if ((error = git_tree_cache_write(&buf, index->tree)) < 0)
2965
+ return error;
2966
+
2967
+ memset(&extension, 0x0, sizeof(struct index_extension));
2968
+ memcpy(&extension.signature, INDEX_EXT_TREECACHE_SIG, 4);
2969
+ extension.extension_size = (uint32_t)buf.size;
2970
+
2971
+ error = write_extension(file, &extension, &buf);
2972
+
2973
+ git_buf_dispose(&buf);
2974
+
2975
+ return error;
2976
+ }
2977
+
2978
+ static void clear_uptodate(git_index *index)
2979
+ {
2980
+ git_index_entry *entry;
2981
+ size_t i;
2982
+
2983
+ git_vector_foreach(&index->entries, i, entry)
2984
+ entry->flags_extended &= ~GIT_INDEX_ENTRY_UPTODATE;
2985
+ }
2986
+
2987
+ static int write_index(git_oid *checksum, git_index *index, git_filebuf *file)
1919
2988
  {
1920
2989
  git_oid hash_final;
1921
2990
  struct index_header header;
1922
2991
  bool is_extended;
2992
+ uint32_t index_version_number;
1923
2993
 
1924
2994
  assert(index && file);
1925
2995
 
1926
- is_extended = is_index_extended(index);
2996
+ if (index->version <= INDEX_VERSION_NUMBER_EXT) {
2997
+ is_extended = is_index_extended(index);
2998
+ index_version_number = is_extended ? INDEX_VERSION_NUMBER_EXT : INDEX_VERSION_NUMBER_LB;
2999
+ } else {
3000
+ index_version_number = index->version;
3001
+ }
1927
3002
 
1928
3003
  header.signature = htonl(INDEX_HEADER_SIG);
1929
- header.version = htonl(is_extended ? INDEX_VERSION_NUMBER_EXT : INDEX_VERSION_NUMBER);
3004
+ header.version = htonl(index_version_number);
1930
3005
  header.entry_count = htonl((uint32_t)index->entries.length);
1931
3006
 
1932
3007
  if (git_filebuf_write(file, &header, sizeof(struct index_header)) < 0)
@@ -1935,7 +3010,9 @@ static int write_index(git_index *index, git_filebuf *file)
1935
3010
  if (write_entries(index, file) < 0)
1936
3011
  return -1;
1937
3012
 
1938
- /* TODO: write tree cache extension */
3013
+ /* write the tree cache extension */
3014
+ if (index->tree != NULL && write_tree_extension(index, file) < 0)
3015
+ return -1;
1939
3016
 
1940
3017
  /* write the rename conflict extension */
1941
3018
  if (index->names.length > 0 && write_name_extension(index, file) < 0)
@@ -1947,19 +3024,34 @@ static int write_index(git_index *index, git_filebuf *file)
1947
3024
 
1948
3025
  /* get out the hash for all the contents we've appended to the file */
1949
3026
  git_filebuf_hash(&hash_final, file);
3027
+ git_oid_cpy(checksum, &hash_final);
1950
3028
 
1951
3029
  /* write it at the end of the file */
1952
- return git_filebuf_write(file, hash_final.id, GIT_OID_RAWSZ);
3030
+ if (git_filebuf_write(file, hash_final.id, GIT_OID_RAWSZ) < 0)
3031
+ return -1;
3032
+
3033
+ /* file entries are no longer up to date */
3034
+ clear_uptodate(index);
3035
+
3036
+ return 0;
1953
3037
  }
1954
3038
 
1955
3039
  int git_index_entry_stage(const git_index_entry *entry)
1956
3040
  {
1957
- return GIT_IDXENTRY_STAGE(entry);
3041
+ return GIT_INDEX_ENTRY_STAGE(entry);
3042
+ }
3043
+
3044
+ int git_index_entry_is_conflict(const git_index_entry *entry)
3045
+ {
3046
+ return (GIT_INDEX_ENTRY_STAGE(entry) > 0);
1958
3047
  }
1959
3048
 
1960
3049
  typedef struct read_tree_data {
1961
3050
  git_index *index;
1962
3051
  git_vector *old_entries;
3052
+ git_vector *new_entries;
3053
+ git_vector_cmp entry_cmp;
3054
+ git_tree_cache *tree;
1963
3055
  } read_tree_data;
1964
3056
 
1965
3057
  static int read_tree_cb(
@@ -1968,6 +3060,7 @@ static int read_tree_cb(
1968
3060
  read_tree_data *data = payload;
1969
3061
  git_index_entry *entry = NULL, *old_entry;
1970
3062
  git_buf path = GIT_BUF_INIT;
3063
+ size_t pos;
1971
3064
 
1972
3065
  if (git_tree_entry__is_tree(tentry))
1973
3066
  return 0;
@@ -1975,40 +3068,28 @@ static int read_tree_cb(
1975
3068
  if (git_buf_joinpath(&path, root, tentry->filename) < 0)
1976
3069
  return -1;
1977
3070
 
1978
- entry = git__calloc(1, sizeof(git_index_entry));
1979
- GITERR_CHECK_ALLOC(entry);
3071
+ if (index_entry_create(&entry, INDEX_OWNER(data->index), path.ptr, NULL, false) < 0)
3072
+ return -1;
1980
3073
 
1981
3074
  entry->mode = tentry->attr;
1982
- entry->oid = tentry->oid;
3075
+ git_oid_cpy(&entry->id, git_tree_entry_id(tentry));
1983
3076
 
1984
3077
  /* 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
- }
3078
+ if (data->old_entries != NULL &&
3079
+ !index_find_in_entries(
3080
+ &pos, data->old_entries, data->entry_cmp, path.ptr, 0, 0) &&
3081
+ (old_entry = git_vector_get(data->old_entries, pos)) != NULL &&
3082
+ entry->mode == old_entry->mode &&
3083
+ git_oid_equal(&entry->id, &old_entry->id))
3084
+ {
3085
+ index_entry_cpy(entry, old_entry);
3086
+ entry->flags_extended = 0;
2001
3087
  }
2002
3088
 
2003
- if (path.size < GIT_IDXENTRY_NAMEMASK)
2004
- entry->flags = path.size & GIT_IDXENTRY_NAMEMASK;
2005
- else
2006
- entry->flags = GIT_IDXENTRY_NAMEMASK;
2007
-
2008
- entry->path = git_buf_detach(&path);
2009
- git_buf_free(&path);
3089
+ index_entry_adjust_namemask(entry, path.size);
3090
+ git_buf_dispose(&path);
2010
3091
 
2011
- if (git_vector_insert(&data->index->entries, entry) < 0) {
3092
+ if (git_vector_insert(data->new_entries, entry) < 0) {
2012
3093
  index_entry_free(entry);
2013
3094
  return -1;
2014
3095
  }
@@ -2020,25 +3101,225 @@ int git_index_read_tree(git_index *index, const git_tree *tree)
2020
3101
  {
2021
3102
  int error = 0;
2022
3103
  git_vector entries = GIT_VECTOR_INIT;
3104
+ git_idxmap *entries_map;
2023
3105
  read_tree_data data;
3106
+ size_t i;
3107
+ git_index_entry *e;
3108
+
3109
+ if (git_idxmap_alloc(&entries_map) < 0)
3110
+ return -1;
3111
+
3112
+ git_vector_set_cmp(&entries, index->entries._cmp); /* match sort */
3113
+
3114
+ data.index = index;
3115
+ data.old_entries = &index->entries;
3116
+ data.new_entries = &entries;
3117
+ data.entry_cmp = index->entries_search;
3118
+
3119
+ index->tree = NULL;
3120
+ git_pool_clear(&index->tree_pool);
2024
3121
 
2025
3122
  git_vector_sort(&index->entries);
2026
3123
 
2027
- git_vector_set_cmp(&entries, index->entries._cmp);
2028
- git_vector_swap(&entries, &index->entries);
3124
+ if ((error = git_tree_walk(tree, GIT_TREEWALK_POST, read_tree_cb, &data)) < 0)
3125
+ goto cleanup;
3126
+
3127
+ if (index->ignore_case)
3128
+ git_idxmap_icase_resize((git_idxmap_icase *) entries_map, entries.length);
3129
+ else
3130
+ git_idxmap_resize(entries_map, entries.length);
2029
3131
 
2030
- git_index_clear(index);
3132
+ git_vector_foreach(&entries, i, e) {
3133
+ INSERT_IN_MAP_EX(index, entries_map, e, &error);
2031
3134
 
2032
- data.index = index;
2033
- data.old_entries = &entries;
3135
+ if (error < 0) {
3136
+ git_error_set(GIT_ERROR_INDEX, "failed to insert entry into map");
3137
+ return error;
3138
+ }
3139
+ }
2034
3140
 
2035
- error = git_tree_walk(tree, GIT_TREEWALK_POST, read_tree_cb, &data);
3141
+ error = 0;
2036
3142
 
2037
- index_entries_free(&entries);
3143
+ git_vector_sort(&entries);
3144
+
3145
+ if ((error = git_index_clear(index)) < 0) {
3146
+ /* well, this isn't good */;
3147
+ } else {
3148
+ git_vector_swap(&entries, &index->entries);
3149
+ entries_map = git__swap(index->entries_map, entries_map);
3150
+ }
3151
+
3152
+ index->dirty = 1;
3153
+
3154
+ cleanup:
2038
3155
  git_vector_free(&entries);
3156
+ git_idxmap_free(entries_map);
3157
+ if (error < 0)
3158
+ return error;
2039
3159
 
2040
- git_vector_sort(&index->entries);
3160
+ error = git_tree_cache_read_tree(&index->tree, tree, &index->tree_pool);
3161
+
3162
+ return error;
3163
+ }
3164
+
3165
+ static int git_index_read_iterator(
3166
+ git_index *index,
3167
+ git_iterator *new_iterator,
3168
+ size_t new_length_hint)
3169
+ {
3170
+ git_vector new_entries = GIT_VECTOR_INIT,
3171
+ remove_entries = GIT_VECTOR_INIT;
3172
+ git_idxmap *new_entries_map = NULL;
3173
+ git_iterator *index_iterator = NULL;
3174
+ git_iterator_options opts = GIT_ITERATOR_OPTIONS_INIT;
3175
+ const git_index_entry *old_entry, *new_entry;
3176
+ git_index_entry *entry;
3177
+ size_t i;
3178
+ int error;
3179
+
3180
+ assert((new_iterator->flags & GIT_ITERATOR_DONT_IGNORE_CASE));
3181
+
3182
+ if ((error = git_vector_init(&new_entries, new_length_hint, index->entries._cmp)) < 0 ||
3183
+ (error = git_vector_init(&remove_entries, index->entries.length, NULL)) < 0 ||
3184
+ (error = git_idxmap_alloc(&new_entries_map)) < 0)
3185
+ goto done;
3186
+
3187
+ if (index->ignore_case && new_length_hint)
3188
+ git_idxmap_icase_resize((git_idxmap_icase *) new_entries_map, new_length_hint);
3189
+ else if (new_length_hint)
3190
+ git_idxmap_resize(new_entries_map, new_length_hint);
3191
+
3192
+ opts.flags = GIT_ITERATOR_DONT_IGNORE_CASE |
3193
+ GIT_ITERATOR_INCLUDE_CONFLICTS;
3194
+
3195
+ if ((error = git_iterator_for_index(&index_iterator,
3196
+ git_index_owner(index), index, &opts)) < 0 ||
3197
+ ((error = git_iterator_current(&old_entry, index_iterator)) < 0 &&
3198
+ error != GIT_ITEROVER) ||
3199
+ ((error = git_iterator_current(&new_entry, new_iterator)) < 0 &&
3200
+ error != GIT_ITEROVER))
3201
+ goto done;
3202
+
3203
+ while (true) {
3204
+ git_index_entry
3205
+ *dup_entry = NULL,
3206
+ *add_entry = NULL,
3207
+ *remove_entry = NULL;
3208
+ int diff;
3209
+
3210
+ error = 0;
3211
+
3212
+ if (old_entry && new_entry)
3213
+ diff = git_index_entry_cmp(old_entry, new_entry);
3214
+ else if (!old_entry && new_entry)
3215
+ diff = 1;
3216
+ else if (old_entry && !new_entry)
3217
+ diff = -1;
3218
+ else
3219
+ break;
3220
+
3221
+ if (diff < 0) {
3222
+ remove_entry = (git_index_entry *)old_entry;
3223
+ } else if (diff > 0) {
3224
+ dup_entry = (git_index_entry *)new_entry;
3225
+ } else {
3226
+ /* Path and stage are equal, if the OID is equal, keep it to
3227
+ * keep the stat cache data.
3228
+ */
3229
+ if (git_oid_equal(&old_entry->id, &new_entry->id) &&
3230
+ old_entry->mode == new_entry->mode) {
3231
+ add_entry = (git_index_entry *)old_entry;
3232
+ } else {
3233
+ dup_entry = (git_index_entry *)new_entry;
3234
+ remove_entry = (git_index_entry *)old_entry;
3235
+ }
3236
+ }
3237
+
3238
+ if (dup_entry) {
3239
+ if ((error = index_entry_dup_nocache(&add_entry, index, dup_entry)) < 0)
3240
+ goto done;
3241
+
3242
+ index_entry_adjust_namemask(add_entry,
3243
+ ((struct entry_internal *)add_entry)->pathlen);
3244
+ }
3245
+
3246
+ /* invalidate this path in the tree cache if this is new (to
3247
+ * invalidate the parent trees)
3248
+ */
3249
+ if (dup_entry && !remove_entry && index->tree)
3250
+ git_tree_cache_invalidate_path(index->tree, dup_entry->path);
3251
+
3252
+ if (add_entry) {
3253
+ if ((error = git_vector_insert(&new_entries, add_entry)) == 0)
3254
+ INSERT_IN_MAP_EX(index, new_entries_map, add_entry, &error);
3255
+ }
3256
+
3257
+ if (remove_entry && error >= 0)
3258
+ error = git_vector_insert(&remove_entries, remove_entry);
3259
+
3260
+ if (error < 0) {
3261
+ git_error_set(GIT_ERROR_INDEX, "failed to insert entry");
3262
+ goto done;
3263
+ }
3264
+
3265
+ if (diff <= 0) {
3266
+ if ((error = git_iterator_advance(&old_entry, index_iterator)) < 0 &&
3267
+ error != GIT_ITEROVER)
3268
+ goto done;
3269
+ }
3270
+
3271
+ if (diff >= 0) {
3272
+ if ((error = git_iterator_advance(&new_entry, new_iterator)) < 0 &&
3273
+ error != GIT_ITEROVER)
3274
+ goto done;
3275
+ }
3276
+ }
3277
+
3278
+ git_index_name_clear(index);
3279
+ git_index_reuc_clear(index);
3280
+
3281
+ git_vector_swap(&new_entries, &index->entries);
3282
+ new_entries_map = git__swap(index->entries_map, new_entries_map);
3283
+
3284
+ git_vector_foreach(&remove_entries, i, entry) {
3285
+ if (index->tree)
3286
+ git_tree_cache_invalidate_path(index->tree, entry->path);
3287
+
3288
+ index_entry_free(entry);
3289
+ }
3290
+
3291
+ clear_uptodate(index);
3292
+
3293
+ index->dirty = 1;
3294
+ error = 0;
3295
+
3296
+ done:
3297
+ git_idxmap_free(new_entries_map);
3298
+ git_vector_free(&new_entries);
3299
+ git_vector_free(&remove_entries);
3300
+ git_iterator_free(index_iterator);
3301
+ return error;
3302
+ }
3303
+
3304
+ int git_index_read_index(
3305
+ git_index *index,
3306
+ const git_index *new_index)
3307
+ {
3308
+ git_iterator *new_iterator = NULL;
3309
+ git_iterator_options opts = GIT_ITERATOR_OPTIONS_INIT;
3310
+ int error;
2041
3311
 
3312
+ opts.flags = GIT_ITERATOR_DONT_IGNORE_CASE |
3313
+ GIT_ITERATOR_INCLUDE_CONFLICTS;
3314
+
3315
+ if ((error = git_iterator_for_index(&new_iterator,
3316
+ git_index_owner(new_index), (git_index *)new_index, &opts)) < 0 ||
3317
+ (error = git_index_read_iterator(index, new_iterator,
3318
+ new_index->entries.length)) < 0)
3319
+ goto done;
3320
+
3321
+ done:
3322
+ git_iterator_free(new_iterator);
2042
3323
  return error;
2043
3324
  }
2044
3325
 
@@ -2047,6 +3328,13 @@ git_repository *git_index_owner(const git_index *index)
2047
3328
  return INDEX_OWNER(index);
2048
3329
  }
2049
3330
 
3331
+ enum {
3332
+ INDEX_ACTION_NONE = 0,
3333
+ INDEX_ACTION_UPDATE = 1,
3334
+ INDEX_ACTION_REMOVE = 2,
3335
+ INDEX_ACTION_ADDALL = 3,
3336
+ };
3337
+
2050
3338
  int git_index_add_all(
2051
3339
  git_index *index,
2052
3340
  const git_strarray *paths,
@@ -2057,30 +3345,16 @@ int git_index_add_all(
2057
3345
  int error;
2058
3346
  git_repository *repo;
2059
3347
  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;
3348
+ git_pathspec ps;
2065
3349
  bool no_fnmatch = (flags & GIT_INDEX_ADD_DISABLE_PATHSPEC_MATCH) != 0;
2066
- int ignorecase;
2067
- git_oid blobid;
2068
3350
 
2069
3351
  assert(index);
2070
3352
 
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
3353
  repo = INDEX_OWNER(index);
2077
3354
  if ((error = git_repository__ensure_not_bare(repo, "index add all")) < 0)
2078
3355
  return error;
2079
3356
 
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)
3357
+ if ((error = git_pathspec__init(&ps, paths)) < 0)
2084
3358
  return error;
2085
3359
 
2086
3360
  /* optionally check that pathspec doesn't mention any ignored files */
@@ -2090,81 +3364,118 @@ int git_index_add_all(
2090
3364
  repo, &ps.pathspec, no_fnmatch)) < 0)
2091
3365
  goto cleanup;
2092
3366
 
2093
- if ((error = git_iterator_for_workdir(
2094
- &wditer, repo, 0, ps.prefix, ps.prefix)) < 0)
2095
- goto cleanup;
3367
+ error = index_apply_to_wd_diff(index, INDEX_ACTION_ADDALL, paths, flags, cb, payload);
2096
3368
 
2097
- while (!(error = git_iterator_advance(&wd, wditer))) {
3369
+ if (error)
3370
+ git_error_set_after_callback(error);
2098
3371
 
2099
- /* check if path actually matches */
2100
- if (!git_pathspec_match_path(
2101
- &ps.pathspec, wd->path, no_fnmatch, ignorecase, &match))
2102
- continue;
3372
+ cleanup:
3373
+ git_iterator_free(wditer);
3374
+ git_pathspec__clear(&ps);
2103
3375
 
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;
3376
+ return error;
3377
+ }
2109
3378
 
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
- }
3379
+ struct foreach_diff_data {
3380
+ git_index *index;
3381
+ const git_pathspec *pathspec;
3382
+ unsigned int flags;
3383
+ git_index_matched_path_cb cb;
3384
+ void *payload;
3385
+ };
2120
3386
 
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
- */
3387
+ static int apply_each_file(const git_diff_delta *delta, float progress, void *payload)
3388
+ {
3389
+ struct foreach_diff_data *data = payload;
3390
+ const char *match, *path;
3391
+ int error = 0;
2124
3392
 
2125
- /* write the blob to disk and get the oid */
2126
- if ((error = git_blob_create_fromworkdir(&blobid, repo, wd->path)) < 0)
2127
- break;
3393
+ GIT_UNUSED(progress);
2128
3394
 
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;
3395
+ path = delta->old_file.path;
2135
3396
 
2136
- /* add working directory item to index */
2137
- if ((error = index_insert(index, entry, 1)) < 0) {
2138
- index_entry_free(entry);
2139
- break;
2140
- }
3397
+ /* We only want those which match the pathspecs */
3398
+ if (!git_pathspec__match(
3399
+ &data->pathspec->pathspec, path, false, (bool)data->index->ignore_case,
3400
+ &match, NULL))
3401
+ return 0;
2141
3402
 
2142
- git_tree_cache_invalidate_path(index->tree, wd->path);
3403
+ if (data->cb)
3404
+ error = data->cb(path, match, data->payload);
2143
3405
 
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
- }
3406
+ if (error > 0) /* skip this entry */
3407
+ return 0;
3408
+ if (error < 0) /* actual error */
3409
+ return error;
3410
+
3411
+ /* If the workdir item does not exist, remove it from the index. */
3412
+ if ((delta->new_file.flags & GIT_DIFF_FLAG_EXISTS) == 0)
3413
+ error = git_index_remove_bypath(data->index, path);
3414
+ else
3415
+ error = git_index_add_bypath(data->index, delta->new_file.path);
3416
+
3417
+ return error;
3418
+ }
3419
+
3420
+ static int index_apply_to_wd_diff(git_index *index, int action, const git_strarray *paths,
3421
+ unsigned int flags,
3422
+ git_index_matched_path_cb cb, void *payload)
3423
+ {
3424
+ int error;
3425
+ git_diff *diff;
3426
+ git_pathspec ps;
3427
+ git_repository *repo;
3428
+ git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
3429
+ struct foreach_diff_data data = {
3430
+ index,
3431
+ NULL,
3432
+ flags,
3433
+ cb,
3434
+ payload,
3435
+ };
3436
+
3437
+ assert(index);
3438
+ assert(action == INDEX_ACTION_UPDATE || action == INDEX_ACTION_ADDALL);
3439
+
3440
+ repo = INDEX_OWNER(index);
3441
+
3442
+ if (!repo) {
3443
+ return create_index_error(-1,
3444
+ "cannot run update; the index is not backed up by a repository.");
2150
3445
  }
2151
3446
 
2152
- if (error == GIT_ITEROVER)
2153
- error = 0;
3447
+ /*
3448
+ * We do the matching ourselves intead of passing the list to
3449
+ * diff because we want to tell the callback which one
3450
+ * matched, which we do not know if we ask diff to filter for us.
3451
+ */
3452
+ if ((error = git_pathspec__init(&ps, paths)) < 0)
3453
+ return error;
2154
3454
 
2155
- cleanup:
2156
- git_iterator_free(wditer);
2157
- git_pathspec_context_free(&ps);
3455
+ opts.flags = GIT_DIFF_INCLUDE_TYPECHANGE;
3456
+ if (action == INDEX_ACTION_ADDALL) {
3457
+ opts.flags |= GIT_DIFF_INCLUDE_UNTRACKED |
3458
+ GIT_DIFF_RECURSE_UNTRACKED_DIRS;
3459
+
3460
+ if (flags == GIT_INDEX_ADD_FORCE)
3461
+ opts.flags |= GIT_DIFF_INCLUDE_IGNORED;
3462
+ }
3463
+
3464
+ if ((error = git_diff_index_to_workdir(&diff, repo, index, &opts)) < 0)
3465
+ goto cleanup;
3466
+
3467
+ data.pathspec = &ps;
3468
+ error = git_diff_foreach(diff, apply_each_file, NULL, NULL, NULL, &data);
3469
+ git_diff_free(diff);
2158
3470
 
3471
+ if (error) /* make sure error is set if callback stopped iteration */
3472
+ git_error_set_after_callback(error);
3473
+
3474
+ cleanup:
3475
+ git_pathspec__clear(&ps);
2159
3476
  return error;
2160
3477
  }
2161
3478
 
2162
- enum {
2163
- INDEX_ACTION_NONE = 0,
2164
- INDEX_ACTION_UPDATE = 1,
2165
- INDEX_ACTION_REMOVE = 2,
2166
- };
2167
-
2168
3479
  static int index_apply_to_all(
2169
3480
  git_index *index,
2170
3481
  int action,
@@ -2174,13 +3485,13 @@ static int index_apply_to_all(
2174
3485
  {
2175
3486
  int error = 0;
2176
3487
  size_t i;
2177
- git_pathspec_context ps;
3488
+ git_pathspec ps;
2178
3489
  const char *match;
2179
3490
  git_buf path = GIT_BUF_INIT;
2180
3491
 
2181
3492
  assert(index);
2182
3493
 
2183
- if ((error = git_pathspec_context_init(&ps, paths)) < 0)
3494
+ if ((error = git_pathspec__init(&ps, paths)) < 0)
2184
3495
  return error;
2185
3496
 
2186
3497
  git_vector_sort(&index->entries);
@@ -2189,8 +3500,9 @@ static int index_apply_to_all(
2189
3500
  git_index_entry *entry = git_vector_get(&index->entries, i);
2190
3501
 
2191
3502
  /* check if path actually matches */
2192
- if (!git_pathspec_match_path(
2193
- &ps.pathspec, entry->path, false, index->ignore_case, &match))
3503
+ if (!git_pathspec__match(
3504
+ &ps.pathspec, entry->path, false, (bool)index->ignore_case,
3505
+ &match, NULL))
2194
3506
  continue;
2195
3507
 
2196
3508
  /* issue notification callback if requested */
@@ -2199,11 +3511,8 @@ static int index_apply_to_all(
2199
3511
  error = 0;
2200
3512
  continue;
2201
3513
  }
2202
- if (error < 0) { /* return < 0 means abort */
2203
- giterr_clear();
2204
- error = GIT_EUSER;
3514
+ if (error < 0) /* return < 0 means abort */
2205
3515
  break;
2206
- }
2207
3516
  }
2208
3517
 
2209
3518
  /* index manipulation may alter entry, so don't depend on it */
@@ -2217,7 +3526,7 @@ static int index_apply_to_all(
2217
3526
  error = git_index_add_bypath(index, path.ptr);
2218
3527
 
2219
3528
  if (error == GIT_ENOTFOUND) {
2220
- giterr_clear();
3529
+ git_error_clear();
2221
3530
 
2222
3531
  error = git_index_remove_bypath(index, path.ptr);
2223
3532
 
@@ -2230,14 +3539,14 @@ static int index_apply_to_all(
2230
3539
  i--; /* back up foreach if we removed this */
2231
3540
  break;
2232
3541
  default:
2233
- giterr_set(GITERR_INVALID, "Unknown index action %d", action);
3542
+ git_error_set(GIT_ERROR_INVALID, "unknown index action %d", action);
2234
3543
  error = -1;
2235
3544
  break;
2236
3545
  }
2237
3546
  }
2238
3547
 
2239
- git_buf_free(&path);
2240
- git_pathspec_context_free(&ps);
3548
+ git_buf_dispose(&path);
3549
+ git_pathspec__clear(&ps);
2241
3550
 
2242
3551
  return error;
2243
3552
  }
@@ -2248,8 +3557,13 @@ int git_index_remove_all(
2248
3557
  git_index_matched_path_cb cb,
2249
3558
  void *payload)
2250
3559
  {
2251
- return index_apply_to_all(
3560
+ int error = index_apply_to_all(
2252
3561
  index, INDEX_ACTION_REMOVE, pathspec, cb, payload);
3562
+
3563
+ if (error) /* make sure error is set if callback stopped iteration */
3564
+ git_error_set_after_callback(error);
3565
+
3566
+ return error;
2253
3567
  }
2254
3568
 
2255
3569
  int git_index_update_all(
@@ -2258,6 +3572,131 @@ int git_index_update_all(
2258
3572
  git_index_matched_path_cb cb,
2259
3573
  void *payload)
2260
3574
  {
2261
- return index_apply_to_all(
2262
- index, INDEX_ACTION_UPDATE, pathspec, cb, payload);
3575
+ int error = index_apply_to_wd_diff(index, INDEX_ACTION_UPDATE, pathspec, 0, cb, payload);
3576
+ if (error) /* make sure error is set if callback stopped iteration */
3577
+ git_error_set_after_callback(error);
3578
+
3579
+ return error;
3580
+ }
3581
+
3582
+ int git_index_snapshot_new(git_vector *snap, git_index *index)
3583
+ {
3584
+ int error;
3585
+
3586
+ GIT_REFCOUNT_INC(index);
3587
+
3588
+ git_atomic_inc(&index->readers);
3589
+ git_vector_sort(&index->entries);
3590
+
3591
+ error = git_vector_dup(snap, &index->entries, index->entries._cmp);
3592
+
3593
+ if (error < 0)
3594
+ git_index_snapshot_release(snap, index);
3595
+
3596
+ return error;
3597
+ }
3598
+
3599
+ void git_index_snapshot_release(git_vector *snap, git_index *index)
3600
+ {
3601
+ git_vector_free(snap);
3602
+
3603
+ git_atomic_dec(&index->readers);
3604
+
3605
+ git_index_free(index);
3606
+ }
3607
+
3608
+ int git_index_snapshot_find(
3609
+ size_t *out, git_vector *entries, git_vector_cmp entry_srch,
3610
+ const char *path, size_t path_len, int stage)
3611
+ {
3612
+ return index_find_in_entries(out, entries, entry_srch, path, path_len, stage);
3613
+ }
3614
+
3615
+ int git_indexwriter_init(
3616
+ git_indexwriter *writer,
3617
+ git_index *index)
3618
+ {
3619
+ int error;
3620
+
3621
+ GIT_REFCOUNT_INC(index);
3622
+
3623
+ writer->index = index;
3624
+
3625
+ if (!index->index_file_path)
3626
+ return create_index_error(-1,
3627
+ "failed to write index: The index is in-memory only");
3628
+
3629
+ if ((error = git_filebuf_open(
3630
+ &writer->file, index->index_file_path, GIT_FILEBUF_HASH_CONTENTS, GIT_INDEX_FILE_MODE)) < 0) {
3631
+
3632
+ if (error == GIT_ELOCKED)
3633
+ git_error_set(GIT_ERROR_INDEX, "the index is locked; this might be due to a concurrent or crashed process");
3634
+
3635
+ return error;
3636
+ }
3637
+
3638
+ writer->should_write = 1;
3639
+
3640
+ return 0;
3641
+ }
3642
+
3643
+ int git_indexwriter_init_for_operation(
3644
+ git_indexwriter *writer,
3645
+ git_repository *repo,
3646
+ unsigned int *checkout_strategy)
3647
+ {
3648
+ git_index *index;
3649
+ int error;
3650
+
3651
+ if ((error = git_repository_index__weakptr(&index, repo)) < 0 ||
3652
+ (error = git_indexwriter_init(writer, index)) < 0)
3653
+ return error;
3654
+
3655
+ writer->should_write = (*checkout_strategy & GIT_CHECKOUT_DONT_WRITE_INDEX) == 0;
3656
+ *checkout_strategy |= GIT_CHECKOUT_DONT_WRITE_INDEX;
3657
+
3658
+ return 0;
3659
+ }
3660
+
3661
+ int git_indexwriter_commit(git_indexwriter *writer)
3662
+ {
3663
+ int error;
3664
+ git_oid checksum = {{ 0 }};
3665
+
3666
+ if (!writer->should_write)
3667
+ return 0;
3668
+
3669
+ git_vector_sort(&writer->index->entries);
3670
+ git_vector_sort(&writer->index->reuc);
3671
+
3672
+ if ((error = write_index(&checksum, writer->index, &writer->file)) < 0) {
3673
+ git_indexwriter_cleanup(writer);
3674
+ return error;
3675
+ }
3676
+
3677
+ if ((error = git_filebuf_commit(&writer->file)) < 0)
3678
+ return error;
3679
+
3680
+ if ((error = git_futils_filestamp_check(
3681
+ &writer->index->stamp, writer->index->index_file_path)) < 0) {
3682
+ git_error_set(GIT_ERROR_OS, "could not read index timestamp");
3683
+ return -1;
3684
+ }
3685
+
3686
+ writer->index->dirty = 0;
3687
+ writer->index->on_disk = 1;
3688
+ git_oid_cpy(&writer->index->checksum, &checksum);
3689
+
3690
+ git_index_free(writer->index);
3691
+ writer->index = NULL;
3692
+
3693
+ return 0;
3694
+ }
3695
+
3696
+ void git_indexwriter_cleanup(git_indexwriter *writer)
3697
+ {
3698
+ git_filebuf_cleanup(&writer->file);
3699
+
3700
+ git_index_free(writer->index);
3701
+ writer->index = NULL;
2263
3702
  }