rugged 0.17.0.b7 → 0.18.0.b1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (310) hide show
  1. data/LICENSE +1 -1
  2. data/README.md +88 -32
  3. data/ext/rugged/extconf.rb +4 -2
  4. data/ext/rugged/rugged.c +72 -10
  5. data/ext/rugged/rugged.h +14 -10
  6. data/ext/rugged/rugged_blob.c +8 -10
  7. data/ext/rugged/rugged_branch.c +11 -14
  8. data/ext/rugged/rugged_commit.c +31 -24
  9. data/ext/rugged/rugged_config.c +2 -2
  10. data/ext/rugged/rugged_index.c +133 -198
  11. data/ext/rugged/rugged_note.c +372 -0
  12. data/ext/rugged/rugged_object.c +50 -22
  13. data/ext/rugged/rugged_reference.c +122 -130
  14. data/ext/rugged/rugged_remote.c +72 -29
  15. data/ext/rugged/rugged_repo.c +402 -20
  16. data/ext/rugged/rugged_revwalk.c +7 -3
  17. data/ext/rugged/rugged_settings.c +110 -0
  18. data/ext/rugged/rugged_signature.c +23 -7
  19. data/ext/rugged/rugged_tag.c +32 -16
  20. data/ext/rugged/rugged_tree.c +44 -15
  21. data/lib/rugged.rb +1 -0
  22. data/lib/rugged/index.rb +8 -0
  23. data/lib/rugged/remote.rb +13 -0
  24. data/lib/rugged/repository.rb +3 -3
  25. data/lib/rugged/version.rb +1 -1
  26. data/test/blob_test.rb +13 -15
  27. data/test/branch_test.rb +32 -67
  28. data/test/commit_test.rb +50 -12
  29. data/test/config_test.rb +12 -11
  30. data/test/coverage/HEAD.json +1 -1
  31. data/test/coverage/cover.rb +40 -21
  32. data/test/errors_test.rb +34 -0
  33. data/test/fixtures/alternate/objects/14/6ae76773c91e3b1d00cf7a338ec55ae58297e2 +0 -0
  34. data/test/fixtures/alternate/objects/14/9c32d47e99d0a3572ff1e70a2e0051bbf347a9 +0 -0
  35. data/test/fixtures/alternate/objects/14/fb3108588f9421bf764041e5e3ac305eb6277f +0 -0
  36. data/test/fixtures/testrepo.git/logs/refs/notes/commits +1 -0
  37. data/test/fixtures/testrepo.git/objects/44/1034f860c1d5d90e4188d11ae0d325176869a8 +1 -0
  38. data/test/fixtures/testrepo.git/objects/60/d415052a33de2150bf68757f6461df4f563ae4 +0 -0
  39. data/test/fixtures/testrepo.git/objects/68/8a8f4ef7496901d15322972f96e212a9e466cc +1 -0
  40. data/test/fixtures/testrepo.git/objects/94/eca2de348d5f672faf56b0decafa5937e3235e +0 -0
  41. data/test/fixtures/testrepo.git/objects/9b/7384fe1676186192842f5d3e129457b62db9e3 +0 -0
  42. data/test/fixtures/testrepo.git/objects/b7/4713326bc972cc15751ed504dca6f6f3b91f7a +3 -0
  43. data/test/fixtures/testrepo.git/refs/notes/commits +1 -0
  44. data/test/index_test.rb +65 -69
  45. data/test/lib_test.rb +76 -11
  46. data/test/note_test.rb +158 -0
  47. data/test/object_test.rb +8 -11
  48. data/test/reference_test.rb +77 -85
  49. data/test/remote_test.rb +86 -8
  50. data/test/repo_pack_test.rb +9 -7
  51. data/test/repo_reset_test.rb +80 -0
  52. data/test/repo_test.rb +176 -53
  53. data/test/tag_test.rb +44 -7
  54. data/test/test_helper.rb +63 -35
  55. data/test/tree_test.rb +34 -13
  56. data/test/walker_test.rb +14 -14
  57. data/vendor/libgit2/Makefile.embed +1 -1
  58. data/vendor/libgit2/deps/http-parser/http_parser.c +974 -578
  59. data/vendor/libgit2/deps/http-parser/http_parser.h +106 -70
  60. data/vendor/libgit2/deps/regex/regcomp.c +7 -6
  61. data/vendor/libgit2/deps/regex/regex_internal.c +1 -1
  62. data/vendor/libgit2/deps/regex/regex_internal.h +12 -3
  63. data/vendor/libgit2/deps/regex/regexec.c +5 -5
  64. data/vendor/libgit2/include/git2.h +5 -1
  65. data/vendor/libgit2/include/git2/attr.h +4 -2
  66. data/vendor/libgit2/include/git2/blob.h +39 -12
  67. data/vendor/libgit2/include/git2/branch.h +123 -35
  68. data/vendor/libgit2/include/git2/checkout.h +206 -48
  69. data/vendor/libgit2/include/git2/clone.h +72 -27
  70. data/vendor/libgit2/include/git2/commit.h +20 -17
  71. data/vendor/libgit2/include/git2/common.h +67 -1
  72. data/vendor/libgit2/include/git2/config.h +81 -60
  73. data/vendor/libgit2/include/git2/cred_helpers.h +53 -0
  74. data/vendor/libgit2/include/git2/diff.h +459 -150
  75. data/vendor/libgit2/include/git2/errors.h +9 -1
  76. data/vendor/libgit2/include/git2/graph.h +41 -0
  77. data/vendor/libgit2/include/git2/ignore.h +7 -6
  78. data/vendor/libgit2/include/git2/index.h +323 -97
  79. data/vendor/libgit2/include/git2/indexer.h +27 -59
  80. data/vendor/libgit2/include/git2/inttypes.h +4 -0
  81. data/vendor/libgit2/include/git2/merge.h +13 -3
  82. data/vendor/libgit2/include/git2/message.h +14 -8
  83. data/vendor/libgit2/include/git2/net.h +9 -7
  84. data/vendor/libgit2/include/git2/notes.h +88 -29
  85. data/vendor/libgit2/include/git2/object.h +16 -6
  86. data/vendor/libgit2/include/git2/odb.h +80 -17
  87. data/vendor/libgit2/include/git2/odb_backend.h +47 -11
  88. data/vendor/libgit2/include/git2/oid.h +26 -17
  89. data/vendor/libgit2/include/git2/pack.h +62 -8
  90. data/vendor/libgit2/include/git2/push.h +131 -0
  91. data/vendor/libgit2/include/git2/refdb.h +103 -0
  92. data/vendor/libgit2/include/git2/refdb_backend.h +109 -0
  93. data/vendor/libgit2/include/git2/reflog.h +30 -21
  94. data/vendor/libgit2/include/git2/refs.h +215 -193
  95. data/vendor/libgit2/include/git2/refspec.h +22 -2
  96. data/vendor/libgit2/include/git2/remote.h +158 -37
  97. data/vendor/libgit2/include/git2/repository.h +150 -31
  98. data/vendor/libgit2/include/git2/reset.h +43 -9
  99. data/vendor/libgit2/include/git2/revparse.h +48 -4
  100. data/vendor/libgit2/include/git2/revwalk.h +25 -10
  101. data/vendor/libgit2/include/git2/signature.h +20 -12
  102. data/vendor/libgit2/include/git2/stash.h +121 -0
  103. data/vendor/libgit2/include/git2/status.h +122 -53
  104. data/vendor/libgit2/include/git2/strarray.h +17 -11
  105. data/vendor/libgit2/include/git2/submodule.h +42 -7
  106. data/vendor/libgit2/include/git2/tag.h +72 -59
  107. data/vendor/libgit2/include/git2/threads.h +4 -2
  108. data/vendor/libgit2/include/git2/trace.h +68 -0
  109. data/vendor/libgit2/include/git2/transport.h +328 -0
  110. data/vendor/libgit2/include/git2/tree.h +149 -120
  111. data/vendor/libgit2/include/git2/types.h +13 -12
  112. data/vendor/libgit2/include/git2/version.h +3 -3
  113. data/vendor/libgit2/src/amiga/map.c +2 -2
  114. data/vendor/libgit2/src/attr.c +58 -48
  115. data/vendor/libgit2/src/attr.h +4 -18
  116. data/vendor/libgit2/src/attr_file.c +30 -6
  117. data/vendor/libgit2/src/attr_file.h +6 -8
  118. data/vendor/libgit2/src/attrcache.h +24 -0
  119. data/vendor/libgit2/src/blob.c +30 -7
  120. data/vendor/libgit2/src/blob.h +1 -1
  121. data/vendor/libgit2/src/branch.c +361 -68
  122. data/vendor/libgit2/src/branch.h +17 -0
  123. data/vendor/libgit2/src/bswap.h +1 -1
  124. data/vendor/libgit2/src/buf_text.c +291 -0
  125. data/vendor/libgit2/src/buf_text.h +122 -0
  126. data/vendor/libgit2/src/buffer.c +27 -101
  127. data/vendor/libgit2/src/buffer.h +54 -39
  128. data/vendor/libgit2/src/cache.c +15 -6
  129. data/vendor/libgit2/src/cache.h +1 -1
  130. data/vendor/libgit2/src/cc-compat.h +3 -1
  131. data/vendor/libgit2/src/checkout.c +1165 -222
  132. data/vendor/libgit2/src/checkout.h +24 -0
  133. data/vendor/libgit2/src/clone.c +171 -86
  134. data/vendor/libgit2/src/commit.c +44 -45
  135. data/vendor/libgit2/src/commit.h +3 -3
  136. data/vendor/libgit2/src/commit_list.c +194 -0
  137. data/vendor/libgit2/src/commit_list.h +49 -0
  138. data/vendor/libgit2/src/common.h +44 -10
  139. data/vendor/libgit2/src/compress.c +1 -1
  140. data/vendor/libgit2/src/compress.h +1 -1
  141. data/vendor/libgit2/src/config.c +211 -124
  142. data/vendor/libgit2/src/config.h +23 -4
  143. data/vendor/libgit2/src/config_cache.c +2 -2
  144. data/vendor/libgit2/src/config_file.c +129 -53
  145. data/vendor/libgit2/src/config_file.h +10 -8
  146. data/vendor/libgit2/src/crlf.c +66 -67
  147. data/vendor/libgit2/src/date.c +12 -12
  148. data/vendor/libgit2/src/delta-apply.c +14 -1
  149. data/vendor/libgit2/src/delta-apply.h +18 -1
  150. data/vendor/libgit2/src/delta.c +40 -107
  151. data/vendor/libgit2/src/delta.h +19 -17
  152. data/vendor/libgit2/src/diff.c +347 -496
  153. data/vendor/libgit2/src/diff.h +27 -1
  154. data/vendor/libgit2/src/diff_output.c +564 -249
  155. data/vendor/libgit2/src/diff_output.h +15 -8
  156. data/vendor/libgit2/src/diff_tform.c +687 -0
  157. data/vendor/libgit2/src/errors.c +27 -36
  158. data/vendor/libgit2/src/fetch.c +13 -351
  159. data/vendor/libgit2/src/fetch.h +13 -3
  160. data/vendor/libgit2/src/fetchhead.c +295 -0
  161. data/vendor/libgit2/src/fetchhead.h +34 -0
  162. data/vendor/libgit2/src/filebuf.c +42 -15
  163. data/vendor/libgit2/src/filebuf.h +4 -2
  164. data/vendor/libgit2/src/fileops.c +466 -113
  165. data/vendor/libgit2/src/fileops.h +154 -28
  166. data/vendor/libgit2/src/filter.c +3 -75
  167. data/vendor/libgit2/src/filter.h +1 -29
  168. data/vendor/libgit2/src/fnmatch.c +1 -1
  169. data/vendor/libgit2/src/fnmatch.h +1 -1
  170. data/vendor/libgit2/src/global.c +54 -10
  171. data/vendor/libgit2/src/global.h +10 -1
  172. data/vendor/libgit2/src/graph.c +178 -0
  173. data/vendor/libgit2/src/hash.c +25 -52
  174. data/vendor/libgit2/src/hash.h +21 -9
  175. data/vendor/libgit2/src/{sha1/sha1.c → hash/hash_generic.c} +20 -12
  176. data/vendor/libgit2/src/hash/hash_generic.h +24 -0
  177. data/vendor/libgit2/src/hash/hash_openssl.h +45 -0
  178. data/vendor/libgit2/src/hash/hash_win32.c +291 -0
  179. data/vendor/libgit2/src/hash/hash_win32.h +140 -0
  180. data/vendor/libgit2/src/hashsig.c +368 -0
  181. data/vendor/libgit2/src/hashsig.h +72 -0
  182. data/vendor/libgit2/src/ignore.c +22 -15
  183. data/vendor/libgit2/src/ignore.h +6 -1
  184. data/vendor/libgit2/src/index.c +770 -171
  185. data/vendor/libgit2/src/index.h +13 -5
  186. data/vendor/libgit2/src/indexer.c +286 -431
  187. data/vendor/libgit2/src/iterator.c +854 -466
  188. data/vendor/libgit2/src/iterator.h +134 -109
  189. data/vendor/libgit2/src/map.h +1 -1
  190. data/vendor/libgit2/src/merge.c +296 -0
  191. data/vendor/libgit2/src/merge.h +22 -0
  192. data/vendor/libgit2/src/message.c +1 -1
  193. data/vendor/libgit2/src/message.h +1 -1
  194. data/vendor/libgit2/src/mwindow.c +35 -30
  195. data/vendor/libgit2/src/mwindow.h +2 -2
  196. data/vendor/libgit2/src/netops.c +162 -98
  197. data/vendor/libgit2/src/netops.h +50 -15
  198. data/vendor/libgit2/src/notes.c +109 -58
  199. data/vendor/libgit2/src/notes.h +2 -1
  200. data/vendor/libgit2/src/object.c +46 -57
  201. data/vendor/libgit2/src/object.h +1 -8
  202. data/vendor/libgit2/src/odb.c +151 -40
  203. data/vendor/libgit2/src/odb.h +5 -1
  204. data/vendor/libgit2/src/odb_loose.c +4 -5
  205. data/vendor/libgit2/src/odb_pack.c +122 -80
  206. data/vendor/libgit2/src/offmap.h +65 -0
  207. data/vendor/libgit2/src/oid.c +12 -4
  208. data/vendor/libgit2/src/oidmap.h +1 -1
  209. data/vendor/libgit2/src/pack-objects.c +88 -61
  210. data/vendor/libgit2/src/pack-objects.h +8 -8
  211. data/vendor/libgit2/src/pack.c +293 -28
  212. data/vendor/libgit2/src/pack.h +49 -4
  213. data/vendor/libgit2/src/path.c +103 -14
  214. data/vendor/libgit2/src/path.h +23 -7
  215. data/vendor/libgit2/src/pathspec.c +168 -0
  216. data/vendor/libgit2/src/pathspec.h +40 -0
  217. data/vendor/libgit2/src/pool.c +29 -4
  218. data/vendor/libgit2/src/pool.h +8 -1
  219. data/vendor/libgit2/src/posix.c +26 -27
  220. data/vendor/libgit2/src/posix.h +2 -3
  221. data/vendor/libgit2/src/pqueue.c +23 -1
  222. data/vendor/libgit2/src/pqueue.h +23 -1
  223. data/vendor/libgit2/src/push.c +653 -0
  224. data/vendor/libgit2/src/push.h +51 -0
  225. data/vendor/libgit2/src/refdb.c +185 -0
  226. data/vendor/libgit2/src/refdb.h +46 -0
  227. data/vendor/libgit2/src/refdb_fs.c +1024 -0
  228. data/vendor/libgit2/src/refdb_fs.h +15 -0
  229. data/vendor/libgit2/src/reflog.c +77 -45
  230. data/vendor/libgit2/src/reflog.h +1 -3
  231. data/vendor/libgit2/src/refs.c +366 -1326
  232. data/vendor/libgit2/src/refs.h +22 -13
  233. data/vendor/libgit2/src/refspec.c +46 -7
  234. data/vendor/libgit2/src/refspec.h +11 -1
  235. data/vendor/libgit2/src/remote.c +758 -120
  236. data/vendor/libgit2/src/remote.h +10 -5
  237. data/vendor/libgit2/src/repo_template.h +6 -6
  238. data/vendor/libgit2/src/repository.c +315 -96
  239. data/vendor/libgit2/src/repository.h +5 -3
  240. data/vendor/libgit2/src/reset.c +99 -81
  241. data/vendor/libgit2/src/revparse.c +157 -84
  242. data/vendor/libgit2/src/revwalk.c +68 -470
  243. data/vendor/libgit2/src/revwalk.h +44 -0
  244. data/vendor/libgit2/src/sha1_lookup.c +1 -1
  245. data/vendor/libgit2/src/sha1_lookup.h +1 -1
  246. data/vendor/libgit2/src/signature.c +68 -200
  247. data/vendor/libgit2/src/signature.h +1 -1
  248. data/vendor/libgit2/src/stash.c +663 -0
  249. data/vendor/libgit2/src/status.c +101 -79
  250. data/vendor/libgit2/src/strmap.h +1 -1
  251. data/vendor/libgit2/src/submodule.c +67 -51
  252. data/vendor/libgit2/src/submodule.h +1 -1
  253. data/vendor/libgit2/src/tag.c +35 -29
  254. data/vendor/libgit2/src/tag.h +1 -1
  255. data/vendor/libgit2/src/thread-utils.c +1 -1
  256. data/vendor/libgit2/src/thread-utils.h +2 -2
  257. data/vendor/libgit2/src/trace.c +39 -0
  258. data/vendor/libgit2/src/trace.h +56 -0
  259. data/vendor/libgit2/src/transport.c +81 -34
  260. data/vendor/libgit2/src/transports/cred.c +60 -0
  261. data/vendor/libgit2/src/transports/cred_helpers.c +49 -0
  262. data/vendor/libgit2/src/transports/git.c +234 -127
  263. data/vendor/libgit2/src/transports/http.c +761 -433
  264. data/vendor/libgit2/src/transports/local.c +460 -64
  265. data/vendor/libgit2/src/transports/smart.c +345 -0
  266. data/vendor/libgit2/src/transports/smart.h +179 -0
  267. data/vendor/libgit2/src/{pkt.c → transports/smart_pkt.c} +131 -12
  268. data/vendor/libgit2/src/transports/smart_protocol.c +856 -0
  269. data/vendor/libgit2/src/transports/winhttp.c +1136 -0
  270. data/vendor/libgit2/src/tree-cache.c +2 -2
  271. data/vendor/libgit2/src/tree-cache.h +1 -1
  272. data/vendor/libgit2/src/tree.c +239 -166
  273. data/vendor/libgit2/src/tree.h +11 -2
  274. data/vendor/libgit2/src/tsort.c +39 -23
  275. data/vendor/libgit2/src/unix/map.c +1 -1
  276. data/vendor/libgit2/src/unix/posix.h +12 -2
  277. data/vendor/libgit2/src/unix/realpath.c +30 -0
  278. data/vendor/libgit2/src/util.c +250 -13
  279. data/vendor/libgit2/src/util.h +71 -14
  280. data/vendor/libgit2/src/vector.c +123 -60
  281. data/vendor/libgit2/src/vector.h +24 -22
  282. data/vendor/libgit2/src/win32/dir.c +1 -1
  283. data/vendor/libgit2/src/win32/dir.h +1 -1
  284. data/vendor/libgit2/src/win32/error.c +77 -0
  285. data/vendor/libgit2/src/win32/error.h +13 -0
  286. data/vendor/libgit2/src/win32/findfile.c +143 -54
  287. data/vendor/libgit2/src/win32/findfile.h +10 -6
  288. data/vendor/libgit2/src/win32/map.c +1 -1
  289. data/vendor/libgit2/src/win32/mingw-compat.h +1 -1
  290. data/vendor/libgit2/src/win32/msvc-compat.h +10 -1
  291. data/vendor/libgit2/src/win32/posix.h +10 -1
  292. data/vendor/libgit2/src/win32/posix_w32.c +132 -63
  293. data/vendor/libgit2/src/win32/precompiled.c +1 -1
  294. data/vendor/libgit2/src/win32/pthread.c +1 -1
  295. data/vendor/libgit2/src/win32/pthread.h +1 -1
  296. data/vendor/libgit2/src/win32/utf-conv.c +5 -5
  297. data/vendor/libgit2/src/win32/utf-conv.h +3 -3
  298. data/vendor/libgit2/src/win32/version.h +20 -0
  299. metadata +308 -252
  300. data/test/fixtures/testrepo.git/objects/4b/825dc642cb6eb9a060e54bf8d69288fbee4904 +0 -0
  301. data/test/fixtures/testrepo.git/objects/7f/043268ea43ce18e3540acaabf9e090c91965b0 +0 -0
  302. data/test/fixtures/testrepo.git/objects/a3/e05719b428a2d0ed7a55c4ce53dcc5768c6d5e +0 -0
  303. data/test/index_test.rb~ +0 -218
  304. data/vendor/libgit2/src/pkt.h +0 -91
  305. data/vendor/libgit2/src/ppc/sha1.c +0 -70
  306. data/vendor/libgit2/src/ppc/sha1.h +0 -26
  307. data/vendor/libgit2/src/protocol.c +0 -110
  308. data/vendor/libgit2/src/protocol.h +0 -21
  309. data/vendor/libgit2/src/sha1.h +0 -33
  310. data/vendor/libgit2/src/transport.h +0 -148
@@ -0,0 +1,51 @@
1
+ /*
2
+ * Copyright (C) the libgit2 contributors. All rights reserved.
3
+ *
4
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
5
+ * a Linking Exception. For full terms see the included COPYING file.
6
+ */
7
+ #ifndef INCLUDE_push_h__
8
+ #define INCLUDE_push_h__
9
+
10
+ #include "git2.h"
11
+
12
+ typedef struct push_spec {
13
+ char *lref;
14
+ char *rref;
15
+
16
+ git_oid loid;
17
+ git_oid roid;
18
+
19
+ bool force;
20
+ } push_spec;
21
+
22
+ typedef struct push_status {
23
+ bool ok;
24
+
25
+ char *ref;
26
+ char *msg;
27
+ } push_status;
28
+
29
+ struct git_push {
30
+ git_repository *repo;
31
+ git_packbuilder *pb;
32
+ git_remote *remote;
33
+ git_vector specs;
34
+ bool report_status;
35
+
36
+ /* report-status */
37
+ bool unpack_ok;
38
+ git_vector status;
39
+
40
+ /* options */
41
+ unsigned pb_parallelism;
42
+ };
43
+
44
+ /**
45
+ * Free the given push status object
46
+ *
47
+ * @param status The push status object
48
+ */
49
+ void git_push_status_free(push_status *status);
50
+
51
+ #endif
@@ -0,0 +1,185 @@
1
+ /*
2
+ * Copyright (C) the libgit2 contributors. All rights reserved.
3
+ *
4
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
5
+ * a Linking Exception. For full terms see the included COPYING file.
6
+ */
7
+
8
+ #include "common.h"
9
+ #include "posix.h"
10
+ #include "git2/object.h"
11
+ #include "git2/refs.h"
12
+ #include "git2/refdb.h"
13
+ #include "hash.h"
14
+ #include "refdb.h"
15
+ #include "refs.h"
16
+
17
+ #include "git2/refdb_backend.h"
18
+
19
+ int git_refdb_new(git_refdb **out, git_repository *repo)
20
+ {
21
+ git_refdb *db;
22
+
23
+ assert(out && repo);
24
+
25
+ db = git__calloc(1, sizeof(*db));
26
+ GITERR_CHECK_ALLOC(db);
27
+
28
+ db->repo = repo;
29
+
30
+ *out = db;
31
+ GIT_REFCOUNT_INC(db);
32
+ return 0;
33
+ }
34
+
35
+ int git_refdb_open(git_refdb **out, git_repository *repo)
36
+ {
37
+ git_refdb *db;
38
+ git_refdb_backend *dir;
39
+
40
+ assert(out && repo);
41
+
42
+ *out = NULL;
43
+
44
+ if (git_refdb_new(&db, repo) < 0)
45
+ return -1;
46
+
47
+ /* Add the default (filesystem) backend */
48
+ if (git_refdb_backend_fs(&dir, repo, db) < 0) {
49
+ git_refdb_free(db);
50
+ return -1;
51
+ }
52
+
53
+ db->repo = repo;
54
+ db->backend = dir;
55
+
56
+ *out = db;
57
+ return 0;
58
+ }
59
+
60
+ int git_refdb_set_backend(git_refdb *db, git_refdb_backend *backend)
61
+ {
62
+ if (db->backend) {
63
+ if(db->backend->free)
64
+ db->backend->free(db->backend);
65
+ else
66
+ git__free(db->backend);
67
+ }
68
+
69
+ db->backend = backend;
70
+
71
+ return 0;
72
+ }
73
+
74
+ int git_refdb_compress(git_refdb *db)
75
+ {
76
+ assert(db);
77
+
78
+ if (db->backend->compress) {
79
+ return db->backend->compress(db->backend);
80
+ }
81
+
82
+ return 0;
83
+ }
84
+
85
+ static void refdb_free(git_refdb *db)
86
+ {
87
+ if (db->backend) {
88
+ if(db->backend->free)
89
+ db->backend->free(db->backend);
90
+ else
91
+ git__free(db->backend);
92
+ }
93
+
94
+ git__free(db);
95
+ }
96
+
97
+ void git_refdb_free(git_refdb *db)
98
+ {
99
+ if (db == NULL)
100
+ return;
101
+
102
+ GIT_REFCOUNT_DEC(db, refdb_free);
103
+ }
104
+
105
+ int git_refdb_exists(int *exists, git_refdb *refdb, const char *ref_name)
106
+ {
107
+ assert(exists && refdb && refdb->backend);
108
+
109
+ return refdb->backend->exists(exists, refdb->backend, ref_name);
110
+ }
111
+
112
+ int git_refdb_lookup(git_reference **out, git_refdb *db, const char *ref_name)
113
+ {
114
+ assert(db && db->backend && ref_name);
115
+
116
+ return db->backend->lookup(out, db->backend, ref_name);
117
+ }
118
+
119
+ int git_refdb_foreach(
120
+ git_refdb *db,
121
+ unsigned int list_flags,
122
+ git_reference_foreach_cb callback,
123
+ void *payload)
124
+ {
125
+ assert(db && db->backend);
126
+
127
+ return db->backend->foreach(db->backend, list_flags, callback, payload);
128
+ }
129
+
130
+ struct glob_cb_data {
131
+ const char *glob;
132
+ git_reference_foreach_cb callback;
133
+ void *payload;
134
+ };
135
+
136
+ static int fromglob_cb(const char *reference_name, void *payload)
137
+ {
138
+ struct glob_cb_data *data = (struct glob_cb_data *)payload;
139
+
140
+ if (!p_fnmatch(data->glob, reference_name, 0))
141
+ return data->callback(reference_name, data->payload);
142
+
143
+ return 0;
144
+ }
145
+
146
+ int git_refdb_foreach_glob(
147
+ git_refdb *db,
148
+ const char *glob,
149
+ unsigned int list_flags,
150
+ git_reference_foreach_cb callback,
151
+ void *payload)
152
+ {
153
+ int error;
154
+ struct glob_cb_data data;
155
+
156
+ assert(db && db->backend && glob && callback);
157
+
158
+ if(db->backend->foreach_glob != NULL)
159
+ error = db->backend->foreach_glob(db->backend,
160
+ glob, list_flags, callback, payload);
161
+ else {
162
+ data.glob = glob;
163
+ data.callback = callback;
164
+ data.payload = payload;
165
+
166
+ error = db->backend->foreach(db->backend,
167
+ list_flags, fromglob_cb, &data);
168
+ }
169
+
170
+ return error;
171
+ }
172
+
173
+ int git_refdb_write(git_refdb *db, const git_reference *ref)
174
+ {
175
+ assert(db && db->backend);
176
+
177
+ return db->backend->write(db->backend, ref);
178
+ }
179
+
180
+ int git_refdb_delete(struct git_refdb *db, const git_reference *ref)
181
+ {
182
+ assert(db && db->backend);
183
+
184
+ return db->backend->delete(db->backend, ref);
185
+ }
@@ -0,0 +1,46 @@
1
+ /*
2
+ * Copyright (C) the libgit2 contributors. All rights reserved.
3
+ *
4
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
5
+ * a Linking Exception. For full terms see the included COPYING file.
6
+ */
7
+ #ifndef INCLUDE_refdb_h__
8
+ #define INCLUDE_refdb_h__
9
+
10
+ #include "git2/refdb.h"
11
+ #include "repository.h"
12
+
13
+ struct git_refdb {
14
+ git_refcount rc;
15
+ git_repository *repo;
16
+ git_refdb_backend *backend;
17
+ };
18
+
19
+ int git_refdb_exists(
20
+ int *exists,
21
+ git_refdb *refdb,
22
+ const char *ref_name);
23
+
24
+ int git_refdb_lookup(
25
+ git_reference **out,
26
+ git_refdb *refdb,
27
+ const char *ref_name);
28
+
29
+ int git_refdb_foreach(
30
+ git_refdb *refdb,
31
+ unsigned int list_flags,
32
+ git_reference_foreach_cb callback,
33
+ void *payload);
34
+
35
+ int git_refdb_foreach_glob(
36
+ git_refdb *refdb,
37
+ const char *glob,
38
+ unsigned int list_flags,
39
+ git_reference_foreach_cb callback,
40
+ void *payload);
41
+
42
+ int git_refdb_write(git_refdb *refdb, const git_reference *ref);
43
+
44
+ int git_refdb_delete(struct git_refdb *refdb, const git_reference *ref);
45
+
46
+ #endif
@@ -0,0 +1,1024 @@
1
+ /*
2
+ * Copyright (C) the libgit2 contributors. All rights reserved.
3
+ *
4
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
5
+ * a Linking Exception. For full terms see the included COPYING file.
6
+ */
7
+
8
+ #include "refs.h"
9
+ #include "hash.h"
10
+ #include "repository.h"
11
+ #include "fileops.h"
12
+ #include "pack.h"
13
+ #include "reflog.h"
14
+ #include "config.h"
15
+ #include "refdb.h"
16
+ #include "refdb_fs.h"
17
+
18
+ #include <git2/tag.h>
19
+ #include <git2/object.h>
20
+ #include <git2/refdb.h>
21
+ #include <git2/refdb_backend.h>
22
+
23
+ GIT__USE_STRMAP;
24
+
25
+ #define DEFAULT_NESTING_LEVEL 5
26
+ #define MAX_NESTING_LEVEL 10
27
+
28
+ enum {
29
+ GIT_PACKREF_HAS_PEEL = 1,
30
+ GIT_PACKREF_WAS_LOOSE = 2
31
+ };
32
+
33
+ struct packref {
34
+ git_oid oid;
35
+ git_oid peel;
36
+ char flags;
37
+ char name[GIT_FLEX_ARRAY];
38
+ };
39
+
40
+ typedef struct refdb_fs_backend {
41
+ git_refdb_backend parent;
42
+
43
+ git_repository *repo;
44
+ const char *path;
45
+ git_refdb *refdb;
46
+
47
+ git_refcache refcache;
48
+ } refdb_fs_backend;
49
+
50
+ static int reference_read(
51
+ git_buf *file_content,
52
+ time_t *mtime,
53
+ const char *repo_path,
54
+ const char *ref_name,
55
+ int *updated)
56
+ {
57
+ git_buf path = GIT_BUF_INIT;
58
+ int result;
59
+
60
+ assert(file_content && repo_path && ref_name);
61
+
62
+ /* Determine the full path of the file */
63
+ if (git_buf_joinpath(&path, repo_path, ref_name) < 0)
64
+ return -1;
65
+
66
+ result = git_futils_readbuffer_updated(file_content, path.ptr, mtime, NULL, updated);
67
+ git_buf_free(&path);
68
+
69
+ return result;
70
+ }
71
+
72
+ static int packed_parse_oid(
73
+ struct packref **ref_out,
74
+ const char **buffer_out,
75
+ const char *buffer_end)
76
+ {
77
+ struct packref *ref = NULL;
78
+
79
+ const char *buffer = *buffer_out;
80
+ const char *refname_begin, *refname_end;
81
+
82
+ size_t refname_len;
83
+ git_oid id;
84
+
85
+ refname_begin = (buffer + GIT_OID_HEXSZ + 1);
86
+ if (refname_begin >= buffer_end || refname_begin[-1] != ' ')
87
+ goto corrupt;
88
+
89
+ /* Is this a valid object id? */
90
+ if (git_oid_fromstr(&id, buffer) < 0)
91
+ goto corrupt;
92
+
93
+ refname_end = memchr(refname_begin, '\n', buffer_end - refname_begin);
94
+ if (refname_end == NULL)
95
+ refname_end = buffer_end;
96
+
97
+ if (refname_end[-1] == '\r')
98
+ refname_end--;
99
+
100
+ refname_len = refname_end - refname_begin;
101
+
102
+ ref = git__malloc(sizeof(struct packref) + refname_len + 1);
103
+ GITERR_CHECK_ALLOC(ref);
104
+
105
+ memcpy(ref->name, refname_begin, refname_len);
106
+ ref->name[refname_len] = 0;
107
+
108
+ git_oid_cpy(&ref->oid, &id);
109
+
110
+ ref->flags = 0;
111
+
112
+ *ref_out = ref;
113
+ *buffer_out = refname_end + 1;
114
+
115
+ return 0;
116
+
117
+ corrupt:
118
+ git__free(ref);
119
+ giterr_set(GITERR_REFERENCE, "The packed references file is corrupted");
120
+ return -1;
121
+ }
122
+
123
+ static int packed_parse_peel(
124
+ struct packref *tag_ref,
125
+ const char **buffer_out,
126
+ const char *buffer_end)
127
+ {
128
+ const char *buffer = *buffer_out + 1;
129
+
130
+ assert(buffer[-1] == '^');
131
+
132
+ /* Ensure it's not the first entry of the file */
133
+ if (tag_ref == NULL)
134
+ goto corrupt;
135
+
136
+ /* Ensure reference is a tag */
137
+ if (git__prefixcmp(tag_ref->name, GIT_REFS_TAGS_DIR) != 0)
138
+ goto corrupt;
139
+
140
+ if (buffer + GIT_OID_HEXSZ > buffer_end)
141
+ goto corrupt;
142
+
143
+ /* Is this a valid object id? */
144
+ if (git_oid_fromstr(&tag_ref->peel, buffer) < 0)
145
+ goto corrupt;
146
+
147
+ buffer = buffer + GIT_OID_HEXSZ;
148
+ if (*buffer == '\r')
149
+ buffer++;
150
+
151
+ if (buffer != buffer_end) {
152
+ if (*buffer == '\n')
153
+ buffer++;
154
+ else
155
+ goto corrupt;
156
+ }
157
+
158
+ *buffer_out = buffer;
159
+ return 0;
160
+
161
+ corrupt:
162
+ giterr_set(GITERR_REFERENCE, "The packed references file is corrupted");
163
+ return -1;
164
+ }
165
+
166
+ static int packed_load(refdb_fs_backend *backend)
167
+ {
168
+ int result, updated;
169
+ git_buf packfile = GIT_BUF_INIT;
170
+ const char *buffer_start, *buffer_end;
171
+ git_refcache *ref_cache = &backend->refcache;
172
+
173
+ /* First we make sure we have allocated the hash table */
174
+ if (ref_cache->packfile == NULL) {
175
+ ref_cache->packfile = git_strmap_alloc();
176
+ GITERR_CHECK_ALLOC(ref_cache->packfile);
177
+ }
178
+
179
+ result = reference_read(&packfile, &ref_cache->packfile_time,
180
+ backend->path, GIT_PACKEDREFS_FILE, &updated);
181
+
182
+ /*
183
+ * If we couldn't find the file, we need to clear the table and
184
+ * return. On any other error, we return that error. If everything
185
+ * went fine and the file wasn't updated, then there's nothing new
186
+ * for us here, so just return. Anything else means we need to
187
+ * refresh the packed refs.
188
+ */
189
+ if (result == GIT_ENOTFOUND) {
190
+ git_strmap_clear(ref_cache->packfile);
191
+ return 0;
192
+ }
193
+
194
+ if (result < 0)
195
+ return -1;
196
+
197
+ if (!updated)
198
+ return 0;
199
+
200
+ /*
201
+ * At this point, we want to refresh the packed refs. We already
202
+ * have the contents in our buffer.
203
+ */
204
+ git_strmap_clear(ref_cache->packfile);
205
+
206
+ buffer_start = (const char *)packfile.ptr;
207
+ buffer_end = (const char *)(buffer_start) + packfile.size;
208
+
209
+ while (buffer_start < buffer_end && buffer_start[0] == '#') {
210
+ buffer_start = strchr(buffer_start, '\n');
211
+ if (buffer_start == NULL)
212
+ goto parse_failed;
213
+
214
+ buffer_start++;
215
+ }
216
+
217
+ while (buffer_start < buffer_end) {
218
+ int err;
219
+ struct packref *ref = NULL;
220
+
221
+ if (packed_parse_oid(&ref, &buffer_start, buffer_end) < 0)
222
+ goto parse_failed;
223
+
224
+ if (buffer_start[0] == '^') {
225
+ if (packed_parse_peel(ref, &buffer_start, buffer_end) < 0)
226
+ goto parse_failed;
227
+ }
228
+
229
+ git_strmap_insert(ref_cache->packfile, ref->name, ref, err);
230
+ if (err < 0)
231
+ goto parse_failed;
232
+ }
233
+
234
+ git_buf_free(&packfile);
235
+ return 0;
236
+
237
+ parse_failed:
238
+ git_strmap_free(ref_cache->packfile);
239
+ ref_cache->packfile = NULL;
240
+ git_buf_free(&packfile);
241
+ return -1;
242
+ }
243
+
244
+ static int loose_parse_oid(git_oid *oid, git_buf *file_content)
245
+ {
246
+ size_t len;
247
+ const char *str;
248
+
249
+ len = git_buf_len(file_content);
250
+ if (len < GIT_OID_HEXSZ)
251
+ goto corrupted;
252
+
253
+ /* str is guranteed to be zero-terminated */
254
+ str = git_buf_cstr(file_content);
255
+
256
+ /* we need to get 40 OID characters from the file */
257
+ if (git_oid_fromstr(oid, git_buf_cstr(file_content)) < 0)
258
+ goto corrupted;
259
+
260
+ /* If the file is longer than 40 chars, the 41st must be a space */
261
+ str += GIT_OID_HEXSZ;
262
+ if (*str == '\0' || git__isspace(*str))
263
+ return 0;
264
+
265
+ corrupted:
266
+ giterr_set(GITERR_REFERENCE, "Corrupted loose reference file");
267
+ return -1;
268
+ }
269
+
270
+ static int loose_lookup_to_packfile(
271
+ struct packref **ref_out,
272
+ refdb_fs_backend *backend,
273
+ const char *name)
274
+ {
275
+ git_buf ref_file = GIT_BUF_INIT;
276
+ struct packref *ref = NULL;
277
+ size_t name_len;
278
+
279
+ *ref_out = NULL;
280
+
281
+ if (reference_read(&ref_file, NULL, backend->path, name, NULL) < 0)
282
+ return -1;
283
+
284
+ git_buf_rtrim(&ref_file);
285
+
286
+ name_len = strlen(name);
287
+ ref = git__malloc(sizeof(struct packref) + name_len + 1);
288
+ GITERR_CHECK_ALLOC(ref);
289
+
290
+ memcpy(ref->name, name, name_len);
291
+ ref->name[name_len] = 0;
292
+
293
+ if (loose_parse_oid(&ref->oid, &ref_file) < 0) {
294
+ git_buf_free(&ref_file);
295
+ git__free(ref);
296
+ return -1;
297
+ }
298
+
299
+ ref->flags = GIT_PACKREF_WAS_LOOSE;
300
+
301
+ *ref_out = ref;
302
+ git_buf_free(&ref_file);
303
+ return 0;
304
+ }
305
+
306
+
307
+ static int _dirent_loose_load(void *data, git_buf *full_path)
308
+ {
309
+ refdb_fs_backend *backend = (refdb_fs_backend *)data;
310
+ void *old_ref = NULL;
311
+ struct packref *ref;
312
+ const char *file_path;
313
+ int err;
314
+
315
+ if (git_path_isdir(full_path->ptr) == true)
316
+ return git_path_direach(full_path, _dirent_loose_load, backend);
317
+
318
+ file_path = full_path->ptr + strlen(backend->path);
319
+
320
+ if (loose_lookup_to_packfile(&ref, backend, file_path) < 0)
321
+ return -1;
322
+
323
+ git_strmap_insert2(
324
+ backend->refcache.packfile, ref->name, ref, old_ref, err);
325
+ if (err < 0) {
326
+ git__free(ref);
327
+ return -1;
328
+ }
329
+
330
+ git__free(old_ref);
331
+ return 0;
332
+ }
333
+
334
+ /*
335
+ * Load all the loose references from the repository
336
+ * into the in-memory Packfile, and build a vector with
337
+ * all the references so it can be written back to
338
+ * disk.
339
+ */
340
+ static int packed_loadloose(refdb_fs_backend *backend)
341
+ {
342
+ git_buf refs_path = GIT_BUF_INIT;
343
+ int result;
344
+
345
+ /* the packfile must have been previously loaded! */
346
+ assert(backend->refcache.packfile);
347
+
348
+ if (git_buf_joinpath(&refs_path, backend->path, GIT_REFS_DIR) < 0)
349
+ return -1;
350
+
351
+ /*
352
+ * Load all the loose files from disk into the Packfile table.
353
+ * This will overwrite any old packed entries with their
354
+ * updated loose versions
355
+ */
356
+ result = git_path_direach(&refs_path, _dirent_loose_load, backend);
357
+ git_buf_free(&refs_path);
358
+
359
+ return result;
360
+ }
361
+
362
+ static int refdb_fs_backend__exists(
363
+ int *exists,
364
+ git_refdb_backend *_backend,
365
+ const char *ref_name)
366
+ {
367
+ refdb_fs_backend *backend;
368
+ git_buf ref_path = GIT_BUF_INIT;
369
+
370
+ assert(_backend);
371
+ backend = (refdb_fs_backend *)_backend;
372
+
373
+ if (packed_load(backend) < 0)
374
+ return -1;
375
+
376
+ if (git_buf_joinpath(&ref_path, backend->path, ref_name) < 0)
377
+ return -1;
378
+
379
+ if (git_path_isfile(ref_path.ptr) == true ||
380
+ git_strmap_exists(backend->refcache.packfile, ref_path.ptr))
381
+ *exists = 1;
382
+ else
383
+ *exists = 0;
384
+
385
+ git_buf_free(&ref_path);
386
+ return 0;
387
+ }
388
+
389
+ static const char *loose_parse_symbolic(git_buf *file_content)
390
+ {
391
+ const unsigned int header_len = (unsigned int)strlen(GIT_SYMREF);
392
+ const char *refname_start;
393
+
394
+ refname_start = (const char *)file_content->ptr;
395
+
396
+ if (git_buf_len(file_content) < header_len + 1) {
397
+ giterr_set(GITERR_REFERENCE, "Corrupted loose reference file");
398
+ return NULL;
399
+ }
400
+
401
+ /*
402
+ * Assume we have already checked for the header
403
+ * before calling this function
404
+ */
405
+ refname_start += header_len;
406
+
407
+ return refname_start;
408
+ }
409
+
410
+ static int loose_lookup(
411
+ git_reference **out,
412
+ refdb_fs_backend *backend,
413
+ const char *ref_name)
414
+ {
415
+ const char *target;
416
+ git_oid oid;
417
+ git_buf ref_file = GIT_BUF_INIT;
418
+ int error = 0;
419
+
420
+ error = reference_read(&ref_file, NULL, backend->path, ref_name, NULL);
421
+
422
+ if (error < 0)
423
+ goto done;
424
+
425
+ if (git__prefixcmp((const char *)(ref_file.ptr), GIT_SYMREF) == 0) {
426
+ git_buf_rtrim(&ref_file);
427
+
428
+ if ((target = loose_parse_symbolic(&ref_file)) == NULL) {
429
+ error = -1;
430
+ goto done;
431
+ }
432
+
433
+ *out = git_reference__alloc_symbolic(backend->refdb, ref_name, target);
434
+ } else {
435
+ if ((error = loose_parse_oid(&oid, &ref_file)) < 0)
436
+ goto done;
437
+
438
+ *out = git_reference__alloc(backend->refdb, ref_name, &oid, NULL);
439
+ }
440
+
441
+ if (*out == NULL)
442
+ error = -1;
443
+
444
+ done:
445
+ git_buf_free(&ref_file);
446
+ return error;
447
+ }
448
+
449
+ static int packed_map_entry(
450
+ struct packref **entry,
451
+ khiter_t *pos,
452
+ refdb_fs_backend *backend,
453
+ const char *ref_name)
454
+ {
455
+ git_strmap *packfile_refs;
456
+
457
+ if (packed_load(backend) < 0)
458
+ return -1;
459
+
460
+ /* Look up on the packfile */
461
+ packfile_refs = backend->refcache.packfile;
462
+
463
+ *pos = git_strmap_lookup_index(packfile_refs, ref_name);
464
+
465
+ if (!git_strmap_valid_index(packfile_refs, *pos)) {
466
+ giterr_set(GITERR_REFERENCE, "Reference '%s' not found", ref_name);
467
+ return GIT_ENOTFOUND;
468
+ }
469
+
470
+ *entry = git_strmap_value_at(packfile_refs, *pos);
471
+
472
+ return 0;
473
+ }
474
+
475
+ static int packed_lookup(
476
+ git_reference **out,
477
+ refdb_fs_backend *backend,
478
+ const char *ref_name)
479
+ {
480
+ struct packref *entry;
481
+ khiter_t pos;
482
+ int error = 0;
483
+
484
+ if ((error = packed_map_entry(&entry, &pos, backend, ref_name)) < 0)
485
+ return error;
486
+
487
+ if ((*out = git_reference__alloc(backend->refdb, ref_name,
488
+ &entry->oid, &entry->peel)) == NULL)
489
+ return -1;
490
+
491
+ return 0;
492
+ }
493
+
494
+ static int refdb_fs_backend__lookup(
495
+ git_reference **out,
496
+ git_refdb_backend *_backend,
497
+ const char *ref_name)
498
+ {
499
+ refdb_fs_backend *backend;
500
+ int result;
501
+
502
+ assert(_backend);
503
+
504
+ backend = (refdb_fs_backend *)_backend;
505
+
506
+ if ((result = loose_lookup(out, backend, ref_name)) == 0)
507
+ return 0;
508
+
509
+ /* only try to lookup this reference on the packfile if it
510
+ * wasn't found on the loose refs; not if there was a critical error */
511
+ if (result == GIT_ENOTFOUND) {
512
+ giterr_clear();
513
+ result = packed_lookup(out, backend, ref_name);
514
+ }
515
+
516
+ return result;
517
+ }
518
+
519
+ struct dirent_list_data {
520
+ refdb_fs_backend *backend;
521
+ size_t repo_path_len;
522
+ unsigned int list_type:2;
523
+
524
+ git_reference_foreach_cb callback;
525
+ void *callback_payload;
526
+ int callback_error;
527
+ };
528
+
529
+ static git_ref_t loose_guess_rtype(const git_buf *full_path)
530
+ {
531
+ git_buf ref_file = GIT_BUF_INIT;
532
+ git_ref_t type;
533
+
534
+ type = GIT_REF_INVALID;
535
+
536
+ if (git_futils_readbuffer(&ref_file, full_path->ptr) == 0) {
537
+ if (git__prefixcmp((const char *)(ref_file.ptr), GIT_SYMREF) == 0)
538
+ type = GIT_REF_SYMBOLIC;
539
+ else
540
+ type = GIT_REF_OID;
541
+ }
542
+
543
+ git_buf_free(&ref_file);
544
+ return type;
545
+ }
546
+
547
+ static int _dirent_loose_listall(void *_data, git_buf *full_path)
548
+ {
549
+ struct dirent_list_data *data = (struct dirent_list_data *)_data;
550
+ const char *file_path = full_path->ptr + data->repo_path_len;
551
+
552
+ if (git_path_isdir(full_path->ptr) == true)
553
+ return git_path_direach(full_path, _dirent_loose_listall, _data);
554
+
555
+ /* do not add twice a reference that exists already in the packfile */
556
+ if (git_strmap_exists(data->backend->refcache.packfile, file_path))
557
+ return 0;
558
+
559
+ if (data->list_type != GIT_REF_LISTALL) {
560
+ if ((data->list_type & loose_guess_rtype(full_path)) == 0)
561
+ return 0; /* we are filtering out this reference */
562
+ }
563
+
564
+ /* Locked references aren't returned */
565
+ if (!git__suffixcmp(file_path, GIT_FILELOCK_EXTENSION))
566
+ return 0;
567
+
568
+ if (data->callback(file_path, data->callback_payload))
569
+ data->callback_error = GIT_EUSER;
570
+
571
+ return data->callback_error;
572
+ }
573
+
574
+ static int refdb_fs_backend__foreach(
575
+ git_refdb_backend *_backend,
576
+ unsigned int list_type,
577
+ git_reference_foreach_cb callback,
578
+ void *payload)
579
+ {
580
+ refdb_fs_backend *backend;
581
+ int result;
582
+ struct dirent_list_data data;
583
+ git_buf refs_path = GIT_BUF_INIT;
584
+ const char *ref_name;
585
+ void *ref = NULL;
586
+
587
+ GIT_UNUSED(ref);
588
+
589
+ assert(_backend);
590
+ backend = (refdb_fs_backend *)_backend;
591
+
592
+ if (packed_load(backend) < 0)
593
+ return -1;
594
+
595
+ /* list all the packed references first */
596
+ if (list_type & GIT_REF_OID) {
597
+ git_strmap_foreach(backend->refcache.packfile, ref_name, ref, {
598
+ if (callback(ref_name, payload))
599
+ return GIT_EUSER;
600
+ });
601
+ }
602
+
603
+ /* now list the loose references, trying not to
604
+ * duplicate the ref names already in the packed-refs file */
605
+
606
+ data.repo_path_len = strlen(backend->path);
607
+ data.list_type = list_type;
608
+ data.backend = backend;
609
+ data.callback = callback;
610
+ data.callback_payload = payload;
611
+ data.callback_error = 0;
612
+
613
+ if (git_buf_joinpath(&refs_path, backend->path, GIT_REFS_DIR) < 0)
614
+ return -1;
615
+
616
+ result = git_path_direach(&refs_path, _dirent_loose_listall, &data);
617
+
618
+ git_buf_free(&refs_path);
619
+
620
+ return data.callback_error ? GIT_EUSER : result;
621
+ }
622
+
623
+ static int loose_write(refdb_fs_backend *backend, const git_reference *ref)
624
+ {
625
+ git_filebuf file = GIT_FILEBUF_INIT;
626
+ git_buf ref_path = GIT_BUF_INIT;
627
+
628
+ /* Remove a possibly existing empty directory hierarchy
629
+ * which name would collide with the reference name
630
+ */
631
+ if (git_futils_rmdir_r(ref->name, backend->path,
632
+ GIT_RMDIR_SKIP_NONEMPTY) < 0)
633
+ return -1;
634
+
635
+ if (git_buf_joinpath(&ref_path, backend->path, ref->name) < 0)
636
+ return -1;
637
+
638
+ if (git_filebuf_open(&file, ref_path.ptr, GIT_FILEBUF_FORCE) < 0) {
639
+ git_buf_free(&ref_path);
640
+ return -1;
641
+ }
642
+
643
+ git_buf_free(&ref_path);
644
+
645
+ if (ref->type == GIT_REF_OID) {
646
+ char oid[GIT_OID_HEXSZ + 1];
647
+
648
+ git_oid_fmt(oid, &ref->target.oid);
649
+ oid[GIT_OID_HEXSZ] = '\0';
650
+
651
+ git_filebuf_printf(&file, "%s\n", oid);
652
+
653
+ } else if (ref->type == GIT_REF_SYMBOLIC) {
654
+ git_filebuf_printf(&file, GIT_SYMREF "%s\n", ref->target.symbolic);
655
+ } else {
656
+ assert(0); /* don't let this happen */
657
+ }
658
+
659
+ return git_filebuf_commit(&file, GIT_REFS_FILE_MODE);
660
+ }
661
+
662
+ static int packed_sort(const void *a, const void *b)
663
+ {
664
+ const struct packref *ref_a = (const struct packref *)a;
665
+ const struct packref *ref_b = (const struct packref *)b;
666
+
667
+ return strcmp(ref_a->name, ref_b->name);
668
+ }
669
+
670
+ /*
671
+ * Find out what object this reference resolves to.
672
+ *
673
+ * For references that point to a 'big' tag (e.g. an
674
+ * actual tag object on the repository), we need to
675
+ * cache on the packfile the OID of the object to
676
+ * which that 'big tag' is pointing to.
677
+ */
678
+ static int packed_find_peel(refdb_fs_backend *backend, struct packref *ref)
679
+ {
680
+ git_object *object;
681
+
682
+ if (ref->flags & GIT_PACKREF_HAS_PEEL)
683
+ return 0;
684
+
685
+ /*
686
+ * Only applies to tags, i.e. references
687
+ * in the /refs/tags folder
688
+ */
689
+ if (git__prefixcmp(ref->name, GIT_REFS_TAGS_DIR) != 0)
690
+ return 0;
691
+
692
+ /*
693
+ * Find the tagged object in the repository
694
+ */
695
+ if (git_object_lookup(&object, backend->repo, &ref->oid, GIT_OBJ_ANY) < 0)
696
+ return -1;
697
+
698
+ /*
699
+ * If the tagged object is a Tag object, we need to resolve it;
700
+ * if the ref is actually a 'weak' ref, we don't need to resolve
701
+ * anything.
702
+ */
703
+ if (git_object_type(object) == GIT_OBJ_TAG) {
704
+ git_tag *tag = (git_tag *)object;
705
+
706
+ /*
707
+ * Find the object pointed at by this tag
708
+ */
709
+ git_oid_cpy(&ref->peel, git_tag_target_id(tag));
710
+ ref->flags |= GIT_PACKREF_HAS_PEEL;
711
+
712
+ /*
713
+ * The reference has now cached the resolved OID, and is
714
+ * marked at such. When written to the packfile, it'll be
715
+ * accompanied by this resolved oid
716
+ */
717
+ }
718
+
719
+ git_object_free(object);
720
+ return 0;
721
+ }
722
+
723
+ /*
724
+ * Write a single reference into a packfile
725
+ */
726
+ static int packed_write_ref(struct packref *ref, git_filebuf *file)
727
+ {
728
+ char oid[GIT_OID_HEXSZ + 1];
729
+
730
+ git_oid_fmt(oid, &ref->oid);
731
+ oid[GIT_OID_HEXSZ] = 0;
732
+
733
+ /*
734
+ * For references that peel to an object in the repo, we must
735
+ * write the resulting peel on a separate line, e.g.
736
+ *
737
+ * 6fa8a902cc1d18527e1355773c86721945475d37 refs/tags/libgit2-0.4
738
+ * ^2ec0cb7959b0bf965d54f95453f5b4b34e8d3100
739
+ *
740
+ * This obviously only applies to tags.
741
+ * The required peels have already been loaded into `ref->peel_target`.
742
+ */
743
+ if (ref->flags & GIT_PACKREF_HAS_PEEL) {
744
+ char peel[GIT_OID_HEXSZ + 1];
745
+ git_oid_fmt(peel, &ref->peel);
746
+ peel[GIT_OID_HEXSZ] = 0;
747
+
748
+ if (git_filebuf_printf(file, "%s %s\n^%s\n", oid, ref->name, peel) < 0)
749
+ return -1;
750
+ } else {
751
+ if (git_filebuf_printf(file, "%s %s\n", oid, ref->name) < 0)
752
+ return -1;
753
+ }
754
+
755
+ return 0;
756
+ }
757
+
758
+ /*
759
+ * Remove all loose references
760
+ *
761
+ * Once we have successfully written a packfile,
762
+ * all the loose references that were packed must be
763
+ * removed from disk.
764
+ *
765
+ * This is a dangerous method; make sure the packfile
766
+ * is well-written, because we are destructing references
767
+ * here otherwise.
768
+ */
769
+ static int packed_remove_loose(
770
+ refdb_fs_backend *backend,
771
+ git_vector *packing_list)
772
+ {
773
+ size_t i;
774
+ git_buf full_path = GIT_BUF_INIT;
775
+ int failed = 0;
776
+
777
+ for (i = 0; i < packing_list->length; ++i) {
778
+ struct packref *ref = git_vector_get(packing_list, i);
779
+
780
+ if ((ref->flags & GIT_PACKREF_WAS_LOOSE) == 0)
781
+ continue;
782
+
783
+ if (git_buf_joinpath(&full_path, backend->path, ref->name) < 0)
784
+ return -1; /* critical; do not try to recover on oom */
785
+
786
+ if (git_path_exists(full_path.ptr) == true && p_unlink(full_path.ptr) < 0) {
787
+ if (failed)
788
+ continue;
789
+
790
+ giterr_set(GITERR_REFERENCE,
791
+ "Failed to remove loose reference '%s' after packing: %s",
792
+ full_path.ptr, strerror(errno));
793
+
794
+ failed = 1;
795
+ }
796
+
797
+ /*
798
+ * if we fail to remove a single file, this is *not* good,
799
+ * but we should keep going and remove as many as possible.
800
+ * After we've removed as many files as possible, we return
801
+ * the error code anyway.
802
+ */
803
+ }
804
+
805
+ git_buf_free(&full_path);
806
+ return failed ? -1 : 0;
807
+ }
808
+
809
+ /*
810
+ * Write all the contents in the in-memory packfile to disk.
811
+ */
812
+ static int packed_write(refdb_fs_backend *backend)
813
+ {
814
+ git_filebuf pack_file = GIT_FILEBUF_INIT;
815
+ size_t i;
816
+ git_buf pack_file_path = GIT_BUF_INIT;
817
+ git_vector packing_list;
818
+ unsigned int total_refs;
819
+
820
+ assert(backend && backend->refcache.packfile);
821
+
822
+ total_refs =
823
+ (unsigned int)git_strmap_num_entries(backend->refcache.packfile);
824
+
825
+ if (git_vector_init(&packing_list, total_refs, packed_sort) < 0)
826
+ return -1;
827
+
828
+ /* Load all the packfile into a vector */
829
+ {
830
+ struct packref *reference;
831
+
832
+ /* cannot fail: vector already has the right size */
833
+ git_strmap_foreach_value(backend->refcache.packfile, reference, {
834
+ git_vector_insert(&packing_list, reference);
835
+ });
836
+ }
837
+
838
+ /* sort the vector so the entries appear sorted on the packfile */
839
+ git_vector_sort(&packing_list);
840
+
841
+ /* Now we can open the file! */
842
+ if (git_buf_joinpath(&pack_file_path,
843
+ backend->path, GIT_PACKEDREFS_FILE) < 0)
844
+ goto cleanup_memory;
845
+
846
+ if (git_filebuf_open(&pack_file, pack_file_path.ptr, 0) < 0)
847
+ goto cleanup_packfile;
848
+
849
+ /* Packfiles have a header... apparently
850
+ * This is in fact not required, but we might as well print it
851
+ * just for kicks */
852
+ if (git_filebuf_printf(&pack_file, "%s\n", GIT_PACKEDREFS_HEADER) < 0)
853
+ goto cleanup_packfile;
854
+
855
+ for (i = 0; i < packing_list.length; ++i) {
856
+ struct packref *ref = (struct packref *)git_vector_get(&packing_list, i);
857
+
858
+ if (packed_find_peel(backend, ref) < 0)
859
+ goto cleanup_packfile;
860
+
861
+ if (packed_write_ref(ref, &pack_file) < 0)
862
+ goto cleanup_packfile;
863
+ }
864
+
865
+ /* if we've written all the references properly, we can commit
866
+ * the packfile to make the changes effective */
867
+ if (git_filebuf_commit(&pack_file, GIT_PACKEDREFS_FILE_MODE) < 0)
868
+ goto cleanup_memory;
869
+
870
+ /* when and only when the packfile has been properly written,
871
+ * we can go ahead and remove the loose refs */
872
+ if (packed_remove_loose(backend, &packing_list) < 0)
873
+ goto cleanup_memory;
874
+
875
+ {
876
+ struct stat st;
877
+ if (p_stat(pack_file_path.ptr, &st) == 0)
878
+ backend->refcache.packfile_time = st.st_mtime;
879
+ }
880
+
881
+ git_vector_free(&packing_list);
882
+ git_buf_free(&pack_file_path);
883
+
884
+ /* we're good now */
885
+ return 0;
886
+
887
+ cleanup_packfile:
888
+ git_filebuf_cleanup(&pack_file);
889
+
890
+ cleanup_memory:
891
+ git_vector_free(&packing_list);
892
+ git_buf_free(&pack_file_path);
893
+
894
+ return -1;
895
+ }
896
+
897
+ static int refdb_fs_backend__write(
898
+ git_refdb_backend *_backend,
899
+ const git_reference *ref)
900
+ {
901
+ refdb_fs_backend *backend;
902
+
903
+ assert(_backend);
904
+ backend = (refdb_fs_backend *)_backend;
905
+
906
+ return loose_write(backend, ref);
907
+ }
908
+
909
+ static int refdb_fs_backend__delete(
910
+ git_refdb_backend *_backend,
911
+ const git_reference *ref)
912
+ {
913
+ refdb_fs_backend *backend;
914
+ git_repository *repo;
915
+ git_buf loose_path = GIT_BUF_INIT;
916
+ struct packref *pack_ref;
917
+ khiter_t pack_ref_pos;
918
+ int error = 0, pack_error;
919
+ bool loose_deleted;
920
+
921
+ assert(_backend);
922
+ assert(ref);
923
+
924
+ backend = (refdb_fs_backend *)_backend;
925
+ repo = backend->repo;
926
+
927
+ /* If a loose reference exists, remove it from the filesystem */
928
+
929
+ if (git_buf_joinpath(&loose_path, repo->path_repository, ref->name) < 0)
930
+ return -1;
931
+
932
+ if (git_path_isfile(loose_path.ptr)) {
933
+ error = p_unlink(loose_path.ptr);
934
+ loose_deleted = 1;
935
+ }
936
+
937
+ git_buf_free(&loose_path);
938
+
939
+ if (error != 0)
940
+ return error;
941
+
942
+ /* If a packed reference exists, remove it from the packfile and repack */
943
+
944
+ if ((pack_error = packed_map_entry(&pack_ref, &pack_ref_pos, backend, ref->name)) == 0) {
945
+ git_strmap_delete_at(backend->refcache.packfile, pack_ref_pos);
946
+ git__free(pack_ref);
947
+
948
+ error = packed_write(backend);
949
+ }
950
+
951
+ if (pack_error == GIT_ENOTFOUND)
952
+ error = loose_deleted ? 0 : GIT_ENOTFOUND;
953
+ else
954
+ error = pack_error;
955
+
956
+ return error;
957
+ }
958
+
959
+ static int refdb_fs_backend__compress(git_refdb_backend *_backend)
960
+ {
961
+ refdb_fs_backend *backend;
962
+
963
+ assert(_backend);
964
+ backend = (refdb_fs_backend *)_backend;
965
+
966
+ if (packed_load(backend) < 0 || /* load the existing packfile */
967
+ packed_loadloose(backend) < 0 || /* add all the loose refs */
968
+ packed_write(backend) < 0) /* write back to disk */
969
+ return -1;
970
+
971
+ return 0;
972
+ }
973
+
974
+ static void refcache_free(git_refcache *refs)
975
+ {
976
+ assert(refs);
977
+
978
+ if (refs->packfile) {
979
+ struct packref *reference;
980
+
981
+ git_strmap_foreach_value(refs->packfile, reference, {
982
+ git__free(reference);
983
+ });
984
+
985
+ git_strmap_free(refs->packfile);
986
+ }
987
+ }
988
+
989
+ static void refdb_fs_backend__free(git_refdb_backend *_backend)
990
+ {
991
+ refdb_fs_backend *backend;
992
+
993
+ assert(_backend);
994
+ backend = (refdb_fs_backend *)_backend;
995
+
996
+ refcache_free(&backend->refcache);
997
+ git__free(backend);
998
+ }
999
+
1000
+ int git_refdb_backend_fs(
1001
+ git_refdb_backend **backend_out,
1002
+ git_repository *repository,
1003
+ git_refdb *refdb)
1004
+ {
1005
+ refdb_fs_backend *backend;
1006
+
1007
+ backend = git__calloc(1, sizeof(refdb_fs_backend));
1008
+ GITERR_CHECK_ALLOC(backend);
1009
+
1010
+ backend->repo = repository;
1011
+ backend->path = repository->path_repository;
1012
+ backend->refdb = refdb;
1013
+
1014
+ backend->parent.exists = &refdb_fs_backend__exists;
1015
+ backend->parent.lookup = &refdb_fs_backend__lookup;
1016
+ backend->parent.foreach = &refdb_fs_backend__foreach;
1017
+ backend->parent.write = &refdb_fs_backend__write;
1018
+ backend->parent.delete = &refdb_fs_backend__delete;
1019
+ backend->parent.compress = &refdb_fs_backend__compress;
1020
+ backend->parent.free = &refdb_fs_backend__free;
1021
+
1022
+ *backend_out = (git_refdb_backend *)backend;
1023
+ return 0;
1024
+ }