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,15 @@
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_fs_h__
8
+ #define INCLUDE_refdb_fs_h__
9
+
10
+ typedef struct {
11
+ git_strmap *packfile;
12
+ time_t packfile_time;
13
+ } git_refcache;
14
+
15
+ #endif
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright (C) 2009-2012 the libgit2 contributors
2
+ * Copyright (C) the libgit2 contributors. All rights reserved.
3
3
  *
4
4
  * This file is part of libgit2, distributed under the GNU GPL v2 with
5
5
  * a Linking Exception. For full terms see the included COPYING file.
@@ -10,7 +10,7 @@
10
10
  #include "filebuf.h"
11
11
  #include "signature.h"
12
12
 
13
- static int reflog_init(git_reflog **reflog, git_reference *ref)
13
+ static int reflog_init(git_reflog **reflog, const git_reference *ref)
14
14
  {
15
15
  git_reflog *log;
16
16
 
@@ -163,9 +163,12 @@ fail:
163
163
 
164
164
  void git_reflog_free(git_reflog *reflog)
165
165
  {
166
- unsigned int i;
166
+ size_t i;
167
167
  git_reflog_entry *entry;
168
168
 
169
+ if (reflog == NULL)
170
+ return;
171
+
169
172
  for (i=0; i < reflog->entries.length; i++) {
170
173
  entry = git_vector_get(&reflog->entries, i);
171
174
 
@@ -177,7 +180,7 @@ void git_reflog_free(git_reflog *reflog)
177
180
  git__free(reflog);
178
181
  }
179
182
 
180
- static int retrieve_reflog_path(git_buf *path, git_reference *ref)
183
+ static int retrieve_reflog_path(git_buf *path, const git_reference *ref)
181
184
  {
182
185
  return git_buf_join_n(path, '/', 3,
183
186
  git_reference_owner(ref)->path_repository, GIT_REFLOG_DIR, ref->name);
@@ -185,7 +188,10 @@ static int retrieve_reflog_path(git_buf *path, git_reference *ref)
185
188
 
186
189
  static int create_new_reflog_file(const char *filepath)
187
190
  {
188
- int fd;
191
+ int fd, error;
192
+
193
+ if ((error = git_futils_mkpath2file(filepath, GIT_REFLOG_DIR_MODE)) < 0)
194
+ return error;
189
195
 
190
196
  if ((fd = p_open(filepath,
191
197
  O_WRONLY | O_CREAT | O_TRUNC,
@@ -195,17 +201,17 @@ static int create_new_reflog_file(const char *filepath)
195
201
  return p_close(fd);
196
202
  }
197
203
 
198
- int git_reflog_read(git_reflog **reflog, git_reference *ref)
204
+ int git_reflog_read(git_reflog **reflog, const git_reference *ref)
199
205
  {
200
206
  int error = -1;
201
207
  git_buf log_path = GIT_BUF_INIT;
202
208
  git_buf log_file = GIT_BUF_INIT;
203
209
  git_reflog *log = NULL;
204
210
 
205
- *reflog = NULL;
206
-
207
211
  assert(reflog && ref);
208
212
 
213
+ *reflog = NULL;
214
+
209
215
  if (reflog_init(&log, ref) < 0)
210
216
  return -1;
211
217
 
@@ -248,7 +254,6 @@ int git_reflog_write(git_reflog *reflog)
248
254
 
249
255
  assert(reflog);
250
256
 
251
-
252
257
  if (git_buf_join_n(&log_path, '/', 3,
253
258
  git_repository_path(reflog->owner), GIT_REFLOG_DIR, reflog->ref_name) < 0)
254
259
  return -1;
@@ -269,7 +274,7 @@ int git_reflog_write(git_reflog *reflog)
269
274
  if ((error = git_filebuf_write(&fbuf, log.ptr, log.size)) < 0)
270
275
  goto cleanup;
271
276
  }
272
-
277
+
273
278
  error = git_filebuf_commit(&fbuf, GIT_REFLOG_FILE_MODE);
274
279
  goto success;
275
280
 
@@ -285,8 +290,8 @@ success:
285
290
  int git_reflog_append(git_reflog *reflog, const git_oid *new_oid,
286
291
  const git_signature *committer, const char *msg)
287
292
  {
288
- int count;
289
293
  git_reflog_entry *entry;
294
+ const git_reflog_entry *previous;
290
295
  const char *newline;
291
296
 
292
297
  assert(reflog && new_oid && committer);
@@ -313,16 +318,12 @@ int git_reflog_append(git_reflog *reflog, const git_oid *new_oid,
313
318
  }
314
319
  }
315
320
 
316
- count = git_reflog_entrycount(reflog);
321
+ previous = git_reflog_entry_byindex(reflog, 0);
317
322
 
318
- if (count == 0)
323
+ if (previous == NULL)
319
324
  git_oid_fromstr(&entry->oid_old, GIT_OID_HEX_ZERO);
320
- else {
321
- const git_reflog_entry *previous;
322
-
323
- previous = git_reflog_entry_byindex(reflog, count -1);
325
+ else
324
326
  git_oid_cpy(&entry->oid_old, &previous->oid_cur);
325
- }
326
327
 
327
328
  git_oid_cpy(&entry->oid_cur, new_oid);
328
329
 
@@ -338,21 +339,26 @@ cleanup:
338
339
 
339
340
  int git_reflog_rename(git_reference *ref, const char *new_name)
340
341
  {
341
- int error = -1, fd;
342
+ int error = 0, fd;
342
343
  git_buf old_path = GIT_BUF_INIT;
343
344
  git_buf new_path = GIT_BUF_INIT;
344
345
  git_buf temp_path = GIT_BUF_INIT;
346
+ git_buf normalized = GIT_BUF_INIT;
345
347
 
346
348
  assert(ref && new_name);
347
349
 
350
+ if ((error = git_reference__normalize_name(
351
+ &normalized, new_name, GIT_REF_FORMAT_ALLOW_ONELEVEL)) < 0)
352
+ return error;
353
+
348
354
  if (git_buf_joinpath(&temp_path, git_reference_owner(ref)->path_repository, GIT_REFLOG_DIR) < 0)
349
355
  return -1;
350
356
 
351
357
  if (git_buf_joinpath(&old_path, git_buf_cstr(&temp_path), ref->name) < 0)
352
- goto cleanup;
358
+ return -1;
353
359
 
354
- if (git_buf_joinpath(&new_path, git_buf_cstr(&temp_path), new_name) < 0)
355
- goto cleanup;
360
+ if (git_buf_joinpath(&new_path, git_buf_cstr(&temp_path), git_buf_cstr(&normalized)) < 0)
361
+ return -1;
356
362
 
357
363
  /*
358
364
  * Move the reflog to a temporary place. This two-phase renaming is required
@@ -362,28 +368,42 @@ int git_reflog_rename(git_reference *ref, const char *new_name)
362
368
  * - a/b/c/d -> a/b/c
363
369
  */
364
370
  if (git_buf_joinpath(&temp_path, git_buf_cstr(&temp_path), "temp_reflog") < 0)
365
- goto cleanup;
371
+ return -1;
366
372
 
367
- if ((fd = git_futils_mktmp(&temp_path, git_buf_cstr(&temp_path))) < 0)
373
+ if ((fd = git_futils_mktmp(&temp_path, git_buf_cstr(&temp_path))) < 0) {
374
+ error = -1;
368
375
  goto cleanup;
376
+ }
377
+
369
378
  p_close(fd);
370
379
 
371
- if (p_rename(git_buf_cstr(&old_path), git_buf_cstr(&temp_path)) < 0)
380
+ if (p_rename(git_buf_cstr(&old_path), git_buf_cstr(&temp_path)) < 0) {
381
+ giterr_set(GITERR_OS, "Failed to rename reflog for %s", new_name);
382
+ error = -1;
372
383
  goto cleanup;
384
+ }
373
385
 
374
386
  if (git_path_isdir(git_buf_cstr(&new_path)) &&
375
- (git_futils_rmdir_r(git_buf_cstr(&new_path), NULL, GIT_DIRREMOVAL_ONLY_EMPTY_DIRS) < 0))
387
+ (git_futils_rmdir_r(git_buf_cstr(&new_path), NULL, GIT_RMDIR_SKIP_NONEMPTY) < 0)) {
388
+ error = -1;
376
389
  goto cleanup;
390
+ }
377
391
 
378
- if (git_futils_mkpath2file(git_buf_cstr(&new_path), GIT_REFLOG_DIR_MODE) < 0)
392
+ if (git_futils_mkpath2file(git_buf_cstr(&new_path), GIT_REFLOG_DIR_MODE) < 0) {
393
+ error = -1;
379
394
  goto cleanup;
395
+ }
380
396
 
381
- error = p_rename(git_buf_cstr(&temp_path), git_buf_cstr(&new_path));
397
+ if (p_rename(git_buf_cstr(&temp_path), git_buf_cstr(&new_path)) < 0) {
398
+ giterr_set(GITERR_OS, "Failed to rename reflog for %s", new_name);
399
+ error = -1;
400
+ }
382
401
 
383
402
  cleanup:
384
403
  git_buf_free(&temp_path);
385
404
  git_buf_free(&old_path);
386
405
  git_buf_free(&new_path);
406
+ git_buf_free(&normalized);
387
407
 
388
408
  return error;
389
409
  }
@@ -403,37 +423,47 @@ int git_reflog_delete(git_reference *ref)
403
423
  return error;
404
424
  }
405
425
 
406
- unsigned int git_reflog_entrycount(git_reflog *reflog)
426
+ size_t git_reflog_entrycount(git_reflog *reflog)
407
427
  {
408
428
  assert(reflog);
409
- return (unsigned int)reflog->entries.length;
429
+ return reflog->entries.length;
430
+ }
431
+
432
+ GIT_INLINE(size_t) reflog_inverse_index(size_t idx, size_t total)
433
+ {
434
+ return (total - 1) - idx;
410
435
  }
411
436
 
412
437
  const git_reflog_entry * git_reflog_entry_byindex(git_reflog *reflog, size_t idx)
413
438
  {
414
439
  assert(reflog);
415
- return git_vector_get(&reflog->entries, idx);
440
+
441
+ if (idx >= reflog->entries.length)
442
+ return NULL;
443
+
444
+ return git_vector_get(
445
+ &reflog->entries, reflog_inverse_index(idx, reflog->entries.length));
416
446
  }
417
447
 
418
- const git_oid * git_reflog_entry_oidold(const git_reflog_entry *entry)
448
+ const git_oid * git_reflog_entry_id_old(const git_reflog_entry *entry)
419
449
  {
420
450
  assert(entry);
421
451
  return &entry->oid_old;
422
452
  }
423
453
 
424
- const git_oid * git_reflog_entry_oidnew(const git_reflog_entry *entry)
454
+ const git_oid * git_reflog_entry_id_new(const git_reflog_entry *entry)
425
455
  {
426
456
  assert(entry);
427
457
  return &entry->oid_cur;
428
458
  }
429
459
 
430
- git_signature * git_reflog_entry_committer(const git_reflog_entry *entry)
460
+ const git_signature * git_reflog_entry_committer(const git_reflog_entry *entry)
431
461
  {
432
462
  assert(entry);
433
463
  return entry->committer;
434
464
  }
435
465
 
436
- char * git_reflog_entry_msg(const git_reflog_entry *entry)
466
+ const char * git_reflog_entry_message(const git_reflog_entry *entry)
437
467
  {
438
468
  assert(entry);
439
469
  return entry->msg;
@@ -441,44 +471,46 @@ char * git_reflog_entry_msg(const git_reflog_entry *entry)
441
471
 
442
472
  int git_reflog_drop(
443
473
  git_reflog *reflog,
444
- unsigned int idx,
474
+ size_t idx,
445
475
  int rewrite_previous_entry)
446
476
  {
447
- unsigned int entrycount;
477
+ size_t entrycount;
448
478
  git_reflog_entry *entry, *previous;
449
479
 
450
480
  assert(reflog);
451
481
 
452
482
  entrycount = git_reflog_entrycount(reflog);
453
483
 
454
- if (idx >= entrycount)
484
+ entry = (git_reflog_entry *)git_reflog_entry_byindex(reflog, idx);
485
+
486
+ if (entry == NULL)
455
487
  return GIT_ENOTFOUND;
456
488
 
457
- entry = git_vector_get(&reflog->entries, idx);
458
489
  reflog_entry_free(entry);
459
490
 
460
- if (git_vector_remove(&reflog->entries, idx) < 0)
491
+ if (git_vector_remove(
492
+ &reflog->entries, reflog_inverse_index(idx, entrycount)) < 0)
461
493
  return -1;
462
494
 
463
495
  if (!rewrite_previous_entry)
464
496
  return 0;
465
497
 
466
- /* No need to rewrite anything when removing the first entry */
498
+ /* No need to rewrite anything when removing the most recent entry */
467
499
  if (idx == 0)
468
500
  return 0;
469
501
 
470
- /* There are no more entries in the log */
502
+ /* Have the latest entry just been dropped? */
471
503
  if (entrycount == 1)
472
504
  return 0;
473
505
 
474
506
  entry = (git_reflog_entry *)git_reflog_entry_byindex(reflog, idx - 1);
475
507
 
476
- /* If the last entry has just been removed... */
508
+ /* If the oldest entry has just been removed... */
477
509
  if (idx == entrycount - 1) {
478
- /* ...clear the oid_old member of the "new" last entry */
510
+ /* ...clear the oid_old member of the "new" oldest entry */
479
511
  if (git_oid_fromstr(&entry->oid_old, GIT_OID_HEX_ZERO) < 0)
480
512
  return -1;
481
-
513
+
482
514
  return 0;
483
515
  }
484
516
 
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright (C) 2009-2012 the libgit2 contributors
2
+ * Copyright (C) the libgit2 contributors. All rights reserved.
3
3
  *
4
4
  * This file is part of libgit2, distributed under the GNU GPL v2 with
5
5
  * a Linking Exception. For full terms see the included COPYING file.
@@ -17,8 +17,6 @@
17
17
 
18
18
  #define GIT_REFLOG_SIZE_MIN (2*GIT_OID_HEXSZ+2+17)
19
19
 
20
- #define GIT_OID_HEX_ZERO "0000000000000000000000000000000000000000"
21
-
22
20
  struct git_reflog_entry {
23
21
  git_oid oid_old;
24
22
  git_oid oid_cur;
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright (C) 2009-2012 the libgit2 contributors
2
+ * Copyright (C) the libgit2 contributors. All rights reserved.
3
3
  *
4
4
  * This file is part of libgit2, distributed under the GNU GPL v2 with
5
5
  * a Linking Exception. For full terms see the included COPYING file.
@@ -11,11 +11,15 @@
11
11
  #include "fileops.h"
12
12
  #include "pack.h"
13
13
  #include "reflog.h"
14
+ #include "refdb.h"
14
15
 
15
16
  #include <git2/tag.h>
16
17
  #include <git2/object.h>
17
18
  #include <git2/oid.h>
18
19
  #include <git2/branch.h>
20
+ #include <git2/refs.h>
21
+ #include <git2/refdb.h>
22
+ #include <git2/refdb_backend.h>
19
23
 
20
24
  GIT__USE_STRMAP;
21
25
 
@@ -27,784 +31,75 @@ enum {
27
31
  GIT_PACKREF_WAS_LOOSE = 2
28
32
  };
29
33
 
30
- struct packref {
31
- git_oid oid;
32
- git_oid peel;
33
- char flags;
34
- char name[GIT_FLEX_ARRAY];
35
- };
36
-
37
- static int reference_read(
38
- git_buf *file_content,
39
- time_t *mtime,
40
- const char *repo_path,
41
- const char *ref_name,
42
- int *updated);
43
-
44
- /* loose refs */
45
- static int loose_parse_symbolic(git_reference *ref, git_buf *file_content);
46
- static int loose_parse_oid(git_oid *ref, git_buf *file_content);
47
- static int loose_lookup(git_reference *ref);
48
- static int loose_lookup_to_packfile(struct packref **ref_out,
49
- git_repository *repo, const char *name);
50
- static int loose_write(git_reference *ref);
51
-
52
- /* packed refs */
53
- static int packed_parse_peel(struct packref *tag_ref,
54
- const char **buffer_out, const char *buffer_end);
55
- static int packed_parse_oid(struct packref **ref_out,
56
- const char **buffer_out, const char *buffer_end);
57
- static int packed_load(git_repository *repo);
58
- static int packed_loadloose(git_repository *repository);
59
- static int packed_write_ref(struct packref *ref, git_filebuf *file);
60
- static int packed_find_peel(git_repository *repo, struct packref *ref);
61
- static int packed_remove_loose(git_repository *repo, git_vector *packing_list);
62
- static int packed_sort(const void *a, const void *b);
63
- static int packed_lookup(git_reference *ref);
64
- static int packed_write(git_repository *repo);
65
-
66
- /* internal helpers */
67
- static int reference_path_available(git_repository *repo,
68
- const char *ref, const char *old_ref);
69
- static int reference_delete(git_reference *ref);
70
- static int reference_lookup(git_reference *ref);
71
-
72
- void git_reference_free(git_reference *reference)
73
- {
74
- if (reference == NULL)
75
- return;
76
-
77
- git__free(reference->name);
78
- reference->name = NULL;
79
-
80
- if (reference->flags & GIT_REF_SYMBOLIC) {
81
- git__free(reference->target.symbolic);
82
- reference->target.symbolic = NULL;
83
- }
84
-
85
- git__free(reference);
86
- }
87
-
88
- static int reference_alloc(
89
- git_reference **ref_out,
90
- git_repository *repo,
91
- const char *name)
92
- {
93
- git_reference *reference = NULL;
94
-
95
- assert(ref_out && repo && name);
96
-
97
- reference = git__malloc(sizeof(git_reference));
98
- GITERR_CHECK_ALLOC(reference);
99
-
100
- memset(reference, 0x0, sizeof(git_reference));
101
- reference->owner = repo;
102
-
103
- reference->name = git__strdup(name);
104
- GITERR_CHECK_ALLOC(reference->name);
105
-
106
- *ref_out = reference;
107
- return 0;
108
- }
109
-
110
- static int reference_read(
111
- git_buf *file_content,
112
- time_t *mtime,
113
- const char *repo_path,
114
- const char *ref_name,
115
- int *updated)
116
- {
117
- git_buf path = GIT_BUF_INIT;
118
- int result;
119
-
120
- assert(file_content && repo_path && ref_name);
121
-
122
- /* Determine the full path of the file */
123
- if (git_buf_joinpath(&path, repo_path, ref_name) < 0)
124
- return -1;
125
-
126
- result = git_futils_readbuffer_updated(file_content, path.ptr, mtime, updated);
127
- git_buf_free(&path);
128
-
129
- return result;
130
- }
131
-
132
- static int loose_parse_symbolic(git_reference *ref, git_buf *file_content)
133
- {
134
- const unsigned int header_len = (unsigned int)strlen(GIT_SYMREF);
135
- const char *refname_start;
136
-
137
- refname_start = (const char *)file_content->ptr;
138
-
139
- if (git_buf_len(file_content) < header_len + 1) {
140
- giterr_set(GITERR_REFERENCE, "Corrupted loose reference file");
141
- return -1;
142
- }
143
-
144
- /*
145
- * Assume we have already checked for the header
146
- * before calling this function
147
- */
148
- refname_start += header_len;
149
-
150
- ref->target.symbolic = git__strdup(refname_start);
151
- GITERR_CHECK_ALLOC(ref->target.symbolic);
152
-
153
- return 0;
154
- }
155
-
156
- static int loose_parse_oid(git_oid *oid, git_buf *file_content)
157
- {
158
- size_t len;
159
- const char *str;
160
-
161
- len = git_buf_len(file_content);
162
- if (len < GIT_OID_HEXSZ)
163
- goto corrupted;
164
-
165
- /* str is guranteed to be zero-terminated */
166
- str = git_buf_cstr(file_content);
167
-
168
- /* If the file is longer than 40 chars, the 41st must be a space */
169
- if (git_oid_fromstr(oid, git_buf_cstr(file_content)) < 0)
170
- goto corrupted;
171
-
172
- /* If the file is longer than 40 chars, the 41st must be a space */
173
- str += GIT_OID_HEXSZ;
174
- if (*str == '\0' || git__isspace(*str))
175
- return 0;
176
-
177
- corrupted:
178
- giterr_set(GITERR_REFERENCE, "Corrupted loose reference file");
179
- return -1;
180
- }
181
-
182
- static git_ref_t loose_guess_rtype(const git_buf *full_path)
183
- {
184
- git_buf ref_file = GIT_BUF_INIT;
185
- git_ref_t type;
186
-
187
- type = GIT_REF_INVALID;
188
-
189
- if (git_futils_readbuffer(&ref_file, full_path->ptr) == 0) {
190
- if (git__prefixcmp((const char *)(ref_file.ptr), GIT_SYMREF) == 0)
191
- type = GIT_REF_SYMBOLIC;
192
- else
193
- type = GIT_REF_OID;
194
- }
195
-
196
- git_buf_free(&ref_file);
197
- return type;
198
- }
199
-
200
- static int loose_lookup(git_reference *ref)
201
- {
202
- int result, updated;
203
- git_buf ref_file = GIT_BUF_INIT;
204
-
205
- result = reference_read(&ref_file, &ref->mtime,
206
- ref->owner->path_repository, ref->name, &updated);
207
-
208
- if (result < 0)
209
- return result;
210
-
211
- if (!updated)
212
- return 0;
213
-
214
- if (ref->flags & GIT_REF_SYMBOLIC) {
215
- git__free(ref->target.symbolic);
216
- ref->target.symbolic = NULL;
217
- }
218
-
219
- ref->flags = 0;
220
-
221
- if (git__prefixcmp((const char *)(ref_file.ptr), GIT_SYMREF) == 0) {
222
- ref->flags |= GIT_REF_SYMBOLIC;
223
- git_buf_rtrim(&ref_file);
224
- result = loose_parse_symbolic(ref, &ref_file);
225
- } else {
226
- ref->flags |= GIT_REF_OID;
227
- result = loose_parse_oid(&ref->target.oid, &ref_file);
228
- }
229
-
230
- git_buf_free(&ref_file);
231
- return result;
232
- }
233
-
234
- static int loose_lookup_to_packfile(
235
- struct packref **ref_out,
236
- git_repository *repo,
237
- const char *name)
238
- {
239
- git_buf ref_file = GIT_BUF_INIT;
240
- struct packref *ref = NULL;
241
- size_t name_len;
242
-
243
- *ref_out = NULL;
244
-
245
- if (reference_read(&ref_file, NULL, repo->path_repository, name, NULL) < 0)
246
- return -1;
247
-
248
- git_buf_rtrim(&ref_file);
249
-
250
- name_len = strlen(name);
251
- ref = git__malloc(sizeof(struct packref) + name_len + 1);
252
- GITERR_CHECK_ALLOC(ref);
253
-
254
- memcpy(ref->name, name, name_len);
255
- ref->name[name_len] = 0;
256
-
257
- if (loose_parse_oid(&ref->oid, &ref_file) < 0) {
258
- git_buf_free(&ref_file);
259
- git__free(ref);
260
- return -1;
261
- }
262
-
263
- ref->flags = GIT_PACKREF_WAS_LOOSE;
264
-
265
- *ref_out = ref;
266
- git_buf_free(&ref_file);
267
- return 0;
268
- }
269
-
270
- static int loose_write(git_reference *ref)
271
- {
272
- git_filebuf file = GIT_FILEBUF_INIT;
273
- git_buf ref_path = GIT_BUF_INIT;
274
- struct stat st;
275
-
276
- if (git_buf_joinpath(&ref_path, ref->owner->path_repository, ref->name) < 0)
277
- return -1;
278
-
279
- /* Remove a possibly existing empty directory hierarchy
280
- * which name would collide with the reference name
281
- */
282
- if (git_path_isdir(git_buf_cstr(&ref_path)) &&
283
- git_futils_rmdir_r(git_buf_cstr(&ref_path), NULL,
284
- GIT_DIRREMOVAL_ONLY_EMPTY_DIRS) < 0) {
285
- git_buf_free(&ref_path);
286
- return -1;
287
- }
288
-
289
- if (git_filebuf_open(&file, ref_path.ptr, GIT_FILEBUF_FORCE) < 0) {
290
- git_buf_free(&ref_path);
291
- return -1;
292
- }
293
-
294
- git_buf_free(&ref_path);
295
-
296
- if (ref->flags & GIT_REF_OID) {
297
- char oid[GIT_OID_HEXSZ + 1];
298
-
299
- git_oid_fmt(oid, &ref->target.oid);
300
- oid[GIT_OID_HEXSZ] = '\0';
301
-
302
- git_filebuf_printf(&file, "%s\n", oid);
303
-
304
- } else if (ref->flags & GIT_REF_SYMBOLIC) {
305
- git_filebuf_printf(&file, GIT_SYMREF "%s\n", ref->target.symbolic);
306
- } else {
307
- assert(0); /* don't let this happen */
308
- }
309
-
310
- if (p_stat(ref_path.ptr, &st) == 0)
311
- ref->mtime = st.st_mtime;
312
-
313
- return git_filebuf_commit(&file, GIT_REFS_FILE_MODE);
314
- }
315
-
316
- static int packed_parse_peel(
317
- struct packref *tag_ref,
318
- const char **buffer_out,
319
- const char *buffer_end)
320
- {
321
- const char *buffer = *buffer_out + 1;
322
-
323
- assert(buffer[-1] == '^');
324
-
325
- /* Ensure it's not the first entry of the file */
326
- if (tag_ref == NULL)
327
- goto corrupt;
328
-
329
- /* Ensure reference is a tag */
330
- if (git__prefixcmp(tag_ref->name, GIT_REFS_TAGS_DIR) != 0)
331
- goto corrupt;
332
-
333
- if (buffer + GIT_OID_HEXSZ >= buffer_end)
334
- goto corrupt;
335
-
336
- /* Is this a valid object id? */
337
- if (git_oid_fromstr(&tag_ref->peel, buffer) < 0)
338
- goto corrupt;
339
-
340
- buffer = buffer + GIT_OID_HEXSZ;
341
- if (*buffer == '\r')
342
- buffer++;
343
-
344
- if (*buffer != '\n')
345
- goto corrupt;
346
-
347
- *buffer_out = buffer + 1;
348
- return 0;
349
-
350
- corrupt:
351
- giterr_set(GITERR_REFERENCE, "The packed references file is corrupted");
352
- return -1;
353
- }
354
-
355
- static int packed_parse_oid(
356
- struct packref **ref_out,
357
- const char **buffer_out,
358
- const char *buffer_end)
359
- {
360
- struct packref *ref = NULL;
361
-
362
- const char *buffer = *buffer_out;
363
- const char *refname_begin, *refname_end;
364
-
365
- size_t refname_len;
366
- git_oid id;
367
-
368
- refname_begin = (buffer + GIT_OID_HEXSZ + 1);
369
- if (refname_begin >= buffer_end || refname_begin[-1] != ' ')
370
- goto corrupt;
371
-
372
- /* Is this a valid object id? */
373
- if (git_oid_fromstr(&id, buffer) < 0)
374
- goto corrupt;
375
-
376
- refname_end = memchr(refname_begin, '\n', buffer_end - refname_begin);
377
- if (refname_end == NULL)
378
- goto corrupt;
379
-
380
- if (refname_end[-1] == '\r')
381
- refname_end--;
382
-
383
- refname_len = refname_end - refname_begin;
384
-
385
- ref = git__malloc(sizeof(struct packref) + refname_len + 1);
386
- GITERR_CHECK_ALLOC(ref);
387
-
388
- memcpy(ref->name, refname_begin, refname_len);
389
- ref->name[refname_len] = 0;
390
-
391
- git_oid_cpy(&ref->oid, &id);
392
-
393
- ref->flags = 0;
394
-
395
- *ref_out = ref;
396
- *buffer_out = refname_end + 1;
397
-
398
- return 0;
399
-
400
- corrupt:
401
- git__free(ref);
402
- giterr_set(GITERR_REFERENCE, "The packed references file is corrupted");
403
- return -1;
404
- }
405
-
406
- static int packed_load(git_repository *repo)
407
- {
408
- int result, updated;
409
- git_buf packfile = GIT_BUF_INIT;
410
- const char *buffer_start, *buffer_end;
411
- git_refcache *ref_cache = &repo->references;
412
-
413
- /* First we make sure we have allocated the hash table */
414
- if (ref_cache->packfile == NULL) {
415
- ref_cache->packfile = git_strmap_alloc();
416
- GITERR_CHECK_ALLOC(ref_cache->packfile);
417
- }
418
-
419
- result = reference_read(&packfile, &ref_cache->packfile_time,
420
- repo->path_repository, GIT_PACKEDREFS_FILE, &updated);
421
-
422
- /*
423
- * If we couldn't find the file, we need to clear the table and
424
- * return. On any other error, we return that error. If everything
425
- * went fine and the file wasn't updated, then there's nothing new
426
- * for us here, so just return. Anything else means we need to
427
- * refresh the packed refs.
428
- */
429
- if (result == GIT_ENOTFOUND) {
430
- git_strmap_clear(ref_cache->packfile);
431
- return 0;
432
- }
433
-
434
- if (result < 0)
435
- return -1;
436
-
437
- if (!updated)
438
- return 0;
439
-
440
- /*
441
- * At this point, we want to refresh the packed refs. We already
442
- * have the contents in our buffer.
443
- */
444
- git_strmap_clear(ref_cache->packfile);
445
-
446
- buffer_start = (const char *)packfile.ptr;
447
- buffer_end = (const char *)(buffer_start) + packfile.size;
448
-
449
- while (buffer_start < buffer_end && buffer_start[0] == '#') {
450
- buffer_start = strchr(buffer_start, '\n');
451
- if (buffer_start == NULL)
452
- goto parse_failed;
453
-
454
- buffer_start++;
455
- }
456
-
457
- while (buffer_start < buffer_end) {
458
- int err;
459
- struct packref *ref = NULL;
460
-
461
- if (packed_parse_oid(&ref, &buffer_start, buffer_end) < 0)
462
- goto parse_failed;
463
-
464
- if (buffer_start[0] == '^') {
465
- if (packed_parse_peel(ref, &buffer_start, buffer_end) < 0)
466
- goto parse_failed;
467
- }
468
-
469
- git_strmap_insert(ref_cache->packfile, ref->name, ref, err);
470
- if (err < 0)
471
- goto parse_failed;
472
- }
473
-
474
- git_buf_free(&packfile);
475
- return 0;
476
-
477
- parse_failed:
478
- git_strmap_free(ref_cache->packfile);
479
- ref_cache->packfile = NULL;
480
- git_buf_free(&packfile);
481
- return -1;
482
- }
483
-
484
-
485
- struct dirent_list_data {
486
- git_repository *repo;
487
- size_t repo_path_len;
488
- unsigned int list_flags;
489
-
490
- int (*callback)(const char *, void *);
491
- void *callback_payload;
492
- int callback_error;
493
- };
494
-
495
- static int _dirent_loose_listall(void *_data, git_buf *full_path)
34
+ static git_reference *alloc_ref(git_refdb *refdb, const char *name)
496
35
  {
497
- struct dirent_list_data *data = (struct dirent_list_data *)_data;
498
- const char *file_path = full_path->ptr + data->repo_path_len;
499
-
500
- if (git_path_isdir(full_path->ptr) == true)
501
- return git_path_direach(full_path, _dirent_loose_listall, _data);
502
-
503
- /* do not add twice a reference that exists already in the packfile */
504
- if ((data->list_flags & GIT_REF_PACKED) != 0 &&
505
- git_strmap_exists(data->repo->references.packfile, file_path))
506
- return 0;
507
-
508
- if (data->list_flags != GIT_REF_LISTALL) {
509
- if ((data->list_flags & loose_guess_rtype(full_path)) == 0)
510
- return 0; /* we are filtering out this reference */
511
- }
36
+ git_reference *ref;
37
+ size_t namelen = strlen(name);
512
38
 
513
- /* Locked references aren't returned */
514
- if (!git__suffixcmp(file_path, GIT_FILELOCK_EXTENSION))
515
- return 0;
39
+ if ((ref = git__calloc(1, sizeof(git_reference) + namelen + 1)) == NULL)
40
+ return NULL;
516
41
 
517
- if (data->callback(file_path, data->callback_payload))
518
- data->callback_error = GIT_EUSER;
42
+ ref->db = refdb;
43
+ memcpy(ref->name, name, namelen + 1);
519
44
 
520
- return data->callback_error;
45
+ return ref;
521
46
  }
522
47
 
523
- static int _dirent_loose_load(void *data, git_buf *full_path)
48
+ git_reference *git_reference__alloc_symbolic(
49
+ git_refdb *refdb,
50
+ const char *name,
51
+ const char *target)
524
52
  {
525
- git_repository *repository = (git_repository *)data;
526
- void *old_ref = NULL;
527
- struct packref *ref;
528
- const char *file_path;
529
- int err;
53
+ git_reference *ref;
530
54
 
531
- if (git_path_isdir(full_path->ptr) == true)
532
- return git_path_direach(full_path, _dirent_loose_load, repository);
55
+ assert(refdb && name && target);
533
56
 
534
- file_path = full_path->ptr + strlen(repository->path_repository);
57
+ ref = alloc_ref(refdb, name);
58
+ if (!ref)
59
+ return NULL;
535
60
 
536
- if (loose_lookup_to_packfile(&ref, repository, file_path) < 0)
537
- return -1;
61
+ ref->type = GIT_REF_SYMBOLIC;
538
62
 
539
- git_strmap_insert2(
540
- repository->references.packfile, ref->name, ref, old_ref, err);
541
- if (err < 0) {
63
+ if ((ref->target.symbolic = git__strdup(target)) == NULL) {
542
64
  git__free(ref);
543
- return -1;
544
- }
545
-
546
- git__free(old_ref);
547
- return 0;
548
- }
549
-
550
- /*
551
- * Load all the loose references from the repository
552
- * into the in-memory Packfile, and build a vector with
553
- * all the references so it can be written back to
554
- * disk.
555
- */
556
- static int packed_loadloose(git_repository *repository)
557
- {
558
- git_buf refs_path = GIT_BUF_INIT;
559
- int result;
560
-
561
- /* the packfile must have been previously loaded! */
562
- assert(repository->references.packfile);
563
-
564
- if (git_buf_joinpath(&refs_path, repository->path_repository, GIT_REFS_DIR) < 0)
565
- return -1;
566
-
567
- /*
568
- * Load all the loose files from disk into the Packfile table.
569
- * This will overwrite any old packed entries with their
570
- * updated loose versions
571
- */
572
- result = git_path_direach(&refs_path, _dirent_loose_load, repository);
573
- git_buf_free(&refs_path);
574
-
575
- return result;
576
- }
577
-
578
- /*
579
- * Write a single reference into a packfile
580
- */
581
- static int packed_write_ref(struct packref *ref, git_filebuf *file)
582
- {
583
- char oid[GIT_OID_HEXSZ + 1];
584
-
585
- git_oid_fmt(oid, &ref->oid);
586
- oid[GIT_OID_HEXSZ] = 0;
587
-
588
- /*
589
- * For references that peel to an object in the repo, we must
590
- * write the resulting peel on a separate line, e.g.
591
- *
592
- * 6fa8a902cc1d18527e1355773c86721945475d37 refs/tags/libgit2-0.4
593
- * ^2ec0cb7959b0bf965d54f95453f5b4b34e8d3100
594
- *
595
- * This obviously only applies to tags.
596
- * The required peels have already been loaded into `ref->peel_target`.
597
- */
598
- if (ref->flags & GIT_PACKREF_HAS_PEEL) {
599
- char peel[GIT_OID_HEXSZ + 1];
600
- git_oid_fmt(peel, &ref->peel);
601
- peel[GIT_OID_HEXSZ] = 0;
602
-
603
- if (git_filebuf_printf(file, "%s %s\n^%s\n", oid, ref->name, peel) < 0)
604
- return -1;
605
- } else {
606
- if (git_filebuf_printf(file, "%s %s\n", oid, ref->name) < 0)
607
- return -1;
608
- }
609
-
610
- return 0;
611
- }
612
-
613
- /*
614
- * Find out what object this reference resolves to.
615
- *
616
- * For references that point to a 'big' tag (e.g. an
617
- * actual tag object on the repository), we need to
618
- * cache on the packfile the OID of the object to
619
- * which that 'big tag' is pointing to.
620
- */
621
- static int packed_find_peel(git_repository *repo, struct packref *ref)
622
- {
623
- git_object *object;
624
-
625
- if (ref->flags & GIT_PACKREF_HAS_PEEL)
626
- return 0;
627
-
628
- /*
629
- * Only applies to tags, i.e. references
630
- * in the /refs/tags folder
631
- */
632
- if (git__prefixcmp(ref->name, GIT_REFS_TAGS_DIR) != 0)
633
- return 0;
634
-
635
- /*
636
- * Find the tagged object in the repository
637
- */
638
- if (git_object_lookup(&object, repo, &ref->oid, GIT_OBJ_ANY) < 0)
639
- return -1;
640
-
641
- /*
642
- * If the tagged object is a Tag object, we need to resolve it;
643
- * if the ref is actually a 'weak' ref, we don't need to resolve
644
- * anything.
645
- */
646
- if (git_object_type(object) == GIT_OBJ_TAG) {
647
- git_tag *tag = (git_tag *)object;
648
-
649
- /*
650
- * Find the object pointed at by this tag
651
- */
652
- git_oid_cpy(&ref->peel, git_tag_target_oid(tag));
653
- ref->flags |= GIT_PACKREF_HAS_PEEL;
654
-
655
- /*
656
- * The reference has now cached the resolved OID, and is
657
- * marked at such. When written to the packfile, it'll be
658
- * accompanied by this resolved oid
659
- */
65
+ return NULL;
660
66
  }
661
67
 
662
- git_object_free(object);
663
- return 0;
68
+ return ref;
664
69
  }
665
70
 
666
- /*
667
- * Remove all loose references
668
- *
669
- * Once we have successfully written a packfile,
670
- * all the loose references that were packed must be
671
- * removed from disk.
672
- *
673
- * This is a dangerous method; make sure the packfile
674
- * is well-written, because we are destructing references
675
- * here otherwise.
676
- */
677
- static int packed_remove_loose(git_repository *repo, git_vector *packing_list)
71
+ git_reference *git_reference__alloc(
72
+ git_refdb *refdb,
73
+ const char *name,
74
+ const git_oid *oid,
75
+ const git_oid *peel)
678
76
  {
679
- unsigned int i;
680
- git_buf full_path = GIT_BUF_INIT;
681
- int failed = 0;
682
-
683
- for (i = 0; i < packing_list->length; ++i) {
684
- struct packref *ref = git_vector_get(packing_list, i);
685
-
686
- if ((ref->flags & GIT_PACKREF_WAS_LOOSE) == 0)
687
- continue;
688
-
689
- if (git_buf_joinpath(&full_path, repo->path_repository, ref->name) < 0)
690
- return -1; /* critical; do not try to recover on oom */
691
-
692
- if (git_path_exists(full_path.ptr) == true && p_unlink(full_path.ptr) < 0) {
693
- if (failed)
694
- continue;
695
-
696
- giterr_set(GITERR_REFERENCE,
697
- "Failed to remove loose reference '%s' after packing: %s",
698
- full_path.ptr, strerror(errno));
77
+ git_reference *ref;
699
78
 
700
- failed = 1;
701
- }
79
+ assert(refdb && name && oid);
702
80
 
703
- /*
704
- * if we fail to remove a single file, this is *not* good,
705
- * but we should keep going and remove as many as possible.
706
- * After we've removed as many files as possible, we return
707
- * the error code anyway.
708
- */
709
- }
81
+ ref = alloc_ref(refdb, name);
82
+ if (!ref)
83
+ return NULL;
710
84
 
711
- git_buf_free(&full_path);
712
- return failed ? -1 : 0;
713
- }
85
+ ref->type = GIT_REF_OID;
86
+ git_oid_cpy(&ref->target.oid, oid);
714
87
 
715
- static int packed_sort(const void *a, const void *b)
716
- {
717
- const struct packref *ref_a = (const struct packref *)a;
718
- const struct packref *ref_b = (const struct packref *)b;
88
+ if (peel != NULL)
89
+ git_oid_cpy(&ref->peel, peel);
719
90
 
720
- return strcmp(ref_a->name, ref_b->name);
91
+ return ref;
721
92
  }
722
93
 
723
- /*
724
- * Write all the contents in the in-memory packfile to disk.
725
- */
726
- static int packed_write(git_repository *repo)
94
+ void git_reference_free(git_reference *reference)
727
95
  {
728
- git_filebuf pack_file = GIT_FILEBUF_INIT;
729
- unsigned int i;
730
- git_buf pack_file_path = GIT_BUF_INIT;
731
- git_vector packing_list;
732
- unsigned int total_refs;
733
-
734
- assert(repo && repo->references.packfile);
735
-
736
- total_refs =
737
- (unsigned int)git_strmap_num_entries(repo->references.packfile);
738
-
739
- if (git_vector_init(&packing_list, total_refs, packed_sort) < 0)
740
- return -1;
741
-
742
- /* Load all the packfile into a vector */
743
- {
744
- struct packref *reference;
745
-
746
- /* cannot fail: vector already has the right size */
747
- git_strmap_foreach_value(repo->references.packfile, reference, {
748
- git_vector_insert(&packing_list, reference);
749
- });
750
- }
751
-
752
- /* sort the vector so the entries appear sorted on the packfile */
753
- git_vector_sort(&packing_list);
754
-
755
- /* Now we can open the file! */
756
- if (git_buf_joinpath(&pack_file_path, repo->path_repository, GIT_PACKEDREFS_FILE) < 0)
757
- goto cleanup_memory;
758
-
759
- if (git_filebuf_open(&pack_file, pack_file_path.ptr, 0) < 0)
760
- goto cleanup_packfile;
761
-
762
- /* Packfiles have a header... apparently
763
- * This is in fact not required, but we might as well print it
764
- * just for kicks */
765
- if (git_filebuf_printf(&pack_file, "%s\n", GIT_PACKEDREFS_HEADER) < 0)
766
- goto cleanup_packfile;
767
-
768
- for (i = 0; i < packing_list.length; ++i) {
769
- struct packref *ref = (struct packref *)git_vector_get(&packing_list, i);
770
-
771
- if (packed_find_peel(repo, ref) < 0)
772
- goto cleanup_packfile;
773
-
774
- if (packed_write_ref(ref, &pack_file) < 0)
775
- goto cleanup_packfile;
776
- }
777
-
778
- /* if we've written all the references properly, we can commit
779
- * the packfile to make the changes effective */
780
- if (git_filebuf_commit(&pack_file, GIT_PACKEDREFS_FILE_MODE) < 0)
781
- goto cleanup_memory;
782
-
783
- /* when and only when the packfile has been properly written,
784
- * we can go ahead and remove the loose refs */
785
- if (packed_remove_loose(repo, &packing_list) < 0)
786
- goto cleanup_memory;
787
-
788
- {
789
- struct stat st;
790
- if (p_stat(pack_file_path.ptr, &st) == 0)
791
- repo->references.packfile_time = st.st_mtime;
792
- }
793
-
794
- git_vector_free(&packing_list);
795
- git_buf_free(&pack_file_path);
796
-
797
- /* we're good now */
798
- return 0;
799
-
800
- cleanup_packfile:
801
- git_filebuf_cleanup(&pack_file);
96
+ if (reference == NULL)
97
+ return;
802
98
 
803
- cleanup_memory:
804
- git_vector_free(&packing_list);
805
- git_buf_free(&pack_file_path);
99
+ if (reference->type == GIT_REF_SYMBOLIC)
100
+ git__free(reference->target.symbolic);
806
101
 
807
- return -1;
102
+ git__free(reference);
808
103
  }
809
104
 
810
105
  struct reference_available_t {
@@ -861,28 +156,6 @@ static int reference_path_available(
861
156
  return 0;
862
157
  }
863
158
 
864
- static int reference_exists(int *exists, git_repository *repo, const char *ref_name)
865
- {
866
- git_buf ref_path = GIT_BUF_INIT;
867
-
868
- if (packed_load(repo) < 0)
869
- return -1;
870
-
871
- if (git_buf_joinpath(&ref_path, repo->path_repository, ref_name) < 0)
872
- return -1;
873
-
874
- if (git_path_isfile(ref_path.ptr) == true ||
875
- git_strmap_exists(repo->references.packfile, ref_path.ptr))
876
- {
877
- *exists = 1;
878
- } else {
879
- *exists = 0;
880
- }
881
-
882
- git_buf_free(&ref_path);
883
- return 0;
884
- }
885
-
886
159
  /*
887
160
  * Check if a reference could be written to disk, based on:
888
161
  *
@@ -898,6 +171,11 @@ static int reference_can_write(
898
171
  const char *previous_name,
899
172
  int force)
900
173
  {
174
+ git_refdb *refdb;
175
+
176
+ if (git_repository_refdb__weakptr(&refdb, repo) < 0)
177
+ return -1;
178
+
901
179
  /* see if the reference shares a path with an existing reference;
902
180
  * if a path is shared, we cannot create the reference, even when forcing */
903
181
  if (reference_path_available(repo, refname, previous_name) < 0)
@@ -908,166 +186,36 @@ static int reference_can_write(
908
186
  if (!force) {
909
187
  int exists;
910
188
 
911
- if (reference_exists(&exists, repo, refname) < 0)
189
+ if (git_refdb_exists(&exists, refdb, refname) < 0)
912
190
  return -1;
913
191
 
914
192
  /* We cannot proceed if the reference already exists and we're not forcing
915
193
  * the rename; the existing one would be overwritten */
916
194
  if (exists) {
917
195
  giterr_set(GITERR_REFERENCE,
918
- "A reference with that name (%s) already exists", refname);
919
- return GIT_EEXISTS;
920
- }
921
- }
922
-
923
- /* FIXME: if the reference exists and we are forcing, do we really need to
924
- * remove the reference first?
925
- *
926
- * Two cases:
927
- *
928
- * - the reference already exists and is loose: not a problem, the file
929
- * gets overwritten on disk
930
- *
931
- * - the reference already exists and is packed: we write a new one as
932
- * loose, which by all means renders the packed one useless
933
- */
934
-
935
- return 0;
936
- }
937
-
938
-
939
- static int packed_lookup(git_reference *ref)
940
- {
941
- struct packref *pack_ref = NULL;
942
- git_strmap *packfile_refs;
943
- khiter_t pos;
944
-
945
- if (packed_load(ref->owner) < 0)
946
- return -1;
947
-
948
- /* maybe the packfile hasn't changed at all, so we don't
949
- * have to re-lookup the reference */
950
- if ((ref->flags & GIT_REF_PACKED) &&
951
- ref->mtime == ref->owner->references.packfile_time)
952
- return 0;
953
-
954
- if (ref->flags & GIT_REF_SYMBOLIC) {
955
- git__free(ref->target.symbolic);
956
- ref->target.symbolic = NULL;
957
- }
958
-
959
- /* Look up on the packfile */
960
- packfile_refs = ref->owner->references.packfile;
961
- pos = git_strmap_lookup_index(packfile_refs, ref->name);
962
- if (!git_strmap_valid_index(packfile_refs, pos)) {
963
- giterr_set(GITERR_REFERENCE, "Reference '%s' not found", ref->name);
964
- return GIT_ENOTFOUND;
965
- }
966
-
967
- pack_ref = git_strmap_value_at(packfile_refs, pos);
968
-
969
- ref->flags = GIT_REF_OID | GIT_REF_PACKED;
970
- ref->mtime = ref->owner->references.packfile_time;
971
- git_oid_cpy(&ref->target.oid, &pack_ref->oid);
972
-
973
- return 0;
974
- }
975
-
976
- static int reference_lookup(git_reference *ref)
977
- {
978
- int result;
979
-
980
- result = loose_lookup(ref);
981
- if (result == 0)
982
- return 0;
983
-
984
- /* only try to lookup this reference on the packfile if it
985
- * wasn't found on the loose refs; not if there was a critical error */
986
- if (result == GIT_ENOTFOUND) {
987
- giterr_clear();
988
- result = packed_lookup(ref);
989
- if (result == 0)
990
- return 0;
991
- }
992
-
993
- /* unexpected error; free the reference */
994
- git_reference_free(ref);
995
- return result;
996
- }
997
-
998
- /*
999
- * Delete a reference.
1000
- * This is an internal method; the reference is removed
1001
- * from disk or the packfile, but the pointer is not freed
1002
- */
1003
- static int reference_delete(git_reference *ref)
1004
- {
1005
- int result;
1006
-
1007
- assert(ref);
1008
-
1009
- /* If the reference is packed, this is an expensive operation.
1010
- * We need to reload the packfile, remove the reference from the
1011
- * packing list, and repack */
1012
- if (ref->flags & GIT_REF_PACKED) {
1013
- git_strmap *packfile_refs;
1014
- struct packref *packref;
1015
- khiter_t pos;
1016
-
1017
- /* load the existing packfile */
1018
- if (packed_load(ref->owner) < 0)
1019
- return -1;
1020
-
1021
- packfile_refs = ref->owner->references.packfile;
1022
- pos = git_strmap_lookup_index(packfile_refs, ref->name);
1023
- if (!git_strmap_valid_index(packfile_refs, pos)) {
1024
- giterr_set(GITERR_REFERENCE,
1025
- "Reference %s stopped existing in the packfile", ref->name);
1026
- return -1;
1027
- }
1028
-
1029
- packref = git_strmap_value_at(packfile_refs, pos);
1030
- git_strmap_delete_at(packfile_refs, pos);
1031
-
1032
- git__free(packref);
1033
- if (packed_write(ref->owner) < 0)
1034
- return -1;
1035
-
1036
- /* If the reference is loose, we can just remove the reference
1037
- * from the filesystem */
1038
- } else {
1039
- git_reference *ref_in_pack;
1040
- git_buf full_path = GIT_BUF_INIT;
1041
-
1042
- if (git_buf_joinpath(&full_path, ref->owner->path_repository, ref->name) < 0)
1043
- return -1;
1044
-
1045
- result = p_unlink(full_path.ptr);
1046
- git_buf_free(&full_path); /* done with path at this point */
1047
-
1048
- if (result < 0) {
1049
- giterr_set(GITERR_OS, "Failed to unlink '%s'", full_path.ptr);
1050
- return -1;
1051
- }
1052
-
1053
- /* When deleting a loose reference, we have to ensure that an older
1054
- * packed version of it doesn't exist */
1055
- if (git_reference_lookup(&ref_in_pack, ref->owner, ref->name) == 0) {
1056
- assert((ref_in_pack->flags & GIT_REF_PACKED) != 0);
1057
- return git_reference_delete(ref_in_pack);
196
+ "A reference with that name (%s) already exists", refname);
197
+ return GIT_EEXISTS;
1058
198
  }
1059
-
1060
- giterr_clear();
1061
199
  }
1062
200
 
201
+ /* FIXME: if the reference exists and we are forcing, do we really need to
202
+ * remove the reference first?
203
+ *
204
+ * Two cases:
205
+ *
206
+ * - the reference already exists and is loose: not a problem, the file
207
+ * gets overwritten on disk
208
+ *
209
+ * - the reference already exists and is packed: we write a new one as
210
+ * loose, which by all means renders the packed one useless
211
+ */
212
+
1063
213
  return 0;
1064
214
  }
1065
215
 
1066
216
  int git_reference_delete(git_reference *ref)
1067
217
  {
1068
- int result = reference_delete(ref);
1069
- git_reference_free(ref);
1070
- return result;
218
+ return git_refdb_delete(ref->db, ref);
1071
219
  }
1072
220
 
1073
221
  int git_reference_lookup(git_reference **ref_out,
@@ -1076,7 +224,7 @@ int git_reference_lookup(git_reference **ref_out,
1076
224
  return git_reference_lookup_resolved(ref_out, repo, name, 0);
1077
225
  }
1078
226
 
1079
- int git_reference_name_to_oid(
227
+ int git_reference_name_to_id(
1080
228
  git_oid *out, git_repository *repo, const char *name)
1081
229
  {
1082
230
  int error;
@@ -1085,7 +233,7 @@ int git_reference_name_to_oid(
1085
233
  if ((error = git_reference_lookup_resolved(&ref, repo, name, -1)) < 0)
1086
234
  return error;
1087
235
 
1088
- git_oid_cpy(out, git_reference_oid(ref));
236
+ git_oid_cpy(out, git_reference_target(ref));
1089
237
  git_reference_free(ref);
1090
238
  return 0;
1091
239
  }
@@ -1096,8 +244,11 @@ int git_reference_lookup_resolved(
1096
244
  const char *name,
1097
245
  int max_nesting)
1098
246
  {
1099
- git_reference *scan;
1100
- int result, nesting;
247
+ char scan_name[GIT_REFNAME_MAX];
248
+ git_ref_t scan_type;
249
+ int error = 0, nesting;
250
+ git_reference *ref = NULL;
251
+ git_refdb *refdb;
1101
252
 
1102
253
  assert(ref_out && repo && name);
1103
254
 
@@ -1107,419 +258,316 @@ int git_reference_lookup_resolved(
1107
258
  max_nesting = MAX_NESTING_LEVEL;
1108
259
  else if (max_nesting < 0)
1109
260
  max_nesting = DEFAULT_NESTING_LEVEL;
261
+
262
+ strncpy(scan_name, name, GIT_REFNAME_MAX);
263
+ scan_type = GIT_REF_SYMBOLIC;
264
+
265
+ if ((error = git_repository_refdb__weakptr(&refdb, repo)) < 0)
266
+ return -1;
1110
267
 
1111
- scan = git__calloc(1, sizeof(git_reference));
1112
- GITERR_CHECK_ALLOC(scan);
1113
-
1114
- scan->name = git__calloc(GIT_REFNAME_MAX + 1, sizeof(char));
1115
- GITERR_CHECK_ALLOC(scan->name);
1116
-
1117
- if ((result = git_reference__normalize_name_lax(
1118
- scan->name,
1119
- GIT_REFNAME_MAX,
1120
- name)) < 0) {
1121
- git_reference_free(scan);
1122
- return result;
1123
- }
1124
-
1125
- scan->target.symbolic = git__strdup(scan->name);
1126
- GITERR_CHECK_ALLOC(scan->target.symbolic);
1127
-
1128
- scan->owner = repo;
1129
- scan->flags = GIT_REF_SYMBOLIC;
268
+ if ((error = git_reference__normalize_name_lax(scan_name, GIT_REFNAME_MAX, name)) < 0)
269
+ return error;
1130
270
 
1131
271
  for (nesting = max_nesting;
1132
- nesting >= 0 && (scan->flags & GIT_REF_SYMBOLIC) != 0;
272
+ nesting >= 0 && scan_type == GIT_REF_SYMBOLIC;
1133
273
  nesting--)
1134
274
  {
1135
- if (nesting != max_nesting)
1136
- strncpy(scan->name, scan->target.symbolic, GIT_REFNAME_MAX);
1137
-
1138
- scan->mtime = 0;
275
+ if (nesting != max_nesting) {
276
+ strncpy(scan_name, ref->target.symbolic, GIT_REFNAME_MAX);
277
+ git_reference_free(ref);
278
+ }
1139
279
 
1140
- if ((result = reference_lookup(scan)) < 0)
1141
- return result; /* lookup git_reference_free on scan already */
280
+ if ((error = git_refdb_lookup(&ref, refdb, scan_name)) < 0)
281
+ return error;
282
+
283
+ scan_type = ref->type;
1142
284
  }
1143
285
 
1144
- if ((scan->flags & GIT_REF_OID) == 0 && max_nesting != 0) {
286
+ if (scan_type != GIT_REF_OID && max_nesting != 0) {
1145
287
  giterr_set(GITERR_REFERENCE,
1146
288
  "Cannot resolve reference (>%u levels deep)", max_nesting);
1147
- git_reference_free(scan);
289
+ git_reference_free(ref);
1148
290
  return -1;
1149
291
  }
1150
292
 
1151
- *ref_out = scan;
293
+ *ref_out = ref;
1152
294
  return 0;
1153
295
  }
1154
296
 
1155
297
  /**
1156
298
  * Getters
1157
299
  */
1158
- git_ref_t git_reference_type(git_reference *ref)
300
+ git_ref_t git_reference_type(const git_reference *ref)
1159
301
  {
1160
302
  assert(ref);
1161
-
1162
- if (ref->flags & GIT_REF_OID)
1163
- return GIT_REF_OID;
1164
-
1165
- if (ref->flags & GIT_REF_SYMBOLIC)
1166
- return GIT_REF_SYMBOLIC;
1167
-
1168
- return GIT_REF_INVALID;
303
+ return ref->type;
1169
304
  }
1170
305
 
1171
- int git_reference_is_packed(git_reference *ref)
306
+ const char *git_reference_name(const git_reference *ref)
1172
307
  {
1173
308
  assert(ref);
1174
- return !!(ref->flags & GIT_REF_PACKED);
309
+ return ref->name;
1175
310
  }
1176
311
 
1177
- const char *git_reference_name(git_reference *ref)
312
+ git_repository *git_reference_owner(const git_reference *ref)
1178
313
  {
1179
314
  assert(ref);
1180
- return ref->name;
315
+ return ref->db->repo;
1181
316
  }
1182
317
 
1183
- git_repository *git_reference_owner(git_reference *ref)
318
+ const git_oid *git_reference_target(const git_reference *ref)
1184
319
  {
1185
320
  assert(ref);
1186
- return ref->owner;
321
+
322
+ if (ref->type != GIT_REF_OID)
323
+ return NULL;
324
+
325
+ return &ref->target.oid;
1187
326
  }
1188
327
 
1189
- const git_oid *git_reference_oid(git_reference *ref)
328
+ const git_oid *git_reference_target_peel(const git_reference *ref)
1190
329
  {
1191
330
  assert(ref);
1192
331
 
1193
- if ((ref->flags & GIT_REF_OID) == 0)
332
+ if (ref->type != GIT_REF_OID || git_oid_iszero(&ref->peel))
1194
333
  return NULL;
1195
334
 
1196
- return &ref->target.oid;
335
+ return &ref->peel;
1197
336
  }
1198
337
 
1199
- const char *git_reference_target(git_reference *ref)
338
+ const char *git_reference_symbolic_target(const git_reference *ref)
1200
339
  {
1201
340
  assert(ref);
1202
341
 
1203
- if ((ref->flags & GIT_REF_SYMBOLIC) == 0)
342
+ if (ref->type != GIT_REF_SYMBOLIC)
1204
343
  return NULL;
1205
344
 
1206
345
  return ref->target.symbolic;
1207
346
  }
1208
347
 
1209
- int git_reference_create_symbolic(
348
+ static int reference__create(
1210
349
  git_reference **ref_out,
1211
350
  git_repository *repo,
1212
351
  const char *name,
1213
- const char *target,
352
+ const git_oid *oid,
353
+ const char *symbolic,
1214
354
  int force)
1215
355
  {
1216
356
  char normalized[GIT_REFNAME_MAX];
357
+ git_refdb *refdb;
1217
358
  git_reference *ref = NULL;
1218
- int error;
1219
-
1220
- if (git_reference__normalize_name_lax(
1221
- normalized,
1222
- sizeof(normalized),
1223
- name) < 0)
1224
- return -1;
359
+ int error = 0;
360
+
361
+ if (ref_out)
362
+ *ref_out = NULL;
1225
363
 
1226
- if ((error = reference_can_write(repo, normalized, NULL, force)) < 0)
364
+ if ((error = git_reference__normalize_name_lax(normalized, sizeof(normalized), name)) < 0 ||
365
+ (error = reference_can_write(repo, normalized, NULL, force)) < 0 ||
366
+ (error = git_repository_refdb__weakptr(&refdb, repo)) < 0)
1227
367
  return error;
1228
368
 
1229
- if (reference_alloc(&ref, repo, normalized) < 0)
1230
- return -1;
1231
-
1232
- ref->flags |= GIT_REF_SYMBOLIC;
369
+ if (oid != NULL) {
370
+ assert(symbolic == NULL);
371
+ ref = git_reference__alloc(refdb, name, oid, NULL);
372
+ } else {
373
+ ref = git_reference__alloc_symbolic(refdb, name, symbolic);
374
+ }
375
+
376
+ GITERR_CHECK_ALLOC(ref);
1233
377
 
1234
- /* set the target; this will normalize the name automatically
1235
- * and write the reference on disk */
1236
- if (git_reference_set_target(ref, target) < 0) {
378
+ if ((error = git_refdb_write(refdb, ref)) < 0) {
1237
379
  git_reference_free(ref);
1238
- return -1;
380
+ return error;
1239
381
  }
1240
- if (ref_out == NULL) {
382
+
383
+ if (ref_out == NULL)
1241
384
  git_reference_free(ref);
1242
- } else {
385
+ else
1243
386
  *ref_out = ref;
1244
- }
1245
387
 
1246
388
  return 0;
1247
389
  }
1248
390
 
1249
- int git_reference_create_oid(
391
+ int git_reference_create(
1250
392
  git_reference **ref_out,
1251
393
  git_repository *repo,
1252
394
  const char *name,
1253
- const git_oid *id,
395
+ const git_oid *oid,
1254
396
  int force)
1255
397
  {
1256
- int error;
1257
- git_reference *ref = NULL;
1258
- char normalized[GIT_REFNAME_MAX];
1259
-
1260
- if (git_reference__normalize_name_lax(
1261
- normalized,
1262
- sizeof(normalized),
1263
- name) < 0)
1264
- return -1;
398
+ git_odb *odb;
399
+ int error = 0;
1265
400
 
1266
- if ((error = reference_can_write(repo, normalized, NULL, force)) < 0)
401
+ assert(repo && name && oid);
402
+
403
+ /* Sanity check the reference being created - target must exist. */
404
+ if ((error = git_repository_odb__weakptr(&odb, repo)) < 0)
1267
405
  return error;
1268
-
1269
- if (reference_alloc(&ref, repo, name) < 0)
1270
- return -1;
1271
-
1272
- ref->flags |= GIT_REF_OID;
1273
-
1274
- /* set the oid; this will write the reference on disk */
1275
- if (git_reference_set_oid(ref, id) < 0) {
1276
- git_reference_free(ref);
406
+
407
+ if (!git_odb_exists(odb, oid)) {
408
+ giterr_set(GITERR_REFERENCE,
409
+ "Target OID for the reference doesn't exist on the repository");
1277
410
  return -1;
1278
411
  }
1279
-
1280
- if (ref_out == NULL) {
1281
- git_reference_free(ref);
1282
- } else {
1283
- *ref_out = ref;
1284
- }
1285
-
1286
- return 0;
412
+
413
+ return reference__create(ref_out, repo, name, oid, NULL, force);
1287
414
  }
1288
- /*
1289
- * Change the OID target of a reference.
1290
- *
1291
- * For both loose and packed references, just change
1292
- * the oid in memory and (over)write the file in disk.
1293
- *
1294
- * We do not repack packed references because of performance
1295
- * reasons.
1296
- */
1297
- int git_reference_set_oid(git_reference *ref, const git_oid *id)
1298
- {
1299
- git_odb *odb = NULL;
1300
415
 
1301
- if ((ref->flags & GIT_REF_OID) == 0) {
1302
- giterr_set(GITERR_REFERENCE, "Cannot set OID on symbolic reference");
1303
- return -1;
1304
- }
416
+ int git_reference_symbolic_create(
417
+ git_reference **ref_out,
418
+ git_repository *repo,
419
+ const char *name,
420
+ const char *target,
421
+ int force)
422
+ {
423
+ char normalized[GIT_REFNAME_MAX];
424
+ int error = 0;
1305
425
 
1306
- assert(ref->owner);
426
+ assert(repo && name && target);
427
+
428
+ if ((error = git_reference__normalize_name_lax(
429
+ normalized, sizeof(normalized), target)) < 0)
430
+ return error;
1307
431
 
1308
- if (git_repository_odb__weakptr(&odb, ref->owner) < 0)
1309
- return -1;
432
+ return reference__create(ref_out, repo, name, NULL, normalized, force);
433
+ }
1310
434
 
1311
- /* Don't let the user create references to OIDs that
1312
- * don't exist in the ODB */
1313
- if (!git_odb_exists(odb, id)) {
1314
- giterr_set(GITERR_REFERENCE,
1315
- "Target OID for the reference doesn't exist on the repository");
435
+ int git_reference_set_target(
436
+ git_reference **out,
437
+ git_reference *ref,
438
+ const git_oid *id)
439
+ {
440
+ assert(out && ref && id);
441
+
442
+ if (ref->type != GIT_REF_OID) {
443
+ giterr_set(GITERR_REFERENCE, "Cannot set OID on symbolic reference");
1316
444
  return -1;
1317
445
  }
1318
446
 
1319
- /* Update the OID value on `ref` */
1320
- git_oid_cpy(&ref->target.oid, id);
1321
-
1322
- /* Write back to disk */
1323
- return loose_write(ref);
447
+ return git_reference_create(out, ref->db->repo, ref->name, id, 1);
1324
448
  }
1325
449
 
1326
- /*
1327
- * Change the target of a symbolic reference.
1328
- *
1329
- * This is easy because symrefs cannot be inside
1330
- * a pack. We just change the target in memory
1331
- * and overwrite the file on disk.
1332
- */
1333
- int git_reference_set_target(git_reference *ref, const char *target)
450
+ int git_reference_symbolic_set_target(
451
+ git_reference **out,
452
+ git_reference *ref,
453
+ const char *target)
1334
454
  {
1335
- char normalized[GIT_REFNAME_MAX];
1336
-
1337
- if ((ref->flags & GIT_REF_SYMBOLIC) == 0) {
455
+ assert(out && ref && target);
456
+
457
+ if (ref->type != GIT_REF_SYMBOLIC) {
1338
458
  giterr_set(GITERR_REFERENCE,
1339
459
  "Cannot set symbolic target on a direct reference");
1340
460
  return -1;
1341
461
  }
1342
-
1343
- if (git_reference__normalize_name_lax(
1344
- normalized,
1345
- sizeof(normalized),
1346
- target))
1347
- return -1;
1348
-
1349
- git__free(ref->target.symbolic);
1350
- ref->target.symbolic = git__strdup(normalized);
1351
- GITERR_CHECK_ALLOC(ref->target.symbolic);
1352
-
1353
- return loose_write(ref);
462
+
463
+ return git_reference_symbolic_create(out, ref->db->repo, ref->name, target, 1);
1354
464
  }
1355
465
 
1356
- int git_reference_rename(git_reference *ref, const char *new_name, int force)
466
+ int git_reference_rename(
467
+ git_reference **out,
468
+ git_reference *ref,
469
+ const char *new_name,
470
+ int force)
1357
471
  {
1358
- int result;
1359
472
  unsigned int normalization_flags;
1360
- git_buf aux_path = GIT_BUF_INIT;
1361
473
  char normalized[GIT_REFNAME_MAX];
1362
474
  bool should_head_be_updated = false;
475
+ git_reference *result = NULL;
476
+ int error = 0;
477
+ int reference_has_log;
478
+
479
+ *out = NULL;
1363
480
 
1364
- normalization_flags = ref->flags & GIT_REF_SYMBOLIC ?
1365
- GIT_REF_FORMAT_ALLOW_ONELEVEL
1366
- : GIT_REF_FORMAT_NORMAL;
1367
-
1368
- if (git_reference_normalize_name(
1369
- normalized,
1370
- sizeof(normalized),
1371
- new_name,
1372
- normalization_flags) < 0)
1373
- return -1;
1374
-
1375
- if ((result = reference_can_write(ref->owner, normalized, ref->name, force)) < 0)
1376
- return result;
1377
-
1378
- /* Initialize path now so we won't get an allocation failure once
1379
- * we actually start removing things. */
1380
- if (git_buf_joinpath(&aux_path, ref->owner->path_repository, new_name) < 0)
1381
- return -1;
1382
-
1383
- /*
1384
- * Check if we have to update HEAD.
1385
- */
1386
- if ((should_head_be_updated = git_branch_is_head(ref)) < 0)
1387
- goto cleanup;
481
+ normalization_flags = ref->type == GIT_REF_SYMBOLIC ?
482
+ GIT_REF_FORMAT_ALLOW_ONELEVEL : GIT_REF_FORMAT_NORMAL;
1388
483
 
1389
- /*
1390
- * Now delete the old ref and remove an possibly existing directory
1391
- * named `new_name`. Note that using the internal `reference_delete`
1392
- * method deletes the ref from disk but doesn't free the pointer, so
1393
- * we can still access the ref's attributes for creating the new one
1394
- */
1395
- if (reference_delete(ref) < 0)
1396
- goto cleanup;
484
+ if ((error = git_reference_normalize_name(
485
+ normalized, sizeof(normalized), new_name, normalization_flags)) < 0 ||
486
+ (error = reference_can_write(ref->db->repo, normalized, ref->name, force)) < 0)
487
+ return error;
1397
488
 
1398
489
  /*
1399
- * Finally we can create the new reference.
490
+ * Create the new reference.
1400
491
  */
1401
- if (ref->flags & GIT_REF_SYMBOLIC) {
1402
- result = git_reference_create_symbolic(
1403
- NULL, ref->owner, new_name, ref->target.symbolic, force);
492
+ if (ref->type == GIT_REF_OID) {
493
+ result = git_reference__alloc(ref->db, new_name,
494
+ &ref->target.oid, &ref->peel);
495
+ } else if (ref->type == GIT_REF_SYMBOLIC) {
496
+ result = git_reference__alloc_symbolic(ref->db, new_name, ref->target.symbolic);
1404
497
  } else {
1405
- result = git_reference_create_oid(
1406
- NULL, ref->owner, new_name, &ref->target.oid, force);
498
+ assert(0);
1407
499
  }
1408
500
 
1409
- if (result < 0)
1410
- goto rollback;
501
+ if (result == NULL)
502
+ return -1;
1411
503
 
1412
- /*
1413
- * Update HEAD it was poiting to the reference being renamed.
1414
- */
1415
- if (should_head_be_updated &&
1416
- git_repository_set_head(ref->owner, new_name) < 0) {
1417
- giterr_set(GITERR_REFERENCE,
1418
- "Failed to update HEAD after renaming reference");
1419
- goto cleanup;
1420
- }
504
+ /* Check if we have to update HEAD. */
505
+ if ((error = git_branch_is_head(ref)) < 0)
506
+ goto on_error;
1421
507
 
1422
- /*
1423
- * Rename the reflog file, if it exists.
1424
- */
1425
- if ((git_reference_has_log(ref)) && (git_reflog_rename(ref, new_name) < 0))
1426
- goto cleanup;
508
+ should_head_be_updated = (error > 0);
1427
509
 
1428
- /*
1429
- * Change the name of the reference given by the user.
1430
- */
1431
- git__free(ref->name);
1432
- ref->name = git__strdup(new_name);
510
+ /* Now delete the old ref and save the new one. */
511
+ if ((error = git_refdb_delete(ref->db, ref)) < 0)
512
+ goto on_error;
513
+
514
+ /* Save the new reference. */
515
+ if ((error = git_refdb_write(ref->db, result)) < 0)
516
+ goto rollback;
517
+
518
+ /* Update HEAD it was poiting to the reference being renamed. */
519
+ if (should_head_be_updated && (error = git_repository_set_head(ref->db->repo, new_name)) < 0) {
520
+ giterr_set(GITERR_REFERENCE, "Failed to update HEAD after renaming reference");
521
+ goto on_error;
522
+ }
1433
523
 
1434
- /* The reference is no longer packed */
1435
- ref->flags &= ~GIT_REF_PACKED;
524
+ /* Rename the reflog file, if it exists. */
525
+ reference_has_log = git_reference_has_log(ref);
526
+ if (reference_has_log < 0) {
527
+ error = reference_has_log;
528
+ goto on_error;
529
+ }
530
+ if (reference_has_log && (error = git_reflog_rename(ref, new_name)) < 0)
531
+ goto on_error;
1436
532
 
1437
- git_buf_free(&aux_path);
1438
- return 0;
533
+ *out = result;
1439
534
 
1440
- cleanup:
1441
- git_buf_free(&aux_path);
1442
- return -1;
535
+ return error;
1443
536
 
1444
537
  rollback:
1445
- /*
1446
- * Try to create the old reference again, ignore failures
1447
- */
1448
- if (ref->flags & GIT_REF_SYMBOLIC)
1449
- git_reference_create_symbolic(
1450
- NULL, ref->owner, ref->name, ref->target.symbolic, 0);
1451
- else
1452
- git_reference_create_oid(
1453
- NULL, ref->owner, ref->name, &ref->target.oid, 0);
538
+ git_refdb_write(ref->db, ref);
1454
539
 
1455
- /* The reference is no longer packed */
1456
- ref->flags &= ~GIT_REF_PACKED;
540
+ on_error:
541
+ git_reference_free(result);
1457
542
 
1458
- git_buf_free(&aux_path);
1459
- return -1;
543
+ return error;
1460
544
  }
1461
545
 
1462
- int git_reference_resolve(git_reference **ref_out, git_reference *ref)
546
+ int git_reference_resolve(git_reference **ref_out, const git_reference *ref)
1463
547
  {
1464
- if (ref->flags & GIT_REF_OID)
1465
- return git_reference_lookup(ref_out, ref->owner, ref->name);
1466
- else
1467
- return git_reference_lookup_resolved(ref_out, ref->owner, ref->target.symbolic, -1);
1468
- }
548
+ switch (git_reference_type(ref)) {
549
+ case GIT_REF_OID:
550
+ return git_reference_lookup(ref_out, ref->db->repo, ref->name);
551
+
552
+ case GIT_REF_SYMBOLIC:
553
+ return git_reference_lookup_resolved(ref_out, ref->db->repo, ref->target.symbolic, -1);
1469
554
 
1470
- int git_reference_packall(git_repository *repo)
1471
- {
1472
- if (packed_load(repo) < 0 || /* load the existing packfile */
1473
- packed_loadloose(repo) < 0 || /* add all the loose refs */
1474
- packed_write(repo) < 0) /* write back to disk */
555
+ default:
556
+ giterr_set(GITERR_REFERENCE, "Invalid reference");
1475
557
  return -1;
1476
-
1477
- return 0;
558
+ }
1478
559
  }
1479
560
 
1480
561
  int git_reference_foreach(
1481
562
  git_repository *repo,
1482
563
  unsigned int list_flags,
1483
- int (*callback)(const char *, void *),
564
+ git_reference_foreach_cb callback,
1484
565
  void *payload)
1485
566
  {
1486
- int result;
1487
- struct dirent_list_data data;
1488
- git_buf refs_path = GIT_BUF_INIT;
1489
-
1490
- /* list all the packed references first */
1491
- if (list_flags & GIT_REF_PACKED) {
1492
- const char *ref_name;
1493
- void *ref;
1494
- GIT_UNUSED(ref);
1495
-
1496
- if (packed_load(repo) < 0)
1497
- return -1;
1498
-
1499
- git_strmap_foreach(repo->references.packfile, ref_name, ref, {
1500
- if (callback(ref_name, payload))
1501
- return GIT_EUSER;
1502
- });
1503
- }
1504
-
1505
- /* now list the loose references, trying not to
1506
- * duplicate the ref names already in the packed-refs file */
1507
-
1508
- data.repo_path_len = strlen(repo->path_repository);
1509
- data.list_flags = list_flags;
1510
- data.repo = repo;
1511
- data.callback = callback;
1512
- data.callback_payload = payload;
1513
- data.callback_error = 0;
1514
-
1515
- if (git_buf_joinpath(&refs_path, repo->path_repository, GIT_REFS_DIR) < 0)
1516
- return -1;
567
+ git_refdb *refdb;
568
+ git_repository_refdb__weakptr(&refdb, repo);
1517
569
 
1518
- result = git_path_direach(&refs_path, _dirent_loose_listall, &data);
1519
-
1520
- git_buf_free(&refs_path);
1521
-
1522
- return data.callback_error ? GIT_EUSER : result;
570
+ return git_refdb_foreach(refdb, list_flags, callback, payload);
1523
571
  }
1524
572
 
1525
573
  static int cb__reflist_add(const char *ref, void *data)
@@ -1553,26 +601,6 @@ int git_reference_list(
1553
601
  return 0;
1554
602
  }
1555
603
 
1556
- int git_reference_reload(git_reference *ref)
1557
- {
1558
- return reference_lookup(ref);
1559
- }
1560
-
1561
- void git_repository__refcache_free(git_refcache *refs)
1562
- {
1563
- assert(refs);
1564
-
1565
- if (refs->packfile) {
1566
- struct packref *reference;
1567
-
1568
- git_strmap_foreach_value(refs->packfile, reference, {
1569
- git__free(reference);
1570
- });
1571
-
1572
- git_strmap_free(refs->packfile);
1573
- }
1574
- }
1575
-
1576
604
  static int is_valid_ref_char(char ch)
1577
605
  {
1578
606
  if ((unsigned) ch <= ' ')
@@ -1596,6 +624,8 @@ static int ensure_segment_validity(const char *name)
1596
624
  {
1597
625
  const char *current = name;
1598
626
  char prev = '\0';
627
+ const int lock_len = (int)strlen(GIT_FILELOCK_EXTENSION);
628
+ int segment_len;
1599
629
 
1600
630
  if (*current == '.')
1601
631
  return -1; /* Refname starts with "." */
@@ -1616,7 +646,14 @@ static int ensure_segment_validity(const char *name)
1616
646
  prev = *current;
1617
647
  }
1618
648
 
1619
- return (int)(current - name);
649
+ segment_len = (int)(current - name);
650
+
651
+ /* A refname component can not end with ".lock" */
652
+ if (segment_len >= lock_len &&
653
+ !memcmp(current - lock_len, GIT_FILELOCK_EXTENSION, lock_len))
654
+ return -1;
655
+
656
+ return segment_len;
1620
657
  }
1621
658
 
1622
659
  static bool is_all_caps_and_underscore(const char *name, size_t len)
@@ -1647,7 +684,7 @@ int git_reference__normalize_name(
1647
684
  // Inspired from https://github.com/git/git/blob/f06d47e7e0d9db709ee204ed13a8a7486149f494/refs.c#L36-100
1648
685
 
1649
686
  char *current;
1650
- int segment_len, segments_count = 0, error = -1;
687
+ int segment_len, segments_count = 0, error = GIT_EINVALIDSPEC;
1651
688
  unsigned int process_flags;
1652
689
  bool normalize = (buf != NULL);
1653
690
  assert(name);
@@ -1655,6 +692,9 @@ int git_reference__normalize_name(
1655
692
  process_flags = flags;
1656
693
  current = (char *)name;
1657
694
 
695
+ if (*current == '/')
696
+ goto cleanup;
697
+
1658
698
  if (normalize)
1659
699
  git_buf_clear(buf);
1660
700
 
@@ -1679,13 +719,19 @@ int git_reference__normalize_name(
1679
719
  git_buf_truncate(buf,
1680
720
  cur_len + segment_len + (segments_count ? 1 : 0));
1681
721
 
1682
- if (git_buf_oom(buf))
722
+ if (git_buf_oom(buf)) {
723
+ error = -1;
1683
724
  goto cleanup;
725
+ }
1684
726
  }
1685
727
 
1686
728
  segments_count++;
1687
729
  }
1688
730
 
731
+ /* No empty segment is allowed when not normalizing */
732
+ if (segment_len == 0 && !normalize)
733
+ goto cleanup;
734
+
1689
735
  if (current[segment_len] == '\0')
1690
736
  break;
1691
737
 
@@ -1704,10 +750,6 @@ int git_reference__normalize_name(
1704
750
  if (current[segment_len - 1] == '/')
1705
751
  goto cleanup;
1706
752
 
1707
- /* A refname can not end with ".lock" */
1708
- if (!git__suffixcmp(name, GIT_FILELOCK_EXTENSION))
1709
- goto cleanup;
1710
-
1711
753
  if ((segments_count == 1 ) && !(flags & GIT_REF_FORMAT_ALLOW_ONELEVEL))
1712
754
  goto cleanup;
1713
755
 
@@ -1723,11 +765,14 @@ int git_reference__normalize_name(
1723
765
  error = 0;
1724
766
 
1725
767
  cleanup:
1726
- if (error)
768
+ if (error == GIT_EINVALIDSPEC)
1727
769
  giterr_set(
1728
770
  GITERR_REFERENCE,
1729
771
  "The given reference name '%s' is not valid", name);
1730
772
 
773
+ if (error && normalize)
774
+ git_buf_free(buf);
775
+
1731
776
  return error;
1732
777
  }
1733
778
 
@@ -1775,92 +820,69 @@ int git_reference__normalize_name_lax(
1775
820
 
1776
821
  int git_reference_cmp(git_reference *ref1, git_reference *ref2)
1777
822
  {
823
+ git_ref_t type1, type2;
1778
824
  assert(ref1 && ref2);
1779
825
 
826
+ type1 = git_reference_type(ref1);
827
+ type2 = git_reference_type(ref2);
828
+
1780
829
  /* let's put symbolic refs before OIDs */
1781
- if ((ref1->flags & GIT_REF_TYPEMASK) != (ref2->flags & GIT_REF_TYPEMASK))
1782
- return (ref1->flags & GIT_REF_SYMBOLIC) ? -1 : 1;
830
+ if (type1 != type2)
831
+ return (type1 == GIT_REF_SYMBOLIC) ? -1 : 1;
1783
832
 
1784
- if (ref1->flags & GIT_REF_SYMBOLIC)
833
+ if (type1 == GIT_REF_SYMBOLIC)
1785
834
  return strcmp(ref1->target.symbolic, ref2->target.symbolic);
1786
835
 
1787
836
  return git_oid_cmp(&ref1->target.oid, &ref2->target.oid);
1788
837
  }
1789
838
 
1790
- /* Update the reference named `ref_name` so it points to `oid` */
1791
- int git_reference__update(git_repository *repo, const git_oid *oid, const char *ref_name)
839
+ static int reference__update_terminal(
840
+ git_repository *repo,
841
+ const char *ref_name,
842
+ const git_oid *oid,
843
+ int nesting)
1792
844
  {
1793
845
  git_reference *ref;
1794
- int res;
846
+ int error = 0;
1795
847
 
1796
- res = git_reference_lookup(&ref, repo, ref_name);
848
+ if (nesting > MAX_NESTING_LEVEL)
849
+ return GIT_ENOTFOUND;
850
+
851
+ error = git_reference_lookup(&ref, repo, ref_name);
1797
852
 
1798
- /* If we haven't found the reference at all, we assume we need to create
1799
- * a new reference and that's it */
1800
- if (res == GIT_ENOTFOUND) {
853
+ /* If we haven't found the reference at all, create a new reference. */
854
+ if (error == GIT_ENOTFOUND) {
1801
855
  giterr_clear();
1802
- return git_reference_create_oid(NULL, repo, ref_name, oid, 1);
856
+ return git_reference_create(NULL, repo, ref_name, oid, 0);
1803
857
  }
1804
-
1805
- if (res < 0)
1806
- return -1;
1807
-
1808
- /* If we have found a reference, but it's symbolic, we need to update
1809
- * the direct reference it points to */
858
+
859
+ if (error < 0)
860
+ return error;
861
+
862
+ /* If the ref is a symbolic reference, follow its target. */
1810
863
  if (git_reference_type(ref) == GIT_REF_SYMBOLIC) {
1811
- git_reference *aux;
1812
- const char *sym_target;
1813
-
1814
- /* The target pointed at by this reference */
1815
- sym_target = git_reference_target(ref);
1816
-
1817
- /* resolve the reference to the target it points to */
1818
- res = git_reference_resolve(&aux, ref);
1819
-
1820
- /*
1821
- * if the symbolic reference pointed to an inexisting ref,
1822
- * this is means we're creating a new branch, for example.
1823
- * We need to create a new direct reference with that name
1824
- */
1825
- if (res == GIT_ENOTFOUND) {
1826
- giterr_clear();
1827
- res = git_reference_create_oid(NULL, repo, sym_target, oid, 1);
1828
- git_reference_free(ref);
1829
- return res;
1830
- }
1831
-
1832
- /* free the original symbolic reference now; not before because
1833
- * we're using the `sym_target` pointer */
864
+ error = reference__update_terminal(repo, git_reference_symbolic_target(ref), oid,
865
+ nesting+1);
1834
866
  git_reference_free(ref);
1835
-
1836
- if (res < 0)
1837
- return -1;
1838
-
1839
- /* store the newly found direct reference in its place */
1840
- ref = aux;
867
+ } else {
868
+ git_reference_free(ref);
869
+ error = git_reference_create(NULL, repo, ref_name, oid, 1);
1841
870
  }
1842
-
1843
- /* ref is made to point to `oid`: ref is either the original reference,
1844
- * or the target of the symbolic reference we've looked up */
1845
- res = git_reference_set_oid(ref, oid);
1846
- git_reference_free(ref);
1847
- return res;
871
+
872
+ return error;
1848
873
  }
1849
874
 
1850
- struct glob_cb_data {
1851
- const char *glob;
1852
- int (*callback)(const char *, void *);
1853
- void *payload;
1854
- };
1855
-
1856
- static int fromglob_cb(const char *reference_name, void *payload)
875
+ /*
876
+ * Starting with the reference given by `ref_name`, follows symbolic
877
+ * references until a direct reference is found and updated the OID
878
+ * on that direct reference to `oid`.
879
+ */
880
+ int git_reference__update_terminal(
881
+ git_repository *repo,
882
+ const char *ref_name,
883
+ const git_oid *oid)
1857
884
  {
1858
- struct glob_cb_data *data = (struct glob_cb_data *)payload;
1859
-
1860
- if (!p_fnmatch(data->glob, reference_name, 0))
1861
- return data->callback(reference_name, data->payload);
1862
-
1863
- return 0;
885
+ return reference__update_terminal(repo, ref_name, oid, 0);
1864
886
  }
1865
887
 
1866
888
  int git_reference_foreach_glob(
@@ -1872,16 +894,13 @@ int git_reference_foreach_glob(
1872
894
  void *payload),
1873
895
  void *payload)
1874
896
  {
1875
- struct glob_cb_data data;
897
+ git_refdb *refdb;
1876
898
 
1877
899
  assert(repo && glob && callback);
1878
900
 
1879
- data.glob = glob;
1880
- data.callback = callback;
1881
- data.payload = payload;
901
+ git_repository_refdb__weakptr(&refdb, repo);
1882
902
 
1883
- return git_reference_foreach(
1884
- repo, list_flags, fromglob_cb, &data);
903
+ return git_refdb_foreach_glob(refdb, glob, list_flags, callback, payload);
1885
904
  }
1886
905
 
1887
906
  int git_reference_has_log(
@@ -1892,7 +911,8 @@ int git_reference_has_log(
1892
911
 
1893
912
  assert(ref);
1894
913
 
1895
- if (git_buf_join_n(&path, '/', 3, ref->owner->path_repository, GIT_REFLOG_DIR, ref->name) < 0)
914
+ if (git_buf_join_n(&path, '/', 3, ref->db->repo->path_repository,
915
+ GIT_REFLOG_DIR, ref->name) < 0)
1896
916
  return -1;
1897
917
 
1898
918
  result = git_path_isfile(git_buf_cstr(&path));
@@ -1901,16 +921,26 @@ int git_reference_has_log(
1901
921
  return result;
1902
922
  }
1903
923
 
924
+ int git_reference__is_branch(const char *ref_name)
925
+ {
926
+ return git__prefixcmp(ref_name, GIT_REFS_HEADS_DIR) == 0;
927
+ }
928
+
1904
929
  int git_reference_is_branch(git_reference *ref)
1905
930
  {
1906
931
  assert(ref);
1907
- return git__prefixcmp(ref->name, GIT_REFS_HEADS_DIR) == 0;
932
+ return git_reference__is_branch(ref->name);
933
+ }
934
+
935
+ int git_reference__is_remote(const char *ref_name)
936
+ {
937
+ return git__prefixcmp(ref_name, GIT_REFS_REMOTES_DIR) == 0;
1908
938
  }
1909
939
 
1910
940
  int git_reference_is_remote(git_reference *ref)
1911
941
  {
1912
942
  assert(ref);
1913
- return git__prefixcmp(ref->name, GIT_REFS_REMOTES_DIR) == 0;
943
+ return git_reference__is_remote(ref->name);
1914
944
  }
1915
945
 
1916
946
  static int peel_error(int error, git_reference *ref, const char* msg)
@@ -1921,15 +951,6 @@ static int peel_error(int error, git_reference *ref, const char* msg)
1921
951
  return error;
1922
952
  }
1923
953
 
1924
- static int reference_target(git_object **object, git_reference *ref)
1925
- {
1926
- const git_oid *oid;
1927
-
1928
- oid = git_reference_oid(ref);
1929
-
1930
- return git_object_lookup(object, git_reference_owner(ref), oid, GIT_OBJ_ANY);
1931
- }
1932
-
1933
954
  int git_reference_peel(
1934
955
  git_object **peeled,
1935
956
  git_reference *ref,
@@ -1941,22 +962,37 @@ int git_reference_peel(
1941
962
 
1942
963
  assert(ref);
1943
964
 
1944
- if ((error = git_reference_resolve(&resolved, ref)) < 0)
1945
- return peel_error(error, ref, "Cannot resolve reference");
965
+ if (ref->type == GIT_REF_OID) {
966
+ resolved = ref;
967
+ } else {
968
+ if ((error = git_reference_resolve(&resolved, ref)) < 0)
969
+ return peel_error(error, ref, "Cannot resolve reference");
970
+ }
971
+
972
+ if (!git_oid_iszero(&resolved->peel)) {
973
+ error = git_object_lookup(&target,
974
+ git_reference_owner(ref), &resolved->peel, GIT_OBJ_ANY);
975
+ } else {
976
+ error = git_object_lookup(&target,
977
+ git_reference_owner(ref), &resolved->target.oid, GIT_OBJ_ANY);
978
+ }
1946
979
 
1947
- if ((error = reference_target(&target, resolved)) < 0) {
980
+ if (error < 0) {
1948
981
  peel_error(error, ref, "Cannot retrieve reference target");
1949
982
  goto cleanup;
1950
983
  }
1951
-
984
+
1952
985
  if (target_type == GIT_OBJ_ANY && git_object_type(target) != GIT_OBJ_TAG)
1953
- error = git_object__dup(peeled, target);
1954
- else
986
+ error = git_object_dup(peeled, target);
987
+ else
1955
988
  error = git_object_peel(peeled, target, target_type);
1956
989
 
1957
990
  cleanup:
1958
991
  git_object_free(target);
1959
- git_reference_free(resolved);
992
+
993
+ if (resolved != ref)
994
+ git_reference_free(resolved);
995
+
1960
996
  return error;
1961
997
  }
1962
998
 
@@ -1964,8 +1000,12 @@ int git_reference__is_valid_name(
1964
1000
  const char *refname,
1965
1001
  unsigned int flags)
1966
1002
  {
1003
+ int error;
1004
+
1005
+ error = git_reference__normalize_name(NULL, refname, flags) == 0;
1967
1006
  giterr_clear();
1968
- return git_reference__normalize_name(NULL, refname, flags) == 0;
1007
+
1008
+ return error;
1969
1009
  }
1970
1010
 
1971
1011
  int git_reference_is_valid_name(