1 /*
2  * Copyright (C) the libgit2 contributors. All rights reserved.
3  *
4  * This file is part of libgit2, distributed under the GNU GPL v2 with
5  * a Linking Exception. For full terms see the included COPYING file.
6  */
7 
8 #include "common.h"
9 
10 #include "git2/types.h"
11 #include "git2/net.h"
12 #include "git2/repository.h"
13 #include "git2/object.h"
14 #include "git2/tag.h"
15 #include "git2/transport.h"
16 #include "git2/revwalk.h"
17 #include "git2/odb_backend.h"
18 #include "git2/pack.h"
19 #include "git2/commit.h"
20 #include "git2/revparse.h"
21 
22 #include "pack-objects.h"
23 #include "refs.h"
24 #include "posix.h"
25 #include "path.h"
26 #include "buffer.h"
27 #include "repository.h"
28 #include "odb.h"
29 #include "push.h"
30 #include "remote.h"
31 #include "proxy.h"
32 
33 typedef struct {
34 	git_transport parent;
35 	git_remote *owner;
36 	char *url;
37 	int direction;
38 	int flags;
39 	git_atomic cancelled;
40 	git_repository *repo;
41 	git_transport_message_cb progress_cb;
42 	git_transport_message_cb error_cb;
43 	void *message_cb_payload;
44 	git_vector refs;
45 	unsigned connected : 1,
46 		have_refs : 1;
47 } transport_local;
48 
free_head(git_remote_head * head)49 static void free_head(git_remote_head *head)
50 {
51 	git__free(head->name);
52 	git__free(head->symref_target);
53 	git__free(head);
54 }
55 
free_heads(git_vector * heads)56 static void free_heads(git_vector *heads)
57 {
58 	git_remote_head *head;
59 	size_t i;
60 
61 	git_vector_foreach(heads, i, head)
62 		free_head(head);
63 
64 	git_vector_free(heads);
65 }
66 
add_ref(transport_local * t,const char * name)67 static int add_ref(transport_local *t, const char *name)
68 {
69 	const char peeled[] = "^{}";
70 	git_reference *ref, *resolved;
71 	git_remote_head *head;
72 	git_oid obj_id;
73 	git_object *obj = NULL, *target = NULL;
74 	git_buf buf = GIT_BUF_INIT;
75 	int error;
76 
77 	if ((error = git_reference_lookup(&ref, t->repo, name)) < 0)
78 		return error;
79 
80 	error = git_reference_resolve(&resolved, ref);
81 	if (error < 0) {
82 		git_reference_free(ref);
83 		if (!strcmp(name, GIT_HEAD_FILE) && error == GIT_ENOTFOUND) {
84 			/* This is actually okay.  Empty repos often have a HEAD that
85 			 * points to a nonexistent "refs/heads/master". */
86 			git_error_clear();
87 			return 0;
88 		}
89 		return error;
90 	}
91 
92 	git_oid_cpy(&obj_id, git_reference_target(resolved));
93 	git_reference_free(resolved);
94 
95 	head = git__calloc(1, sizeof(git_remote_head));
96 	GIT_ERROR_CHECK_ALLOC(head);
97 
98 	head->name = git__strdup(name);
99 	GIT_ERROR_CHECK_ALLOC(head->name);
100 
101 	git_oid_cpy(&head->oid, &obj_id);
102 
103 	if (git_reference_type(ref) == GIT_REFERENCE_SYMBOLIC) {
104 		head->symref_target = git__strdup(git_reference_symbolic_target(ref));
105 		GIT_ERROR_CHECK_ALLOC(head->symref_target);
106 	}
107 	git_reference_free(ref);
108 
109 	if ((error = git_vector_insert(&t->refs, head)) < 0) {
110 		free_head(head);
111 		return error;
112 	}
113 
114 	/* If it's not a tag, we don't need to try to peel it */
115 	if (git__prefixcmp(name, GIT_REFS_TAGS_DIR))
116 		return 0;
117 
118 	if ((error = git_object_lookup(&obj, t->repo, &head->oid, GIT_OBJECT_ANY)) < 0)
119 		return error;
120 
121 	head = NULL;
122 
123 	/* If it's not an annotated tag, or if we're mocking
124 	 * git-receive-pack, just get out */
125 	if (git_object_type(obj) != GIT_OBJECT_TAG ||
126 		t->direction != GIT_DIRECTION_FETCH) {
127 		git_object_free(obj);
128 		return 0;
129 	}
130 
131 	/* And if it's a tag, peel it, and add it to the list */
132 	head = git__calloc(1, sizeof(git_remote_head));
133 	GIT_ERROR_CHECK_ALLOC(head);
134 
135 	if (git_buf_join(&buf, 0, name, peeled) < 0) {
136 		free_head(head);
137 		return -1;
138 	}
139 	head->name = git_buf_detach(&buf);
140 
141 	if (!(error = git_tag_peel(&target, (git_tag *)obj))) {
142 		git_oid_cpy(&head->oid, git_object_id(target));
143 
144 		if ((error = git_vector_insert(&t->refs, head)) < 0) {
145 			free_head(head);
146 		}
147 	}
148 
149 	git_object_free(obj);
150 	git_object_free(target);
151 
152 	return error;
153 }
154 
store_refs(transport_local * t)155 static int store_refs(transport_local *t)
156 {
157 	size_t i;
158 	git_remote_head *head;
159 	git_strarray ref_names = {0};
160 
161 	assert(t);
162 
163 	if (git_reference_list(&ref_names, t->repo) < 0)
164 		goto on_error;
165 
166 	/* Clear all heads we might have fetched in a previous connect */
167 	git_vector_foreach(&t->refs, i, head) {
168 		git__free(head->name);
169 		git__free(head);
170 	}
171 
172 	/* Clear the vector so we can reuse it */
173 	git_vector_clear(&t->refs);
174 
175 	/* Sort the references first */
176 	git__tsort((void **)ref_names.strings, ref_names.count, &git__strcmp_cb);
177 
178 	/* Add HEAD iff direction is fetch */
179 	if (t->direction == GIT_DIRECTION_FETCH && add_ref(t, GIT_HEAD_FILE) < 0)
180 		goto on_error;
181 
182 	for (i = 0; i < ref_names.count; ++i) {
183 		if (add_ref(t, ref_names.strings[i]) < 0)
184 			goto on_error;
185 	}
186 
187 	t->have_refs = 1;
188 	git_strarray_dispose(&ref_names);
189 	return 0;
190 
191 on_error:
192 	git_vector_free(&t->refs);
193 	git_strarray_dispose(&ref_names);
194 	return -1;
195 }
196 
197 /*
198  * Try to open the url as a git directory. The direction doesn't
199  * matter in this case because we're calculating the heads ourselves.
200  */
local_connect(git_transport * transport,const char * url,git_credential_acquire_cb cred_acquire_cb,void * cred_acquire_payload,const git_proxy_options * proxy,int direction,int flags)201 static int local_connect(
202 	git_transport *transport,
203 	const char *url,
204 	git_credential_acquire_cb cred_acquire_cb,
205 	void *cred_acquire_payload,
206 	const git_proxy_options *proxy,
207 	int direction, int flags)
208 {
209 	git_repository *repo;
210 	int error;
211 	transport_local *t = (transport_local *) transport;
212 	const char *path;
213 	git_buf buf = GIT_BUF_INIT;
214 
215 	GIT_UNUSED(cred_acquire_cb);
216 	GIT_UNUSED(cred_acquire_payload);
217 	GIT_UNUSED(proxy);
218 
219 	if (t->connected)
220 		return 0;
221 
222 	free_heads(&t->refs);
223 
224 	t->url = git__strdup(url);
225 	GIT_ERROR_CHECK_ALLOC(t->url);
226 	t->direction = direction;
227 	t->flags = flags;
228 
229 	/* 'url' may be a url or path; convert to a path */
230 	if ((error = git_path_from_url_or_path(&buf, url)) < 0) {
231 		git_buf_dispose(&buf);
232 		return error;
233 	}
234 	path = git_buf_cstr(&buf);
235 
236 	error = git_repository_open(&repo, path);
237 
238 	git_buf_dispose(&buf);
239 
240 	if (error < 0)
241 		return -1;
242 
243 	t->repo = repo;
244 
245 	if (store_refs(t) < 0)
246 		return -1;
247 
248 	t->connected = 1;
249 
250 	return 0;
251 }
252 
local_ls(const git_remote_head *** out,size_t * size,git_transport * transport)253 static int local_ls(const git_remote_head ***out, size_t *size, git_transport *transport)
254 {
255 	transport_local *t = (transport_local *)transport;
256 
257 	if (!t->have_refs) {
258 		git_error_set(GIT_ERROR_NET, "the transport has not yet loaded the refs");
259 		return -1;
260 	}
261 
262 	*out = (const git_remote_head **)t->refs.contents;
263 	*size = t->refs.length;
264 
265 	return 0;
266 }
267 
local_negotiate_fetch(git_transport * transport,git_repository * repo,const git_remote_head * const * refs,size_t count)268 static int local_negotiate_fetch(
269 	git_transport *transport,
270 	git_repository *repo,
271 	const git_remote_head * const *refs,
272 	size_t count)
273 {
274 	transport_local *t = (transport_local*)transport;
275 	git_remote_head *rhead;
276 	unsigned int i;
277 
278 	GIT_UNUSED(refs);
279 	GIT_UNUSED(count);
280 
281 	/* Fill in the loids */
282 	git_vector_foreach(&t->refs, i, rhead) {
283 		git_object *obj;
284 
285 		int error = git_revparse_single(&obj, repo, rhead->name);
286 		if (!error)
287 			git_oid_cpy(&rhead->loid, git_object_id(obj));
288 		else if (error != GIT_ENOTFOUND)
289 			return error;
290 		else
291 			git_error_clear();
292 		git_object_free(obj);
293 	}
294 
295 	return 0;
296 }
297 
local_push_update_remote_ref(git_repository * remote_repo,const char * lref,const char * rref,git_oid * loid,git_oid * roid)298 static int local_push_update_remote_ref(
299 	git_repository *remote_repo,
300 	const char *lref,
301 	const char *rref,
302 	git_oid *loid,
303 	git_oid *roid)
304 {
305 	int error;
306 	git_reference *remote_ref = NULL;
307 
308 	/* check for lhs, if it's empty it means to delete */
309 	if (lref[0] != '\0') {
310 		/* Create or update a ref */
311 		error = git_reference_create(NULL, remote_repo, rref, loid,
312 					     !git_oid_is_zero(roid), NULL);
313 	} else {
314 		/* Delete a ref */
315 		if ((error = git_reference_lookup(&remote_ref, remote_repo, rref)) < 0) {
316 			if (error == GIT_ENOTFOUND)
317 				error = 0;
318 			return error;
319 		}
320 
321 		error = git_reference_delete(remote_ref);
322 		git_reference_free(remote_ref);
323 	}
324 
325 	return error;
326 }
327 
transfer_to_push_transfer(const git_indexer_progress * stats,void * payload)328 static int transfer_to_push_transfer(const git_indexer_progress *stats, void *payload)
329 {
330 	const git_remote_callbacks *cbs = payload;
331 
332 	if (!cbs || !cbs->push_transfer_progress)
333 		return 0;
334 
335 	return cbs->push_transfer_progress(stats->received_objects, stats->total_objects, stats->received_bytes,
336 					   cbs->payload);
337 }
338 
local_push(git_transport * transport,git_push * push,const git_remote_callbacks * cbs)339 static int local_push(
340 	git_transport *transport,
341 	git_push *push,
342 	const git_remote_callbacks *cbs)
343 {
344 	transport_local *t = (transport_local *)transport;
345 	git_repository *remote_repo = NULL;
346 	push_spec *spec;
347 	char *url = NULL;
348 	const char *path;
349 	git_buf buf = GIT_BUF_INIT, odb_path = GIT_BUF_INIT;
350 	int error;
351 	size_t j;
352 
353 	GIT_UNUSED(cbs);
354 
355 	/* 'push->remote->url' may be a url or path; convert to a path */
356 	if ((error = git_path_from_url_or_path(&buf, push->remote->url)) < 0) {
357 		git_buf_dispose(&buf);
358 		return error;
359 	}
360 	path = git_buf_cstr(&buf);
361 
362 	error = git_repository_open(&remote_repo, path);
363 
364 	git_buf_dispose(&buf);
365 
366 	if (error < 0)
367 		return error;
368 
369 	/* We don't currently support pushing locally to non-bare repos. Proper
370 	   non-bare repo push support would require checking configs to see if
371 	   we should override the default 'don't let this happen' behavior.
372 
373 	   Note that this is only an issue when pushing to the current branch,
374 	   but we forbid all pushes just in case */
375 	if (!remote_repo->is_bare) {
376 		error = GIT_EBAREREPO;
377 		git_error_set(GIT_ERROR_INVALID, "local push doesn't (yet) support pushing to non-bare repos.");
378 		goto on_error;
379 	}
380 
381 	if ((error = git_repository_item_path(&odb_path, remote_repo, GIT_REPOSITORY_ITEM_OBJECTS)) < 0
382 		|| (error = git_buf_joinpath(&odb_path, odb_path.ptr, "pack")) < 0)
383 		goto on_error;
384 
385 	error = git_packbuilder_write(push->pb, odb_path.ptr, 0, transfer_to_push_transfer, (void *) cbs);
386 	git_buf_dispose(&odb_path);
387 
388 	if (error < 0)
389 		goto on_error;
390 
391 	push->unpack_ok = 1;
392 
393 	git_vector_foreach(&push->specs, j, spec) {
394 		push_status *status;
395 		const git_error *last;
396 		char *ref = spec->refspec.dst;
397 
398 		status = git__calloc(1, sizeof(push_status));
399 		if (!status)
400 			goto on_error;
401 
402 		status->ref = git__strdup(ref);
403 		if (!status->ref) {
404 			git_push_status_free(status);
405 			goto on_error;
406 		}
407 
408 		error = local_push_update_remote_ref(remote_repo, spec->refspec.src, spec->refspec.dst,
409 			&spec->loid, &spec->roid);
410 
411 		switch (error) {
412 			case GIT_OK:
413 				break;
414 			case GIT_EINVALIDSPEC:
415 				status->msg = git__strdup("funny refname");
416 				break;
417 			case GIT_ENOTFOUND:
418 				status->msg = git__strdup("Remote branch not found to delete");
419 				break;
420 			default:
421 				last = git_error_last();
422 
423 				if (last && last->message)
424 					status->msg = git__strdup(last->message);
425 				else
426 					status->msg = git__strdup("Unspecified error encountered");
427 				break;
428 		}
429 
430 		/* failed to allocate memory for a status message */
431 		if (error < 0 && !status->msg) {
432 			git_push_status_free(status);
433 			goto on_error;
434 		}
435 
436 		/* failed to insert the ref update status */
437 		if ((error = git_vector_insert(&push->status, status)) < 0) {
438 			git_push_status_free(status);
439 			goto on_error;
440 		}
441 	}
442 
443 	if (push->specs.length) {
444 		int flags = t->flags;
445 		url = git__strdup(t->url);
446 
447 		if (!url || t->parent.close(&t->parent) < 0 ||
448 			t->parent.connect(&t->parent, url,
449 			NULL, NULL, NULL, GIT_DIRECTION_PUSH, flags))
450 			goto on_error;
451 	}
452 
453 	error = 0;
454 
455 on_error:
456 	git_repository_free(remote_repo);
457 	git__free(url);
458 
459 	return error;
460 }
461 
462 typedef struct foreach_data {
463 	git_indexer_progress *stats;
464 	git_indexer_progress_cb progress_cb;
465 	void *progress_payload;
466 	git_odb_writepack *writepack;
467 } foreach_data;
468 
foreach_cb(void * buf,size_t len,void * payload)469 static int foreach_cb(void *buf, size_t len, void *payload)
470 {
471 	foreach_data *data = (foreach_data*)payload;
472 
473 	data->stats->received_bytes += len;
474 	return data->writepack->append(data->writepack, buf, len, data->stats);
475 }
476 
477 static const char *counting_objects_fmt = "Counting objects %d\r";
478 static const char *compressing_objects_fmt = "Compressing objects: %.0f%% (%d/%d)";
479 
local_counting(int stage,unsigned int current,unsigned int total,void * payload)480 static int local_counting(int stage, unsigned int current, unsigned int total, void *payload)
481 {
482 	git_buf progress_info = GIT_BUF_INIT;
483 	transport_local *t = payload;
484 	int error;
485 
486 	if (!t->progress_cb)
487 		return 0;
488 
489 	if (stage == GIT_PACKBUILDER_ADDING_OBJECTS) {
490 		git_buf_printf(&progress_info, counting_objects_fmt, current);
491 	} else if (stage == GIT_PACKBUILDER_DELTAFICATION) {
492 		float perc = (((float) current) / total) * 100;
493 		git_buf_printf(&progress_info, compressing_objects_fmt, perc, current, total);
494 		if (current == total)
495 			git_buf_printf(&progress_info, ", done\n");
496 		else
497 			git_buf_putc(&progress_info, '\r');
498 
499 	}
500 
501 	if (git_buf_oom(&progress_info))
502 		return -1;
503 
504 	error = t->progress_cb(git_buf_cstr(&progress_info), (int)git_buf_len(&progress_info), t->message_cb_payload);
505 	git_buf_dispose(&progress_info);
506 
507 	return error;
508 }
509 
foreach_reference_cb(git_reference * reference,void * payload)510 static int foreach_reference_cb(git_reference *reference, void *payload)
511 {
512 	git_revwalk *walk = (git_revwalk *)payload;
513 	int error;
514 
515 	if (git_reference_type(reference) != GIT_REFERENCE_DIRECT) {
516 		git_reference_free(reference);
517 		return 0;
518 	}
519 
520 	error = git_revwalk_hide(walk, git_reference_target(reference));
521 	/* The reference is in the local repository, so the target may not
522 	 * exist on the remote.  It also may not be a commit. */
523 	if (error == GIT_ENOTFOUND || error == GIT_ERROR_INVALID) {
524 		git_error_clear();
525 		error = 0;
526 	}
527 
528 	git_reference_free(reference);
529 
530 	return error;
531 }
532 
local_download_pack(git_transport * transport,git_repository * repo,git_indexer_progress * stats,git_indexer_progress_cb progress_cb,void * progress_payload)533 static int local_download_pack(
534 		git_transport *transport,
535 		git_repository *repo,
536 		git_indexer_progress *stats,
537 		git_indexer_progress_cb progress_cb,
538 		void *progress_payload)
539 {
540 	transport_local *t = (transport_local*)transport;
541 	git_revwalk *walk = NULL;
542 	git_remote_head *rhead;
543 	unsigned int i;
544 	int error = -1;
545 	git_packbuilder *pack = NULL;
546 	git_odb_writepack *writepack = NULL;
547 	git_odb *odb = NULL;
548 	git_buf progress_info = GIT_BUF_INIT;
549 
550 	if ((error = git_revwalk_new(&walk, t->repo)) < 0)
551 		goto cleanup;
552 	git_revwalk_sorting(walk, GIT_SORT_TIME);
553 
554 	if ((error = git_packbuilder_new(&pack, t->repo)) < 0)
555 		goto cleanup;
556 
557 	git_packbuilder_set_callbacks(pack, local_counting, t);
558 
559 	stats->total_objects = 0;
560 	stats->indexed_objects = 0;
561 	stats->received_objects = 0;
562 	stats->received_bytes = 0;
563 
564 	git_vector_foreach(&t->refs, i, rhead) {
565 		git_object *obj;
566 		if ((error = git_object_lookup(&obj, t->repo, &rhead->oid, GIT_OBJECT_ANY)) < 0)
567 			goto cleanup;
568 
569 		if (git_object_type(obj) == GIT_OBJECT_COMMIT) {
570 			/* Revwalker includes only wanted commits */
571 			error = git_revwalk_push(walk, &rhead->oid);
572 		} else {
573 			/* Tag or some other wanted object. Add it on its own */
574 			error = git_packbuilder_insert_recur(pack, &rhead->oid, rhead->name);
575 		}
576 		git_object_free(obj);
577 		if (error < 0)
578 			goto cleanup;
579 	}
580 
581 	if ((error = git_reference_foreach(repo, foreach_reference_cb, walk)))
582 		goto cleanup;
583 
584 	if ((error = git_packbuilder_insert_walk(pack, walk)))
585 		goto cleanup;
586 
587 	if ((error = git_buf_printf(&progress_info, counting_objects_fmt, git_packbuilder_object_count(pack))) < 0)
588 		goto cleanup;
589 
590 	if (t->progress_cb &&
591 	    (error = t->progress_cb(git_buf_cstr(&progress_info), (int)git_buf_len(&progress_info), t->message_cb_payload)) < 0)
592 		goto cleanup;
593 
594 	/* Walk the objects, building a packfile */
595 	if ((error = git_repository_odb__weakptr(&odb, repo)) < 0)
596 		goto cleanup;
597 
598 	/* One last one with the newline */
599 	git_buf_clear(&progress_info);
600 	git_buf_printf(&progress_info, counting_objects_fmt, git_packbuilder_object_count(pack));
601 	if ((error = git_buf_putc(&progress_info, '\n')) < 0)
602 		goto cleanup;
603 
604 	if (t->progress_cb &&
605 	    (error = t->progress_cb(git_buf_cstr(&progress_info), (int)git_buf_len(&progress_info), t->message_cb_payload)) < 0)
606 		goto cleanup;
607 
608 	if ((error = git_odb_write_pack(&writepack, odb, progress_cb, progress_payload)) != 0)
609 		goto cleanup;
610 
611 	/* Write the data to the ODB */
612 	{
613 		foreach_data data = {0};
614 		data.stats = stats;
615 		data.progress_cb = progress_cb;
616 		data.progress_payload = progress_payload;
617 		data.writepack = writepack;
618 
619 		/* autodetect */
620 		git_packbuilder_set_threads(pack, 0);
621 
622 		if ((error = git_packbuilder_foreach(pack, foreach_cb, &data)) != 0)
623 			goto cleanup;
624 	}
625 
626 	error = writepack->commit(writepack, stats);
627 
628 cleanup:
629 	if (writepack) writepack->free(writepack);
630 	git_buf_dispose(&progress_info);
631 	git_packbuilder_free(pack);
632 	git_revwalk_free(walk);
633 	return error;
634 }
635 
local_set_callbacks(git_transport * transport,git_transport_message_cb progress_cb,git_transport_message_cb error_cb,git_transport_certificate_check_cb certificate_check_cb,void * message_cb_payload)636 static int local_set_callbacks(
637 	git_transport *transport,
638 	git_transport_message_cb progress_cb,
639 	git_transport_message_cb error_cb,
640 	git_transport_certificate_check_cb certificate_check_cb,
641 	void *message_cb_payload)
642 {
643 	transport_local *t = (transport_local *)transport;
644 
645 	GIT_UNUSED(certificate_check_cb);
646 
647 	t->progress_cb = progress_cb;
648 	t->error_cb = error_cb;
649 	t->message_cb_payload = message_cb_payload;
650 
651 	return 0;
652 }
653 
local_is_connected(git_transport * transport)654 static int local_is_connected(git_transport *transport)
655 {
656 	transport_local *t = (transport_local *)transport;
657 
658 	return t->connected;
659 }
660 
local_read_flags(git_transport * transport,int * flags)661 static int local_read_flags(git_transport *transport, int *flags)
662 {
663 	transport_local *t = (transport_local *)transport;
664 
665 	*flags = t->flags;
666 
667 	return 0;
668 }
669 
local_cancel(git_transport * transport)670 static void local_cancel(git_transport *transport)
671 {
672 	transport_local *t = (transport_local *)transport;
673 
674 	git_atomic_set(&t->cancelled, 1);
675 }
676 
local_close(git_transport * transport)677 static int local_close(git_transport *transport)
678 {
679 	transport_local *t = (transport_local *)transport;
680 
681 	t->connected = 0;
682 
683 	if (t->repo) {
684 		git_repository_free(t->repo);
685 		t->repo = NULL;
686 	}
687 
688 	if (t->url) {
689 		git__free(t->url);
690 		t->url = NULL;
691 	}
692 
693 	return 0;
694 }
695 
local_free(git_transport * transport)696 static void local_free(git_transport *transport)
697 {
698 	transport_local *t = (transport_local *)transport;
699 
700 	free_heads(&t->refs);
701 
702 	/* Close the transport, if it's still open. */
703 	local_close(transport);
704 
705 	/* Free the transport */
706 	git__free(t);
707 }
708 
709 /**************
710  * Public API *
711  **************/
712 
git_transport_local(git_transport ** out,git_remote * owner,void * param)713 int git_transport_local(git_transport **out, git_remote *owner, void *param)
714 {
715 	int error;
716 	transport_local *t;
717 
718 	GIT_UNUSED(param);
719 
720 	t = git__calloc(1, sizeof(transport_local));
721 	GIT_ERROR_CHECK_ALLOC(t);
722 
723 	t->parent.version = GIT_TRANSPORT_VERSION;
724 	t->parent.set_callbacks = local_set_callbacks;
725 	t->parent.connect = local_connect;
726 	t->parent.negotiate_fetch = local_negotiate_fetch;
727 	t->parent.download_pack = local_download_pack;
728 	t->parent.push = local_push;
729 	t->parent.close = local_close;
730 	t->parent.free = local_free;
731 	t->parent.ls = local_ls;
732 	t->parent.is_connected = local_is_connected;
733 	t->parent.read_flags = local_read_flags;
734 	t->parent.cancel = local_cancel;
735 
736 	if ((error = git_vector_init(&t->refs, 0, NULL)) < 0) {
737 		git__free(t);
738 		return error;
739 	}
740 
741 	t->owner = owner;
742 
743 	*out = (git_transport *) t;
744 
745 	return 0;
746 }
747