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,6 +5,8 @@
5
5
  * a Linking Exception. For full terms see the included COPYING file.
6
6
  */
7
7
 
8
+ #include "refdb_fs.h"
9
+
8
10
  #include "refs.h"
9
11
  #include "hash.h"
10
12
  #include "repository.h"
@@ -13,16 +15,17 @@
13
15
  #include "pack.h"
14
16
  #include "reflog.h"
15
17
  #include "refdb.h"
16
- #include "refdb_fs.h"
17
18
  #include "iterator.h"
19
+ #include "sortedcache.h"
20
+ #include "signature.h"
18
21
 
19
22
  #include <git2/tag.h>
20
23
  #include <git2/object.h>
21
24
  #include <git2/refdb.h>
25
+ #include <git2/branch.h>
22
26
  #include <git2/sys/refdb_backend.h>
23
27
  #include <git2/sys/refs.h>
24
-
25
- GIT__USE_STRMAP;
28
+ #include <git2/sys/reflog.h>
26
29
 
27
30
  #define DEFAULT_NESTING_LEVEL 5
28
31
  #define MAX_NESTING_LEVEL 10
@@ -51,245 +54,159 @@ typedef struct refdb_fs_backend {
51
54
  git_refdb_backend parent;
52
55
 
53
56
  git_repository *repo;
54
- char *path;
57
+ /* path to git directory */
58
+ char *gitpath;
59
+ /* path to common objects' directory */
60
+ char *commonpath;
55
61
 
56
- git_refcache refcache;
62
+ git_sortedcache *refcache;
57
63
  int peeling_mode;
64
+ git_iterator_flag_t iterator_flags;
65
+ uint32_t direach_flags;
66
+ int fsync;
58
67
  } refdb_fs_backend;
59
68
 
60
- static int reference_read(
61
- git_buf *file_content,
62
- time_t *mtime,
63
- const char *repo_path,
64
- const char *ref_name,
65
- int *updated)
66
- {
67
- git_buf path = GIT_BUF_INIT;
68
- int result;
69
-
70
- assert(file_content && repo_path && ref_name);
71
-
72
- /* Determine the full path of the file */
73
- if (git_buf_joinpath(&path, repo_path, ref_name) < 0)
74
- return -1;
75
-
76
- result = git_futils_readbuffer_updated(file_content, path.ptr, mtime, NULL, updated);
77
- git_buf_free(&path);
78
-
79
- return result;
80
- }
81
-
82
- static int packed_parse_oid(
83
- struct packref **ref_out,
84
- const char **buffer_out,
85
- const char *buffer_end)
86
- {
87
- struct packref *ref = NULL;
88
-
89
- const char *buffer = *buffer_out;
90
- const char *refname_begin, *refname_end;
91
-
92
- size_t refname_len;
93
- git_oid id;
94
-
95
- refname_begin = (buffer + GIT_OID_HEXSZ + 1);
96
- if (refname_begin >= buffer_end || refname_begin[-1] != ' ')
97
- goto corrupt;
98
-
99
- /* Is this a valid object id? */
100
- if (git_oid_fromstr(&id, buffer) < 0)
101
- goto corrupt;
102
-
103
- refname_end = memchr(refname_begin, '\n', buffer_end - refname_begin);
104
- if (refname_end == NULL)
105
- refname_end = buffer_end;
106
-
107
- if (refname_end[-1] == '\r')
108
- refname_end--;
109
-
110
- refname_len = refname_end - refname_begin;
111
-
112
- ref = git__calloc(1, sizeof(struct packref) + refname_len + 1);
113
- GITERR_CHECK_ALLOC(ref);
69
+ static int refdb_reflog_fs__delete(git_refdb_backend *_backend, const char *name);
114
70
 
115
- memcpy(ref->name, refname_begin, refname_len);
116
- ref->name[refname_len] = 0;
117
-
118
- git_oid_cpy(&ref->oid, &id);
119
-
120
- *ref_out = ref;
121
- *buffer_out = refname_end + 1;
122
- return 0;
123
-
124
- corrupt:
125
- git__free(ref);
126
- giterr_set(GITERR_REFERENCE, "The packed references file is corrupted");
127
- return -1;
128
- }
129
-
130
- static int packed_parse_peel(
131
- struct packref *tag_ref,
132
- const char **buffer_out,
133
- const char *buffer_end)
71
+ static int packref_cmp(const void *a_, const void *b_)
134
72
  {
135
- const char *buffer = *buffer_out + 1;
136
-
137
- assert(buffer[-1] == '^');
138
-
139
- /* Ensure it's not the first entry of the file */
140
- if (tag_ref == NULL)
141
- goto corrupt;
142
-
143
- if (buffer + GIT_OID_HEXSZ > buffer_end)
144
- goto corrupt;
145
-
146
- /* Is this a valid object id? */
147
- if (git_oid_fromstr(&tag_ref->peel, buffer) < 0)
148
- goto corrupt;
149
-
150
- buffer = buffer + GIT_OID_HEXSZ;
151
- if (*buffer == '\r')
152
- buffer++;
153
-
154
- if (buffer != buffer_end) {
155
- if (*buffer == '\n')
156
- buffer++;
157
- else
158
- goto corrupt;
159
- }
160
-
161
- tag_ref->flags |= PACKREF_HAS_PEEL;
162
- *buffer_out = buffer;
163
- return 0;
164
-
165
- corrupt:
166
- giterr_set(GITERR_REFERENCE, "The packed references file is corrupted");
167
- return -1;
73
+ const struct packref *a = a_, *b = b_;
74
+ return strcmp(a->name, b->name);
168
75
  }
169
76
 
170
- static int packed_load(refdb_fs_backend *backend)
77
+ static int packed_reload(refdb_fs_backend *backend)
171
78
  {
172
- int result, updated;
173
- git_buf packfile = GIT_BUF_INIT;
174
- const char *buffer_start, *buffer_end;
175
- git_refcache *ref_cache = &backend->refcache;
176
-
177
- /* First we make sure we have allocated the hash table */
178
- if (ref_cache->packfile == NULL) {
179
- ref_cache->packfile = git_strmap_alloc();
180
- GITERR_CHECK_ALLOC(ref_cache->packfile);
181
- }
79
+ int error;
80
+ git_buf packedrefs = GIT_BUF_INIT;
81
+ char *scan, *eof, *eol;
182
82
 
183
- if (backend->path == NULL)
83
+ if (!backend->gitpath)
184
84
  return 0;
185
85
 
186
- result = reference_read(&packfile, &ref_cache->packfile_time,
187
- backend->path, GIT_PACKEDREFS_FILE, &updated);
86
+ error = git_sortedcache_lockandload(backend->refcache, &packedrefs);
188
87
 
189
88
  /*
190
- * If we couldn't find the file, we need to clear the table and
191
- * return. On any other error, we return that error. If everything
192
- * went fine and the file wasn't updated, then there's nothing new
193
- * for us here, so just return. Anything else means we need to
194
- * refresh the packed refs.
89
+ * If we can't find the packed-refs, clear table and return.
90
+ * Any other error just gets passed through.
91
+ * If no error, and file wasn't changed, just return.
92
+ * Anything else means we need to refresh the packed refs.
195
93
  */
196
- if (result == GIT_ENOTFOUND) {
197
- git_strmap_clear(ref_cache->packfile);
198
- return 0;
94
+ if (error <= 0) {
95
+ if (error == GIT_ENOTFOUND) {
96
+ git_sortedcache_clear(backend->refcache, true);
97
+ git_error_clear();
98
+ error = 0;
99
+ }
100
+ return error;
199
101
  }
200
102
 
201
- if (result < 0)
202
- return -1;
203
-
204
- if (!updated)
205
- return 0;
103
+ /* At this point, refresh the packed refs from the loaded buffer. */
206
104
 
207
- /*
208
- * At this point, we want to refresh the packed refs. We already
209
- * have the contents in our buffer.
210
- */
211
- git_strmap_clear(ref_cache->packfile);
105
+ git_sortedcache_clear(backend->refcache, false);
212
106
 
213
- buffer_start = (const char *)packfile.ptr;
214
- buffer_end = (const char *)(buffer_start) + packfile.size;
107
+ scan = (char *)packedrefs.ptr;
108
+ eof = scan + packedrefs.size;
215
109
 
216
110
  backend->peeling_mode = PEELING_NONE;
217
111
 
218
- if (buffer_start[0] == '#') {
112
+ if (*scan == '#') {
219
113
  static const char *traits_header = "# pack-refs with: ";
220
114
 
221
- if (git__prefixcmp(buffer_start, traits_header) == 0) {
222
- char *traits = (char *)buffer_start + strlen(traits_header);
223
- char *traits_end = strchr(traits, '\n');
115
+ if (git__prefixcmp(scan, traits_header) == 0) {
116
+ scan += strlen(traits_header);
117
+ eol = strchr(scan, '\n');
224
118
 
225
- if (traits_end == NULL)
119
+ if (!eol)
226
120
  goto parse_failed;
121
+ *eol = '\0';
227
122
 
228
- *traits_end = '\0';
229
-
230
- if (strstr(traits, " fully-peeled ") != NULL) {
123
+ if (strstr(scan, " fully-peeled ") != NULL) {
231
124
  backend->peeling_mode = PEELING_FULL;
232
- } else if (strstr(traits, " peeled ") != NULL) {
125
+ } else if (strstr(scan, " peeled ") != NULL) {
233
126
  backend->peeling_mode = PEELING_STANDARD;
234
127
  }
235
128
 
236
- buffer_start = traits_end + 1;
129
+ scan = eol + 1;
237
130
  }
238
131
  }
239
132
 
240
- while (buffer_start < buffer_end && buffer_start[0] == '#') {
241
- buffer_start = strchr(buffer_start, '\n');
242
- if (buffer_start == NULL)
133
+ while (scan < eof && *scan == '#') {
134
+ if (!(eol = strchr(scan, '\n')))
243
135
  goto parse_failed;
244
-
245
- buffer_start++;
136
+ scan = eol + 1;
246
137
  }
247
138
 
248
- while (buffer_start < buffer_end) {
249
- int err;
250
- struct packref *ref = NULL;
139
+ while (scan < eof) {
140
+ struct packref *ref;
141
+ git_oid oid;
251
142
 
252
- if (packed_parse_oid(&ref, &buffer_start, buffer_end) < 0)
143
+ /* parse "<OID> <refname>\n" */
144
+
145
+ if (git_oid_fromstr(&oid, scan) < 0)
253
146
  goto parse_failed;
147
+ scan += GIT_OID_HEXSZ;
254
148
 
255
- if (buffer_start[0] == '^') {
256
- if (packed_parse_peel(ref, &buffer_start, buffer_end) < 0)
257
- goto parse_failed;
258
- } else if (backend->peeling_mode == PEELING_FULL ||
259
- (backend->peeling_mode == PEELING_STANDARD &&
260
- git__prefixcmp(ref->name, GIT_REFS_TAGS_DIR) == 0)) {
261
- ref->flags |= PACKREF_CANNOT_PEEL;
262
- }
149
+ if (*scan++ != ' ')
150
+ goto parse_failed;
151
+ if (!(eol = strchr(scan, '\n')))
152
+ goto parse_failed;
153
+ *eol = '\0';
154
+ if (eol[-1] == '\r')
155
+ eol[-1] = '\0';
263
156
 
264
- git_strmap_insert(ref_cache->packfile, ref->name, ref, err);
265
- if (err < 0)
157
+ if (git_sortedcache_upsert((void **)&ref, backend->refcache, scan) < 0)
266
158
  goto parse_failed;
159
+ scan = eol + 1;
160
+
161
+ git_oid_cpy(&ref->oid, &oid);
162
+
163
+ /* look for optional "^<OID>\n" */
164
+
165
+ if (*scan == '^') {
166
+ if (git_oid_fromstr(&oid, scan + 1) < 0)
167
+ goto parse_failed;
168
+ scan += GIT_OID_HEXSZ + 1;
169
+
170
+ if (scan < eof) {
171
+ if (!(eol = strchr(scan, '\n')))
172
+ goto parse_failed;
173
+ scan = eol + 1;
174
+ }
175
+
176
+ git_oid_cpy(&ref->peel, &oid);
177
+ ref->flags |= PACKREF_HAS_PEEL;
178
+ }
179
+ else if (backend->peeling_mode == PEELING_FULL ||
180
+ (backend->peeling_mode == PEELING_STANDARD &&
181
+ git__prefixcmp(ref->name, GIT_REFS_TAGS_DIR) == 0))
182
+ ref->flags |= PACKREF_CANNOT_PEEL;
267
183
  }
268
184
 
269
- git_buf_free(&packfile);
185
+ git_sortedcache_wunlock(backend->refcache);
186
+ git_buf_dispose(&packedrefs);
187
+
270
188
  return 0;
271
189
 
272
190
  parse_failed:
273
- git_strmap_free(ref_cache->packfile);
274
- ref_cache->packfile = NULL;
275
- git_buf_free(&packfile);
191
+ git_error_set(GIT_ERROR_REFERENCE, "corrupted packed references file");
192
+
193
+ git_sortedcache_clear(backend->refcache, false);
194
+ git_sortedcache_wunlock(backend->refcache);
195
+ git_buf_dispose(&packedrefs);
196
+
276
197
  return -1;
277
198
  }
278
199
 
279
- static int loose_parse_oid(git_oid *oid, const char *filename, git_buf *file_content)
200
+ static int loose_parse_oid(
201
+ git_oid *oid, const char *filename, git_buf *file_content)
280
202
  {
281
- size_t len;
282
- const char *str;
203
+ const char *str = git_buf_cstr(file_content);
283
204
 
284
- len = git_buf_len(file_content);
285
- if (len < GIT_OID_HEXSZ)
205
+ if (git_buf_len(file_content) < GIT_OID_HEXSZ)
286
206
  goto corrupted;
287
207
 
288
- /* str is guranteed to be zero-terminated */
289
- str = git_buf_cstr(file_content);
290
-
291
208
  /* we need to get 40 OID characters from the file */
292
- if (git_oid_fromstr(oid, git_buf_cstr(file_content)) < 0)
209
+ if (git_oid_fromstr(oid, str) < 0)
293
210
  goto corrupted;
294
211
 
295
212
  /* If the file is longer than 40 chars, the 41st must be a space */
@@ -298,72 +215,84 @@ static int loose_parse_oid(git_oid *oid, const char *filename, git_buf *file_con
298
215
  return 0;
299
216
 
300
217
  corrupted:
301
- giterr_set(GITERR_REFERENCE, "Corrupted loose reference file: %s", filename);
218
+ git_error_set(GIT_ERROR_REFERENCE, "corrupted loose reference file: %s", filename);
302
219
  return -1;
303
220
  }
304
221
 
305
- static int loose_lookup_to_packfile(
306
- struct packref **ref_out,
307
- refdb_fs_backend *backend,
308
- const char *name)
222
+ static int loose_readbuffer(git_buf *buf, const char *base, const char *path)
223
+ {
224
+ int error;
225
+
226
+ /* build full path to file */
227
+ if ((error = git_buf_joinpath(buf, base, path)) < 0 ||
228
+ (error = git_futils_readbuffer(buf, buf->ptr)) < 0)
229
+ git_buf_dispose(buf);
230
+
231
+ return error;
232
+ }
233
+
234
+ static int loose_lookup_to_packfile(refdb_fs_backend *backend, const char *name)
309
235
  {
236
+ int error = 0;
310
237
  git_buf ref_file = GIT_BUF_INIT;
311
238
  struct packref *ref = NULL;
312
- size_t name_len;
239
+ git_oid oid;
313
240
 
314
- *ref_out = NULL;
241
+ /* if we fail to load the loose reference, assume someone changed
242
+ * the filesystem under us and skip it...
243
+ */
244
+ if (loose_readbuffer(&ref_file, backend->gitpath, name) < 0) {
245
+ git_error_clear();
246
+ goto done;
247
+ }
315
248
 
316
- if (reference_read(&ref_file, NULL, backend->path, name, NULL) < 0)
317
- return -1;
249
+ /* skip symbolic refs */
250
+ if (!git__prefixcmp(git_buf_cstr(&ref_file), GIT_SYMREF))
251
+ goto done;
318
252
 
319
- git_buf_rtrim(&ref_file);
253
+ /* parse OID from file */
254
+ if ((error = loose_parse_oid(&oid, name, &ref_file)) < 0)
255
+ goto done;
320
256
 
321
- name_len = strlen(name);
322
- ref = git__calloc(1, sizeof(struct packref) + name_len + 1);
323
- GITERR_CHECK_ALLOC(ref);
257
+ git_sortedcache_wlock(backend->refcache);
324
258
 
325
- memcpy(ref->name, name, name_len);
326
- ref->name[name_len] = 0;
259
+ if (!(error = git_sortedcache_upsert(
260
+ (void **)&ref, backend->refcache, name))) {
327
261
 
328
- if (loose_parse_oid(&ref->oid, name, &ref_file) < 0) {
329
- git_buf_free(&ref_file);
330
- git__free(ref);
331
- return -1;
262
+ git_oid_cpy(&ref->oid, &oid);
263
+ ref->flags = PACKREF_WAS_LOOSE;
332
264
  }
333
265
 
334
- ref->flags = PACKREF_WAS_LOOSE;
266
+ git_sortedcache_wunlock(backend->refcache);
335
267
 
336
- *ref_out = ref;
337
- git_buf_free(&ref_file);
338
- return 0;
268
+ done:
269
+ git_buf_dispose(&ref_file);
270
+ return error;
339
271
  }
340
272
 
341
-
342
- static int _dirent_loose_load(void *data, git_buf *full_path)
273
+ static int _dirent_loose_load(void *payload, git_buf *full_path)
343
274
  {
344
- refdb_fs_backend *backend = (refdb_fs_backend *)data;
345
- void *old_ref = NULL;
346
- struct packref *ref;
275
+ refdb_fs_backend *backend = payload;
347
276
  const char *file_path;
348
- int err;
349
-
350
- if (git_path_isdir(full_path->ptr) == true)
351
- return git_path_direach(full_path, _dirent_loose_load, backend);
352
277
 
353
- file_path = full_path->ptr + strlen(backend->path);
278
+ if (git__suffixcmp(full_path->ptr, ".lock") == 0)
279
+ return 0;
354
280
 
355
- if (loose_lookup_to_packfile(&ref, backend, file_path) < 0)
356
- return -1;
281
+ if (git_path_isdir(full_path->ptr)) {
282
+ int error = git_path_direach(
283
+ full_path, backend->direach_flags, _dirent_loose_load, backend);
284
+ /* Race with the filesystem, ignore it */
285
+ if (error == GIT_ENOTFOUND) {
286
+ git_error_clear();
287
+ return 0;
288
+ }
357
289
 
358
- git_strmap_insert2(
359
- backend->refcache.packfile, ref->name, ref, old_ref, err);
360
- if (err < 0) {
361
- git__free(ref);
362
- return -1;
290
+ return error;
363
291
  }
364
292
 
365
- git__free(old_ref);
366
- return 0;
293
+ file_path = full_path->ptr + strlen(backend->gitpath);
294
+
295
+ return loose_lookup_to_packfile(backend, file_path);
367
296
  }
368
297
 
369
298
  /*
@@ -374,13 +303,10 @@ static int _dirent_loose_load(void *data, git_buf *full_path)
374
303
  */
375
304
  static int packed_loadloose(refdb_fs_backend *backend)
376
305
  {
306
+ int error;
377
307
  git_buf refs_path = GIT_BUF_INIT;
378
- int result;
379
-
380
- /* the packfile must have been previously loaded! */
381
- assert(backend->refcache.packfile);
382
308
 
383
- if (git_buf_joinpath(&refs_path, backend->path, GIT_REFS_DIR) < 0)
309
+ if (git_buf_joinpath(&refs_path, backend->gitpath, GIT_REFS_DIR) < 0)
384
310
  return -1;
385
311
 
386
312
  /*
@@ -388,10 +314,12 @@ static int packed_loadloose(refdb_fs_backend *backend)
388
314
  * This will overwrite any old packed entries with their
389
315
  * updated loose versions
390
316
  */
391
- result = git_path_direach(&refs_path, _dirent_loose_load, backend);
392
- git_buf_free(&refs_path);
317
+ error = git_path_direach(
318
+ &refs_path, backend->direach_flags, _dirent_loose_load, backend);
393
319
 
394
- return result;
320
+ git_buf_dispose(&refs_path);
321
+
322
+ return error;
395
323
  }
396
324
 
397
325
  static int refdb_fs_backend__exists(
@@ -399,25 +327,20 @@ static int refdb_fs_backend__exists(
399
327
  git_refdb_backend *_backend,
400
328
  const char *ref_name)
401
329
  {
402
- refdb_fs_backend *backend;
330
+ refdb_fs_backend *backend = (refdb_fs_backend *)_backend;
403
331
  git_buf ref_path = GIT_BUF_INIT;
332
+ int error;
404
333
 
405
- assert(_backend);
406
- backend = (refdb_fs_backend *)_backend;
407
-
408
- if (packed_load(backend) < 0)
409
- return -1;
334
+ assert(backend);
410
335
 
411
- if (git_buf_joinpath(&ref_path, backend->path, ref_name) < 0)
412
- return -1;
336
+ if ((error = packed_reload(backend)) < 0 ||
337
+ (error = git_buf_joinpath(&ref_path, backend->gitpath, ref_name)) < 0)
338
+ return error;
413
339
 
414
- if (git_path_isfile(ref_path.ptr) == true ||
415
- git_strmap_exists(backend->refcache.packfile, ref_path.ptr))
416
- *exists = 1;
417
- else
418
- *exists = 0;
340
+ *exists = git_path_isfile(ref_path.ptr) ||
341
+ (git_sortedcache_lookup(backend->refcache, ref_name) != NULL);
419
342
 
420
- git_buf_free(&ref_path);
343
+ git_buf_dispose(&ref_path);
421
344
  return 0;
422
345
  }
423
346
 
@@ -429,7 +352,7 @@ static const char *loose_parse_symbolic(git_buf *file_content)
429
352
  refname_start = (const char *)file_content->ptr;
430
353
 
431
354
  if (git_buf_len(file_content) < header_len + 1) {
432
- giterr_set(GITERR_REFERENCE, "Corrupted loose reference file");
355
+ git_error_set(GIT_ERROR_REFERENCE, "corrupted loose reference file");
433
356
  return NULL;
434
357
  }
435
358
 
@@ -442,69 +365,63 @@ static const char *loose_parse_symbolic(git_buf *file_content)
442
365
  return refname_start;
443
366
  }
444
367
 
368
+ /*
369
+ * Returns whether a reference is stored per worktree or not.
370
+ * Per-worktree references are:
371
+ *
372
+ * - all pseudorefs, e.g. HEAD and MERGE_HEAD
373
+ * - all references stored inside of "refs/bisect/"
374
+ */
375
+ static bool is_per_worktree_ref(const char *ref_name)
376
+ {
377
+ return git__prefixcmp(ref_name, "refs/") != 0 ||
378
+ git__prefixcmp(ref_name, "refs/bisect/") == 0;
379
+ }
380
+
445
381
  static int loose_lookup(
446
382
  git_reference **out,
447
383
  refdb_fs_backend *backend,
448
384
  const char *ref_name)
449
385
  {
450
- const char *target;
451
- git_oid oid;
452
386
  git_buf ref_file = GIT_BUF_INIT;
453
387
  int error = 0;
388
+ const char *ref_dir;
454
389
 
455
- error = reference_read(&ref_file, NULL, backend->path, ref_name, NULL);
390
+ if (out)
391
+ *out = NULL;
456
392
 
457
- if (error < 0)
458
- goto done;
393
+ if (is_per_worktree_ref(ref_name))
394
+ ref_dir = backend->gitpath;
395
+ else
396
+ ref_dir = backend->commonpath;
397
+
398
+ if ((error = loose_readbuffer(&ref_file, ref_dir, ref_name)) < 0)
399
+ /* cannot read loose ref file - gah */;
400
+ else if (git__prefixcmp(git_buf_cstr(&ref_file), GIT_SYMREF) == 0) {
401
+ const char *target;
459
402
 
460
- if (git__prefixcmp((const char *)(ref_file.ptr), GIT_SYMREF) == 0) {
461
403
  git_buf_rtrim(&ref_file);
462
404
 
463
- if ((target = loose_parse_symbolic(&ref_file)) == NULL) {
405
+ if (!(target = loose_parse_symbolic(&ref_file)))
464
406
  error = -1;
465
- goto done;
466
- }
467
-
468
- *out = git_reference__alloc_symbolic(ref_name, target);
407
+ else if (out != NULL)
408
+ *out = git_reference__alloc_symbolic(ref_name, target);
469
409
  } else {
470
- if ((error = loose_parse_oid(&oid, ref_name, &ref_file)) < 0)
471
- goto done;
410
+ git_oid oid;
472
411
 
473
- *out = git_reference__alloc(ref_name, &oid, NULL);
412
+ if (!(error = loose_parse_oid(&oid, ref_name, &ref_file)) &&
413
+ out != NULL)
414
+ *out = git_reference__alloc(ref_name, &oid, NULL);
474
415
  }
475
416
 
476
- if (*out == NULL)
477
- error = -1;
478
-
479
- done:
480
- git_buf_free(&ref_file);
417
+ git_buf_dispose(&ref_file);
481
418
  return error;
482
419
  }
483
420
 
484
- static int packed_map_entry(
485
- struct packref **entry,
486
- khiter_t *pos,
487
- refdb_fs_backend *backend,
488
- const char *ref_name)
421
+ static int ref_error_notfound(const char *name)
489
422
  {
490
- git_strmap *packfile_refs;
491
-
492
- if (packed_load(backend) < 0)
493
- return -1;
494
-
495
- /* Look up on the packfile */
496
- packfile_refs = backend->refcache.packfile;
497
-
498
- *pos = git_strmap_lookup_index(packfile_refs, ref_name);
499
-
500
- if (!git_strmap_valid_index(packfile_refs, *pos)) {
501
- giterr_set(GITERR_REFERENCE, "Reference '%s' not found", ref_name);
502
- return GIT_ENOTFOUND;
503
- }
504
-
505
- *entry = git_strmap_value_at(packfile_refs, *pos);
506
-
507
- return 0;
423
+ git_error_set(GIT_ERROR_REFERENCE, "reference '%s' not found", name);
424
+ return GIT_ENOTFOUND;
508
425
  }
509
426
 
510
427
  static int packed_lookup(
@@ -512,18 +429,27 @@ static int packed_lookup(
512
429
  refdb_fs_backend *backend,
513
430
  const char *ref_name)
514
431
  {
515
- struct packref *entry;
516
- khiter_t pos;
517
432
  int error = 0;
433
+ struct packref *entry;
518
434
 
519
- if ((error = packed_map_entry(&entry, &pos, backend, ref_name)) < 0)
435
+ if ((error = packed_reload(backend)) < 0)
520
436
  return error;
521
437
 
522
- if ((*out = git_reference__alloc(ref_name,
523
- &entry->oid, &entry->peel)) == NULL)
438
+ if (git_sortedcache_rlock(backend->refcache) < 0)
524
439
  return -1;
525
440
 
526
- return 0;
441
+ entry = git_sortedcache_lookup(backend->refcache, ref_name);
442
+ if (!entry) {
443
+ error = ref_error_notfound(ref_name);
444
+ } else {
445
+ *out = git_reference__alloc(ref_name, &entry->oid, &entry->peel);
446
+ if (!*out)
447
+ error = -1;
448
+ }
449
+
450
+ git_sortedcache_runlock(backend->refcache);
451
+
452
+ return error;
527
453
  }
528
454
 
529
455
  static int refdb_fs_backend__lookup(
@@ -531,75 +457,105 @@ static int refdb_fs_backend__lookup(
531
457
  git_refdb_backend *_backend,
532
458
  const char *ref_name)
533
459
  {
534
- refdb_fs_backend *backend;
535
- int result;
536
-
537
- assert(_backend);
460
+ refdb_fs_backend *backend = (refdb_fs_backend *)_backend;
461
+ int error;
538
462
 
539
- backend = (refdb_fs_backend *)_backend;
463
+ assert(backend);
540
464
 
541
- if ((result = loose_lookup(out, backend, ref_name)) == 0)
465
+ if (!(error = loose_lookup(out, backend, ref_name)))
542
466
  return 0;
543
467
 
544
468
  /* only try to lookup this reference on the packfile if it
545
469
  * wasn't found on the loose refs; not if there was a critical error */
546
- if (result == GIT_ENOTFOUND) {
547
- giterr_clear();
548
- result = packed_lookup(out, backend, ref_name);
470
+ if (error == GIT_ENOTFOUND) {
471
+ git_error_clear();
472
+ error = packed_lookup(out, backend, ref_name);
549
473
  }
550
474
 
551
- return result;
475
+ return error;
552
476
  }
553
477
 
554
478
  typedef struct {
555
479
  git_reference_iterator parent;
556
480
 
557
481
  char *glob;
482
+
483
+ git_pool pool;
558
484
  git_vector loose;
559
- unsigned int loose_pos;
560
- khiter_t packed_pos;
485
+
486
+ git_sortedcache *cache;
487
+ size_t loose_pos;
488
+ size_t packed_pos;
561
489
  } refdb_fs_iter;
562
490
 
563
491
  static void refdb_fs_backend__iterator_free(git_reference_iterator *_iter)
564
492
  {
565
493
  refdb_fs_iter *iter = (refdb_fs_iter *) _iter;
566
- char *loose_path;
567
- size_t i;
568
-
569
- git_vector_foreach(&iter->loose, i, loose_path) {
570
- git__free(loose_path);
571
- }
572
494
 
573
495
  git_vector_free(&iter->loose);
574
-
575
- git__free(iter->glob);
496
+ git_pool_clear(&iter->pool);
497
+ git_sortedcache_free(iter->cache);
576
498
  git__free(iter);
577
499
  }
578
500
 
579
501
  static int iter_load_loose_paths(refdb_fs_backend *backend, refdb_fs_iter *iter)
580
502
  {
581
- git_strmap *packfile = backend->refcache.packfile;
503
+ int error = 0;
582
504
  git_buf path = GIT_BUF_INIT;
583
- git_iterator *fsit;
505
+ git_iterator *fsit = NULL;
506
+ git_iterator_options fsit_opts = GIT_ITERATOR_OPTIONS_INIT;
584
507
  const git_index_entry *entry = NULL;
508
+ const char *ref_prefix = GIT_REFS_DIR;
509
+ size_t ref_prefix_len = strlen(ref_prefix);
585
510
 
586
- if (!backend->path) /* do nothing if no path for loose refs */
511
+ if (!backend->commonpath) /* do nothing if no commonpath for loose refs */
587
512
  return 0;
588
513
 
589
- if (git_buf_printf(&path, "%s/refs", backend->path) < 0)
590
- return -1;
514
+ fsit_opts.flags = backend->iterator_flags;
515
+
516
+ if (iter->glob) {
517
+ const char *last_sep = NULL;
518
+ const char *pos;
519
+ for (pos = iter->glob; *pos; ++pos) {
520
+ switch (*pos) {
521
+ case '?':
522
+ case '*':
523
+ case '[':
524
+ case '\\':
525
+ break;
526
+ case '/':
527
+ last_sep = pos;
528
+ /* FALLTHROUGH */
529
+ default:
530
+ continue;
531
+ }
532
+ break;
533
+ }
534
+ if (last_sep) {
535
+ ref_prefix = iter->glob;
536
+ ref_prefix_len = (last_sep - ref_prefix) + 1;
537
+ }
538
+ }
591
539
 
592
- if (git_iterator_for_filesystem(&fsit, git_buf_cstr(&path), 0, NULL, NULL) < 0)
593
- return -1;
540
+ if ((error = git_buf_printf(&path, "%s/", backend->commonpath)) < 0 ||
541
+ (error = git_buf_put(&path, ref_prefix, ref_prefix_len)) < 0) {
542
+ git_buf_dispose(&path);
543
+ return error;
544
+ }
545
+
546
+ if ((error = git_iterator_for_filesystem(&fsit, path.ptr, &fsit_opts)) < 0) {
547
+ git_buf_dispose(&path);
548
+ return (iter->glob && error == GIT_ENOTFOUND)? 0 : error;
549
+ }
594
550
 
595
- git_vector_init(&iter->loose, 8, NULL);
596
- git_buf_sets(&path, GIT_REFS_DIR);
551
+ error = git_buf_sets(&path, ref_prefix);
597
552
 
598
- while (!git_iterator_advance(&entry, fsit)) {
553
+ while (!error && !git_iterator_advance(&entry, fsit)) {
599
554
  const char *ref_name;
600
- khiter_t pos;
555
+ struct packref *ref;
556
+ char *ref_dup;
601
557
 
602
- git_buf_truncate(&path, strlen(GIT_REFS_DIR));
558
+ git_buf_truncate(&path, ref_prefix_len);
603
559
  git_buf_puts(&path, entry->path);
604
560
  ref_name = git_buf_cstr(&path);
605
561
 
@@ -607,27 +563,32 @@ static int iter_load_loose_paths(refdb_fs_backend *backend, refdb_fs_iter *iter)
607
563
  (iter->glob && p_fnmatch(iter->glob, ref_name, 0) != 0))
608
564
  continue;
609
565
 
610
- pos = git_strmap_lookup_index(packfile, ref_name);
611
- if (git_strmap_valid_index(packfile, pos)) {
612
- struct packref *ref = git_strmap_value_at(packfile, pos);
566
+ git_sortedcache_rlock(backend->refcache);
567
+ ref = git_sortedcache_lookup(backend->refcache, ref_name);
568
+ if (ref)
613
569
  ref->flags |= PACKREF_SHADOWED;
614
- }
570
+ git_sortedcache_runlock(backend->refcache);
615
571
 
616
- git_vector_insert(&iter->loose, git__strdup(ref_name));
572
+ ref_dup = git_pool_strdup(&iter->pool, ref_name);
573
+ if (!ref_dup)
574
+ error = -1;
575
+ else
576
+ error = git_vector_insert(&iter->loose, ref_dup);
617
577
  }
618
578
 
619
579
  git_iterator_free(fsit);
620
- git_buf_free(&path);
580
+ git_buf_dispose(&path);
621
581
 
622
- return 0;
582
+ return error;
623
583
  }
624
584
 
625
585
  static int refdb_fs_backend__iterator_next(
626
586
  git_reference **out, git_reference_iterator *_iter)
627
587
  {
588
+ int error = GIT_ITEROVER;
628
589
  refdb_fs_iter *iter = (refdb_fs_iter *)_iter;
629
590
  refdb_fs_backend *backend = (refdb_fs_backend *)iter->parent.db->backend;
630
- git_strmap *packfile = backend->refcache.packfile;
591
+ struct packref *ref;
631
592
 
632
593
  while (iter->loose_pos < iter->loose.length) {
633
594
  const char *path = git_vector_get(&iter->loose, iter->loose_pos++);
@@ -635,102 +596,113 @@ static int refdb_fs_backend__iterator_next(
635
596
  if (loose_lookup(out, backend, path) == 0)
636
597
  return 0;
637
598
 
638
- giterr_clear();
599
+ git_error_clear();
639
600
  }
640
601
 
641
- while (iter->packed_pos < kh_end(packfile)) {
642
- struct packref *ref = NULL;
643
-
644
- while (!kh_exist(packfile, iter->packed_pos)) {
645
- iter->packed_pos++;
646
- if (iter->packed_pos == kh_end(packfile))
647
- return GIT_ITEROVER;
648
- }
602
+ if (!iter->cache) {
603
+ if ((error = git_sortedcache_copy(&iter->cache, backend->refcache, 1, NULL, NULL)) < 0)
604
+ return error;
605
+ }
649
606
 
650
- ref = kh_val(packfile, iter->packed_pos);
651
- iter->packed_pos++;
607
+ error = GIT_ITEROVER;
608
+ while (iter->packed_pos < git_sortedcache_entrycount(iter->cache)) {
609
+ ref = git_sortedcache_entry(iter->cache, iter->packed_pos++);
610
+ if (!ref) /* stop now if another thread deleted refs and we past end */
611
+ break;
652
612
 
653
613
  if (ref->flags & PACKREF_SHADOWED)
654
614
  continue;
655
-
656
615
  if (iter->glob && p_fnmatch(iter->glob, ref->name, 0) != 0)
657
616
  continue;
658
617
 
659
618
  *out = git_reference__alloc(ref->name, &ref->oid, &ref->peel);
660
- if (*out == NULL)
661
- return -1;
662
-
663
- return 0;
619
+ error = (*out != NULL) ? 0 : -1;
620
+ break;
664
621
  }
665
622
 
666
- return GIT_ITEROVER;
623
+ return error;
667
624
  }
668
625
 
669
626
  static int refdb_fs_backend__iterator_next_name(
670
627
  const char **out, git_reference_iterator *_iter)
671
628
  {
629
+ int error = GIT_ITEROVER;
672
630
  refdb_fs_iter *iter = (refdb_fs_iter *)_iter;
673
631
  refdb_fs_backend *backend = (refdb_fs_backend *)iter->parent.db->backend;
674
- git_strmap *packfile = backend->refcache.packfile;
632
+ struct packref *ref;
675
633
 
676
634
  while (iter->loose_pos < iter->loose.length) {
677
635
  const char *path = git_vector_get(&iter->loose, iter->loose_pos++);
678
636
 
679
- if (git_strmap_exists(packfile, path))
680
- continue;
637
+ if (loose_lookup(NULL, backend, path) == 0) {
638
+ *out = path;
639
+ return 0;
640
+ }
681
641
 
682
- *out = path;
683
- return 0;
642
+ git_error_clear();
684
643
  }
685
644
 
686
- while (iter->packed_pos < kh_end(packfile)) {
687
- while (!kh_exist(packfile, iter->packed_pos)) {
688
- iter->packed_pos++;
689
- if (iter->packed_pos == kh_end(packfile))
690
- return GIT_ITEROVER;
691
- }
645
+ if (!iter->cache) {
646
+ if ((error = git_sortedcache_copy(&iter->cache, backend->refcache, 1, NULL, NULL)) < 0)
647
+ return error;
648
+ }
692
649
 
693
- *out = kh_key(packfile, iter->packed_pos);
694
- iter->packed_pos++;
650
+ error = GIT_ITEROVER;
651
+ while (iter->packed_pos < git_sortedcache_entrycount(iter->cache)) {
652
+ ref = git_sortedcache_entry(iter->cache, iter->packed_pos++);
653
+ if (!ref) /* stop now if another thread deleted refs and we past end */
654
+ break;
695
655
 
696
- if (iter->glob && p_fnmatch(iter->glob, *out, 0) != 0)
656
+ if (ref->flags & PACKREF_SHADOWED)
657
+ continue;
658
+ if (iter->glob && p_fnmatch(iter->glob, ref->name, 0) != 0)
697
659
  continue;
698
660
 
699
- return 0;
661
+ *out = ref->name;
662
+ error = 0;
663
+ break;
700
664
  }
701
665
 
702
- return GIT_ITEROVER;
666
+ return error;
703
667
  }
704
668
 
705
669
  static int refdb_fs_backend__iterator(
706
670
  git_reference_iterator **out, git_refdb_backend *_backend, const char *glob)
707
671
  {
672
+ int error;
708
673
  refdb_fs_iter *iter;
709
- refdb_fs_backend *backend;
674
+ refdb_fs_backend *backend = (refdb_fs_backend *)_backend;
710
675
 
711
- assert(_backend);
712
- backend = (refdb_fs_backend *)_backend;
676
+ assert(backend);
713
677
 
714
- if (packed_load(backend) < 0)
715
- return -1;
678
+ if ((error = packed_reload(backend)) < 0)
679
+ return error;
716
680
 
717
681
  iter = git__calloc(1, sizeof(refdb_fs_iter));
718
- GITERR_CHECK_ALLOC(iter);
682
+ GIT_ERROR_CHECK_ALLOC(iter);
683
+
684
+ git_pool_init(&iter->pool, 1);
719
685
 
720
- if (glob != NULL)
721
- iter->glob = git__strdup(glob);
686
+ if (git_vector_init(&iter->loose, 8, NULL) < 0)
687
+ goto fail;
688
+
689
+ if (glob != NULL &&
690
+ (iter->glob = git_pool_strdup(&iter->pool, glob)) == NULL)
691
+ goto fail;
722
692
 
723
693
  iter->parent.next = refdb_fs_backend__iterator_next;
724
694
  iter->parent.next_name = refdb_fs_backend__iterator_next_name;
725
695
  iter->parent.free = refdb_fs_backend__iterator_free;
726
696
 
727
- if (iter_load_loose_paths(backend, iter) < 0) {
728
- refdb_fs_backend__iterator_free((git_reference_iterator *)iter);
729
- return -1;
730
- }
697
+ if (iter_load_loose_paths(backend, iter) < 0)
698
+ goto fail;
731
699
 
732
700
  *out = (git_reference_iterator *)iter;
733
701
  return 0;
702
+
703
+ fail:
704
+ refdb_fs_backend__iterator_free((git_reference_iterator *)iter);
705
+ return -1;
734
706
  }
735
707
 
736
708
  static bool ref_is_available(
@@ -756,80 +728,152 @@ static int reference_path_available(
756
728
  const char* old_ref,
757
729
  int force)
758
730
  {
759
- struct packref *this_ref;
731
+ size_t i;
732
+ int error;
760
733
 
761
- if (packed_load(backend) < 0)
762
- return -1;
734
+ if ((error = packed_reload(backend)) < 0)
735
+ return error;
763
736
 
764
737
  if (!force) {
765
738
  int exists;
766
739
 
767
- if (refdb_fs_backend__exists(&exists, (git_refdb_backend *)backend, new_ref) < 0)
768
- return -1;
740
+ if ((error = refdb_fs_backend__exists(
741
+ &exists, (git_refdb_backend *)backend, new_ref)) < 0) {
742
+ return error;
743
+ }
769
744
 
770
745
  if (exists) {
771
- giterr_set(GITERR_REFERENCE,
772
- "Failed to write reference '%s': a reference with "
773
- " that name already exists.", new_ref);
746
+ git_error_set(GIT_ERROR_REFERENCE,
747
+ "failed to write reference '%s': a reference with "
748
+ "that name already exists.", new_ref);
774
749
  return GIT_EEXISTS;
775
750
  }
776
751
  }
777
752
 
778
- git_strmap_foreach_value(backend->refcache.packfile, this_ref, {
779
- if (!ref_is_available(old_ref, new_ref, this_ref->name)) {
780
- giterr_set(GITERR_REFERENCE,
781
- "The path to reference '%s' collides with an existing one", new_ref);
753
+ git_sortedcache_rlock(backend->refcache);
754
+
755
+ for (i = 0; i < git_sortedcache_entrycount(backend->refcache); ++i) {
756
+ struct packref *ref = git_sortedcache_entry(backend->refcache, i);
757
+
758
+ if (ref && !ref_is_available(old_ref, new_ref, ref->name)) {
759
+ git_sortedcache_runlock(backend->refcache);
760
+ git_error_set(GIT_ERROR_REFERENCE,
761
+ "path to reference '%s' collides with existing one", new_ref);
782
762
  return -1;
783
763
  }
784
- });
785
-
764
+ }
765
+
766
+ git_sortedcache_runlock(backend->refcache);
786
767
  return 0;
787
768
  }
788
769
 
789
- static int loose_write(refdb_fs_backend *backend, const git_reference *ref)
770
+ static int loose_lock(git_filebuf *file, refdb_fs_backend *backend, const char *name)
790
771
  {
791
- git_filebuf file = GIT_FILEBUF_INIT;
772
+ int error, filebuf_flags;
792
773
  git_buf ref_path = GIT_BUF_INIT;
774
+ const char *basedir;
775
+
776
+ assert(file && backend && name);
777
+
778
+ if (!git_path_isvalid(backend->repo, name, 0, GIT_PATH_REJECT_FILESYSTEM_DEFAULTS)) {
779
+ git_error_set(GIT_ERROR_INVALID, "invalid reference name '%s'", name);
780
+ return GIT_EINVALIDSPEC;
781
+ }
782
+
783
+ if (is_per_worktree_ref(name))
784
+ basedir = backend->gitpath;
785
+ else
786
+ basedir = backend->commonpath;
793
787
 
794
788
  /* Remove a possibly existing empty directory hierarchy
795
789
  * which name would collide with the reference name
796
790
  */
797
- if (git_futils_rmdir_r(ref->name, backend->path, GIT_RMDIR_SKIP_NONEMPTY) < 0)
798
- return -1;
791
+ if ((error = git_futils_rmdir_r(name, basedir, GIT_RMDIR_SKIP_NONEMPTY)) < 0)
792
+ return error;
799
793
 
800
- if (git_buf_joinpath(&ref_path, backend->path, ref->name) < 0)
794
+ if (git_buf_joinpath(&ref_path, basedir, name) < 0)
801
795
  return -1;
802
796
 
803
- if (git_filebuf_open(&file, ref_path.ptr, GIT_FILEBUF_FORCE) < 0) {
804
- git_buf_free(&ref_path);
805
- return -1;
806
- }
797
+ filebuf_flags = GIT_FILEBUF_FORCE;
798
+ if (backend->fsync)
799
+ filebuf_flags |= GIT_FILEBUF_FSYNC;
807
800
 
808
- git_buf_free(&ref_path);
801
+ error = git_filebuf_open(file, ref_path.ptr, filebuf_flags, GIT_REFS_FILE_MODE);
809
802
 
810
- if (ref->type == GIT_REF_OID) {
811
- char oid[GIT_OID_HEXSZ + 1];
803
+ if (error == GIT_EDIRECTORY)
804
+ git_error_set(GIT_ERROR_REFERENCE, "cannot lock ref '%s', there are refs beneath that folder", name);
812
805
 
813
- git_oid_fmt(oid, &ref->target.oid);
814
- oid[GIT_OID_HEXSZ] = '\0';
806
+ git_buf_dispose(&ref_path);
807
+ return error;
808
+ }
809
+
810
+ static int loose_commit(git_filebuf *file, const git_reference *ref)
811
+ {
812
+ assert(file && ref);
815
813
 
816
- git_filebuf_printf(&file, "%s\n", oid);
814
+ if (ref->type == GIT_REFERENCE_DIRECT) {
815
+ char oid[GIT_OID_HEXSZ + 1];
816
+ git_oid_nfmt(oid, sizeof(oid), &ref->target.oid);
817
817
 
818
- } else if (ref->type == GIT_REF_SYMBOLIC) {
819
- git_filebuf_printf(&file, GIT_SYMREF "%s\n", ref->target.symbolic);
818
+ git_filebuf_printf(file, "%s\n", oid);
819
+ } else if (ref->type == GIT_REFERENCE_SYMBOLIC) {
820
+ git_filebuf_printf(file, GIT_SYMREF "%s\n", ref->target.symbolic);
820
821
  } else {
821
822
  assert(0); /* don't let this happen */
822
823
  }
823
824
 
824
- return git_filebuf_commit(&file, GIT_REFS_FILE_MODE);
825
+ return git_filebuf_commit(file);
826
+ }
827
+
828
+ static int refdb_fs_backend__lock(void **out, git_refdb_backend *_backend, const char *refname)
829
+ {
830
+ int error;
831
+ git_filebuf *lock;
832
+ refdb_fs_backend *backend = (refdb_fs_backend *) _backend;
833
+
834
+ lock = git__calloc(1, sizeof(git_filebuf));
835
+ GIT_ERROR_CHECK_ALLOC(lock);
836
+
837
+ if ((error = loose_lock(lock, backend, refname)) < 0) {
838
+ git__free(lock);
839
+ return error;
840
+ }
841
+
842
+ *out = lock;
843
+ return 0;
825
844
  }
826
845
 
827
- static int packed_sort(const void *a, const void *b)
846
+ static int refdb_fs_backend__write_tail(
847
+ git_refdb_backend *_backend,
848
+ const git_reference *ref,
849
+ git_filebuf *file,
850
+ int update_reflog,
851
+ const git_signature *who,
852
+ const char *message,
853
+ const git_oid *old_id,
854
+ const char *old_target);
855
+
856
+ static int refdb_fs_backend__delete_tail(
857
+ git_refdb_backend *_backend,
858
+ git_filebuf *file,
859
+ const char *ref_name,
860
+ const git_oid *old_id, const char *old_target);
861
+
862
+ static int refdb_fs_backend__unlock(git_refdb_backend *backend, void *payload, int success, int update_reflog,
863
+ const git_reference *ref, const git_signature *sig, const char *message)
828
864
  {
829
- const struct packref *ref_a = (const struct packref *)a;
830
- const struct packref *ref_b = (const struct packref *)b;
865
+ git_filebuf *lock = (git_filebuf *) payload;
866
+ int error = 0;
867
+
868
+ if (success == 2)
869
+ error = refdb_fs_backend__delete_tail(backend, lock, ref->name, NULL, NULL);
870
+ else if (success)
871
+ error = refdb_fs_backend__write_tail(backend, ref, lock, update_reflog, sig, message, NULL, NULL);
872
+ else
873
+ git_filebuf_cleanup(lock);
831
874
 
832
- return strcmp(ref_a->name, ref_b->name);
875
+ git__free(lock);
876
+ return error;
833
877
  }
834
878
 
835
879
  /*
@@ -850,7 +894,7 @@ static int packed_find_peel(refdb_fs_backend *backend, struct packref *ref)
850
894
  /*
851
895
  * Find the tagged object in the repository
852
896
  */
853
- if (git_object_lookup(&object, backend->repo, &ref->oid, GIT_OBJ_ANY) < 0)
897
+ if (git_object_lookup(&object, backend->repo, &ref->oid, GIT_OBJECT_ANY) < 0)
854
898
  return -1;
855
899
 
856
900
  /*
@@ -858,7 +902,7 @@ static int packed_find_peel(refdb_fs_backend *backend, struct packref *ref)
858
902
  * if the ref is actually a 'weak' ref, we don't need to resolve
859
903
  * anything.
860
904
  */
861
- if (git_object_type(object) == GIT_OBJ_TAG) {
905
+ if (git_object_type(object) == GIT_OBJECT_TAG) {
862
906
  git_tag *tag = (git_tag *)object;
863
907
 
864
908
  /*
@@ -884,9 +928,7 @@ static int packed_find_peel(refdb_fs_backend *backend, struct packref *ref)
884
928
  static int packed_write_ref(struct packref *ref, git_filebuf *file)
885
929
  {
886
930
  char oid[GIT_OID_HEXSZ + 1];
887
-
888
- git_oid_fmt(oid, &ref->oid);
889
- oid[GIT_OID_HEXSZ] = 0;
931
+ git_oid_nfmt(oid, sizeof(oid), &ref->oid);
890
932
 
891
933
  /*
892
934
  * For references that peel to an object in the repo, we must
@@ -900,8 +942,7 @@ static int packed_write_ref(struct packref *ref, git_filebuf *file)
900
942
  */
901
943
  if (ref->flags & PACKREF_HAS_PEEL) {
902
944
  char peel[GIT_OID_HEXSZ + 1];
903
- git_oid_fmt(peel, &ref->peel);
904
- peel[GIT_OID_HEXSZ] = 0;
945
+ git_oid_nfmt(peel, sizeof(peel), &ref->peel);
905
946
 
906
947
  if (git_filebuf_printf(file, "%s %s\n^%s\n", oid, ref->name, peel) < 0)
907
948
  return -1;
@@ -924,44 +965,65 @@ static int packed_write_ref(struct packref *ref, git_filebuf *file)
924
965
  * is well-written, because we are destructing references
925
966
  * here otherwise.
926
967
  */
927
- static int packed_remove_loose(
928
- refdb_fs_backend *backend,
929
- git_vector *packing_list)
968
+ static int packed_remove_loose(refdb_fs_backend *backend)
930
969
  {
931
970
  size_t i;
932
- git_buf full_path = GIT_BUF_INIT;
933
- int failed = 0;
971
+ git_filebuf lock = GIT_FILEBUF_INIT;
972
+ git_buf ref_content = GIT_BUF_INIT;
973
+ int error = 0;
934
974
 
935
- for (i = 0; i < packing_list->length; ++i) {
936
- struct packref *ref = git_vector_get(packing_list, i);
975
+ /* backend->refcache is already locked when this is called */
937
976
 
938
- if ((ref->flags & PACKREF_WAS_LOOSE) == 0)
939
- continue;
977
+ for (i = 0; i < git_sortedcache_entrycount(backend->refcache); ++i) {
978
+ struct packref *ref = git_sortedcache_entry(backend->refcache, i);
979
+ git_oid current_id;
940
980
 
941
- if (git_buf_joinpath(&full_path, backend->path, ref->name) < 0)
942
- return -1; /* critical; do not try to recover on oom */
981
+ if (!ref || !(ref->flags & PACKREF_WAS_LOOSE))
982
+ continue;
943
983
 
944
- if (git_path_exists(full_path.ptr) == true && p_unlink(full_path.ptr) < 0) {
945
- if (failed)
946
- continue;
984
+ git_filebuf_cleanup(&lock);
947
985
 
948
- giterr_set(GITERR_REFERENCE,
949
- "Failed to remove loose reference '%s' after packing: %s",
950
- full_path.ptr, strerror(errno));
986
+ /* We need to stop anybody from updating the ref while we try to do a safe delete */
987
+ error = loose_lock(&lock, backend, ref->name);
988
+ /* If someone else is updating it, let them do it */
989
+ if (error == GIT_EEXISTS || error == GIT_ENOTFOUND)
990
+ continue;
951
991
 
952
- failed = 1;
992
+ if (error < 0) {
993
+ git_buf_dispose(&ref_content);
994
+ git_error_set(GIT_ERROR_REFERENCE, "failed to lock loose reference '%s'", ref->name);
995
+ return error;
953
996
  }
954
997
 
998
+ error = git_futils_readbuffer(&ref_content, lock.path_original);
999
+ /* Someone else beat us to cleaning up the ref, let's simply continue */
1000
+ if (error == GIT_ENOTFOUND)
1001
+ continue;
1002
+
1003
+ /* This became a symref between us packing and trying to delete it, so ignore it */
1004
+ if (!git__prefixcmp(ref_content.ptr, GIT_SYMREF))
1005
+ continue;
1006
+
1007
+ /* Figure out the current id; if we find a bad ref file, skip it so we can do the rest */
1008
+ if (loose_parse_oid(&current_id, lock.path_original, &ref_content) < 0)
1009
+ continue;
1010
+
1011
+ /* If the ref moved since we packed it, we must not delete it */
1012
+ if (!git_oid_equal(&current_id, &ref->oid))
1013
+ continue;
1014
+
955
1015
  /*
956
1016
  * if we fail to remove a single file, this is *not* good,
957
1017
  * but we should keep going and remove as many as possible.
958
- * After we've removed as many files as possible, we return
959
- * the error code anyway.
1018
+ * If we fail to remove, the ref is still in the old state, so
1019
+ * we haven't lost information.
960
1020
  */
1021
+ p_unlink(lock.path_original);
961
1022
  }
962
1023
 
963
- git_buf_free(&full_path);
964
- return failed ? -1 : 0;
1024
+ git_buf_dispose(&ref_content);
1025
+ git_filebuf_cleanup(&lock);
1026
+ return 0;
965
1027
  }
966
1028
 
967
1029
  /*
@@ -969,309 +1031,1116 @@ static int packed_remove_loose(
969
1031
  */
970
1032
  static int packed_write(refdb_fs_backend *backend)
971
1033
  {
1034
+ git_sortedcache *refcache = backend->refcache;
972
1035
  git_filebuf pack_file = GIT_FILEBUF_INIT;
1036
+ int error, open_flags = 0;
973
1037
  size_t i;
974
- git_buf pack_file_path = GIT_BUF_INIT;
975
- git_vector packing_list;
976
- unsigned int total_refs;
977
-
978
- assert(backend && backend->refcache.packfile);
979
-
980
- total_refs =
981
- (unsigned int)git_strmap_num_entries(backend->refcache.packfile);
982
-
983
- if (git_vector_init(&packing_list, total_refs, packed_sort) < 0)
984
- return -1;
985
-
986
- /* Load all the packfile into a vector */
987
- {
988
- struct packref *reference;
989
1038
 
990
- /* cannot fail: vector already has the right size */
991
- git_strmap_foreach_value(backend->refcache.packfile, reference, {
992
- git_vector_insert(&packing_list, reference);
993
- });
994
- }
995
-
996
- /* sort the vector so the entries appear sorted on the packfile */
997
- git_vector_sort(&packing_list);
1039
+ /* lock the cache to updates while we do this */
1040
+ if ((error = git_sortedcache_wlock(refcache)) < 0)
1041
+ return error;
998
1042
 
999
- /* Now we can open the file! */
1000
- if (git_buf_joinpath(&pack_file_path,
1001
- backend->path, GIT_PACKEDREFS_FILE) < 0)
1002
- goto cleanup_memory;
1043
+ if (backend->fsync)
1044
+ open_flags = GIT_FILEBUF_FSYNC;
1003
1045
 
1004
- if (git_filebuf_open(&pack_file, pack_file_path.ptr, 0) < 0)
1005
- goto cleanup_packfile;
1046
+ /* Open the file! */
1047
+ if ((error = git_filebuf_open(&pack_file, git_sortedcache_path(refcache), open_flags, GIT_PACKEDREFS_FILE_MODE)) < 0)
1048
+ goto fail;
1006
1049
 
1007
1050
  /* Packfiles have a header... apparently
1008
1051
  * This is in fact not required, but we might as well print it
1009
1052
  * just for kicks */
1010
- if (git_filebuf_printf(&pack_file, "%s\n", GIT_PACKEDREFS_HEADER) < 0)
1011
- goto cleanup_packfile;
1053
+ if ((error = git_filebuf_printf(&pack_file, "%s\n", GIT_PACKEDREFS_HEADER)) < 0)
1054
+ goto fail;
1012
1055
 
1013
- for (i = 0; i < packing_list.length; ++i) {
1014
- struct packref *ref = (struct packref *)git_vector_get(&packing_list, i);
1056
+ for (i = 0; i < git_sortedcache_entrycount(refcache); ++i) {
1057
+ struct packref *ref = git_sortedcache_entry(refcache, i);
1058
+ assert(ref);
1015
1059
 
1016
- if (packed_find_peel(backend, ref) < 0)
1017
- goto cleanup_packfile;
1060
+ if ((error = packed_find_peel(backend, ref)) < 0)
1061
+ goto fail;
1018
1062
 
1019
- if (packed_write_ref(ref, &pack_file) < 0)
1020
- goto cleanup_packfile;
1063
+ if ((error = packed_write_ref(ref, &pack_file)) < 0)
1064
+ goto fail;
1021
1065
  }
1022
1066
 
1023
1067
  /* if we've written all the references properly, we can commit
1024
1068
  * the packfile to make the changes effective */
1025
- if (git_filebuf_commit(&pack_file, GIT_PACKEDREFS_FILE_MODE) < 0)
1026
- goto cleanup_memory;
1069
+ if ((error = git_filebuf_commit(&pack_file)) < 0)
1070
+ goto fail;
1027
1071
 
1028
1072
  /* when and only when the packfile has been properly written,
1029
1073
  * we can go ahead and remove the loose refs */
1030
- if (packed_remove_loose(backend, &packing_list) < 0)
1031
- goto cleanup_memory;
1074
+ if ((error = packed_remove_loose(backend)) < 0)
1075
+ goto fail;
1032
1076
 
1033
- {
1034
- struct stat st;
1035
- if (p_stat(pack_file_path.ptr, &st) == 0)
1036
- backend->refcache.packfile_time = st.st_mtime;
1037
- }
1038
-
1039
- git_vector_free(&packing_list);
1040
- git_buf_free(&pack_file_path);
1077
+ git_sortedcache_updated(refcache);
1078
+ git_sortedcache_wunlock(refcache);
1041
1079
 
1042
1080
  /* we're good now */
1043
1081
  return 0;
1044
1082
 
1045
- cleanup_packfile:
1083
+ fail:
1046
1084
  git_filebuf_cleanup(&pack_file);
1085
+ git_sortedcache_wunlock(refcache);
1047
1086
 
1048
- cleanup_memory:
1049
- git_vector_free(&packing_list);
1050
- git_buf_free(&pack_file_path);
1087
+ return error;
1088
+ }
1051
1089
 
1052
- return -1;
1090
+ static int reflog_append(refdb_fs_backend *backend, const git_reference *ref, const git_oid *old, const git_oid *new, const git_signature *author, const char *message);
1091
+ static int has_reflog(git_repository *repo, const char *name);
1092
+
1093
+ static int should_write_reflog(int *write, git_repository *repo, const char *name)
1094
+ {
1095
+ int error, logall;
1096
+
1097
+ error = git_repository__cvar(&logall, repo, GIT_CVAR_LOGALLREFUPDATES);
1098
+ if (error < 0)
1099
+ return error;
1100
+
1101
+ /* Defaults to the opposite of the repo being bare */
1102
+ if (logall == GIT_LOGALLREFUPDATES_UNSET)
1103
+ logall = !git_repository_is_bare(repo);
1104
+
1105
+ *write = 0;
1106
+ switch (logall) {
1107
+ case GIT_LOGALLREFUPDATES_FALSE:
1108
+ *write = 0;
1109
+ break;
1110
+
1111
+ case GIT_LOGALLREFUPDATES_TRUE:
1112
+ /* Only write if it already has a log,
1113
+ * or if it's under heads/, remotes/ or notes/
1114
+ */
1115
+ *write = has_reflog(repo, name) ||
1116
+ !git__prefixcmp(name, GIT_REFS_HEADS_DIR) ||
1117
+ !git__strcmp(name, GIT_HEAD_FILE) ||
1118
+ !git__prefixcmp(name, GIT_REFS_REMOTES_DIR) ||
1119
+ !git__prefixcmp(name, GIT_REFS_NOTES_DIR);
1120
+ break;
1121
+
1122
+ case GIT_LOGALLREFUPDATES_ALWAYS:
1123
+ *write = 1;
1124
+ break;
1125
+ }
1126
+
1127
+ return 0;
1128
+ }
1129
+
1130
+ static int cmp_old_ref(int *cmp, git_refdb_backend *backend, const char *name,
1131
+ const git_oid *old_id, const char *old_target)
1132
+ {
1133
+ int error = 0;
1134
+ git_reference *old_ref = NULL;
1135
+
1136
+ *cmp = 0;
1137
+ /* It "matches" if there is no old value to compare against */
1138
+ if (!old_id && !old_target)
1139
+ return 0;
1140
+
1141
+ if ((error = refdb_fs_backend__lookup(&old_ref, backend, name)) < 0)
1142
+ goto out;
1143
+
1144
+ /* If the types don't match, there's no way the values do */
1145
+ if (old_id && old_ref->type != GIT_REFERENCE_DIRECT) {
1146
+ *cmp = -1;
1147
+ goto out;
1148
+ }
1149
+ if (old_target && old_ref->type != GIT_REFERENCE_SYMBOLIC) {
1150
+ *cmp = 1;
1151
+ goto out;
1152
+ }
1153
+
1154
+ if (old_id && old_ref->type == GIT_REFERENCE_DIRECT)
1155
+ *cmp = git_oid_cmp(old_id, &old_ref->target.oid);
1156
+
1157
+ if (old_target && old_ref->type == GIT_REFERENCE_SYMBOLIC)
1158
+ *cmp = git__strcmp(old_target, old_ref->target.symbolic);
1159
+
1160
+ out:
1161
+ git_reference_free(old_ref);
1162
+
1163
+ return error;
1164
+ }
1165
+
1166
+ /*
1167
+ * The git.git comment regarding this, for your viewing pleasure:
1168
+ *
1169
+ * Special hack: If a branch is updated directly and HEAD
1170
+ * points to it (may happen on the remote side of a push
1171
+ * for example) then logically the HEAD reflog should be
1172
+ * updated too.
1173
+ * A generic solution implies reverse symref information,
1174
+ * but finding all symrefs pointing to the given branch
1175
+ * would be rather costly for this rare event (the direct
1176
+ * update of a branch) to be worth it. So let's cheat and
1177
+ * check with HEAD only which should cover 99% of all usage
1178
+ * scenarios (even 100% of the default ones).
1179
+ */
1180
+ static int maybe_append_head(refdb_fs_backend *backend, const git_reference *ref, const git_signature *who, const char *message)
1181
+ {
1182
+ int error;
1183
+ git_oid old_id;
1184
+ git_reference *tmp = NULL, *head = NULL, *peeled = NULL;
1185
+ const char *name;
1186
+
1187
+ if (ref->type == GIT_REFERENCE_SYMBOLIC)
1188
+ return 0;
1189
+
1190
+ /* if we can't resolve, we use {0}*40 as old id */
1191
+ if (git_reference_name_to_id(&old_id, backend->repo, ref->name) < 0)
1192
+ memset(&old_id, 0, sizeof(old_id));
1193
+
1194
+ if ((error = git_reference_lookup(&head, backend->repo, GIT_HEAD_FILE)) < 0)
1195
+ return error;
1196
+
1197
+ if (git_reference_type(head) == GIT_REFERENCE_DIRECT)
1198
+ goto cleanup;
1199
+
1200
+ if ((error = git_reference_lookup(&tmp, backend->repo, GIT_HEAD_FILE)) < 0)
1201
+ goto cleanup;
1202
+
1203
+ /* Go down the symref chain until we find the branch */
1204
+ while (git_reference_type(tmp) == GIT_REFERENCE_SYMBOLIC) {
1205
+ error = git_reference_lookup(&peeled, backend->repo, git_reference_symbolic_target(tmp));
1206
+ if (error < 0)
1207
+ break;
1208
+
1209
+ git_reference_free(tmp);
1210
+ tmp = peeled;
1211
+ }
1212
+
1213
+ if (error == GIT_ENOTFOUND) {
1214
+ error = 0;
1215
+ name = git_reference_symbolic_target(tmp);
1216
+ } else if (error < 0) {
1217
+ goto cleanup;
1218
+ } else {
1219
+ name = git_reference_name(tmp);
1220
+ }
1221
+
1222
+ if (strcmp(name, ref->name))
1223
+ goto cleanup;
1224
+
1225
+ error = reflog_append(backend, head, &old_id, git_reference_target(ref), who, message);
1226
+
1227
+ cleanup:
1228
+ git_reference_free(tmp);
1229
+ git_reference_free(head);
1230
+ return error;
1053
1231
  }
1054
1232
 
1055
1233
  static int refdb_fs_backend__write(
1056
1234
  git_refdb_backend *_backend,
1057
1235
  const git_reference *ref,
1058
- int force)
1236
+ int force,
1237
+ const git_signature *who,
1238
+ const char *message,
1239
+ const git_oid *old_id,
1240
+ const char *old_target)
1059
1241
  {
1060
- refdb_fs_backend *backend;
1061
- int error;
1242
+ refdb_fs_backend *backend = (refdb_fs_backend *)_backend;
1243
+ git_filebuf file = GIT_FILEBUF_INIT;
1244
+ int error = 0;
1062
1245
 
1063
- assert(_backend);
1064
- backend = (refdb_fs_backend *)_backend;
1246
+ assert(backend);
1065
1247
 
1066
- error = reference_path_available(backend, ref->name, NULL, force);
1067
- if (error < 0)
1248
+ if ((error = reference_path_available(backend, ref->name, NULL, force)) < 0)
1068
1249
  return error;
1069
1250
 
1070
- return loose_write(backend, ref);
1251
+ /* We need to perform the reflog append and old value check under the ref's lock */
1252
+ if ((error = loose_lock(&file, backend, ref->name)) < 0)
1253
+ return error;
1254
+
1255
+ return refdb_fs_backend__write_tail(_backend, ref, &file, true, who, message, old_id, old_target);
1256
+ }
1257
+
1258
+ static int refdb_fs_backend__write_tail(
1259
+ git_refdb_backend *_backend,
1260
+ const git_reference *ref,
1261
+ git_filebuf *file,
1262
+ int update_reflog,
1263
+ const git_signature *who,
1264
+ const char *message,
1265
+ const git_oid *old_id,
1266
+ const char *old_target)
1267
+ {
1268
+ refdb_fs_backend *backend = (refdb_fs_backend *)_backend;
1269
+ int error = 0, cmp = 0, should_write;
1270
+ const char *new_target = NULL;
1271
+ const git_oid *new_id = NULL;
1272
+
1273
+ if ((error = cmp_old_ref(&cmp, _backend, ref->name, old_id, old_target)) < 0)
1274
+ goto on_error;
1275
+
1276
+ if (cmp) {
1277
+ git_error_set(GIT_ERROR_REFERENCE, "old reference value does not match");
1278
+ error = GIT_EMODIFIED;
1279
+ goto on_error;
1280
+ }
1281
+
1282
+ if (ref->type == GIT_REFERENCE_SYMBOLIC)
1283
+ new_target = ref->target.symbolic;
1284
+ else
1285
+ new_id = &ref->target.oid;
1286
+
1287
+ error = cmp_old_ref(&cmp, _backend, ref->name, new_id, new_target);
1288
+ if (error < 0 && error != GIT_ENOTFOUND)
1289
+ goto on_error;
1290
+
1291
+ /* Don't update if we have the same value */
1292
+ if (!error && !cmp) {
1293
+ error = 0;
1294
+ goto on_error; /* not really error */
1295
+ }
1296
+
1297
+ if (update_reflog) {
1298
+ if ((error = should_write_reflog(&should_write, backend->repo, ref->name)) < 0)
1299
+ goto on_error;
1300
+
1301
+ if (should_write) {
1302
+ if ((error = reflog_append(backend, ref, NULL, NULL, who, message)) < 0)
1303
+ goto on_error;
1304
+ if ((error = maybe_append_head(backend, ref, who, message)) < 0)
1305
+ goto on_error;
1306
+ }
1307
+ }
1308
+
1309
+ return loose_commit(file, ref);
1310
+
1311
+ on_error:
1312
+ git_filebuf_cleanup(file);
1313
+ return error;
1314
+ }
1315
+
1316
+ static void refdb_fs_backend__try_delete_empty_ref_hierarchie(
1317
+ refdb_fs_backend *backend,
1318
+ const char *ref_name,
1319
+ bool reflog)
1320
+ {
1321
+ git_buf relative_path = GIT_BUF_INIT;
1322
+ git_buf base_path = GIT_BUF_INIT;
1323
+ size_t commonlen;
1324
+
1325
+ assert(backend && ref_name);
1326
+
1327
+ if (git_buf_sets(&relative_path, ref_name) < 0)
1328
+ goto cleanup;
1329
+
1330
+ git_path_squash_slashes(&relative_path);
1331
+ if ((commonlen = git_path_common_dirlen("refs/heads/", git_buf_cstr(&relative_path))) == strlen("refs/heads/") ||
1332
+ (commonlen = git_path_common_dirlen("refs/tags/", git_buf_cstr(&relative_path))) == strlen("refs/tags/") ||
1333
+ (commonlen = git_path_common_dirlen("refs/remotes/", git_buf_cstr(&relative_path))) == strlen("refs/remotes/")) {
1334
+
1335
+ git_buf_truncate(&relative_path, commonlen);
1336
+
1337
+ if (reflog) {
1338
+ if (git_buf_join3(&base_path, '/', backend->commonpath, GIT_REFLOG_DIR, git_buf_cstr(&relative_path)) < 0)
1339
+ goto cleanup;
1340
+ } else {
1341
+ if (git_buf_joinpath(&base_path, backend->commonpath, git_buf_cstr(&relative_path)) < 0)
1342
+ goto cleanup;
1343
+ }
1344
+
1345
+ git_futils_rmdir_r(ref_name + commonlen, git_buf_cstr(&base_path), GIT_RMDIR_EMPTY_PARENTS | GIT_RMDIR_SKIP_ROOT);
1346
+ }
1347
+
1348
+ cleanup:
1349
+ git_buf_dispose(&relative_path);
1350
+ git_buf_dispose(&base_path);
1071
1351
  }
1072
1352
 
1073
1353
  static int refdb_fs_backend__delete(
1074
1354
  git_refdb_backend *_backend,
1075
- const char *ref_name)
1355
+ const char *ref_name,
1356
+ const git_oid *old_id, const char *old_target)
1076
1357
  {
1077
- refdb_fs_backend *backend;
1078
- git_buf loose_path = GIT_BUF_INIT;
1079
- struct packref *pack_ref;
1080
- khiter_t pack_ref_pos;
1358
+ refdb_fs_backend *backend = (refdb_fs_backend *)_backend;
1359
+ git_filebuf file = GIT_FILEBUF_INIT;
1081
1360
  int error = 0;
1361
+
1362
+ assert(backend && ref_name);
1363
+
1364
+ if ((error = loose_lock(&file, backend, ref_name)) < 0)
1365
+ return error;
1366
+
1367
+ if ((error = refdb_reflog_fs__delete(_backend, ref_name)) < 0) {
1368
+ git_filebuf_cleanup(&file);
1369
+ return error;
1370
+ }
1371
+
1372
+ return refdb_fs_backend__delete_tail(_backend, &file, ref_name, old_id, old_target);
1373
+ }
1374
+
1375
+ static int refdb_fs_backend__delete_tail(
1376
+ git_refdb_backend *_backend,
1377
+ git_filebuf *file,
1378
+ const char *ref_name,
1379
+ const git_oid *old_id, const char *old_target)
1380
+ {
1381
+ refdb_fs_backend *backend = (refdb_fs_backend *)_backend;
1382
+ git_buf loose_path = GIT_BUF_INIT;
1383
+ size_t pack_pos;
1384
+ int error = 0, cmp = 0;
1082
1385
  bool loose_deleted = 0;
1083
1386
 
1084
- assert(_backend);
1085
- assert(ref_name);
1387
+ error = cmp_old_ref(&cmp, _backend, ref_name, old_id, old_target);
1388
+ if (error < 0)
1389
+ goto cleanup;
1086
1390
 
1087
- backend = (refdb_fs_backend *)_backend;
1391
+ if (cmp) {
1392
+ git_error_set(GIT_ERROR_REFERENCE, "old reference value does not match");
1393
+ error = GIT_EMODIFIED;
1394
+ goto cleanup;
1395
+ }
1088
1396
 
1089
1397
  /* If a loose reference exists, remove it from the filesystem */
1090
- if (git_buf_joinpath(&loose_path, backend->path, ref_name) < 0)
1398
+ if (git_buf_joinpath(&loose_path, backend->commonpath, ref_name) < 0)
1091
1399
  return -1;
1092
1400
 
1093
- if (git_path_isfile(loose_path.ptr)) {
1094
- error = p_unlink(loose_path.ptr);
1095
- loose_deleted = 1;
1096
- }
1097
1401
 
1098
- git_buf_free(&loose_path);
1402
+ error = p_unlink(loose_path.ptr);
1403
+ if (error < 0 && errno == ENOENT)
1404
+ error = 0;
1405
+ else if (error < 0)
1406
+ goto cleanup;
1407
+ else if (error == 0)
1408
+ loose_deleted = 1;
1099
1409
 
1100
- if (error != 0)
1101
- return error;
1410
+ if ((error = packed_reload(backend)) < 0)
1411
+ goto cleanup;
1102
1412
 
1103
1413
  /* If a packed reference exists, remove it from the packfile and repack */
1104
- error = packed_map_entry(&pack_ref, &pack_ref_pos, backend, ref_name);
1414
+ if ((error = git_sortedcache_wlock(backend->refcache)) < 0)
1415
+ goto cleanup;
1416
+
1417
+ if (!(error = git_sortedcache_lookup_index(
1418
+ &pack_pos, backend->refcache, ref_name)))
1419
+ error = git_sortedcache_remove(backend->refcache, pack_pos);
1105
1420
 
1106
- if (error == GIT_ENOTFOUND)
1107
- return loose_deleted ? 0 : GIT_ENOTFOUND;
1421
+ git_sortedcache_wunlock(backend->refcache);
1108
1422
 
1109
- if (error == 0) {
1110
- git_strmap_delete_at(backend->refcache.packfile, pack_ref_pos);
1111
- git__free(pack_ref);
1112
- error = packed_write(backend);
1423
+ if (error == GIT_ENOTFOUND) {
1424
+ error = loose_deleted ? 0 : ref_error_notfound(ref_name);
1425
+ goto cleanup;
1113
1426
  }
1114
1427
 
1428
+ error = packed_write(backend);
1429
+
1430
+ cleanup:
1431
+ git_buf_dispose(&loose_path);
1432
+ git_filebuf_cleanup(file);
1433
+ if (loose_deleted)
1434
+ refdb_fs_backend__try_delete_empty_ref_hierarchie(backend, ref_name, false);
1115
1435
  return error;
1116
1436
  }
1117
1437
 
1438
+ static int refdb_reflog_fs__rename(git_refdb_backend *_backend, const char *old_name, const char *new_name);
1439
+
1118
1440
  static int refdb_fs_backend__rename(
1119
1441
  git_reference **out,
1120
1442
  git_refdb_backend *_backend,
1121
1443
  const char *old_name,
1122
1444
  const char *new_name,
1123
- int force)
1445
+ int force,
1446
+ const git_signature *who,
1447
+ const char *message)
1124
1448
  {
1125
- refdb_fs_backend *backend;
1449
+ refdb_fs_backend *backend = (refdb_fs_backend *)_backend;
1126
1450
  git_reference *old, *new;
1451
+ git_filebuf file = GIT_FILEBUF_INIT;
1127
1452
  int error;
1128
1453
 
1129
- assert(_backend);
1130
- backend = (refdb_fs_backend *)_backend;
1454
+ assert(backend);
1131
1455
 
1132
- error = reference_path_available(backend, new_name, old_name, force);
1133
- if (error < 0)
1456
+ if ((error = reference_path_available(
1457
+ backend, new_name, old_name, force)) < 0 ||
1458
+ (error = refdb_fs_backend__lookup(&old, _backend, old_name)) < 0)
1134
1459
  return error;
1135
1460
 
1136
- error = refdb_fs_backend__lookup(&old, _backend, old_name);
1137
- if (error < 0)
1461
+ if ((error = refdb_fs_backend__delete(_backend, old_name, NULL, NULL)) < 0) {
1462
+ git_reference_free(old);
1138
1463
  return error;
1464
+ }
1139
1465
 
1140
- error = refdb_fs_backend__delete(_backend, old_name);
1141
- if (error < 0) {
1466
+ new = git_reference__set_name(old, new_name);
1467
+ if (!new) {
1142
1468
  git_reference_free(old);
1469
+ return -1;
1470
+ }
1471
+
1472
+ if ((error = loose_lock(&file, backend, new->name)) < 0) {
1473
+ git_reference_free(new);
1143
1474
  return error;
1144
1475
  }
1145
1476
 
1146
- new = realloc(old, sizeof(git_reference) + strlen(new_name) + 1);
1147
- memcpy(new->name, new_name, strlen(new_name) + 1);
1477
+ /* Try to rename the refog; it's ok if the old doesn't exist */
1478
+ error = refdb_reflog_fs__rename(_backend, old_name, new_name);
1479
+ if (((error == 0) || (error == GIT_ENOTFOUND)) &&
1480
+ ((error = reflog_append(backend, new, git_reference_target(new), NULL, who, message)) < 0)) {
1481
+ git_reference_free(new);
1482
+ git_filebuf_cleanup(&file);
1483
+ return error;
1484
+ }
1148
1485
 
1149
- error = loose_write(backend, new);
1150
1486
  if (error < 0) {
1151
1487
  git_reference_free(new);
1488
+ git_filebuf_cleanup(&file);
1152
1489
  return error;
1153
1490
  }
1154
1491
 
1155
- if (out) {
1156
- *out = new;
1157
- } else {
1492
+
1493
+ if ((error = loose_commit(&file, new)) < 0 || out == NULL) {
1158
1494
  git_reference_free(new);
1495
+ return error;
1159
1496
  }
1160
1497
 
1498
+ *out = new;
1161
1499
  return 0;
1162
1500
  }
1163
1501
 
1164
1502
  static int refdb_fs_backend__compress(git_refdb_backend *_backend)
1165
1503
  {
1166
- refdb_fs_backend *backend;
1504
+ int error;
1505
+ refdb_fs_backend *backend = (refdb_fs_backend *)_backend;
1167
1506
 
1168
- assert(_backend);
1169
- backend = (refdb_fs_backend *)_backend;
1507
+ assert(backend);
1170
1508
 
1171
- if (packed_load(backend) < 0 || /* load the existing packfile */
1172
- packed_loadloose(backend) < 0 || /* add all the loose refs */
1173
- packed_write(backend) < 0) /* write back to disk */
1174
- return -1;
1509
+ if ((error = packed_reload(backend)) < 0 || /* load the existing packfile */
1510
+ (error = packed_loadloose(backend)) < 0 || /* add all the loose refs */
1511
+ (error = packed_write(backend)) < 0) /* write back to disk */
1512
+ return error;
1175
1513
 
1176
1514
  return 0;
1177
1515
  }
1178
1516
 
1179
- static void refcache_free(git_refcache *refs)
1180
- {
1181
- assert(refs);
1182
-
1183
- if (refs->packfile) {
1184
- struct packref *reference;
1185
-
1186
- git_strmap_foreach_value(refs->packfile, reference, {
1187
- git__free(reference);
1188
- });
1189
-
1190
- git_strmap_free(refs->packfile);
1191
- }
1192
- }
1193
-
1194
1517
  static void refdb_fs_backend__free(git_refdb_backend *_backend)
1195
1518
  {
1196
- refdb_fs_backend *backend;
1519
+ refdb_fs_backend *backend = (refdb_fs_backend *)_backend;
1197
1520
 
1198
- assert(_backend);
1199
- backend = (refdb_fs_backend *)_backend;
1521
+ assert(backend);
1200
1522
 
1201
- refcache_free(&backend->refcache);
1202
- git__free(backend->path);
1523
+ git_sortedcache_free(backend->refcache);
1524
+ git__free(backend->gitpath);
1525
+ git__free(backend->commonpath);
1203
1526
  git__free(backend);
1204
1527
  }
1205
1528
 
1206
- static int setup_namespace(git_buf *path, git_repository *repo)
1529
+ static char *setup_namespace(git_repository *repo, const char *in)
1207
1530
  {
1208
- char *parts, *start, *end;
1531
+ git_buf path = GIT_BUF_INIT;
1532
+ char *parts, *start, *end, *out = NULL;
1209
1533
 
1210
- /* Not all repositories have a path */
1211
- if (repo->path_repository == NULL)
1212
- return 0;
1534
+ if (!in)
1535
+ goto done;
1213
1536
 
1214
- /* Load the path to the repo first */
1215
- git_buf_puts(path, repo->path_repository);
1537
+ git_buf_puts(&path, in);
1216
1538
 
1217
1539
  /* if the repo is not namespaced, nothing else to do */
1218
- if (repo->namespace == NULL)
1219
- return 0;
1540
+ if (repo->namespace == NULL) {
1541
+ out = git_buf_detach(&path);
1542
+ goto done;
1543
+ }
1220
1544
 
1221
1545
  parts = end = git__strdup(repo->namespace);
1222
1546
  if (parts == NULL)
1223
- return -1;
1547
+ goto done;
1224
1548
 
1225
- /**
1549
+ /*
1226
1550
  * From `man gitnamespaces`:
1227
1551
  * namespaces which include a / will expand to a hierarchy
1228
1552
  * of namespaces; for example, GIT_NAMESPACE=foo/bar will store
1229
1553
  * refs under refs/namespaces/foo/refs/namespaces/bar/
1230
1554
  */
1231
- while ((start = git__strsep(&end, "/")) != NULL) {
1232
- git_buf_printf(path, "refs/namespaces/%s/", start);
1233
- }
1555
+ while ((start = git__strsep(&end, "/")) != NULL)
1556
+ git_buf_printf(&path, "refs/namespaces/%s/", start);
1234
1557
 
1235
- git_buf_printf(path, "refs/namespaces/%s/refs", end);
1558
+ git_buf_printf(&path, "refs/namespaces/%s/refs", end);
1236
1559
  git__free(parts);
1237
1560
 
1238
1561
  /* Make sure that the folder with the namespace exists */
1239
- if (git_futils_mkdir_r(git_buf_cstr(path), repo->path_repository, 0777) < 0)
1562
+ if (git_futils_mkdir_relative(git_buf_cstr(&path), in, 0777,
1563
+ GIT_MKDIR_PATH, NULL) < 0)
1564
+ goto done;
1565
+
1566
+ /* Return root of the namespaced gitpath, i.e. without the trailing '/refs' */
1567
+ git_buf_rtruncate_at_char(&path, '/');
1568
+ out = git_buf_detach(&path);
1569
+
1570
+ done:
1571
+ git_buf_dispose(&path);
1572
+ return out;
1573
+ }
1574
+
1575
+ static int reflog_alloc(git_reflog **reflog, const char *name)
1576
+ {
1577
+ git_reflog *log;
1578
+
1579
+ *reflog = NULL;
1580
+
1581
+ log = git__calloc(1, sizeof(git_reflog));
1582
+ GIT_ERROR_CHECK_ALLOC(log);
1583
+
1584
+ log->ref_name = git__strdup(name);
1585
+ GIT_ERROR_CHECK_ALLOC(log->ref_name);
1586
+
1587
+ if (git_vector_init(&log->entries, 0, NULL) < 0) {
1588
+ git__free(log->ref_name);
1589
+ git__free(log);
1240
1590
  return -1;
1591
+ }
1592
+
1593
+ *reflog = log;
1241
1594
 
1242
- /* Return the root of the namespaced path, i.e. without the trailing '/refs' */
1243
- git_buf_rtruncate_at_char(path, '/');
1244
1595
  return 0;
1245
1596
  }
1246
1597
 
1598
+ static int reflog_parse(git_reflog *log, const char *buf, size_t buf_size)
1599
+ {
1600
+ const char *ptr;
1601
+ git_reflog_entry *entry;
1602
+
1603
+ #define seek_forward(_increase) do { \
1604
+ if (_increase >= buf_size) { \
1605
+ git_error_set(GIT_ERROR_INVALID, "ran out of data while parsing reflog"); \
1606
+ goto fail; \
1607
+ } \
1608
+ buf += _increase; \
1609
+ buf_size -= _increase; \
1610
+ } while (0)
1611
+
1612
+ while (buf_size > GIT_REFLOG_SIZE_MIN) {
1613
+ entry = git__calloc(1, sizeof(git_reflog_entry));
1614
+ GIT_ERROR_CHECK_ALLOC(entry);
1615
+
1616
+ entry->committer = git__calloc(1, sizeof(git_signature));
1617
+ GIT_ERROR_CHECK_ALLOC(entry->committer);
1618
+
1619
+ if (git_oid_fromstrn(&entry->oid_old, buf, GIT_OID_HEXSZ) < 0)
1620
+ goto fail;
1621
+ seek_forward(GIT_OID_HEXSZ + 1);
1622
+
1623
+ if (git_oid_fromstrn(&entry->oid_cur, buf, GIT_OID_HEXSZ) < 0)
1624
+ goto fail;
1625
+ seek_forward(GIT_OID_HEXSZ + 1);
1626
+
1627
+ ptr = buf;
1628
+
1629
+ /* Seek forward to the end of the signature. */
1630
+ while (*buf && *buf != '\t' && *buf != '\n')
1631
+ seek_forward(1);
1632
+
1633
+ if (git_signature__parse(entry->committer, &ptr, buf + 1, NULL, *buf) < 0)
1634
+ goto fail;
1635
+
1636
+ if (*buf == '\t') {
1637
+ /* We got a message. Read everything till we reach LF. */
1638
+ seek_forward(1);
1639
+ ptr = buf;
1640
+
1641
+ while (*buf && *buf != '\n')
1642
+ seek_forward(1);
1643
+
1644
+ entry->msg = git__strndup(ptr, buf - ptr);
1645
+ GIT_ERROR_CHECK_ALLOC(entry->msg);
1646
+ } else
1647
+ entry->msg = NULL;
1648
+
1649
+ while (*buf && *buf == '\n' && buf_size > 1)
1650
+ seek_forward(1);
1651
+
1652
+ if (git_vector_insert(&log->entries, entry) < 0)
1653
+ goto fail;
1654
+ }
1655
+
1656
+ return 0;
1657
+
1658
+ #undef seek_forward
1659
+
1660
+ fail:
1661
+ git_reflog_entry__free(entry);
1662
+
1663
+ return -1;
1664
+ }
1665
+
1666
+ static int create_new_reflog_file(const char *filepath)
1667
+ {
1668
+ int fd, error;
1669
+
1670
+ if ((error = git_futils_mkpath2file(filepath, GIT_REFLOG_DIR_MODE)) < 0)
1671
+ return error;
1672
+
1673
+ if ((fd = p_open(filepath,
1674
+ O_WRONLY | O_CREAT,
1675
+ GIT_REFLOG_FILE_MODE)) < 0)
1676
+ return -1;
1677
+
1678
+ return p_close(fd);
1679
+ }
1680
+
1681
+ GIT_INLINE(int) retrieve_reflog_path(git_buf *path, git_repository *repo, const char *name)
1682
+ {
1683
+ if (strcmp(name, GIT_HEAD_FILE) == 0)
1684
+ return git_buf_join3(path, '/', repo->gitdir, GIT_REFLOG_DIR, name);
1685
+ return git_buf_join3(path, '/', repo->commondir, GIT_REFLOG_DIR, name);
1686
+ }
1687
+
1688
+ static int refdb_reflog_fs__ensure_log(git_refdb_backend *_backend, const char *name)
1689
+ {
1690
+ refdb_fs_backend *backend;
1691
+ git_repository *repo;
1692
+ git_buf path = GIT_BUF_INIT;
1693
+ int error;
1694
+
1695
+ assert(_backend && name);
1696
+
1697
+ backend = (refdb_fs_backend *) _backend;
1698
+ repo = backend->repo;
1699
+
1700
+ if ((error = retrieve_reflog_path(&path, repo, name)) < 0)
1701
+ return error;
1702
+
1703
+ error = create_new_reflog_file(git_buf_cstr(&path));
1704
+ git_buf_dispose(&path);
1705
+
1706
+ return error;
1707
+ }
1708
+
1709
+ static int has_reflog(git_repository *repo, const char *name)
1710
+ {
1711
+ int ret = 0;
1712
+ git_buf path = GIT_BUF_INIT;
1713
+
1714
+ if (retrieve_reflog_path(&path, repo, name) < 0)
1715
+ goto cleanup;
1716
+
1717
+ ret = git_path_isfile(git_buf_cstr(&path));
1718
+
1719
+ cleanup:
1720
+ git_buf_dispose(&path);
1721
+ return ret;
1722
+ }
1723
+
1724
+ static int refdb_reflog_fs__has_log(git_refdb_backend *_backend, const char *name)
1725
+ {
1726
+ refdb_fs_backend *backend;
1727
+
1728
+ assert(_backend && name);
1729
+
1730
+ backend = (refdb_fs_backend *) _backend;
1731
+
1732
+ return has_reflog(backend->repo, name);
1733
+ }
1734
+
1735
+ static int refdb_reflog_fs__read(git_reflog **out, git_refdb_backend *_backend, const char *name)
1736
+ {
1737
+ int error = -1;
1738
+ git_buf log_path = GIT_BUF_INIT;
1739
+ git_buf log_file = GIT_BUF_INIT;
1740
+ git_reflog *log = NULL;
1741
+ git_repository *repo;
1742
+ refdb_fs_backend *backend;
1743
+
1744
+ assert(out && _backend && name);
1745
+
1746
+ backend = (refdb_fs_backend *) _backend;
1747
+ repo = backend->repo;
1748
+
1749
+ if (reflog_alloc(&log, name) < 0)
1750
+ return -1;
1751
+
1752
+ if (retrieve_reflog_path(&log_path, repo, name) < 0)
1753
+ goto cleanup;
1754
+
1755
+ error = git_futils_readbuffer(&log_file, git_buf_cstr(&log_path));
1756
+ if (error < 0 && error != GIT_ENOTFOUND)
1757
+ goto cleanup;
1758
+
1759
+ if ((error == GIT_ENOTFOUND) &&
1760
+ ((error = create_new_reflog_file(git_buf_cstr(&log_path))) < 0))
1761
+ goto cleanup;
1762
+
1763
+ if ((error = reflog_parse(log,
1764
+ git_buf_cstr(&log_file), git_buf_len(&log_file))) < 0)
1765
+ goto cleanup;
1766
+
1767
+ *out = log;
1768
+ goto success;
1769
+
1770
+ cleanup:
1771
+ git_reflog_free(log);
1772
+
1773
+ success:
1774
+ git_buf_dispose(&log_file);
1775
+ git_buf_dispose(&log_path);
1776
+
1777
+ return error;
1778
+ }
1779
+
1780
+ static int serialize_reflog_entry(
1781
+ git_buf *buf,
1782
+ const git_oid *oid_old,
1783
+ const git_oid *oid_new,
1784
+ const git_signature *committer,
1785
+ const char *msg)
1786
+ {
1787
+ char raw_old[GIT_OID_HEXSZ+1];
1788
+ char raw_new[GIT_OID_HEXSZ+1];
1789
+
1790
+ git_oid_tostr(raw_old, GIT_OID_HEXSZ+1, oid_old);
1791
+ git_oid_tostr(raw_new, GIT_OID_HEXSZ+1, oid_new);
1792
+
1793
+ git_buf_clear(buf);
1794
+
1795
+ git_buf_puts(buf, raw_old);
1796
+ git_buf_putc(buf, ' ');
1797
+ git_buf_puts(buf, raw_new);
1798
+
1799
+ git_signature__writebuf(buf, " ", committer);
1800
+
1801
+ /* drop trailing LF */
1802
+ git_buf_rtrim(buf);
1803
+
1804
+ if (msg) {
1805
+ git_buf_putc(buf, '\t');
1806
+ git_buf_puts(buf, msg);
1807
+ }
1808
+
1809
+ git_buf_putc(buf, '\n');
1810
+
1811
+ return git_buf_oom(buf);
1812
+ }
1813
+
1814
+ static int lock_reflog(git_filebuf *file, refdb_fs_backend *backend, const char *refname)
1815
+ {
1816
+ git_repository *repo;
1817
+ git_buf log_path = GIT_BUF_INIT;
1818
+ int error;
1819
+
1820
+ repo = backend->repo;
1821
+
1822
+ if (!git_path_isvalid(backend->repo, refname, 0, GIT_PATH_REJECT_FILESYSTEM_DEFAULTS)) {
1823
+ git_error_set(GIT_ERROR_INVALID, "invalid reference name '%s'", refname);
1824
+ return GIT_EINVALIDSPEC;
1825
+ }
1826
+
1827
+ if (retrieve_reflog_path(&log_path, repo, refname) < 0)
1828
+ return -1;
1829
+
1830
+ if (!git_path_isfile(git_buf_cstr(&log_path))) {
1831
+ git_error_set(GIT_ERROR_INVALID,
1832
+ "log file for reference '%s' doesn't exist", refname);
1833
+ error = -1;
1834
+ goto cleanup;
1835
+ }
1836
+
1837
+ error = git_filebuf_open(file, git_buf_cstr(&log_path), 0, GIT_REFLOG_FILE_MODE);
1838
+
1839
+ cleanup:
1840
+ git_buf_dispose(&log_path);
1841
+
1842
+ return error;
1843
+ }
1844
+
1845
+ static int refdb_reflog_fs__write(git_refdb_backend *_backend, git_reflog *reflog)
1846
+ {
1847
+ int error = -1;
1848
+ unsigned int i;
1849
+ git_reflog_entry *entry;
1850
+ refdb_fs_backend *backend;
1851
+ git_buf log = GIT_BUF_INIT;
1852
+ git_filebuf fbuf = GIT_FILEBUF_INIT;
1853
+
1854
+ assert(_backend && reflog);
1855
+
1856
+ backend = (refdb_fs_backend *) _backend;
1857
+
1858
+ if ((error = lock_reflog(&fbuf, backend, reflog->ref_name)) < 0)
1859
+ return -1;
1860
+
1861
+ git_vector_foreach(&reflog->entries, i, entry) {
1862
+ if (serialize_reflog_entry(&log, &(entry->oid_old), &(entry->oid_cur), entry->committer, entry->msg) < 0)
1863
+ goto cleanup;
1864
+
1865
+ if ((error = git_filebuf_write(&fbuf, log.ptr, log.size)) < 0)
1866
+ goto cleanup;
1867
+ }
1868
+
1869
+ error = git_filebuf_commit(&fbuf);
1870
+ goto success;
1871
+
1872
+ cleanup:
1873
+ git_filebuf_cleanup(&fbuf);
1874
+
1875
+ success:
1876
+ git_buf_dispose(&log);
1877
+
1878
+ return error;
1879
+ }
1880
+
1881
+ /* Append to the reflog, must be called under reference lock */
1882
+ static int reflog_append(refdb_fs_backend *backend, const git_reference *ref, const git_oid *old, const git_oid *new, const git_signature *who, const char *message)
1883
+ {
1884
+ int error, is_symbolic, open_flags;
1885
+ git_oid old_id = {{0}}, new_id = {{0}};
1886
+ git_buf buf = GIT_BUF_INIT, path = GIT_BUF_INIT;
1887
+ git_repository *repo = backend->repo;
1888
+
1889
+ is_symbolic = ref->type == GIT_REFERENCE_SYMBOLIC;
1890
+
1891
+ /* "normal" symbolic updates do not write */
1892
+ if (is_symbolic &&
1893
+ strcmp(ref->name, GIT_HEAD_FILE) &&
1894
+ !(old && new))
1895
+ return 0;
1896
+
1897
+ /* From here on is_symoblic also means that it's HEAD */
1898
+
1899
+ if (old) {
1900
+ git_oid_cpy(&old_id, old);
1901
+ } else {
1902
+ error = git_reference_name_to_id(&old_id, repo, ref->name);
1903
+ if (error < 0 && error != GIT_ENOTFOUND)
1904
+ return error;
1905
+ }
1906
+
1907
+ if (new) {
1908
+ git_oid_cpy(&new_id, new);
1909
+ } else {
1910
+ if (!is_symbolic) {
1911
+ git_oid_cpy(&new_id, git_reference_target(ref));
1912
+ } else {
1913
+ error = git_reference_name_to_id(&new_id, repo, git_reference_symbolic_target(ref));
1914
+ if (error < 0 && error != GIT_ENOTFOUND)
1915
+ return error;
1916
+ /* detaching HEAD does not create an entry */
1917
+ if (error == GIT_ENOTFOUND)
1918
+ return 0;
1919
+
1920
+ git_error_clear();
1921
+ }
1922
+ }
1923
+
1924
+ if ((error = serialize_reflog_entry(&buf, &old_id, &new_id, who, message)) < 0)
1925
+ goto cleanup;
1926
+
1927
+ if ((error = retrieve_reflog_path(&path, repo, ref->name)) < 0)
1928
+ goto cleanup;
1929
+
1930
+ if (((error = git_futils_mkpath2file(git_buf_cstr(&path), 0777)) < 0) &&
1931
+ (error != GIT_EEXISTS)) {
1932
+ goto cleanup;
1933
+ }
1934
+
1935
+ /* If the new branch matches part of the namespace of a previously deleted branch,
1936
+ * there maybe an obsolete/unused directory (or directory hierarchy) in the way.
1937
+ */
1938
+ if (git_path_isdir(git_buf_cstr(&path))) {
1939
+ if ((error = git_futils_rmdir_r(git_buf_cstr(&path), NULL, GIT_RMDIR_SKIP_NONEMPTY)) < 0) {
1940
+ if (error == GIT_ENOTFOUND)
1941
+ error = 0;
1942
+ } else if (git_path_isdir(git_buf_cstr(&path))) {
1943
+ git_error_set(GIT_ERROR_REFERENCE, "cannot create reflog at '%s', there are reflogs beneath that folder",
1944
+ ref->name);
1945
+ error = GIT_EDIRECTORY;
1946
+ }
1947
+
1948
+ if (error != 0)
1949
+ goto cleanup;
1950
+ }
1951
+
1952
+ open_flags = O_WRONLY | O_CREAT | O_APPEND;
1953
+
1954
+ if (backend->fsync)
1955
+ open_flags |= O_FSYNC;
1956
+
1957
+ error = git_futils_writebuffer(&buf, git_buf_cstr(&path), open_flags, GIT_REFLOG_FILE_MODE);
1958
+
1959
+ cleanup:
1960
+ git_buf_dispose(&buf);
1961
+ git_buf_dispose(&path);
1962
+
1963
+ return error;
1964
+ }
1965
+
1966
+ static int refdb_reflog_fs__rename(git_refdb_backend *_backend, const char *old_name, const char *new_name)
1967
+ {
1968
+ int error = 0, fd;
1969
+ git_buf old_path = GIT_BUF_INIT;
1970
+ git_buf new_path = GIT_BUF_INIT;
1971
+ git_buf temp_path = GIT_BUF_INIT;
1972
+ git_buf normalized = GIT_BUF_INIT;
1973
+ git_repository *repo;
1974
+ refdb_fs_backend *backend;
1975
+
1976
+ assert(_backend && old_name && new_name);
1977
+
1978
+ backend = (refdb_fs_backend *) _backend;
1979
+ repo = backend->repo;
1980
+
1981
+ if ((error = git_reference__normalize_name(
1982
+ &normalized, new_name, GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL)) < 0)
1983
+ return error;
1984
+
1985
+ if (git_buf_joinpath(&temp_path, repo->gitdir, GIT_REFLOG_DIR) < 0)
1986
+ return -1;
1987
+
1988
+ if (git_buf_joinpath(&old_path, git_buf_cstr(&temp_path), old_name) < 0)
1989
+ return -1;
1990
+
1991
+ if (git_buf_joinpath(&new_path, git_buf_cstr(&temp_path), git_buf_cstr(&normalized)) < 0)
1992
+ return -1;
1993
+
1994
+ if (!git_path_exists(git_buf_cstr(&old_path))) {
1995
+ error = GIT_ENOTFOUND;
1996
+ goto cleanup;
1997
+ }
1998
+
1999
+ /*
2000
+ * Move the reflog to a temporary place. This two-phase renaming is required
2001
+ * in order to cope with funny renaming use cases when one tries to move a reference
2002
+ * to a partially colliding namespace:
2003
+ * - a/b -> a/b/c
2004
+ * - a/b/c/d -> a/b/c
2005
+ */
2006
+ if (git_buf_joinpath(&temp_path, git_buf_cstr(&temp_path), "temp_reflog") < 0)
2007
+ return -1;
2008
+
2009
+ if ((fd = git_futils_mktmp(&temp_path, git_buf_cstr(&temp_path), GIT_REFLOG_FILE_MODE)) < 0) {
2010
+ error = -1;
2011
+ goto cleanup;
2012
+ }
2013
+
2014
+ p_close(fd);
2015
+
2016
+ if (p_rename(git_buf_cstr(&old_path), git_buf_cstr(&temp_path)) < 0) {
2017
+ git_error_set(GIT_ERROR_OS, "failed to rename reflog for %s", new_name);
2018
+ error = -1;
2019
+ goto cleanup;
2020
+ }
2021
+
2022
+ if (git_path_isdir(git_buf_cstr(&new_path)) &&
2023
+ (git_futils_rmdir_r(git_buf_cstr(&new_path), NULL, GIT_RMDIR_SKIP_NONEMPTY) < 0)) {
2024
+ error = -1;
2025
+ goto cleanup;
2026
+ }
2027
+
2028
+ if (git_futils_mkpath2file(git_buf_cstr(&new_path), GIT_REFLOG_DIR_MODE) < 0) {
2029
+ error = -1;
2030
+ goto cleanup;
2031
+ }
2032
+
2033
+ if (p_rename(git_buf_cstr(&temp_path), git_buf_cstr(&new_path)) < 0) {
2034
+ git_error_set(GIT_ERROR_OS, "failed to rename reflog for %s", new_name);
2035
+ error = -1;
2036
+ }
2037
+
2038
+ cleanup:
2039
+ git_buf_dispose(&temp_path);
2040
+ git_buf_dispose(&old_path);
2041
+ git_buf_dispose(&new_path);
2042
+ git_buf_dispose(&normalized);
2043
+
2044
+ return error;
2045
+ }
2046
+
2047
+ static int refdb_reflog_fs__delete(git_refdb_backend *_backend, const char *name)
2048
+ {
2049
+ refdb_fs_backend *backend = (refdb_fs_backend *) _backend;
2050
+ git_buf path = GIT_BUF_INIT;
2051
+ int error;
2052
+
2053
+ assert(_backend && name);
2054
+
2055
+ if ((error = retrieve_reflog_path(&path, backend->repo, name)) < 0)
2056
+ goto out;
2057
+
2058
+ if (!git_path_exists(path.ptr))
2059
+ goto out;
2060
+
2061
+ if ((error = p_unlink(path.ptr)) < 0)
2062
+ goto out;
2063
+
2064
+ refdb_fs_backend__try_delete_empty_ref_hierarchie(backend, name, true);
2065
+
2066
+ out:
2067
+ git_buf_dispose(&path);
2068
+
2069
+ return error;
2070
+ }
2071
+
1247
2072
  int git_refdb_backend_fs(
1248
2073
  git_refdb_backend **backend_out,
1249
2074
  git_repository *repository)
1250
2075
  {
1251
- git_buf path = GIT_BUF_INIT;
2076
+ int t = 0;
2077
+ git_buf gitpath = GIT_BUF_INIT;
1252
2078
  refdb_fs_backend *backend;
1253
2079
 
1254
2080
  backend = git__calloc(1, sizeof(refdb_fs_backend));
1255
- GITERR_CHECK_ALLOC(backend);
2081
+ GIT_ERROR_CHECK_ALLOC(backend);
1256
2082
 
1257
2083
  backend->repo = repository;
1258
2084
 
1259
- if (setup_namespace(&path, repository) < 0) {
1260
- git__free(backend);
1261
- return -1;
2085
+ if (repository->gitdir) {
2086
+ backend->gitpath = setup_namespace(repository, repository->gitdir);
2087
+
2088
+ if (backend->gitpath == NULL)
2089
+ goto fail;
1262
2090
  }
1263
2091
 
1264
- backend->path = git_buf_detach(&path);
2092
+ if (repository->commondir) {
2093
+ backend->commonpath = setup_namespace(repository, repository->commondir);
2094
+
2095
+ if (backend->commonpath == NULL)
2096
+ goto fail;
2097
+ }
2098
+
2099
+ if (git_buf_joinpath(&gitpath, backend->commonpath, GIT_PACKEDREFS_FILE) < 0 ||
2100
+ git_sortedcache_new(
2101
+ &backend->refcache, offsetof(struct packref, name),
2102
+ NULL, NULL, packref_cmp, git_buf_cstr(&gitpath)) < 0)
2103
+ goto fail;
2104
+
2105
+ git_buf_dispose(&gitpath);
2106
+
2107
+ if (!git_repository__cvar(&t, backend->repo, GIT_CVAR_IGNORECASE) && t) {
2108
+ backend->iterator_flags |= GIT_ITERATOR_IGNORE_CASE;
2109
+ backend->direach_flags |= GIT_PATH_DIR_IGNORE_CASE;
2110
+ }
2111
+ if (!git_repository__cvar(&t, backend->repo, GIT_CVAR_PRECOMPOSE) && t) {
2112
+ backend->iterator_flags |= GIT_ITERATOR_PRECOMPOSE_UNICODE;
2113
+ backend->direach_flags |= GIT_PATH_DIR_PRECOMPOSE_UNICODE;
2114
+ }
2115
+ if ((!git_repository__cvar(&t, backend->repo, GIT_CVAR_FSYNCOBJECTFILES) && t) ||
2116
+ git_repository__fsync_gitdir)
2117
+ backend->fsync = 1;
2118
+ backend->iterator_flags |= GIT_ITERATOR_DESCEND_SYMLINKS;
1265
2119
 
1266
2120
  backend->parent.exists = &refdb_fs_backend__exists;
1267
2121
  backend->parent.lookup = &refdb_fs_backend__lookup;
1268
2122
  backend->parent.iterator = &refdb_fs_backend__iterator;
1269
2123
  backend->parent.write = &refdb_fs_backend__write;
1270
- backend->parent.delete = &refdb_fs_backend__delete;
2124
+ backend->parent.del = &refdb_fs_backend__delete;
1271
2125
  backend->parent.rename = &refdb_fs_backend__rename;
1272
2126
  backend->parent.compress = &refdb_fs_backend__compress;
2127
+ backend->parent.lock = &refdb_fs_backend__lock;
2128
+ backend->parent.unlock = &refdb_fs_backend__unlock;
2129
+ backend->parent.has_log = &refdb_reflog_fs__has_log;
2130
+ backend->parent.ensure_log = &refdb_reflog_fs__ensure_log;
1273
2131
  backend->parent.free = &refdb_fs_backend__free;
2132
+ backend->parent.reflog_read = &refdb_reflog_fs__read;
2133
+ backend->parent.reflog_write = &refdb_reflog_fs__write;
2134
+ backend->parent.reflog_rename = &refdb_reflog_fs__rename;
2135
+ backend->parent.reflog_delete = &refdb_reflog_fs__delete;
1274
2136
 
1275
2137
  *backend_out = (git_refdb_backend *)backend;
1276
2138
  return 0;
2139
+
2140
+ fail:
2141
+ git_buf_dispose(&gitpath);
2142
+ git__free(backend->gitpath);
2143
+ git__free(backend->commonpath);
2144
+ git__free(backend);
2145
+ return -1;
1277
2146
  }