File Coverage

deps/libgit2/src/transports/local.c
Criterion Covered Total %
statement 147 347 42.3
branch 42 170 24.7
condition n/a
subroutine n/a
pod n/a
total 189 517 36.5


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