rugged 0.18.0.gh.de28323 → 0.19.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (283) hide show
  1. data/README.md +9 -4
  2. data/Rakefile +1 -1
  3. data/ext/rugged/extconf.rb +10 -0
  4. data/ext/rugged/rugged.c +153 -86
  5. data/ext/rugged/rugged.h +44 -33
  6. data/ext/rugged/rugged_blob.c +288 -60
  7. data/ext/rugged/rugged_branch.c +82 -57
  8. data/ext/rugged/rugged_commit.c +83 -86
  9. data/ext/rugged/rugged_config.c +68 -68
  10. data/ext/rugged/rugged_diff.c +509 -0
  11. data/ext/rugged/rugged_diff_delta.c +94 -0
  12. data/ext/rugged/rugged_diff_hunk.c +100 -0
  13. data/ext/rugged/rugged_diff_line.c +79 -0
  14. data/ext/rugged/rugged_diff_patch.c +169 -0
  15. data/ext/rugged/rugged_index.c +539 -8
  16. data/ext/rugged/rugged_note.c +74 -80
  17. data/ext/rugged/rugged_object.c +63 -8
  18. data/ext/rugged/rugged_reference.c +231 -145
  19. data/ext/rugged/rugged_remote.c +509 -53
  20. data/ext/rugged/rugged_repo.c +572 -236
  21. data/ext/rugged/rugged_revwalk.c +59 -36
  22. data/ext/rugged/rugged_settings.c +7 -9
  23. data/ext/rugged/rugged_signature.c +7 -11
  24. data/ext/rugged/rugged_tag.c +93 -39
  25. data/ext/rugged/rugged_tree.c +321 -58
  26. data/lib/rugged.rb +1 -0
  27. data/lib/rugged/commit.rb +16 -1
  28. data/lib/rugged/console.rb +9 -0
  29. data/lib/rugged/diff.rb +19 -0
  30. data/lib/rugged/diff/delta.rb +54 -0
  31. data/lib/rugged/diff/hunk.rb +23 -0
  32. data/lib/rugged/diff/line.rb +29 -0
  33. data/lib/rugged/diff/patch.rb +28 -0
  34. data/lib/rugged/repository.rb +36 -39
  35. data/lib/rugged/version.rb +1 -1
  36. data/test/blob_test.rb +308 -1
  37. data/test/branch_test.rb +7 -0
  38. data/test/commit_test.rb +7 -10
  39. data/test/coverage/cover.rb +9 -1
  40. data/test/diff_test.rb +777 -0
  41. data/test/fixtures/archive.tar.gz +0 -0
  42. data/test/fixtures/attr/attr0 +1 -0
  43. data/test/fixtures/attr/attr1 +29 -0
  44. data/test/fixtures/attr/attr2 +21 -0
  45. data/test/fixtures/attr/attr3 +4 -0
  46. data/test/fixtures/attr/binfile +1 -0
  47. data/test/fixtures/attr/dir/file +0 -0
  48. data/test/fixtures/attr/file +1 -0
  49. data/test/fixtures/attr/gitattributes +29 -0
  50. data/test/fixtures/attr/gitignore +2 -0
  51. data/test/fixtures/attr/ign +1 -0
  52. data/test/fixtures/attr/macro_bad +1 -0
  53. data/test/fixtures/attr/macro_test +1 -0
  54. data/test/fixtures/attr/root_test1 +1 -0
  55. data/test/fixtures/attr/root_test2 +6 -0
  56. data/test/fixtures/attr/root_test3 +19 -0
  57. data/test/fixtures/attr/root_test4.txt +14 -0
  58. data/test/fixtures/attr/sub/abc +37 -0
  59. data/test/fixtures/attr/sub/dir/file +0 -0
  60. data/test/fixtures/attr/sub/file +1 -0
  61. data/test/fixtures/attr/sub/ign/file +1 -0
  62. data/test/fixtures/attr/sub/ign/sub/file +1 -0
  63. data/test/fixtures/attr/sub/sub/dir +0 -0
  64. data/test/fixtures/attr/sub/sub/file +1 -0
  65. data/test/fixtures/attr/sub/sub/subsub.txt +1 -0
  66. data/test/fixtures/attr/sub/subdir_test1 +2 -0
  67. data/test/fixtures/attr/sub/subdir_test2.txt +1 -0
  68. data/test/fixtures/diff/another.txt +38 -0
  69. data/test/fixtures/diff/readme.txt +36 -0
  70. data/test/fixtures/mergedrepo/conflicts-one.txt +5 -0
  71. data/test/fixtures/mergedrepo/conflicts-two.txt +5 -0
  72. data/test/fixtures/mergedrepo/one.txt +10 -0
  73. data/test/fixtures/mergedrepo/two.txt +12 -0
  74. data/test/fixtures/status/current_file +1 -0
  75. data/test/fixtures/status/ignored_file +1 -0
  76. data/test/fixtures/status/modified_file +2 -0
  77. data/test/fixtures/status/new_file +1 -0
  78. data/test/fixtures/status/staged_changes +2 -0
  79. data/test/fixtures/status/staged_changes_modified_file +3 -0
  80. data/test/fixtures/status/staged_delete_modified_file +1 -0
  81. data/test/fixtures/status/staged_new_file +1 -0
  82. data/test/fixtures/status/staged_new_file_modified_file +2 -0
  83. data/test/fixtures/status/subdir.txt +2 -0
  84. data/test/fixtures/status/subdir/current_file +1 -0
  85. data/test/fixtures/status/subdir/modified_file +2 -0
  86. data/test/fixtures/status/subdir/new_file +1 -0
  87. data/test/fixtures/status//350/277/231 +1 -0
  88. data/test/fixtures/testrepo.git/config +5 -0
  89. data/test/fixtures/testrepo.git/objects/77/71329dfa3002caf8c61a0ceb62a31d09023f37 +0 -0
  90. data/test/fixtures/text_file.md +464 -0
  91. data/test/fixtures/unsymlinked.git/HEAD +1 -0
  92. data/test/fixtures/unsymlinked.git/config +6 -0
  93. data/test/fixtures/unsymlinked.git/description +1 -0
  94. data/test/fixtures/unsymlinked.git/info/exclude +2 -0
  95. data/test/fixtures/unsymlinked.git/objects/08/8b64704e0d6b8bd061dea879418cb5442a3fbf +0 -0
  96. data/test/fixtures/unsymlinked.git/objects/13/a5e939bca25940c069fd2169d993dba328e30b +0 -0
  97. data/test/fixtures/unsymlinked.git/objects/19/bf568e59e3a0b363cafb4106226e62d4a4c41c +0 -0
  98. data/test/fixtures/unsymlinked.git/objects/58/1fadd35b4cf320d102a152f918729011604773 +0 -0
  99. data/test/fixtures/unsymlinked.git/objects/5c/87b6791e8b13da658a14d1ef7e09b5dc3bac8c +0 -0
  100. data/test/fixtures/unsymlinked.git/objects/6f/e5f5398af85fb3de8a6aba0339b6d3bfa26a27 +0 -0
  101. data/test/fixtures/unsymlinked.git/objects/7f/ccd75616ec188b8f1b23d67506a334cc34a49d +0 -0
  102. data/test/fixtures/unsymlinked.git/objects/80/6999882bf91d24241e4077906b9017605eb1f3 +0 -0
  103. data/test/fixtures/unsymlinked.git/objects/83/7d176303c5005505ec1e4a30231c40930c0230 +0 -0
  104. data/test/fixtures/unsymlinked.git/objects/a8/595ccca04f40818ae0155c8f9c77a230e597b6 +2 -0
  105. data/test/fixtures/unsymlinked.git/objects/cf/8f1cf5cce859c438d6cc067284cb5e161206e7 +0 -0
  106. data/test/fixtures/unsymlinked.git/objects/d5/278d05c8607ec420bfee4cf219fbc0eeebfd6a +0 -0
  107. data/test/fixtures/unsymlinked.git/objects/f4/e16fb76536591a41454194058d048d8e4dd2e9 +0 -0
  108. data/test/fixtures/unsymlinked.git/objects/f9/e65619d93fdf2673882e0a261c5e93b1a84006 +0 -0
  109. data/test/fixtures/unsymlinked.git/refs/heads/exe-file +1 -0
  110. data/test/fixtures/unsymlinked.git/refs/heads/master +1 -0
  111. data/test/fixtures/unsymlinked.git/refs/heads/reg-file +1 -0
  112. data/test/index_test.rb +120 -0
  113. data/test/reference_test.rb +38 -3
  114. data/test/remote_test.rb +224 -3
  115. data/test/repo_reset_test.rb +2 -0
  116. data/test/repo_test.rb +147 -10
  117. data/test/test_helper.rb +5 -2
  118. data/vendor/libgit2/include/git2/attr.h +3 -3
  119. data/vendor/libgit2/include/git2/blob.h +11 -17
  120. data/vendor/libgit2/include/git2/branch.h +3 -2
  121. data/vendor/libgit2/include/git2/checkout.h +7 -0
  122. data/vendor/libgit2/include/git2/clone.h +3 -0
  123. data/vendor/libgit2/include/git2/commit.h +61 -66
  124. data/vendor/libgit2/include/git2/common.h +73 -42
  125. data/vendor/libgit2/include/git2/config.h +57 -71
  126. data/vendor/libgit2/include/git2/cred_helpers.h +2 -2
  127. data/vendor/libgit2/include/git2/diff.h +179 -30
  128. data/vendor/libgit2/include/git2/errors.h +3 -3
  129. data/vendor/libgit2/include/git2/index.h +225 -146
  130. data/vendor/libgit2/include/git2/indexer.h +2 -22
  131. data/vendor/libgit2/include/git2/inttypes.h +9 -9
  132. data/vendor/libgit2/include/git2/merge.h +123 -5
  133. data/vendor/libgit2/include/git2/odb.h +59 -38
  134. data/vendor/libgit2/include/git2/odb_backend.h +45 -104
  135. data/vendor/libgit2/include/git2/oid.h +30 -19
  136. data/vendor/libgit2/include/git2/pack.h +21 -3
  137. data/vendor/libgit2/include/git2/refdb.h +0 -35
  138. data/vendor/libgit2/include/git2/refs.h +93 -31
  139. data/vendor/libgit2/include/git2/refspec.h +17 -0
  140. data/vendor/libgit2/include/git2/remote.h +60 -20
  141. data/vendor/libgit2/include/git2/repository.h +48 -70
  142. data/vendor/libgit2/include/git2/reset.h +3 -3
  143. data/vendor/libgit2/include/git2/revparse.h +22 -0
  144. data/vendor/libgit2/include/git2/stash.h +1 -1
  145. data/vendor/libgit2/include/git2/status.h +131 -56
  146. data/vendor/libgit2/include/git2/strarray.h +2 -2
  147. data/vendor/libgit2/include/git2/submodule.h +16 -16
  148. data/vendor/libgit2/include/git2/sys/commit.h +46 -0
  149. data/vendor/libgit2/include/git2/sys/config.h +71 -0
  150. data/vendor/libgit2/include/git2/sys/index.h +179 -0
  151. data/vendor/libgit2/include/git2/sys/odb_backend.h +86 -0
  152. data/vendor/libgit2/include/git2/sys/refdb_backend.h +158 -0
  153. data/vendor/libgit2/include/git2/sys/refs.h +38 -0
  154. data/vendor/libgit2/include/git2/sys/repository.h +106 -0
  155. data/vendor/libgit2/include/git2/tag.h +44 -18
  156. data/vendor/libgit2/include/git2/trace.h +1 -2
  157. data/vendor/libgit2/include/git2/transport.h +74 -0
  158. data/vendor/libgit2/include/git2/tree.h +12 -22
  159. data/vendor/libgit2/include/git2/types.h +33 -0
  160. data/vendor/libgit2/include/git2/version.h +2 -2
  161. data/vendor/libgit2/src/array.h +66 -0
  162. data/vendor/libgit2/src/attr.c +26 -13
  163. data/vendor/libgit2/src/attr_file.c +3 -2
  164. data/vendor/libgit2/src/attr_file.h +3 -3
  165. data/vendor/libgit2/src/attrcache.h +4 -4
  166. data/vendor/libgit2/src/blob.c +13 -9
  167. data/vendor/libgit2/src/blob.h +2 -2
  168. data/vendor/libgit2/src/branch.c +67 -49
  169. data/vendor/libgit2/src/cache.c +224 -54
  170. data/vendor/libgit2/src/cache.h +33 -20
  171. data/vendor/libgit2/src/checkout.c +145 -85
  172. data/vendor/libgit2/src/clone.c +62 -50
  173. data/vendor/libgit2/src/commit.c +74 -40
  174. data/vendor/libgit2/src/commit.h +2 -3
  175. data/vendor/libgit2/src/commit_list.c +14 -8
  176. data/vendor/libgit2/src/config.c +119 -36
  177. data/vendor/libgit2/src/config.h +3 -0
  178. data/vendor/libgit2/src/config_cache.c +24 -7
  179. data/vendor/libgit2/src/config_file.c +9 -6
  180. data/vendor/libgit2/src/crlf.c +4 -2
  181. data/vendor/libgit2/src/date.c +3 -3
  182. data/vendor/libgit2/src/delta.c +1 -1
  183. data/vendor/libgit2/src/diff.c +681 -303
  184. data/vendor/libgit2/src/diff.h +34 -2
  185. data/vendor/libgit2/src/diff_driver.c +405 -0
  186. data/vendor/libgit2/src/diff_driver.h +49 -0
  187. data/vendor/libgit2/src/diff_file.c +447 -0
  188. data/vendor/libgit2/src/diff_file.h +58 -0
  189. data/vendor/libgit2/src/diff_patch.c +995 -0
  190. data/vendor/libgit2/src/diff_patch.h +46 -0
  191. data/vendor/libgit2/src/diff_print.c +430 -0
  192. data/vendor/libgit2/src/diff_tform.c +464 -203
  193. data/vendor/libgit2/src/diff_xdiff.c +166 -0
  194. data/vendor/libgit2/src/diff_xdiff.h +28 -0
  195. data/vendor/libgit2/src/fetch.c +11 -4
  196. data/vendor/libgit2/src/fileops.c +85 -61
  197. data/vendor/libgit2/src/fileops.h +4 -0
  198. data/vendor/libgit2/src/global.c +10 -2
  199. data/vendor/libgit2/src/global.h +0 -8
  200. data/vendor/libgit2/src/hash/hash_generic.h +3 -3
  201. data/vendor/libgit2/src/hash/hash_win32.h +4 -4
  202. data/vendor/libgit2/src/hashsig.c +0 -1
  203. data/vendor/libgit2/src/ignore.c +68 -28
  204. data/vendor/libgit2/src/ignore.h +10 -1
  205. data/vendor/libgit2/src/index.c +666 -84
  206. data/vendor/libgit2/src/index.h +6 -0
  207. data/vendor/libgit2/src/indexer.c +10 -28
  208. data/vendor/libgit2/src/iterator.c +427 -283
  209. data/vendor/libgit2/src/iterator.h +58 -4
  210. data/vendor/libgit2/src/merge.c +1892 -32
  211. data/vendor/libgit2/src/merge.h +132 -5
  212. data/vendor/libgit2/src/merge_file.c +174 -0
  213. data/vendor/libgit2/src/merge_file.h +71 -0
  214. data/vendor/libgit2/src/mwindow.c +1 -1
  215. data/vendor/libgit2/src/notes.c +45 -48
  216. data/vendor/libgit2/src/object.c +89 -127
  217. data/vendor/libgit2/src/object.h +0 -1
  218. data/vendor/libgit2/src/object_api.c +129 -0
  219. data/vendor/libgit2/src/odb.c +156 -59
  220. data/vendor/libgit2/src/odb.h +5 -2
  221. data/vendor/libgit2/src/odb_loose.c +31 -17
  222. data/vendor/libgit2/src/odb_pack.c +39 -43
  223. data/vendor/libgit2/src/oid.c +62 -27
  224. data/vendor/libgit2/src/oid.h +33 -0
  225. data/vendor/libgit2/src/oidmap.h +4 -6
  226. data/vendor/libgit2/src/pack-objects.c +54 -22
  227. data/vendor/libgit2/src/pack.c +98 -56
  228. data/vendor/libgit2/src/pack.h +3 -1
  229. data/vendor/libgit2/src/pathspec.c +26 -1
  230. data/vendor/libgit2/src/pathspec.h +14 -0
  231. data/vendor/libgit2/src/pool.c +5 -0
  232. data/vendor/libgit2/src/posix.c +2 -2
  233. data/vendor/libgit2/src/posix.h +3 -0
  234. data/vendor/libgit2/src/push.c +13 -10
  235. data/vendor/libgit2/src/refdb.c +82 -62
  236. data/vendor/libgit2/src/refdb.h +16 -16
  237. data/vendor/libgit2/src/refdb_fs.c +386 -133
  238. data/vendor/libgit2/src/reflog.c +3 -1
  239. data/vendor/libgit2/src/refs.c +247 -221
  240. data/vendor/libgit2/src/refs.h +2 -1
  241. data/vendor/libgit2/src/refspec.c +18 -1
  242. data/vendor/libgit2/src/refspec.h +3 -1
  243. data/vendor/libgit2/src/remote.c +434 -253
  244. data/vendor/libgit2/src/remote.h +5 -3
  245. data/vendor/libgit2/src/repository.c +197 -111
  246. data/vendor/libgit2/src/repository.h +26 -5
  247. data/vendor/libgit2/src/reset.c +1 -1
  248. data/vendor/libgit2/src/revparse.c +84 -79
  249. data/vendor/libgit2/src/revwalk.c +1 -1
  250. data/vendor/libgit2/src/signature.c +22 -10
  251. data/vendor/libgit2/src/stash.c +5 -2
  252. data/vendor/libgit2/src/status.c +311 -107
  253. data/vendor/libgit2/src/status.h +23 -0
  254. data/vendor/libgit2/src/submodule.c +21 -13
  255. data/vendor/libgit2/src/tag.c +42 -31
  256. data/vendor/libgit2/src/tag.h +2 -3
  257. data/vendor/libgit2/src/thread-utils.h +105 -3
  258. data/vendor/libgit2/src/trace.c +1 -2
  259. data/vendor/libgit2/src/trace.h +3 -3
  260. data/vendor/libgit2/src/transport.c +18 -6
  261. data/vendor/libgit2/src/transports/cred.c +103 -1
  262. data/vendor/libgit2/src/transports/local.c +19 -9
  263. data/vendor/libgit2/src/transports/smart_protocol.c +32 -12
  264. data/vendor/libgit2/src/transports/ssh.c +519 -0
  265. data/vendor/libgit2/src/transports/winhttp.c +3 -1
  266. data/vendor/libgit2/src/tree.c +26 -28
  267. data/vendor/libgit2/src/tree.h +3 -3
  268. data/vendor/libgit2/src/unix/posix.h +2 -0
  269. data/vendor/libgit2/src/util.c +43 -6
  270. data/vendor/libgit2/src/util.h +40 -12
  271. data/vendor/libgit2/src/vector.c +3 -5
  272. data/vendor/libgit2/src/vector.h +9 -0
  273. data/vendor/libgit2/src/win32/dir.c +1 -1
  274. data/vendor/libgit2/src/win32/error.c +2 -0
  275. data/vendor/libgit2/src/win32/findfile.c +3 -6
  276. data/vendor/libgit2/src/win32/posix_w32.c +85 -59
  277. data/vendor/libgit2/src/win32/pthread.c +16 -8
  278. data/vendor/libgit2/src/win32/pthread.h +7 -4
  279. metadata +407 -306
  280. data/test/coverage/HEAD.json +0 -1
  281. data/vendor/libgit2/include/git2/refdb_backend.h +0 -109
  282. data/vendor/libgit2/src/diff_output.c +0 -1819
  283. data/vendor/libgit2/src/diff_output.h +0 -93
@@ -25,14 +25,14 @@ GIT_INLINE(void) git_trace__write_fmt(
25
25
  git_trace_level_t level,
26
26
  const char *fmt, ...)
27
27
  {
28
- git_trace_callback callback = git_trace__data.callback;
28
+ git_trace_callback callback = git_trace__data.callback;
29
29
  git_buf message = GIT_BUF_INIT;
30
30
  va_list ap;
31
-
31
+
32
32
  va_start(ap, fmt);
33
33
  git_buf_vprintf(&message, fmt, ap);
34
34
  va_end(ap);
35
-
35
+
36
36
  callback(level, git_buf_cstr(&message));
37
37
 
38
38
  git_buf_free(&message);
@@ -18,19 +18,27 @@ typedef struct transport_definition {
18
18
  void *param;
19
19
  } transport_definition;
20
20
 
21
- static transport_definition local_transport_definition = { "file://", 1, git_transport_local, NULL };
22
- static transport_definition dummy_transport_definition = { NULL, 1, git_transport_dummy, NULL };
23
-
24
21
  static git_smart_subtransport_definition http_subtransport_definition = { git_smart_subtransport_http, 1 };
25
22
  static git_smart_subtransport_definition git_subtransport_definition = { git_smart_subtransport_git, 0 };
23
+ #ifdef GIT_SSH
24
+ static git_smart_subtransport_definition ssh_subtransport_definition = { git_smart_subtransport_ssh, 0 };
25
+ #endif
26
+
27
+ static transport_definition local_transport_definition = { "file://", 1, git_transport_local, NULL };
28
+ #ifdef GIT_SSH
29
+ static transport_definition ssh_transport_definition = { "ssh://", 1, git_transport_smart, &ssh_subtransport_definition };
30
+ #else
31
+ static transport_definition dummy_transport_definition = { NULL, 1, git_transport_dummy, NULL };
32
+ #endif
26
33
 
27
34
  static transport_definition transports[] = {
28
35
  {"git://", 1, git_transport_smart, &git_subtransport_definition},
29
36
  {"http://", 1, git_transport_smart, &http_subtransport_definition},
30
37
  {"https://", 1, git_transport_smart, &http_subtransport_definition},
31
38
  {"file://", 1, git_transport_local, NULL},
32
- {"git+ssh://", 1, git_transport_dummy, NULL},
33
- {"ssh+git://", 1, git_transport_dummy, NULL},
39
+ #ifdef GIT_SSH
40
+ {"ssh://", 1, git_transport_smart, &ssh_subtransport_definition},
41
+ #endif
34
42
  {NULL, 0, 0}
35
43
  };
36
44
 
@@ -73,7 +81,11 @@ static int transport_find_fn(const char *url, git_transport_cb *callback, void *
73
81
  /* It could be a SSH remote path. Check to see if there's a :
74
82
  * SSH is an unsupported transport mechanism in this version of libgit2 */
75
83
  if (!definition && strrchr(url, ':'))
76
- definition = &dummy_transport_definition;
84
+ #ifdef GIT_SSH
85
+ definition = &ssh_transport_definition;
86
+ #else
87
+ definition = &dummy_transport_definition;
88
+ #endif
77
89
 
78
90
  /* Check to see if the path points to a file on the local file system */
79
91
  if (!definition && git_path_exists(url) && git_path_isdir(url))
@@ -17,7 +17,7 @@ static void plaintext_free(struct git_cred *cred)
17
17
  git__free(c->username);
18
18
 
19
19
  /* Zero the memory which previously held the password */
20
- memset(c->password, 0x0, pass_len);
20
+ git__memzero(c->password, pass_len);
21
21
  git__free(c->password);
22
22
 
23
23
  memset(c, 0, sizeof(*c));
@@ -58,3 +58,105 @@ int git_cred_userpass_plaintext_new(
58
58
  *cred = &c->parent;
59
59
  return 0;
60
60
  }
61
+
62
+ #ifdef GIT_SSH
63
+ static void ssh_keyfile_passphrase_free(struct git_cred *cred)
64
+ {
65
+ git_cred_ssh_keyfile_passphrase *c = (git_cred_ssh_keyfile_passphrase *)cred;
66
+ size_t pass_len = strlen(c->passphrase);
67
+
68
+ if (c->publickey) {
69
+ git__free(c->publickey);
70
+ }
71
+
72
+ git__free(c->privatekey);
73
+
74
+ if (c->passphrase) {
75
+ /* Zero the memory which previously held the passphrase */
76
+ git__memzero(c->passphrase, pass_len);
77
+ git__free(c->passphrase);
78
+ }
79
+
80
+ memset(c, 0, sizeof(*c));
81
+
82
+ git__free(c);
83
+ }
84
+
85
+ int git_cred_ssh_keyfile_passphrase_new(
86
+ git_cred **cred,
87
+ const char *publickey,
88
+ const char *privatekey,
89
+ const char *passphrase)
90
+ {
91
+ git_cred_ssh_keyfile_passphrase *c;
92
+
93
+ assert(cred && privatekey);
94
+
95
+ c = git__calloc(1, sizeof(git_cred_ssh_keyfile_passphrase));
96
+ GITERR_CHECK_ALLOC(c);
97
+
98
+ c->parent.credtype = GIT_CREDTYPE_SSH_KEYFILE_PASSPHRASE;
99
+ c->parent.free = ssh_keyfile_passphrase_free;
100
+
101
+ c->privatekey = git__strdup(privatekey);
102
+ GITERR_CHECK_ALLOC(c->privatekey);
103
+
104
+ if (publickey) {
105
+ c->publickey = git__strdup(publickey);
106
+ GITERR_CHECK_ALLOC(c->publickey);
107
+ }
108
+
109
+ if (passphrase) {
110
+ c->passphrase = git__strdup(passphrase);
111
+ GITERR_CHECK_ALLOC(c->passphrase);
112
+ }
113
+
114
+ *cred = &c->parent;
115
+ return 0;
116
+ }
117
+
118
+ static void ssh_publickey_free(struct git_cred *cred)
119
+ {
120
+ git_cred_ssh_publickey *c = (git_cred_ssh_publickey *)cred;
121
+
122
+ git__free(c->publickey);
123
+
124
+ c->sign_callback = NULL;
125
+ c->sign_data = NULL;
126
+
127
+ memset(c, 0, sizeof(*c));
128
+
129
+ git__free(c);
130
+ }
131
+
132
+ int git_cred_ssh_publickey_new(
133
+ git_cred **cred,
134
+ const char *publickey,
135
+ size_t publickey_len,
136
+ LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC((*sign_callback)),
137
+ void *sign_data)
138
+ {
139
+ git_cred_ssh_publickey *c;
140
+
141
+ if (!cred)
142
+ return -1;
143
+
144
+ c = git__malloc(sizeof(git_cred_ssh_publickey));
145
+ GITERR_CHECK_ALLOC(c);
146
+
147
+ c->parent.credtype = GIT_CREDTYPE_SSH_PUBLICKEY;
148
+ c->parent.free = ssh_publickey_free;
149
+
150
+ c->publickey = git__malloc(publickey_len);
151
+ GITERR_CHECK_ALLOC(c->publickey);
152
+
153
+ memcpy(c->publickey, publickey, publickey_len);
154
+
155
+ c->publickey_len = publickey_len;
156
+ c->sign_callback = sign_callback;
157
+ c->sign_data = sign_data;
158
+
159
+ *cred = &c->parent;
160
+ return 0;
161
+ }
162
+ #endif
@@ -119,15 +119,24 @@ on_error:
119
119
 
120
120
  static int store_refs(transport_local *t)
121
121
  {
122
- unsigned int i;
122
+ size_t i;
123
+ git_remote_head *head;
123
124
  git_strarray ref_names = {0};
124
125
 
125
126
  assert(t);
126
127
 
127
- if (git_reference_list(&ref_names, t->repo, GIT_REF_LISTALL) < 0 ||
128
- git_vector_init(&t->refs, ref_names.count, NULL) < 0)
128
+ if (git_reference_list(&ref_names, t->repo) < 0)
129
129
  goto on_error;
130
130
 
131
+ /* Clear all heads we might have fetched in a previous connect */
132
+ git_vector_foreach(&t->refs, i, head) {
133
+ git__free(head->name);
134
+ git__free(head);
135
+ }
136
+
137
+ /* Clear the vector so we can reuse it */
138
+ git_vector_clear(&t->refs);
139
+
131
140
  /* Sort the references first */
132
141
  git__tsort((void **)ref_names.strings, ref_names.count, &git__strcmp_cb);
133
142
 
@@ -282,7 +291,7 @@ static int local_push_copy_object(
282
291
  odb_obj_size) < 0 ||
283
292
  odb_stream->finalize_write(&remote_odb_obj_oid, odb_stream) < 0) {
284
293
  error = -1;
285
- } else if (git_oid_cmp(&obj->id, &remote_odb_obj_oid) != 0) {
294
+ } else if (git_oid__cmp(&obj->id, &remote_odb_obj_oid) != 0) {
286
295
  giterr_set(GITERR_ODB, "Error when writing object to remote odb "
287
296
  "during local push operation. Remote odb object oid does not "
288
297
  "match local oid.");
@@ -348,7 +357,7 @@ static int local_push(
348
357
  if ((error = git_repository_open(&remote_repo, push->remote->url)) < 0)
349
358
  return error;
350
359
 
351
- /* We don't currently support pushing locally to non-bare repos. Proper
360
+ /* We don't currently support pushing locally to non-bare repos. Proper
352
361
  non-bare repo push support would require checking configs to see if
353
362
  we should override the default 'don't let this happen' behavior */
354
363
  if (!remote_repo->is_bare) {
@@ -495,7 +504,7 @@ static int local_download_pack(
495
504
  /* Tag or some other wanted object. Add it on its own */
496
505
  error = git_packbuilder_insert(pack, &rhead->oid, rhead->name);
497
506
  }
498
- git_object_free(obj);
507
+ git_object_free(obj);
499
508
  }
500
509
 
501
510
  /* Walk the objects, building a packfile */
@@ -593,9 +602,6 @@ static void local_free(git_transport *transport)
593
602
  size_t i;
594
603
  git_remote_head *head;
595
604
 
596
- /* Close the transport, if it's still open. */
597
- local_close(transport);
598
-
599
605
  git_vector_foreach(&t->refs, i, head) {
600
606
  git__free(head->name);
601
607
  git__free(head);
@@ -603,6 +609,9 @@ static void local_free(git_transport *transport)
603
609
 
604
610
  git_vector_free(&t->refs);
605
611
 
612
+ /* Close the transport, if it's still open. */
613
+ local_close(transport);
614
+
606
615
  /* Free the transport */
607
616
  git__free(t);
608
617
  }
@@ -632,6 +641,7 @@ int git_transport_local(git_transport **out, git_remote *owner, void *param)
632
641
  t->parent.read_flags = local_read_flags;
633
642
  t->parent.cancel = local_cancel;
634
643
 
644
+ git_vector_init(&t->refs, 0, NULL);
635
645
  t->owner = owner;
636
646
 
637
647
  *out = (git_transport *) t;
@@ -5,6 +5,7 @@
5
5
  * a Linking Exception. For full terms see the included COPYING file.
6
6
  */
7
7
  #include "git2.h"
8
+ #include "git2/odb_backend.h"
8
9
 
9
10
  #include "smart.h"
10
11
  #include "refs.h"
@@ -20,12 +21,18 @@ int git_smart__store_refs(transport_smart *t, int flushes)
20
21
  gitno_buffer *buf = &t->buffer;
21
22
  git_vector *refs = &t->refs;
22
23
  int error, flush = 0, recvd;
23
- const char *line_end;
24
- git_pkt *pkt;
24
+ const char *line_end = NULL;
25
+ git_pkt *pkt = NULL;
26
+ git_pkt_ref *ref;
27
+ size_t i;
25
28
 
26
29
  /* Clear existing refs in case git_remote_connect() is called again
27
30
  * after git_remote_disconnect().
28
31
  */
32
+ git_vector_foreach(refs, i, ref) {
33
+ git__free(ref->head.name);
34
+ git__free(ref);
35
+ }
29
36
  git_vector_clear(refs);
30
37
 
31
38
  do {
@@ -128,7 +135,7 @@ int git_smart__detect_caps(git_pkt_ref *pkt, transport_smart_caps *caps)
128
135
  static int recv_pkt(git_pkt **out, gitno_buffer *buf)
129
136
  {
130
137
  const char *ptr = buf->data, *line_end = ptr;
131
- git_pkt *pkt;
138
+ git_pkt *pkt = NULL;
132
139
  int pkt_type, error = 0, ret;
133
140
 
134
141
  do {
@@ -186,7 +193,7 @@ static int fetch_setup_walk(git_revwalk **out, git_repository *repo)
186
193
  unsigned int i;
187
194
  git_reference *ref;
188
195
 
189
- if (git_reference_list(&refs, repo, GIT_REF_LISTALL) < 0)
196
+ if (git_reference_list(&refs, repo) < 0)
190
197
  return -1;
191
198
 
192
199
  if (git_revwalk_new(&walk, repo) < 0)
@@ -569,7 +576,7 @@ static int add_push_report_pkt(git_push *push, git_pkt *pkt)
569
576
 
570
577
  switch (pkt->type) {
571
578
  case GIT_PKT_OK:
572
- status = git__malloc(sizeof(push_status));
579
+ status = git__calloc(1, sizeof(push_status));
573
580
  GITERR_CHECK_ALLOC(status);
574
581
  status->msg = NULL;
575
582
  status->ref = git__strdup(((git_pkt_ok *)pkt)->ref);
@@ -633,8 +640,8 @@ static int add_push_report_sideband_pkt(git_push *push, git_pkt_data *data_pkt)
633
640
 
634
641
  static int parse_report(gitno_buffer *buf, git_push *push)
635
642
  {
636
- git_pkt *pkt;
637
- const char *line_end;
643
+ git_pkt *pkt = NULL;
644
+ const char *line_end = NULL;
638
645
  int error, recvd;
639
646
 
640
647
  for (;;) {
@@ -806,13 +813,13 @@ int git_smart__push(git_transport *transport, git_push *push)
806
813
  transport_smart *t = (transport_smart *)transport;
807
814
  git_smart_subtransport_stream *s;
808
815
  git_buf pktline = GIT_BUF_INIT;
809
- int error = -1;
816
+ int error = -1, need_pack = 0;
817
+ push_spec *spec;
818
+ unsigned int i;
810
819
 
811
820
  #ifdef PUSH_DEBUG
812
821
  {
813
822
  git_remote_head *head;
814
- push_spec *spec;
815
- unsigned int i;
816
823
  char hex[41]; hex[40] = '\0';
817
824
 
818
825
  git_vector_foreach(&push->remote->refs, i, head) {
@@ -830,10 +837,23 @@ int git_smart__push(git_transport *transport, git_push *push)
830
837
  }
831
838
  #endif
832
839
 
840
+ /*
841
+ * Figure out if we need to send a packfile; which is in all
842
+ * cases except when we only send delete commands
843
+ */
844
+ git_vector_foreach(&push->specs, i, spec) {
845
+ if (spec->lref) {
846
+ need_pack = 1;
847
+ break;
848
+ }
849
+ }
850
+
833
851
  if (git_smart__get_push_stream(t, &s) < 0 ||
834
852
  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)
853
+ s->write(s, git_buf_cstr(&pktline), git_buf_len(&pktline)) < 0)
854
+ goto on_error;
855
+
856
+ if (need_pack && git_packbuilder_foreach(push->pb, &stream_thunk, s) < 0)
837
857
  goto on_error;
838
858
 
839
859
  /* If we sent nothing or the server doesn't support report-status, then
@@ -0,0 +1,519 @@
1
+ /*
2
+ * Copyright (C) the libgit2 contributors. All rights reserved.
3
+ *
4
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
5
+ * a Linking Exception. For full terms see the included COPYING file.
6
+ */
7
+
8
+ #ifdef GIT_SSH
9
+
10
+ #include "git2.h"
11
+ #include "buffer.h"
12
+ #include "netops.h"
13
+ #include "smart.h"
14
+
15
+ #include <libssh2.h>
16
+
17
+ #define OWNING_SUBTRANSPORT(s) ((ssh_subtransport *)(s)->parent.subtransport)
18
+
19
+ static const char prefix_ssh[] = "ssh://";
20
+ static const char default_user[] = "git";
21
+ static const char cmd_uploadpack[] = "git-upload-pack";
22
+ static const char cmd_receivepack[] = "git-receive-pack";
23
+
24
+ typedef struct {
25
+ git_smart_subtransport_stream parent;
26
+ gitno_socket socket;
27
+ LIBSSH2_SESSION *session;
28
+ LIBSSH2_CHANNEL *channel;
29
+ const char *cmd;
30
+ char *url;
31
+ unsigned sent_command : 1;
32
+ } ssh_stream;
33
+
34
+ typedef struct {
35
+ git_smart_subtransport parent;
36
+ transport_smart *owner;
37
+ ssh_stream *current_stream;
38
+ git_cred *cred;
39
+ } ssh_subtransport;
40
+
41
+ /*
42
+ * Create a git protocol request.
43
+ *
44
+ * For example: git-upload-pack '/libgit2/libgit2'
45
+ */
46
+ static int gen_proto(git_buf *request, const char *cmd, const char *url)
47
+ {
48
+ char *repo;
49
+
50
+ if (!git__prefixcmp(url, prefix_ssh)) {
51
+ url = url + strlen(prefix_ssh);
52
+ repo = strchr(url, '/');
53
+ } else {
54
+ repo = strchr(url, ':');
55
+ }
56
+
57
+ if (!repo) {
58
+ return -1;
59
+ }
60
+
61
+ int len = strlen(cmd) + 1 /* Space */ + 1 /* Quote */ + strlen(repo) + 1 /* Quote */ + 1;
62
+
63
+ git_buf_grow(request, len);
64
+ git_buf_printf(request, "%s '%s'", cmd, repo);
65
+ git_buf_putc(request, '\0');
66
+
67
+ if (git_buf_oom(request))
68
+ return -1;
69
+
70
+ return 0;
71
+ }
72
+
73
+ static int send_command(ssh_stream *s)
74
+ {
75
+ int error;
76
+ git_buf request = GIT_BUF_INIT;
77
+
78
+ error = gen_proto(&request, s->cmd, s->url);
79
+ if (error < 0)
80
+ goto cleanup;
81
+
82
+ error = libssh2_channel_exec(
83
+ s->channel,
84
+ request.ptr
85
+ );
86
+
87
+ if (0 != error)
88
+ goto cleanup;
89
+
90
+ s->sent_command = 1;
91
+
92
+ cleanup:
93
+ git_buf_free(&request);
94
+ return error;
95
+ }
96
+
97
+ static int ssh_stream_read(
98
+ git_smart_subtransport_stream *stream,
99
+ char *buffer,
100
+ size_t buf_size,
101
+ size_t *bytes_read)
102
+ {
103
+ ssh_stream *s = (ssh_stream *)stream;
104
+
105
+ *bytes_read = 0;
106
+
107
+ if (!s->sent_command && send_command(s) < 0)
108
+ return -1;
109
+
110
+ int rc = libssh2_channel_read(s->channel, buffer, buf_size);
111
+ if (rc < 0)
112
+ return -1;
113
+
114
+ *bytes_read = rc;
115
+
116
+ return 0;
117
+ }
118
+
119
+ static int ssh_stream_write(
120
+ git_smart_subtransport_stream *stream,
121
+ const char *buffer,
122
+ size_t len)
123
+ {
124
+ ssh_stream *s = (ssh_stream *)stream;
125
+
126
+ if (!s->sent_command && send_command(s) < 0)
127
+ return -1;
128
+
129
+ int rc = libssh2_channel_write(s->channel, buffer, len);
130
+ if (rc < 0) {
131
+ return -1;
132
+ }
133
+
134
+ return rc;
135
+ }
136
+
137
+ static void ssh_stream_free(git_smart_subtransport_stream *stream)
138
+ {
139
+ ssh_stream *s = (ssh_stream *)stream;
140
+ ssh_subtransport *t = OWNING_SUBTRANSPORT(s);
141
+ int ret;
142
+
143
+ GIT_UNUSED(ret);
144
+
145
+ t->current_stream = NULL;
146
+
147
+ if (s->channel) {
148
+ libssh2_channel_close(s->channel);
149
+ libssh2_channel_free(s->channel);
150
+ s->channel = NULL;
151
+ }
152
+
153
+ if (s->session) {
154
+ libssh2_session_free(s->session), s->session = NULL;
155
+ }
156
+
157
+ if (s->socket.socket) {
158
+ ret = gitno_close(&s->socket);
159
+ assert(!ret);
160
+ }
161
+
162
+ git__free(s->url);
163
+ git__free(s);
164
+ }
165
+
166
+ static int ssh_stream_alloc(
167
+ ssh_subtransport *t,
168
+ const char *url,
169
+ const char *cmd,
170
+ git_smart_subtransport_stream **stream)
171
+ {
172
+ ssh_stream *s;
173
+
174
+ if (!stream)
175
+ return -1;
176
+
177
+ s = git__calloc(sizeof(ssh_stream), 1);
178
+ GITERR_CHECK_ALLOC(s);
179
+
180
+ s->parent.subtransport = &t->parent;
181
+ s->parent.read = ssh_stream_read;
182
+ s->parent.write = ssh_stream_write;
183
+ s->parent.free = ssh_stream_free;
184
+
185
+ s->cmd = cmd;
186
+ s->url = git__strdup(url);
187
+
188
+ if (!s->url) {
189
+ git__free(s);
190
+ return -1;
191
+ }
192
+
193
+ *stream = &s->parent;
194
+ return 0;
195
+ }
196
+
197
+ static int git_ssh_extract_url_parts(
198
+ char **host,
199
+ char **username,
200
+ const char *url)
201
+ {
202
+ char *colon, *at;
203
+ const char *start;
204
+
205
+ colon = strchr(url, ':');
206
+
207
+ if (colon == NULL) {
208
+ giterr_set(GITERR_NET, "Malformed URL: missing :");
209
+ return -1;
210
+ }
211
+
212
+ at = strchr(url, '@');
213
+ if (at) {
214
+ start = at+1;
215
+ *username = git__substrdup(url, at - url);
216
+ } else {
217
+ start = url;
218
+ *username = git__strdup(default_user);
219
+ }
220
+
221
+ *host = git__substrdup(start, colon - start);
222
+
223
+ return 0;
224
+ }
225
+
226
+ static int _git_ssh_authenticate_session(
227
+ LIBSSH2_SESSION* session,
228
+ const char *user,
229
+ git_cred* cred
230
+ )
231
+ {
232
+ int rc;
233
+ do {
234
+ switch (cred->credtype) {
235
+ case GIT_CREDTYPE_USERPASS_PLAINTEXT: {
236
+ git_cred_userpass_plaintext *c = (git_cred_userpass_plaintext *)cred;
237
+ rc = libssh2_userauth_password(
238
+ session,
239
+ c->username,
240
+ c->password
241
+ );
242
+ break;
243
+ }
244
+ case GIT_CREDTYPE_SSH_KEYFILE_PASSPHRASE: {
245
+ git_cred_ssh_keyfile_passphrase *c = (git_cred_ssh_keyfile_passphrase *)cred;
246
+ rc = libssh2_userauth_publickey_fromfile(
247
+ session,
248
+ user,
249
+ c->publickey,
250
+ c->privatekey,
251
+ c->passphrase
252
+ );
253
+ break;
254
+ }
255
+ case GIT_CREDTYPE_SSH_PUBLICKEY: {
256
+ git_cred_ssh_publickey *c = (git_cred_ssh_publickey *)cred;
257
+ rc = libssh2_userauth_publickey(
258
+ session,
259
+ user,
260
+ (const unsigned char *)c->publickey,
261
+ c->publickey_len,
262
+ c->sign_callback,
263
+ &c->sign_data
264
+ );
265
+ break;
266
+ }
267
+ default:
268
+ rc = LIBSSH2_ERROR_AUTHENTICATION_FAILED;
269
+ }
270
+ } while (LIBSSH2_ERROR_EAGAIN == rc || LIBSSH2_ERROR_TIMEOUT == rc);
271
+
272
+ return rc;
273
+ }
274
+
275
+ static int _git_ssh_session_create
276
+ (
277
+ LIBSSH2_SESSION** session,
278
+ gitno_socket socket
279
+ )
280
+ {
281
+ if (!session) {
282
+ return -1;
283
+ }
284
+
285
+ LIBSSH2_SESSION* s = libssh2_session_init();
286
+ if (!s)
287
+ return -1;
288
+
289
+ int rc = 0;
290
+ do {
291
+ rc = libssh2_session_startup(s, socket.socket);
292
+ } while (LIBSSH2_ERROR_EAGAIN == rc || LIBSSH2_ERROR_TIMEOUT == rc);
293
+
294
+ if (0 != rc) {
295
+ goto on_error;
296
+ }
297
+
298
+ libssh2_session_set_blocking(s, 1);
299
+
300
+ *session = s;
301
+
302
+ return 0;
303
+
304
+ on_error:
305
+ if (s) {
306
+ libssh2_session_free(s), s = NULL;
307
+ }
308
+
309
+ return -1;
310
+ }
311
+
312
+ static int _git_ssh_setup_conn(
313
+ ssh_subtransport *t,
314
+ const char *url,
315
+ const char *cmd,
316
+ git_smart_subtransport_stream **stream
317
+ )
318
+ {
319
+ char *host, *port=NULL, *user=NULL, *pass=NULL;
320
+ const char *default_port="22";
321
+ ssh_stream *s;
322
+ LIBSSH2_SESSION* session=NULL;
323
+ LIBSSH2_CHANNEL* channel=NULL;
324
+
325
+ *stream = NULL;
326
+ if (ssh_stream_alloc(t, url, cmd, stream) < 0)
327
+ return -1;
328
+
329
+ s = (ssh_stream *)*stream;
330
+
331
+ if (!git__prefixcmp(url, prefix_ssh)) {
332
+ url = url + strlen(prefix_ssh);
333
+ if (gitno_extract_url_parts(&host, &port, &user, &pass, url, default_port) < 0)
334
+ goto on_error;
335
+ } else {
336
+ if (git_ssh_extract_url_parts(&host, &user, url) < 0)
337
+ goto on_error;
338
+ port = git__strdup(default_port);
339
+ GITERR_CHECK_ALLOC(port);
340
+ }
341
+
342
+ if (gitno_connect(&s->socket, host, port, 0) < 0)
343
+ goto on_error;
344
+
345
+ if (user && pass) {
346
+ if (git_cred_userpass_plaintext_new(&t->cred, user, pass) < 0)
347
+ goto on_error;
348
+ } else {
349
+ if (t->owner->cred_acquire_cb(&t->cred,
350
+ t->owner->url,
351
+ user,
352
+ GIT_CREDTYPE_USERPASS_PLAINTEXT | GIT_CREDTYPE_SSH_KEYFILE_PASSPHRASE,
353
+ t->owner->cred_acquire_payload) < 0)
354
+ return -1;
355
+ }
356
+ assert(t->cred);
357
+
358
+ if (!user) {
359
+ user = git__strdup(default_user);
360
+ }
361
+
362
+ if (_git_ssh_session_create(&session, s->socket) < 0)
363
+ goto on_error;
364
+
365
+ if (_git_ssh_authenticate_session(session, user, t->cred) < 0)
366
+ goto on_error;
367
+
368
+ channel = libssh2_channel_open_session(session);
369
+ if (!channel)
370
+ goto on_error;
371
+
372
+ libssh2_channel_set_blocking(channel, 1);
373
+
374
+ s->session = session;
375
+ s->channel = channel;
376
+
377
+ t->current_stream = s;
378
+ git__free(host);
379
+ git__free(port);
380
+ git__free(user);
381
+ git__free(pass);
382
+
383
+ return 0;
384
+
385
+ on_error:
386
+ if (*stream)
387
+ ssh_stream_free(*stream);
388
+
389
+ git__free(host);
390
+ git__free(port);
391
+ git__free(user);
392
+ git__free(pass);
393
+
394
+ if (session)
395
+ libssh2_session_free(session), session = NULL;
396
+
397
+ return -1;
398
+ }
399
+
400
+ static int ssh_uploadpack_ls(
401
+ ssh_subtransport *t,
402
+ const char *url,
403
+ git_smart_subtransport_stream **stream)
404
+ {
405
+ if (_git_ssh_setup_conn(t, url, cmd_uploadpack, stream) < 0)
406
+ return -1;
407
+
408
+ return 0;
409
+ }
410
+
411
+ static int ssh_uploadpack(
412
+ ssh_subtransport *t,
413
+ const char *url,
414
+ git_smart_subtransport_stream **stream)
415
+ {
416
+ GIT_UNUSED(url);
417
+
418
+ if (t->current_stream) {
419
+ *stream = &t->current_stream->parent;
420
+ return 0;
421
+ }
422
+
423
+ giterr_set(GITERR_NET, "Must call UPLOADPACK_LS before UPLOADPACK");
424
+ return -1;
425
+ }
426
+
427
+ static int ssh_receivepack_ls(
428
+ ssh_subtransport *t,
429
+ const char *url,
430
+ git_smart_subtransport_stream **stream)
431
+ {
432
+ if (_git_ssh_setup_conn(t, url, cmd_receivepack, stream) < 0)
433
+ return -1;
434
+
435
+ return 0;
436
+ }
437
+
438
+ static int ssh_receivepack(
439
+ ssh_subtransport *t,
440
+ const char *url,
441
+ git_smart_subtransport_stream **stream)
442
+ {
443
+ GIT_UNUSED(url);
444
+
445
+ if (t->current_stream) {
446
+ *stream = &t->current_stream->parent;
447
+ return 0;
448
+ }
449
+
450
+ giterr_set(GITERR_NET, "Must call RECEIVEPACK_LS before RECEIVEPACK");
451
+ return -1;
452
+ }
453
+
454
+ static int _ssh_action(
455
+ git_smart_subtransport_stream **stream,
456
+ git_smart_subtransport *subtransport,
457
+ const char *url,
458
+ git_smart_service_t action)
459
+ {
460
+ ssh_subtransport *t = (ssh_subtransport *) subtransport;
461
+
462
+ switch (action) {
463
+ case GIT_SERVICE_UPLOADPACK_LS:
464
+ return ssh_uploadpack_ls(t, url, stream);
465
+
466
+ case GIT_SERVICE_UPLOADPACK:
467
+ return ssh_uploadpack(t, url, stream);
468
+
469
+ case GIT_SERVICE_RECEIVEPACK_LS:
470
+ return ssh_receivepack_ls(t, url, stream);
471
+
472
+ case GIT_SERVICE_RECEIVEPACK:
473
+ return ssh_receivepack(t, url, stream);
474
+ }
475
+
476
+ *stream = NULL;
477
+ return -1;
478
+ }
479
+
480
+ static int _ssh_close(git_smart_subtransport *subtransport)
481
+ {
482
+ ssh_subtransport *t = (ssh_subtransport *) subtransport;
483
+
484
+ assert(!t->current_stream);
485
+
486
+ GIT_UNUSED(t);
487
+
488
+ return 0;
489
+ }
490
+
491
+ static void _ssh_free(git_smart_subtransport *subtransport)
492
+ {
493
+ ssh_subtransport *t = (ssh_subtransport *) subtransport;
494
+
495
+ assert(!t->current_stream);
496
+
497
+ git__free(t);
498
+ }
499
+
500
+ int git_smart_subtransport_ssh(git_smart_subtransport **out, git_transport *owner)
501
+ {
502
+ ssh_subtransport *t;
503
+
504
+ if (!out)
505
+ return -1;
506
+
507
+ t = git__calloc(sizeof(ssh_subtransport), 1);
508
+ GITERR_CHECK_ALLOC(t);
509
+
510
+ t->owner = (transport_smart *)owner;
511
+ t->parent.action = _ssh_action;
512
+ t->parent.close = _ssh_close;
513
+ t->parent.free = _ssh_free;
514
+
515
+ *out = (git_smart_subtransport *) t;
516
+ return 0;
517
+ }
518
+
519
+ #endif