]> git.proxmox.com Git - libgit2.git/blame - src/transports/local.c
New upstream version 0.28.4+dfsg.1
[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 */
eae0bfdc 7
8f866dae 8#include "common.h"
eae0bfdc 9
8f866dae 10#include "git2/types.h"
8f866dae
CMN
11#include "git2/net.h"
12#include "git2/repository.h"
d6258deb
CMN
13#include "git2/object.h"
14#include "git2/tag.h"
41fb1ca0 15#include "git2/transport.h"
505da062
BS
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"
eae0bfdc 21
505da062
BS
22#include "pack-objects.h"
23#include "refs.h"
84dd3820 24#include "posix.h"
e2580375 25#include "path.h"
26#include "buffer.h"
505da062
BS
27#include "repository.h"
28#include "odb.h"
20858f6e 29#include "push.h"
30#include "remote.h"
07bd3e57 31#include "proxy.h"
8f866dae 32
0a9a38e5 33typedef struct {
4e913309 34 git_transport parent;
613d5eb9 35 git_remote *owner;
41fb1ca0
PK
36 char *url;
37 int direction;
38 int flags;
39 git_atomic cancelled;
0a9a38e5 40 git_repository *repo;
4fd2bda9
CMN
41 git_transport_message_cb progress_cb;
42 git_transport_message_cb error_cb;
43 void *message_cb_payload;
41fb1ca0 44 git_vector refs;
67ba7d20
CMN
45 unsigned connected : 1,
46 have_refs : 1;
4e913309 47} transport_local;
0a9a38e5 48
4c4408c3
CMN
49static 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
f7fcb18f
CMN
56static 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
d88d4311 67static int add_ref(transport_local *t, const char *name)
d6258deb 68{
d6258deb 69 const char peeled[] = "^{}";
04865aa0 70 git_reference *ref, *resolved;
d6258deb 71 git_remote_head *head;
04865aa0 72 git_oid obj_id;
a62053a0
CMN
73 git_object *obj = NULL, *target = NULL;
74 git_buf buf = GIT_BUF_INIT;
b524fe1a 75 int error;
d6258deb 76
04865aa0
CMN
77 if ((error = git_reference_lookup(&ref, t->repo, name)) < 0)
78 return error;
79
80 error = git_reference_resolve(&resolved, ref);
b524fe1a 81 if (error < 0) {
04865aa0 82 git_reference_free(ref);
2a2d1ab0 83 if (!strcmp(name, GIT_HEAD_FILE) && error == GIT_ENOTFOUND) {
25e0b157
RB
84 /* This is actually okay. Empty repos often have a HEAD that
85 * points to a nonexistent "refs/heads/master". */
ac3d33df 86 git_error_clear();
b524fe1a
BS
87 return 0;
88 }
89 return error;
ad4b5beb
CMN
90 }
91
04865aa0
CMN
92 git_oid_cpy(&obj_id, git_reference_target(resolved));
93 git_reference_free(resolved);
94
25e0b157 95 head = git__calloc(1, sizeof(git_remote_head));
ac3d33df 96 GIT_ERROR_CHECK_ALLOC(head);
25e0b157
RB
97
98 head->name = git__strdup(name);
ac3d33df 99 GIT_ERROR_CHECK_ALLOC(head->name);
25e0b157 100
04865aa0
CMN
101 git_oid_cpy(&head->oid, &obj_id);
102
ac3d33df 103 if (git_reference_type(ref) == GIT_REFERENCE_SYMBOLIC) {
04865aa0 104 head->symref_target = git__strdup(git_reference_symbolic_target(ref));
ac3d33df 105 GIT_ERROR_CHECK_ALLOC(head->symref_target);
04865aa0
CMN
106 }
107 git_reference_free(ref);
25e0b157
RB
108
109 if ((error = git_vector_insert(&t->refs, head)) < 0) {
4c4408c3 110 free_head(head);
25e0b157 111 return error;
f201d613 112 }
d6258deb
CMN
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))
a62053a0 116 return 0;
d6258deb 117
ac3d33df 118 if ((error = git_object_lookup(&obj, t->repo, &head->oid, GIT_OBJECT_ANY)) < 0)
25e0b157 119 return error;
d6258deb 120
db1f7e59 121 head = NULL;
122
20858f6e 123 /* If it's not an annotated tag, or if we're mocking
124 * git-receive-pack, just get out */
ac3d33df 125 if (git_object_type(obj) != GIT_OBJECT_TAG ||
20858f6e 126 t->direction != GIT_DIRECTION_FETCH) {
a62053a0
CMN
127 git_object_free(obj);
128 return 0;
129 }
d6258deb
CMN
130
131 /* And if it's a tag, peel it, and add it to the list */
6762fe08 132 head = git__calloc(1, sizeof(git_remote_head));
ac3d33df 133 GIT_ERROR_CHECK_ALLOC(head);
25e0b157 134
6f73e026
JG
135 if (git_buf_join(&buf, 0, name, peeled) < 0) {
136 free_head(head);
a62053a0 137 return -1;
6f73e026 138 }
a62053a0 139 head->name = git_buf_detach(&buf);
d6258deb 140
25e0b157
RB
141 if (!(error = git_tag_peel(&target, (git_tag *)obj))) {
142 git_oid_cpy(&head->oid, git_object_id(target));
79fd4230 143
25e0b157 144 if ((error = git_vector_insert(&t->refs, head)) < 0) {
4c4408c3 145 free_head(head);
25e0b157
RB
146 }
147 }
75abd2b9 148
45e79e37 149 git_object_free(obj);
a62053a0 150 git_object_free(target);
25e0b157
RB
151
152 return error;
d6258deb
CMN
153}
154
d88d4311 155static int store_refs(transport_local *t)
8f866dae 156{
edbaa63a
AS
157 size_t i;
158 git_remote_head *head;
d88d4311 159 git_strarray ref_names = {0};
d6258deb 160
d88d4311 161 assert(t);
7e305056 162
edbaa63a 163 if (git_reference_list(&ref_names, t->repo) < 0)
a62053a0 164 goto on_error;
d6258deb 165
edbaa63a
AS
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
7e305056 175 /* Sort the references first */
d88d4311 176 git__tsort((void **)ref_names.strings, ref_names.count, &git__strcmp_cb);
7e305056 177
20858f6e 178 /* Add HEAD iff direction is fetch */
179 if (t->direction == GIT_DIRECTION_FETCH && add_ref(t, GIT_HEAD_FILE) < 0)
a62053a0 180 goto on_error;
7e305056 181
d88d4311 182 for (i = 0; i < ref_names.count; ++i) {
a62053a0
CMN
183 if (add_ref(t, ref_names.strings[i]) < 0)
184 goto on_error;
7e305056 185 }
d6258deb 186
67ba7d20 187 t->have_refs = 1;
a1515693 188 git_strarray_free(&ref_names);
a62053a0
CMN
189 return 0;
190
191on_error:
41fb1ca0 192 git_vector_free(&t->refs);
d88d4311 193 git_strarray_free(&ref_names);
a62053a0 194 return -1;
d88d4311 195}
0a9a38e5 196
d88d4311
VM
197/*
198 * Try to open the url as a git directory. The direction doesn't
04865aa0 199 * matter in this case because we're calculating the heads ourselves.
d88d4311 200 */
091361f5
PK
201static int local_connect(
202 git_transport *transport,
203 const char *url,
204 git_cred_acquire_cb cred_acquire_cb,
59bccf33 205 void *cred_acquire_payload,
07bd3e57 206 const git_proxy_options *proxy,
091361f5 207 int direction, int flags)
d88d4311
VM
208{
209 git_repository *repo;
210 int error;
211 transport_local *t = (transport_local *) transport;
212 const char *path;
e2580375 213 git_buf buf = GIT_BUF_INIT;
214
091361f5 215 GIT_UNUSED(cred_acquire_cb);
59bccf33 216 GIT_UNUSED(cred_acquire_payload);
07bd3e57 217 GIT_UNUSED(proxy);
091361f5 218
5187b609
CMN
219 if (t->connected)
220 return 0;
221
f7fcb18f
CMN
222 free_heads(&t->refs);
223
41fb1ca0 224 t->url = git__strdup(url);
ac3d33df 225 GIT_ERROR_CHECK_ALLOC(t->url);
41fb1ca0
PK
226 t->direction = direction;
227 t->flags = flags;
d88d4311 228
8bf476ac 229 /* 'url' may be a url or path; convert to a path */
18d7896c 230 if ((error = git_path_from_url_or_path(&buf, url)) < 0) {
ac3d33df 231 git_buf_dispose(&buf);
8bf476ac 232 return error;
a62053a0 233 }
8bf476ac 234 path = git_buf_cstr(&buf);
d88d4311
VM
235
236 error = git_repository_open(&repo, path);
e2580375 237
ac3d33df 238 git_buf_dispose(&buf);
e2580375 239
a62053a0
CMN
240 if (error < 0)
241 return -1;
d88d4311 242
db1f7e59 243 t->repo = repo;
244
a62053a0
CMN
245 if (store_refs(t) < 0)
246 return -1;
d88d4311 247
41fb1ca0
PK
248 t->connected = 1;
249
250 return 0;
251}
252
359dce72 253static int local_ls(const git_remote_head ***out, size_t *size, git_transport *transport)
41fb1ca0
PK
254{
255 transport_local *t = (transport_local *)transport;
41fb1ca0 256
67ba7d20 257 if (!t->have_refs) {
ac3d33df 258 git_error_set(GIT_ERROR_NET, "the transport has not yet loaded the refs");
41fb1ca0
PK
259 return -1;
260 }
261
25e0b157 262 *out = (const git_remote_head **)t->refs.contents;
359dce72 263 *size = t->refs.length;
d88d4311 264
a62053a0 265 return 0;
d6258deb
CMN
266}
267
41fb1ca0
PK
268static int local_negotiate_fetch(
269 git_transport *transport,
270 git_repository *repo,
505da062
BS
271 const git_remote_head * const *refs,
272 size_t count)
a167002f 273{
505da062
BS
274 transport_local *t = (transport_local*)transport;
275 git_remote_head *rhead;
276 unsigned int i;
277
41fb1ca0
PK
278 GIT_UNUSED(refs);
279 GIT_UNUSED(count);
a167002f 280
505da062
BS
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;
9f77b3f6 290 else
ac3d33df 291 git_error_clear();
3dee3655 292 git_object_free(obj);
505da062
BS
293 }
294
295 return 0;
296}
297
20858f6e 298static 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
d5c84f67
CMN
308 /* check for lhs, if it's empty it means to delete */
309 if (lref[0] != '\0') {
20858f6e 310 /* Create or update a ref */
d5c84f67 311 error = git_reference_create(NULL, remote_repo, rref, loid,
659cf202 312 !git_oid_iszero(roid), NULL);
20858f6e 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
d5c84f67 321 error = git_reference_delete(remote_ref);
20858f6e 322 git_reference_free(remote_ref);
323 }
324
d5c84f67 325 return error;
20858f6e 326}
327
4a5b781a
CMN
328static int transfer_to_push_transfer(const git_transfer_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
20858f6e 339static int local_push(
340 git_transport *transport,
8f0104ec
CMN
341 git_push *push,
342 const git_remote_callbacks *cbs)
20858f6e 343{
344 transport_local *t = (transport_local *)transport;
20858f6e 345 git_repository *remote_repo = NULL;
346 push_spec *spec;
347 char *url = NULL;
4e974c97 348 const char *path;
4a5b781a 349 git_buf buf = GIT_BUF_INIT, odb_path = GIT_BUF_INIT;
20858f6e 350 int error;
20858f6e 351 size_t j;
352
8f0104ec
CMN
353 GIT_UNUSED(cbs);
354
8bf476ac 355 /* 'push->remote->url' may be a url or path; convert to a path */
18d7896c 356 if ((error = git_path_from_url_or_path(&buf, push->remote->url)) < 0) {
ac3d33df 357 git_buf_dispose(&buf);
8bf476ac 358 return error;
4e974c97 359 }
8bf476ac 360 path = git_buf_cstr(&buf);
4e974c97
GD
361
362 error = git_repository_open(&remote_repo, path);
363
ac3d33df 364 git_buf_dispose(&buf);
4e974c97
GD
365
366 if (error < 0)
20858f6e 367 return error;
368
1fed6b07 369 /* We don't currently support pushing locally to non-bare repos. Proper
20858f6e 370 non-bare repo push support would require checking configs to see if
81c0fb08
CMN
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 */
20858f6e 375 if (!remote_repo->is_bare) {
f42d546c 376 error = GIT_EBAREREPO;
ac3d33df 377 git_error_set(GIT_ERROR_INVALID, "local push doesn't (yet) support pushing to non-bare repos.");
20858f6e 378 goto on_error;
379 }
380
c5f3da96
PS
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)
20858f6e 383 goto on_error;
384
4a5b781a 385 error = git_packbuilder_write(push->pb, odb_path.ptr, 0, transfer_to_push_transfer, (void *) cbs);
ac3d33df 386 git_buf_dispose(&odb_path);
4a5b781a
CMN
387
388 if (error < 0)
389 goto on_error;
20858f6e 390
391 push->unpack_ok = 1;
392
393 git_vector_foreach(&push->specs, j, spec) {
394 push_status *status;
395 const git_error *last;
aad638f3 396 char *ref = spec->refspec.dst;
20858f6e 397
392702ee 398 status = git__calloc(1, sizeof(push_status));
20858f6e 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
aad638f3 408 error = local_push_update_remote_ref(remote_repo, spec->refspec.src, spec->refspec.dst,
20858f6e 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:
ac3d33df 421 last = git_error_last();
20858f6e 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,
07bd3e57 449 NULL, NULL, NULL, GIT_DIRECTION_PUSH, flags))
20858f6e 450 goto on_error;
451 }
452
453 error = 0;
454
455on_error:
456 git_repository_free(remote_repo);
457 git__free(url);
458
459 return error;
460}
461
505da062
BS
462typedef struct foreach_data {
463 git_transfer_progress *stats;
48e60ae7 464 git_transfer_progress_cb progress_cb;
505da062
BS
465 void *progress_payload;
466 git_odb_writepack *writepack;
467} foreach_data;
468
469static 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;
a6154f21 474 return data->writepack->append(data->writepack, buf, len, data->stats);
505da062
BS
475}
476
4fd2bda9 477static const char *counting_objects_fmt = "Counting objects %d\r";
8cec2b8a
CMN
478static const char *compressing_objects_fmt = "Compressing objects: %.0f%% (%d/%d)";
479
480static 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;
542a7de0 484 int error;
8cec2b8a
CMN
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
542a7de0 504 error = t->progress_cb(git_buf_cstr(&progress_info), git_buf_len(&progress_info), t->message_cb_payload);
ac3d33df 505 git_buf_dispose(&progress_info);
542a7de0
CMN
506
507 return error;
8cec2b8a 508}
4fd2bda9 509
eae0bfdc
PP
510static int foreach_reference_cb(git_reference *reference, void *payload)
511{
512 git_revwalk *walk = (git_revwalk *)payload;
4b3ec53c
XL
513 int error;
514
ac3d33df 515 if (git_reference_type(reference) != GIT_REFERENCE_DIRECT) {
4b3ec53c
XL
516 git_reference_free(reference);
517 return 0;
518 }
eae0bfdc 519
4b3ec53c 520 error = git_revwalk_hide(walk, git_reference_target(reference));
eae0bfdc
PP
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. */
ac3d33df
JK
523 if (error == GIT_ENOTFOUND || error == GIT_ERROR_INVALID) {
524 git_error_clear();
eae0bfdc
PP
525 error = 0;
526 }
527
528 git_reference_free(reference);
529
530 return error;
531}
532
505da062
BS
533static int local_download_pack(
534 git_transport *transport,
535 git_repository *repo,
536 git_transfer_progress *stats,
48e60ae7 537 git_transfer_progress_cb progress_cb,
505da062
BS
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;
505da062
BS
545 git_packbuilder *pack = NULL;
546 git_odb_writepack *writepack = NULL;
90207709 547 git_odb *odb = NULL;
4fd2bda9 548 git_buf progress_info = GIT_BUF_INIT;
505da062
BS
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
8cec2b8a
CMN
557 git_packbuilder_set_callbacks(pack, local_counting, t);
558
505da062
BS
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;
ac3d33df 566 if ((error = git_object_lookup(&obj, t->repo, &rhead->oid, GIT_OBJECT_ANY)) < 0)
505da062
BS
567 goto cleanup;
568
ac3d33df 569 if (git_object_type(obj) == GIT_OBJECT_COMMIT) {
505da062
BS
570 /* Revwalker includes only wanted commits */
571 error = git_revwalk_push(walk, &rhead->oid);
505da062 572 } else {
c84a9dd2
CMN
573 /* Tag or some other wanted object. Add it on its own */
574 error = git_packbuilder_insert_recur(pack, &rhead->oid, rhead->name);
505da062 575 }
0cb16fe9 576 git_object_free(obj);
e68b31a1
CMN
577 if (error < 0)
578 goto cleanup;
505da062
BS
579 }
580
eae0bfdc
PP
581 if ((error = git_reference_foreach(repo, foreach_reference_cb, walk)))
582 goto cleanup;
583
e68b31a1
CMN
584 if ((error = git_packbuilder_insert_walk(pack, walk)))
585 goto cleanup;
586
4fd2bda9
CMN
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), git_buf_len(&progress_info), t->message_cb_payload)) < 0)
592 goto cleanup;
593
505da062 594 /* Walk the objects, building a packfile */
90207709
BS
595 if ((error = git_repository_odb__weakptr(&odb, repo)) < 0)
596 goto cleanup;
505da062 597
4fd2bda9
CMN
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), git_buf_len(&progress_info), t->message_cb_payload)) < 0)
606 goto cleanup;
607
25e0b157 608 if ((error = git_odb_write_pack(&writepack, odb, progress_cb, progress_payload)) != 0)
90207709 609 goto cleanup;
505da062
BS
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
0ef54a63
CMN
619 /* autodetect */
620 git_packbuilder_set_threads(pack, 0);
621
25e0b157 622 if ((error = git_packbuilder_foreach(pack, foreach_cb, &data)) != 0)
505da062
BS
623 goto cleanup;
624 }
e68b31a1 625
505da062
BS
626 error = writepack->commit(writepack, stats);
627
628cleanup:
629 if (writepack) writepack->free(writepack);
ac3d33df 630 git_buf_dispose(&progress_info);
505da062
BS
631 git_packbuilder_free(pack);
632 git_revwalk_free(walk);
633 return error;
a167002f
MS
634}
635
4fd2bda9
CMN
636static 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
613d5eb9 654static int local_is_connected(git_transport *transport)
41fb1ca0
PK
655{
656 transport_local *t = (transport_local *)transport;
657
613d5eb9 658 return t->connected;
41fb1ca0
PK
659}
660
661static 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
670static void local_cancel(git_transport *transport)
671{
672 transport_local *t = (transport_local *)transport;
673
674 git_atomic_set(&t->cancelled, 1);
675}
676
854eccbb 677static int local_close(git_transport *transport)
d6258deb 678{
d88d4311
VM
679 transport_local *t = (transport_local *)transport;
680
41fb1ca0 681 t->connected = 0;
20858f6e 682
683 if (t->repo) {
684 git_repository_free(t->repo);
685 t->repo = NULL;
686 }
687
20858f6e 688 if (t->url) {
689 git__free(t->url);
690 t->url = NULL;
691 }
d88d4311 692
a62053a0 693 return 0;
8f866dae
CMN
694}
695
d6258deb
CMN
696static void local_free(git_transport *transport)
697{
20858f6e 698 transport_local *t = (transport_local *)transport;
9728cfde 699
f7fcb18f 700 free_heads(&t->refs);
edbaa63a 701
20858f6e 702 /* Close the transport, if it's still open. */
703 local_close(transport);
a2888919 704
20858f6e 705 /* Free the transport */
3286c408 706 git__free(t);
d6258deb
CMN
707}
708
8f866dae
CMN
709/**************
710 * Public API *
711 **************/
712
613d5eb9 713int git_transport_local(git_transport **out, git_remote *owner, void *param)
8f866dae 714{
6f73e026 715 int error;
4e913309
CMN
716 transport_local *t;
717
41fb1ca0
PK
718 GIT_UNUSED(param);
719
10711769 720 t = git__calloc(1, sizeof(transport_local));
ac3d33df 721 GIT_ERROR_CHECK_ALLOC(t);
4e913309 722
10711769 723 t->parent.version = GIT_TRANSPORT_VERSION;
4fd2bda9 724 t->parent.set_callbacks = local_set_callbacks;
4e913309 725 t->parent.connect = local_connect;
a167002f 726 t->parent.negotiate_fetch = local_negotiate_fetch;
505da062 727 t->parent.download_pack = local_download_pack;
20858f6e 728 t->parent.push = local_push;
4e913309
CMN
729 t->parent.close = local_close;
730 t->parent.free = local_free;
41fb1ca0
PK
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;
4e913309 735
6f73e026
JG
736 if ((error = git_vector_init(&t->refs, 0, NULL)) < 0) {
737 git__free(t);
738 return error;
739 }
740
613d5eb9
PK
741 t->owner = owner;
742
4e913309 743 *out = (git_transport *) t;
8f866dae 744
a62053a0 745 return 0;
8f866dae 746}