slight code simplification, seeing that clear_meta(NULL) is fine
[got-portable.git] / lib / dump.c
blob8481193cde399b11e51efd92ba078b61ca73d833
1 /*
2 * Copyright (c) 2023 Omar Polo <op@openbsd.org>
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 #include "got_compat.h"
19 #include <sys/queue.h>
20 #include <sys/types.h>
22 #include <ctype.h>
23 #include <limits.h>
24 #include <stdint.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <time.h>
30 #include "got_error.h"
31 #include "got_cancel.h"
32 #include "got_reference.h"
33 #include "got_repository.h"
34 #include "got_repository_admin.h" /* XXX for pack_progress */
35 #include "got_object.h"
36 #include "got_opentemp.h"
37 #include "got_repository_dump.h"
39 #include "got_lib_delta.h"
40 #include "got_lib_hash.h"
41 #include "got_lib_object.h"
42 #include "got_lib_object_idset.h"
43 #include "got_lib_ratelimit.h"
44 #include "got_lib_pack_create.h"
46 #define GIT_BUNDLE_SIGNATURE_V2 "# v2 git bundle"
47 #define GIT_BUNDLE_SIGNATURE_V3 "# v3 git bundle"
49 struct idvec {
50 struct got_object_id **ids;
51 size_t len;
52 size_t size;
55 static const struct got_error *
56 idvec_push(struct idvec *v, struct got_object_id *id)
58 size_t newsize;
59 void *t;
61 if (v->len == v->size) {
62 newsize = v->size + 8;
63 t = reallocarray(v->ids, newsize, sizeof(*v->ids));
64 if (t == NULL)
65 return got_error_from_errno("reallocarray");
66 v->ids = t;
67 v->size = newsize;
70 v->ids[v->len++] = id;
71 return NULL;
74 static void
75 idvec_free(struct idvec *v)
77 size_t i;
79 for (i = 0; i < v->len; ++i)
80 free(v->ids[i]);
81 free(v->ids);
84 const struct got_error *
85 got_repo_dump(FILE *out, struct got_reflist_head *include_refs,
86 struct got_reflist_head *exclude_refs, struct got_repository *repo,
87 got_pack_progress_cb progress_cb, void *progress_arg,
88 got_cancel_cb cancel_cb, void *cancel_arg)
90 const struct got_error *err = NULL;
91 struct got_ratelimit rl;
92 struct got_object_id packhash;
93 FILE *delta_cache = NULL;
94 struct got_reflist_entry *e;
95 struct got_object_id *id = NULL;
96 struct got_commit_object *commit = NULL;
97 struct idvec ours, theirs;
98 char *nl, *s, *hex, *logmsg = NULL;
99 const char *refname, *signature;
100 enum got_hash_algorithm algo;
101 int r;
103 algo = got_repo_get_object_format(repo);
104 switch (algo) {
105 case GOT_HASH_SHA1:
106 signature = GIT_BUNDLE_SIGNATURE_V2;
107 break;
108 case GOT_HASH_SHA256:
109 signature = GIT_BUNDLE_SIGNATURE_V3;
110 break;
111 default:
112 return got_error(GOT_ERR_OBJECT_FORMAT);
115 got_ratelimit_init(&rl, 0, 500);
117 memset(&ours, 0, sizeof(ours));
118 memset(&theirs, 0, sizeof(theirs));
120 r = fprintf(out, "%s\n", signature);
121 if (r != strlen(GIT_BUNDLE_SIGNATURE_V2) + 1)
122 return got_ferror(out, GOT_ERR_IO);
124 if (algo == GOT_HASH_SHA256)
125 fprintf(out, "@object-format=sha256\n");
127 TAILQ_FOREACH(e, exclude_refs, entry) {
128 err = got_ref_resolve(&id, repo, e->ref);
129 if (err)
130 goto done;
132 idvec_push(&theirs, id);
133 if (err)
134 goto done;
136 err = got_object_open_as_commit(&commit, repo, id);
137 if (err)
138 goto done;
140 err = got_object_commit_get_logmsg(&logmsg, commit);
141 if (err)
142 goto done;
144 s = logmsg;
145 while (isspace((unsigned char)*s))
146 s++;
147 nl = strchr(s, '\n');
148 if (nl)
149 *nl = '\0';
151 err = got_object_id_str(&hex, id);
152 if (err)
153 goto done;
154 fprintf(out, "-%s %s\n", hex, s);
155 free(hex);
157 got_object_commit_close(commit);
158 commit = NULL;
160 free(logmsg);
161 logmsg = NULL;
164 TAILQ_FOREACH(e, include_refs, entry) {
165 err = got_ref_resolve(&id, repo, e->ref);
166 if (err)
167 goto done;
169 err = idvec_push(&ours, id);
170 if (err)
171 goto done;
173 refname = got_ref_get_name(e->ref);
175 err = got_object_id_str(&hex, id);
176 if (err)
177 goto done;
178 fprintf(out, "%s %s\n", hex, refname);
179 free(hex);
182 if (fputc('\n', out) == EOF || fflush(out) == EOF) {
183 err = got_ferror(out, GOT_ERR_IO);
184 goto done;
187 delta_cache = got_opentemp();
188 if (delta_cache == NULL) {
189 err = got_error_from_errno("got_opentemp");
190 goto done;
193 err = got_pack_create(&packhash, fileno(out), delta_cache,
194 theirs.ids, theirs.len, ours.ids, ours.len,
195 repo, 0, 0, 0, progress_cb, progress_arg, &rl,
196 cancel_cb, cancel_arg);
198 done:
199 idvec_free(&ours);
200 idvec_free(&theirs);
201 if (commit)
202 got_object_commit_close(commit);
203 if (delta_cache && fclose(delta_cache) == EOF && err == NULL)
204 err = got_error_from_errno("fclose");
205 return err;