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