rugged 0.17.0.b7 → 0.18.0.b1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+ }