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
@@ -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.
@@ -12,12 +12,11 @@
12
12
  #include "git2/refs.h"
13
13
  #include "git2/revwalk.h"
14
14
 
15
- #include "pkt.h"
15
+ #include "smart.h"
16
16
  #include "util.h"
17
17
  #include "netops.h"
18
18
  #include "posix.h"
19
19
  #include "buffer.h"
20
- #include "protocol.h"
21
20
 
22
21
  #include <ctype.h>
23
22
 
@@ -123,6 +122,7 @@ static int err_pkt(git_pkt **out, const char *line, size_t len)
123
122
  GITERR_CHECK_ALLOC(pkt);
124
123
 
125
124
  pkt->type = GIT_PKT_ERR;
125
+ pkt->len = (int)len;
126
126
  memcpy(pkt->error, line, len);
127
127
  pkt->error[len] = '\0';
128
128
 
@@ -167,6 +167,25 @@ static int progress_pkt(git_pkt **out, const char *line, size_t len)
167
167
  return 0;
168
168
  }
169
169
 
170
+ static int sideband_error_pkt(git_pkt **out, const char *line, size_t len)
171
+ {
172
+ git_pkt_err *pkt;
173
+
174
+ line++;
175
+ len--;
176
+ pkt = git__malloc(sizeof(git_pkt_err) + len + 1);
177
+ GITERR_CHECK_ALLOC(pkt);
178
+
179
+ pkt->type = GIT_PKT_ERR;
180
+ pkt->len = (int)len;
181
+ memcpy(pkt->error, line, len);
182
+ pkt->error[len] = '\0';
183
+
184
+ *out = (git_pkt *)pkt;
185
+
186
+ return 0;
187
+ }
188
+
170
189
  /*
171
190
  * Parse an other-ref line.
172
191
  */
@@ -215,6 +234,83 @@ error_out:
215
234
  return error;
216
235
  }
217
236
 
237
+ static int ok_pkt(git_pkt **out, const char *line, size_t len)
238
+ {
239
+ git_pkt_ok *pkt;
240
+ const char *ptr;
241
+
242
+ pkt = git__malloc(sizeof(*pkt));
243
+ GITERR_CHECK_ALLOC(pkt);
244
+
245
+ pkt->type = GIT_PKT_OK;
246
+
247
+ line += 3; /* skip "ok " */
248
+ ptr = strchr(line, '\n');
249
+ len = ptr - line;
250
+
251
+ pkt->ref = git__malloc(len + 1);
252
+ GITERR_CHECK_ALLOC(pkt->ref);
253
+
254
+ memcpy(pkt->ref, line, len);
255
+ pkt->ref[len] = '\0';
256
+
257
+ *out = (git_pkt *)pkt;
258
+ return 0;
259
+ }
260
+
261
+ static int ng_pkt(git_pkt **out, const char *line, size_t len)
262
+ {
263
+ git_pkt_ng *pkt;
264
+ const char *ptr;
265
+
266
+ pkt = git__malloc(sizeof(*pkt));
267
+ GITERR_CHECK_ALLOC(pkt);
268
+
269
+ pkt->type = GIT_PKT_NG;
270
+
271
+ line += 3; /* skip "ng " */
272
+ ptr = strchr(line, ' ');
273
+ len = ptr - line;
274
+
275
+ pkt->ref = git__malloc(len + 1);
276
+ GITERR_CHECK_ALLOC(pkt->ref);
277
+
278
+ memcpy(pkt->ref, line, len);
279
+ pkt->ref[len] = '\0';
280
+
281
+ line = ptr + 1;
282
+ ptr = strchr(line, '\n');
283
+ len = ptr - line;
284
+
285
+ pkt->msg = git__malloc(len + 1);
286
+ GITERR_CHECK_ALLOC(pkt->msg);
287
+
288
+ memcpy(pkt->msg, line, len);
289
+ pkt->msg[len] = '\0';
290
+
291
+ *out = (git_pkt *)pkt;
292
+ return 0;
293
+ }
294
+
295
+ static int unpack_pkt(git_pkt **out, const char *line, size_t len)
296
+ {
297
+ git_pkt_unpack *pkt;
298
+
299
+ GIT_UNUSED(len);
300
+
301
+ pkt = git__malloc(sizeof(*pkt));
302
+ GITERR_CHECK_ALLOC(pkt);
303
+
304
+ pkt->type = GIT_PKT_UNPACK;
305
+ if (!git__prefixcmp(line, "unpack ok"))
306
+ pkt->unpack_ok = 1;
307
+ else
308
+ pkt->unpack_ok = 0;
309
+
310
+ *out = (git_pkt *)pkt;
311
+ return 0;
312
+ }
313
+
218
314
  static int32_t parse_len(const char *line)
219
315
  {
220
316
  char num[PKT_LEN_SIZE + 1];
@@ -304,6 +400,8 @@ int git_pkt_parse_line(
304
400
  ret = data_pkt(head, line, len);
305
401
  else if (*line == GIT_SIDE_BAND_PROGRESS)
306
402
  ret = progress_pkt(head, line, len);
403
+ else if (*line == GIT_SIDE_BAND_ERROR)
404
+ ret = sideband_error_pkt(head, line, len);
307
405
  else if (!git__prefixcmp(line, "ACK"))
308
406
  ret = ack_pkt(head, line, len);
309
407
  else if (!git__prefixcmp(line, "NAK"))
@@ -312,6 +410,12 @@ int git_pkt_parse_line(
312
410
  ret = err_pkt(head, line, len);
313
411
  else if (*line == '#')
314
412
  ret = comment_pkt(head, line, len);
413
+ else if (!git__prefixcmp(line, "ok"))
414
+ ret = ok_pkt(head, line, len);
415
+ else if (!git__prefixcmp(line, "ng"))
416
+ ret = ng_pkt(head, line, len);
417
+ else if (!git__prefixcmp(line, "unpack"))
418
+ ret = unpack_pkt(head, line, len);
315
419
  else
316
420
  ret = ref_pkt(head, line, len);
317
421
 
@@ -327,6 +431,17 @@ void git_pkt_free(git_pkt *pkt)
327
431
  git__free(p->head.name);
328
432
  }
329
433
 
434
+ if (pkt->type == GIT_PKT_OK) {
435
+ git_pkt_ok *p = (git_pkt_ok *) pkt;
436
+ git__free(p->ref);
437
+ }
438
+
439
+ if (pkt->type == GIT_PKT_NG) {
440
+ git_pkt_ng *p = (git_pkt_ng *) pkt;
441
+ git__free(p->ref);
442
+ git__free(p->msg);
443
+ }
444
+
330
445
  git__free(pkt);
331
446
  }
332
447
 
@@ -335,7 +450,7 @@ int git_pkt_buffer_flush(git_buf *buf)
335
450
  return git_buf_put(buf, pkt_flush_str, strlen(pkt_flush_str));
336
451
  }
337
452
 
338
- static int buffer_want_with_caps(git_remote_head *head, git_transport_caps *caps, git_buf *buf)
453
+ static int buffer_want_with_caps(const git_remote_head *head, transport_smart_caps *caps, git_buf *buf)
339
454
  {
340
455
  git_buf str = GIT_BUF_INIT;
341
456
  char oid[GIT_OID_HEXSZ +1] = {0};
@@ -376,28 +491,32 @@ static int buffer_want_with_caps(git_remote_head *head, git_transport_caps *caps
376
491
  * is overwrite the OID each time.
377
492
  */
378
493
 
379
- int git_pkt_buffer_wants(const git_vector *refs, git_transport_caps *caps, git_buf *buf)
494
+ int git_pkt_buffer_wants(
495
+ const git_remote_head * const *refs,
496
+ size_t count,
497
+ transport_smart_caps *caps,
498
+ git_buf *buf)
380
499
  {
381
- unsigned int i = 0;
382
- git_remote_head *head;
500
+ size_t i = 0;
501
+ const git_remote_head *head;
383
502
 
384
503
  if (caps->common) {
385
- for (; i < refs->length; ++i) {
386
- head = refs->contents[i];
504
+ for (; i < count; ++i) {
505
+ head = refs[i];
387
506
  if (!head->local)
388
507
  break;
389
508
  }
390
509
 
391
- if (buffer_want_with_caps(refs->contents[i], caps, buf) < 0)
510
+ if (buffer_want_with_caps(refs[i], caps, buf) < 0)
392
511
  return -1;
393
512
 
394
513
  i++;
395
514
  }
396
515
 
397
- for (; i < refs->length; ++i) {
516
+ for (; i < count; ++i) {
398
517
  char oid[GIT_OID_HEXSZ];
399
518
 
400
- head = refs->contents[i];
519
+ head = refs[i];
401
520
  if (head->local)
402
521
  continue;
403
522
 
@@ -0,0 +1,856 @@
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
+ #include "git2.h"
8
+
9
+ #include "smart.h"
10
+ #include "refs.h"
11
+ #include "repository.h"
12
+ #include "push.h"
13
+ #include "pack-objects.h"
14
+ #include "remote.h"
15
+
16
+ #define NETWORK_XFER_THRESHOLD (100*1024)
17
+
18
+ int git_smart__store_refs(transport_smart *t, int flushes)
19
+ {
20
+ gitno_buffer *buf = &t->buffer;
21
+ git_vector *refs = &t->refs;
22
+ int error, flush = 0, recvd;
23
+ const char *line_end;
24
+ git_pkt *pkt;
25
+
26
+ /* Clear existing refs in case git_remote_connect() is called again
27
+ * after git_remote_disconnect().
28
+ */
29
+ git_vector_clear(refs);
30
+
31
+ do {
32
+ if (buf->offset > 0)
33
+ error = git_pkt_parse_line(&pkt, buf->data, &line_end, buf->offset);
34
+ else
35
+ error = GIT_EBUFS;
36
+
37
+ if (error < 0 && error != GIT_EBUFS)
38
+ return -1;
39
+
40
+ if (error == GIT_EBUFS) {
41
+ if ((recvd = gitno_recv(buf)) < 0)
42
+ return -1;
43
+
44
+ if (recvd == 0 && !flush) {
45
+ giterr_set(GITERR_NET, "Early EOF");
46
+ return -1;
47
+ }
48
+
49
+ continue;
50
+ }
51
+
52
+ gitno_consume(buf, line_end);
53
+ if (pkt->type == GIT_PKT_ERR) {
54
+ giterr_set(GITERR_NET, "Remote error: %s", ((git_pkt_err *)pkt)->error);
55
+ git__free(pkt);
56
+ return -1;
57
+ }
58
+
59
+ if (pkt->type != GIT_PKT_FLUSH && git_vector_insert(refs, pkt) < 0)
60
+ return -1;
61
+
62
+ if (pkt->type == GIT_PKT_FLUSH) {
63
+ flush++;
64
+ git_pkt_free(pkt);
65
+ }
66
+ } while (flush < flushes);
67
+
68
+ return flush;
69
+ }
70
+
71
+ int git_smart__detect_caps(git_pkt_ref *pkt, transport_smart_caps *caps)
72
+ {
73
+ const char *ptr;
74
+
75
+ /* No refs or capabilites, odd but not a problem */
76
+ if (pkt == NULL || pkt->capabilities == NULL)
77
+ return 0;
78
+
79
+ ptr = pkt->capabilities;
80
+ while (ptr != NULL && *ptr != '\0') {
81
+ if (*ptr == ' ')
82
+ ptr++;
83
+
84
+ if (!git__prefixcmp(ptr, GIT_CAP_OFS_DELTA)) {
85
+ caps->common = caps->ofs_delta = 1;
86
+ ptr += strlen(GIT_CAP_OFS_DELTA);
87
+ continue;
88
+ }
89
+
90
+ if (!git__prefixcmp(ptr, GIT_CAP_MULTI_ACK)) {
91
+ caps->common = caps->multi_ack = 1;
92
+ ptr += strlen(GIT_CAP_MULTI_ACK);
93
+ continue;
94
+ }
95
+
96
+ if (!git__prefixcmp(ptr, GIT_CAP_INCLUDE_TAG)) {
97
+ caps->common = caps->include_tag = 1;
98
+ ptr += strlen(GIT_CAP_INCLUDE_TAG);
99
+ continue;
100
+ }
101
+
102
+ /* Keep side-band check after side-band-64k */
103
+ if (!git__prefixcmp(ptr, GIT_CAP_SIDE_BAND_64K)) {
104
+ caps->common = caps->side_band_64k = 1;
105
+ ptr += strlen(GIT_CAP_SIDE_BAND_64K);
106
+ continue;
107
+ }
108
+
109
+ if (!git__prefixcmp(ptr, GIT_CAP_SIDE_BAND)) {
110
+ caps->common = caps->side_band = 1;
111
+ ptr += strlen(GIT_CAP_SIDE_BAND);
112
+ continue;
113
+ }
114
+
115
+ if (!git__prefixcmp(ptr, GIT_CAP_DELETE_REFS)) {
116
+ caps->common = caps->delete_refs = 1;
117
+ ptr += strlen(GIT_CAP_DELETE_REFS);
118
+ continue;
119
+ }
120
+
121
+ /* We don't know this capability, so skip it */
122
+ ptr = strchr(ptr, ' ');
123
+ }
124
+
125
+ return 0;
126
+ }
127
+
128
+ static int recv_pkt(git_pkt **out, gitno_buffer *buf)
129
+ {
130
+ const char *ptr = buf->data, *line_end = ptr;
131
+ git_pkt *pkt;
132
+ int pkt_type, error = 0, ret;
133
+
134
+ do {
135
+ if (buf->offset > 0)
136
+ error = git_pkt_parse_line(&pkt, ptr, &line_end, buf->offset);
137
+ else
138
+ error = GIT_EBUFS;
139
+
140
+ if (error == 0)
141
+ break; /* return the pkt */
142
+
143
+ if (error < 0 && error != GIT_EBUFS)
144
+ return -1;
145
+
146
+ if ((ret = gitno_recv(buf)) < 0)
147
+ return -1;
148
+ } while (error);
149
+
150
+ gitno_consume(buf, line_end);
151
+ pkt_type = pkt->type;
152
+ if (out != NULL)
153
+ *out = pkt;
154
+ else
155
+ git__free(pkt);
156
+
157
+ return pkt_type;
158
+ }
159
+
160
+ static int store_common(transport_smart *t)
161
+ {
162
+ git_pkt *pkt = NULL;
163
+ gitno_buffer *buf = &t->buffer;
164
+
165
+ do {
166
+ if (recv_pkt(&pkt, buf) < 0)
167
+ return -1;
168
+
169
+ if (pkt->type == GIT_PKT_ACK) {
170
+ if (git_vector_insert(&t->common, pkt) < 0)
171
+ return -1;
172
+ } else {
173
+ git__free(pkt);
174
+ return 0;
175
+ }
176
+
177
+ } while (1);
178
+
179
+ return 0;
180
+ }
181
+
182
+ static int fetch_setup_walk(git_revwalk **out, git_repository *repo)
183
+ {
184
+ git_revwalk *walk;
185
+ git_strarray refs;
186
+ unsigned int i;
187
+ git_reference *ref;
188
+
189
+ if (git_reference_list(&refs, repo, GIT_REF_LISTALL) < 0)
190
+ return -1;
191
+
192
+ if (git_revwalk_new(&walk, repo) < 0)
193
+ return -1;
194
+
195
+ git_revwalk_sorting(walk, GIT_SORT_TIME);
196
+
197
+ for (i = 0; i < refs.count; ++i) {
198
+ /* No tags */
199
+ if (!git__prefixcmp(refs.strings[i], GIT_REFS_TAGS_DIR))
200
+ continue;
201
+
202
+ if (git_reference_lookup(&ref, repo, refs.strings[i]) < 0)
203
+ goto on_error;
204
+
205
+ if (git_reference_type(ref) == GIT_REF_SYMBOLIC)
206
+ continue;
207
+ if (git_revwalk_push(walk, git_reference_target(ref)) < 0)
208
+ goto on_error;
209
+
210
+ git_reference_free(ref);
211
+ }
212
+
213
+ git_strarray_free(&refs);
214
+ *out = walk;
215
+ return 0;
216
+
217
+ on_error:
218
+ git_reference_free(ref);
219
+ git_strarray_free(&refs);
220
+ return -1;
221
+ }
222
+
223
+ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, const git_remote_head * const *refs, size_t count)
224
+ {
225
+ transport_smart *t = (transport_smart *)transport;
226
+ gitno_buffer *buf = &t->buffer;
227
+ git_buf data = GIT_BUF_INIT;
228
+ git_revwalk *walk = NULL;
229
+ int error = -1, pkt_type;
230
+ unsigned int i;
231
+ git_oid oid;
232
+
233
+ /* No own logic, do our thing */
234
+ if ((error = git_pkt_buffer_wants(refs, count, &t->caps, &data)) < 0)
235
+ return error;
236
+
237
+ if ((error = fetch_setup_walk(&walk, repo)) < 0)
238
+ goto on_error;
239
+ /*
240
+ * We don't support any kind of ACK extensions, so the negotiation
241
+ * boils down to sending what we have and listening for an ACK
242
+ * every once in a while.
243
+ */
244
+ i = 0;
245
+ while (true) {
246
+ error = git_revwalk_next(&oid, walk);
247
+
248
+ if (error < 0) {
249
+ if (GIT_ITEROVER == error)
250
+ break;
251
+
252
+ goto on_error;
253
+ }
254
+
255
+ git_pkt_buffer_have(&oid, &data);
256
+ i++;
257
+ if (i % 20 == 0) {
258
+ if (t->cancelled.val) {
259
+ giterr_set(GITERR_NET, "The fetch was cancelled by the user");
260
+ error = GIT_EUSER;
261
+ goto on_error;
262
+ }
263
+
264
+ git_pkt_buffer_flush(&data);
265
+ if (git_buf_oom(&data)) {
266
+ error = -1;
267
+ goto on_error;
268
+ }
269
+
270
+ if ((error = git_smart__negotiation_step(&t->parent, data.ptr, data.size)) < 0)
271
+ goto on_error;
272
+
273
+ git_buf_clear(&data);
274
+ if (t->caps.multi_ack) {
275
+ if ((error = store_common(t)) < 0)
276
+ goto on_error;
277
+ } else {
278
+ pkt_type = recv_pkt(NULL, buf);
279
+
280
+ if (pkt_type == GIT_PKT_ACK) {
281
+ break;
282
+ } else if (pkt_type == GIT_PKT_NAK) {
283
+ continue;
284
+ } else if (pkt_type < 0) {
285
+ /* recv_pkt returned an error */
286
+ error = pkt_type;
287
+ goto on_error;
288
+ } else {
289
+ giterr_set(GITERR_NET, "Unexpected pkt type");
290
+ error = -1;
291
+ goto on_error;
292
+ }
293
+ }
294
+ }
295
+
296
+ if (t->common.length > 0)
297
+ break;
298
+
299
+ if (i % 20 == 0 && t->rpc) {
300
+ git_pkt_ack *pkt;
301
+ unsigned int i;
302
+
303
+ if ((error = git_pkt_buffer_wants(refs, count, &t->caps, &data)) < 0)
304
+ goto on_error;
305
+
306
+ git_vector_foreach(&t->common, i, pkt) {
307
+ if ((error = git_pkt_buffer_have(&pkt->oid, &data)) < 0)
308
+ goto on_error;
309
+ }
310
+
311
+ if (git_buf_oom(&data)) {
312
+ error = -1;
313
+ goto on_error;
314
+ }
315
+ }
316
+ }
317
+
318
+ /* Tell the other end that we're done negotiating */
319
+ if (t->rpc && t->common.length > 0) {
320
+ git_pkt_ack *pkt;
321
+ unsigned int i;
322
+
323
+ if ((error = git_pkt_buffer_wants(refs, count, &t->caps, &data)) < 0)
324
+ goto on_error;
325
+
326
+ git_vector_foreach(&t->common, i, pkt) {
327
+ if ((error = git_pkt_buffer_have(&pkt->oid, &data)) < 0)
328
+ goto on_error;
329
+ }
330
+
331
+ if (git_buf_oom(&data)) {
332
+ error = -1;
333
+ goto on_error;
334
+ }
335
+ }
336
+
337
+ if ((error = git_pkt_buffer_done(&data)) < 0)
338
+ goto on_error;
339
+
340
+ if (t->cancelled.val) {
341
+ giterr_set(GITERR_NET, "The fetch was cancelled by the user");
342
+ error = GIT_EUSER;
343
+ goto on_error;
344
+ }
345
+ if ((error = git_smart__negotiation_step(&t->parent, data.ptr, data.size)) < 0)
346
+ goto on_error;
347
+
348
+ git_buf_free(&data);
349
+ git_revwalk_free(walk);
350
+
351
+ /* Now let's eat up whatever the server gives us */
352
+ if (!t->caps.multi_ack) {
353
+ pkt_type = recv_pkt(NULL, buf);
354
+
355
+ if (pkt_type < 0) {
356
+ return pkt_type;
357
+ } else if (pkt_type != GIT_PKT_ACK && pkt_type != GIT_PKT_NAK) {
358
+ giterr_set(GITERR_NET, "Unexpected pkt type");
359
+ return -1;
360
+ }
361
+ } else {
362
+ git_pkt_ack *pkt;
363
+ do {
364
+ if ((error = recv_pkt((git_pkt **)&pkt, buf)) < 0)
365
+ return error;
366
+
367
+ if (pkt->type == GIT_PKT_NAK ||
368
+ (pkt->type == GIT_PKT_ACK && pkt->status != GIT_ACK_CONTINUE)) {
369
+ git__free(pkt);
370
+ break;
371
+ }
372
+
373
+ git__free(pkt);
374
+ } while (1);
375
+ }
376
+
377
+ return 0;
378
+
379
+ on_error:
380
+ git_revwalk_free(walk);
381
+ git_buf_free(&data);
382
+ return error;
383
+ }
384
+
385
+ static int no_sideband(transport_smart *t, struct git_odb_writepack *writepack, gitno_buffer *buf, git_transfer_progress *stats)
386
+ {
387
+ int recvd;
388
+
389
+ do {
390
+ if (t->cancelled.val) {
391
+ giterr_set(GITERR_NET, "The fetch was cancelled by the user");
392
+ return GIT_EUSER;
393
+ }
394
+
395
+ if (writepack->add(writepack, buf->data, buf->offset, stats) < 0)
396
+ return -1;
397
+
398
+ gitno_consume_n(buf, buf->offset);
399
+
400
+ if ((recvd = gitno_recv(buf)) < 0)
401
+ return -1;
402
+ } while(recvd > 0);
403
+
404
+ if (writepack->commit(writepack, stats))
405
+ return -1;
406
+
407
+ return 0;
408
+ }
409
+
410
+ struct network_packetsize_payload
411
+ {
412
+ git_transfer_progress_callback callback;
413
+ void *payload;
414
+ git_transfer_progress *stats;
415
+ size_t last_fired_bytes;
416
+ };
417
+
418
+ static void network_packetsize(size_t received, void *payload)
419
+ {
420
+ struct network_packetsize_payload *npp = (struct network_packetsize_payload*)payload;
421
+
422
+ /* Accumulate bytes */
423
+ npp->stats->received_bytes += received;
424
+
425
+ /* Fire notification if the threshold is reached */
426
+ if ((npp->stats->received_bytes - npp->last_fired_bytes) > NETWORK_XFER_THRESHOLD) {
427
+ npp->last_fired_bytes = npp->stats->received_bytes;
428
+ npp->callback(npp->stats, npp->payload);
429
+ }
430
+ }
431
+
432
+ int git_smart__download_pack(
433
+ git_transport *transport,
434
+ git_repository *repo,
435
+ git_transfer_progress *stats,
436
+ git_transfer_progress_callback progress_cb,
437
+ void *progress_payload)
438
+ {
439
+ transport_smart *t = (transport_smart *)transport;
440
+ gitno_buffer *buf = &t->buffer;
441
+ git_odb *odb;
442
+ struct git_odb_writepack *writepack = NULL;
443
+ int error = -1;
444
+ struct network_packetsize_payload npp = {0};
445
+
446
+ memset(stats, 0, sizeof(git_transfer_progress));
447
+
448
+ if (progress_cb) {
449
+ npp.callback = progress_cb;
450
+ npp.payload = progress_payload;
451
+ npp.stats = stats;
452
+ t->packetsize_cb = &network_packetsize;
453
+ t->packetsize_payload = &npp;
454
+
455
+ /* We might have something in the buffer already from negotiate_fetch */
456
+ if (t->buffer.offset > 0)
457
+ t->packetsize_cb(t->buffer.offset, t->packetsize_payload);
458
+ }
459
+
460
+ if ((error = git_repository_odb__weakptr(&odb, repo)) < 0 ||
461
+ ((error = git_odb_write_pack(&writepack, odb, progress_cb, progress_payload)) < 0))
462
+ goto on_error;
463
+
464
+ /*
465
+ * If the remote doesn't support the side-band, we can feed
466
+ * the data directly to the pack writer. Otherwise, we need to
467
+ * check which one belongs there.
468
+ */
469
+ if (!t->caps.side_band && !t->caps.side_band_64k) {
470
+ if (no_sideband(t, writepack, buf, stats) < 0)
471
+ goto on_error;
472
+
473
+ goto on_success;
474
+ }
475
+
476
+ do {
477
+ git_pkt *pkt;
478
+
479
+ if (t->cancelled.val) {
480
+ giterr_set(GITERR_NET, "The fetch was cancelled by the user");
481
+ error = GIT_EUSER;
482
+ goto on_error;
483
+ }
484
+
485
+ if (recv_pkt(&pkt, buf) < 0)
486
+ goto on_error;
487
+
488
+ if (pkt->type == GIT_PKT_PROGRESS) {
489
+ if (t->progress_cb) {
490
+ git_pkt_progress *p = (git_pkt_progress *) pkt;
491
+ t->progress_cb(p->data, p->len, t->message_cb_payload);
492
+ }
493
+ git__free(pkt);
494
+ } else if (pkt->type == GIT_PKT_DATA) {
495
+ git_pkt_data *p = (git_pkt_data *) pkt;
496
+ error = writepack->add(writepack, p->data, p->len, stats);
497
+
498
+ git__free(pkt);
499
+ if (error < 0)
500
+ goto on_error;
501
+ } else if (pkt->type == GIT_PKT_FLUSH) {
502
+ /* A flush indicates the end of the packfile */
503
+ git__free(pkt);
504
+ break;
505
+ }
506
+ } while (1);
507
+
508
+ if (writepack->commit(writepack, stats) < 0)
509
+ goto on_error;
510
+
511
+ on_success:
512
+ error = 0;
513
+
514
+ on_error:
515
+ if (writepack)
516
+ writepack->free(writepack);
517
+
518
+ /* Trailing execution of progress_cb, if necessary */
519
+ if (npp.callback && npp.stats->received_bytes > npp.last_fired_bytes)
520
+ npp.callback(npp.stats, npp.payload);
521
+
522
+ return error;
523
+ }
524
+
525
+ static int gen_pktline(git_buf *buf, git_push *push)
526
+ {
527
+ push_spec *spec;
528
+ size_t i, len;
529
+ char old_id[41], new_id[41];
530
+
531
+ old_id[40] = '\0'; new_id[40] = '\0';
532
+
533
+ git_vector_foreach(&push->specs, i, spec) {
534
+ len = 2*GIT_OID_HEXSZ + 7 + strlen(spec->rref);
535
+
536
+ if (i == 0) {
537
+ ++len; /* '\0' */
538
+ if (push->report_status)
539
+ len += strlen(GIT_CAP_REPORT_STATUS) + 1;
540
+ len += strlen(GIT_CAP_SIDE_BAND_64K) + 1;
541
+ }
542
+
543
+ git_oid_fmt(old_id, &spec->roid);
544
+ git_oid_fmt(new_id, &spec->loid);
545
+
546
+ git_buf_printf(buf, "%04"PRIxZ"%s %s %s", len, old_id, new_id, spec->rref);
547
+
548
+ if (i == 0) {
549
+ git_buf_putc(buf, '\0');
550
+ /* Core git always starts their capabilities string with a space */
551
+ if (push->report_status) {
552
+ git_buf_putc(buf, ' ');
553
+ git_buf_printf(buf, GIT_CAP_REPORT_STATUS);
554
+ }
555
+ git_buf_putc(buf, ' ');
556
+ git_buf_printf(buf, GIT_CAP_SIDE_BAND_64K);
557
+ }
558
+
559
+ git_buf_putc(buf, '\n');
560
+ }
561
+
562
+ git_buf_puts(buf, "0000");
563
+ return git_buf_oom(buf) ? -1 : 0;
564
+ }
565
+
566
+ static int add_push_report_pkt(git_push *push, git_pkt *pkt)
567
+ {
568
+ push_status *status;
569
+
570
+ switch (pkt->type) {
571
+ case GIT_PKT_OK:
572
+ status = git__malloc(sizeof(push_status));
573
+ GITERR_CHECK_ALLOC(status);
574
+ status->msg = NULL;
575
+ status->ref = git__strdup(((git_pkt_ok *)pkt)->ref);
576
+ if (!status->ref ||
577
+ git_vector_insert(&push->status, status) < 0) {
578
+ git_push_status_free(status);
579
+ return -1;
580
+ }
581
+ break;
582
+ case GIT_PKT_NG:
583
+ status = git__calloc(sizeof(push_status), 1);
584
+ GITERR_CHECK_ALLOC(status);
585
+ status->ref = git__strdup(((git_pkt_ng *)pkt)->ref);
586
+ status->msg = git__strdup(((git_pkt_ng *)pkt)->msg);
587
+ if (!status->ref || !status->msg ||
588
+ git_vector_insert(&push->status, status) < 0) {
589
+ git_push_status_free(status);
590
+ return -1;
591
+ }
592
+ break;
593
+ case GIT_PKT_UNPACK:
594
+ push->unpack_ok = ((git_pkt_unpack *)pkt)->unpack_ok;
595
+ break;
596
+ case GIT_PKT_FLUSH:
597
+ return GIT_ITEROVER;
598
+ default:
599
+ giterr_set(GITERR_NET, "report-status: protocol error");
600
+ return -1;
601
+ }
602
+
603
+ return 0;
604
+ }
605
+
606
+ static int add_push_report_sideband_pkt(git_push *push, git_pkt_data *data_pkt)
607
+ {
608
+ git_pkt *pkt;
609
+ const char *line = data_pkt->data, *line_end;
610
+ size_t line_len = data_pkt->len;
611
+ int error;
612
+
613
+ while (line_len > 0) {
614
+ error = git_pkt_parse_line(&pkt, line, &line_end, line_len);
615
+
616
+ if (error < 0)
617
+ return error;
618
+
619
+ /* Advance in the buffer */
620
+ line_len -= (line_end - line);
621
+ line = line_end;
622
+
623
+ error = add_push_report_pkt(push, pkt);
624
+
625
+ git_pkt_free(pkt);
626
+
627
+ if (error < 0 && error != GIT_ITEROVER)
628
+ return error;
629
+ }
630
+
631
+ return 0;
632
+ }
633
+
634
+ static int parse_report(gitno_buffer *buf, git_push *push)
635
+ {
636
+ git_pkt *pkt;
637
+ const char *line_end;
638
+ int error, recvd;
639
+
640
+ for (;;) {
641
+ if (buf->offset > 0)
642
+ error = git_pkt_parse_line(&pkt, buf->data,
643
+ &line_end, buf->offset);
644
+ else
645
+ error = GIT_EBUFS;
646
+
647
+ if (error < 0 && error != GIT_EBUFS)
648
+ return -1;
649
+
650
+ if (error == GIT_EBUFS) {
651
+ if ((recvd = gitno_recv(buf)) < 0)
652
+ return -1;
653
+
654
+ if (recvd == 0) {
655
+ giterr_set(GITERR_NET, "Early EOF");
656
+ return -1;
657
+ }
658
+ continue;
659
+ }
660
+
661
+ gitno_consume(buf, line_end);
662
+
663
+ error = 0;
664
+
665
+ switch (pkt->type) {
666
+ case GIT_PKT_DATA:
667
+ /* This is a sideband packet which contains other packets */
668
+ error = add_push_report_sideband_pkt(push, (git_pkt_data *)pkt);
669
+ break;
670
+ case GIT_PKT_ERR:
671
+ giterr_set(GITERR_NET, "report-status: Error reported: %s",
672
+ ((git_pkt_err *)pkt)->error);
673
+ error = -1;
674
+ break;
675
+ case GIT_PKT_PROGRESS:
676
+ break;
677
+ default:
678
+ error = add_push_report_pkt(push, pkt);
679
+ break;
680
+ }
681
+
682
+ git_pkt_free(pkt);
683
+
684
+ /* add_push_report_pkt returns GIT_ITEROVER when it receives a flush */
685
+ if (error == GIT_ITEROVER)
686
+ return 0;
687
+
688
+ if (error < 0)
689
+ return error;
690
+ }
691
+ }
692
+
693
+ static int add_ref_from_push_spec(git_vector *refs, push_spec *push_spec)
694
+ {
695
+ git_pkt_ref *added = git__calloc(1, sizeof(git_pkt_ref));
696
+ GITERR_CHECK_ALLOC(added);
697
+
698
+ added->type = GIT_PKT_REF;
699
+ git_oid_cpy(&added->head.oid, &push_spec->loid);
700
+ added->head.name = git__strdup(push_spec->rref);
701
+
702
+ if (!added->head.name ||
703
+ git_vector_insert(refs, added) < 0) {
704
+ git_pkt_free((git_pkt *)added);
705
+ return -1;
706
+ }
707
+
708
+ return 0;
709
+ }
710
+
711
+ static int update_refs_from_report(
712
+ git_vector *refs,
713
+ git_vector *push_specs,
714
+ git_vector *push_report)
715
+ {
716
+ git_pkt_ref *ref;
717
+ push_spec *push_spec;
718
+ push_status *push_status;
719
+ size_t i, j, refs_len;
720
+ int cmp;
721
+
722
+ /* For each push spec we sent to the server, we should have
723
+ * gotten back a status packet in the push report */
724
+ if (push_specs->length != push_report->length) {
725
+ giterr_set(GITERR_NET, "report-status: protocol error");
726
+ return -1;
727
+ }
728
+
729
+ /* We require that push_specs be sorted with push_spec_rref_cmp,
730
+ * and that push_report be sorted with push_status_ref_cmp */
731
+ git_vector_sort(push_specs);
732
+ git_vector_sort(push_report);
733
+
734
+ git_vector_foreach(push_specs, i, push_spec) {
735
+ push_status = git_vector_get(push_report, i);
736
+
737
+ /* For each push spec we sent to the server, we should have
738
+ * gotten back a status packet in the push report which matches */
739
+ if (strcmp(push_spec->rref, push_status->ref)) {
740
+ giterr_set(GITERR_NET, "report-status: protocol error");
741
+ return -1;
742
+ }
743
+ }
744
+
745
+ /* We require that refs be sorted with ref_name_cmp */
746
+ git_vector_sort(refs);
747
+ i = j = 0;
748
+ refs_len = refs->length;
749
+
750
+ /* Merge join push_specs with refs */
751
+ while (i < push_specs->length && j < refs_len) {
752
+ push_spec = git_vector_get(push_specs, i);
753
+ push_status = git_vector_get(push_report, i);
754
+ ref = git_vector_get(refs, j);
755
+
756
+ cmp = strcmp(push_spec->rref, ref->head.name);
757
+
758
+ /* Iterate appropriately */
759
+ if (cmp <= 0) i++;
760
+ if (cmp >= 0) j++;
761
+
762
+ /* Add case */
763
+ if (cmp < 0 &&
764
+ !push_status->msg &&
765
+ add_ref_from_push_spec(refs, push_spec) < 0)
766
+ return -1;
767
+
768
+ /* Update case, delete case */
769
+ if (cmp == 0 &&
770
+ !push_status->msg)
771
+ git_oid_cpy(&ref->head.oid, &push_spec->loid);
772
+ }
773
+
774
+ for (; i < push_specs->length; i++) {
775
+ push_spec = git_vector_get(push_specs, i);
776
+ push_status = git_vector_get(push_report, i);
777
+
778
+ /* Add case */
779
+ if (!push_status->msg &&
780
+ add_ref_from_push_spec(refs, push_spec) < 0)
781
+ return -1;
782
+ }
783
+
784
+ /* Remove any refs which we updated to have a zero OID. */
785
+ git_vector_rforeach(refs, i, ref) {
786
+ if (git_oid_iszero(&ref->head.oid)) {
787
+ git_vector_remove(refs, i);
788
+ git_pkt_free((git_pkt *)ref);
789
+ }
790
+ }
791
+
792
+ git_vector_sort(refs);
793
+
794
+ return 0;
795
+ }
796
+
797
+ static int stream_thunk(void *buf, size_t size, void *data)
798
+ {
799
+ git_smart_subtransport_stream *s = (git_smart_subtransport_stream *)data;
800
+
801
+ return s->write(s, (const char *)buf, size);
802
+ }
803
+
804
+ int git_smart__push(git_transport *transport, git_push *push)
805
+ {
806
+ transport_smart *t = (transport_smart *)transport;
807
+ git_smart_subtransport_stream *s;
808
+ git_buf pktline = GIT_BUF_INIT;
809
+ int error = -1;
810
+
811
+ #ifdef PUSH_DEBUG
812
+ {
813
+ git_remote_head *head;
814
+ push_spec *spec;
815
+ unsigned int i;
816
+ char hex[41]; hex[40] = '\0';
817
+
818
+ git_vector_foreach(&push->remote->refs, i, head) {
819
+ git_oid_fmt(hex, &head->oid);
820
+ fprintf(stderr, "%s (%s)\n", hex, head->name);
821
+ }
822
+
823
+ git_vector_foreach(&push->specs, i, spec) {
824
+ git_oid_fmt(hex, &spec->roid);
825
+ fprintf(stderr, "%s (%s) -> ", hex, spec->lref);
826
+ git_oid_fmt(hex, &spec->loid);
827
+ fprintf(stderr, "%s (%s)\n", hex, spec->rref ?
828
+ spec->rref : spec->lref);
829
+ }
830
+ }
831
+ #endif
832
+
833
+ if (git_smart__get_push_stream(t, &s) < 0 ||
834
+ gen_pktline(&pktline, push) < 0 ||
835
+ s->write(s, git_buf_cstr(&pktline), git_buf_len(&pktline)) < 0 ||
836
+ git_packbuilder_foreach(push->pb, &stream_thunk, s) < 0)
837
+ goto on_error;
838
+
839
+ /* If we sent nothing or the server doesn't support report-status, then
840
+ * we consider the pack to have been unpacked successfully */
841
+ if (!push->specs.length || !push->report_status)
842
+ push->unpack_ok = 1;
843
+ else if (parse_report(&t->buffer, push) < 0)
844
+ goto on_error;
845
+
846
+ if (push->status.length &&
847
+ update_refs_from_report(&t->refs, &push->specs, &push->status) < 0)
848
+ goto on_error;
849
+
850
+ error = 0;
851
+
852
+ on_error:
853
+ git_buf_free(&pktline);
854
+
855
+ return error;
856
+ }